feat(27-shipment-tracking-backend): infrastruktura sledzenia przesylek — statusy, tracking services, cron handler
Dwupoziomowy system statusow dostawy (normalized + raw z API), implementacje trackingu dla InPost ShipX, Apaczka i Allegro WZA, cron handler odpytujacy aktywne przesylki co 15 minut. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
128
src/Modules/Shipments/InpostTrackingService.php
Normal file
128
src/Modules/Shipments/InpostTrackingService.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Shipments;
|
||||
|
||||
use App\Modules\Settings\InpostIntegrationRepository;
|
||||
use Throwable;
|
||||
|
||||
final class InpostTrackingService implements ShipmentTrackingInterface
|
||||
{
|
||||
private const API_BASE_PRODUCTION = 'https://api-shipx-pl.easypack24.net/v1';
|
||||
private const API_BASE_SANDBOX = 'https://sandbox-api-shipx-pl.easypack24.net/v1';
|
||||
|
||||
public function __construct(
|
||||
private readonly InpostIntegrationRepository $inpostRepository
|
||||
) {
|
||||
}
|
||||
|
||||
public function supports(string $provider): bool
|
||||
{
|
||||
return $provider === 'inpost';
|
||||
}
|
||||
|
||||
public function getDeliveryStatus(array $package): ?array
|
||||
{
|
||||
$shipmentId = trim((string) ($package['shipment_id'] ?? ''));
|
||||
if ($shipmentId === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->fetchStatus($shipmentId);
|
||||
}
|
||||
|
||||
private function fetchStatus(string $shipmentId): ?array
|
||||
{
|
||||
try {
|
||||
$token = $this->resolveToken();
|
||||
if ($token === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$settings = $this->inpostRepository->getSettings();
|
||||
$env = (string) ($settings['environment'] ?? 'sandbox');
|
||||
$url = $this->apiBaseUrl($env) . '/shipments/' . rawurlencode($shipmentId);
|
||||
|
||||
$response = $this->apiRequest($url, $token);
|
||||
$rawStatus = strtolower(trim((string) ($response['status'] ?? '')));
|
||||
|
||||
return $rawStatus !== '' ? [
|
||||
'status' => DeliveryStatus::normalize('inpost', $rawStatus),
|
||||
'status_raw' => $rawStatus,
|
||||
'description' => DeliveryStatus::description('inpost', $rawStatus),
|
||||
] : null;
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveToken(): ?string
|
||||
{
|
||||
$token = $this->inpostRepository->getDecryptedToken();
|
||||
return ($token !== null && trim($token) !== '') ? trim($token) : null;
|
||||
}
|
||||
|
||||
private function apiBaseUrl(string $environment): string
|
||||
{
|
||||
return strtolower(trim($environment)) === 'production'
|
||||
? self::API_BASE_PRODUCTION
|
||||
: self::API_BASE_SANDBOX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function apiRequest(string $url, string $token): array
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
if ($ch === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$opts = [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_SSL_VERIFYHOST => 2,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: Bearer ' . $token,
|
||||
'Accept: application/json',
|
||||
],
|
||||
];
|
||||
|
||||
$caPath = $this->getCaBundlePath();
|
||||
if ($caPath !== null) {
|
||||
$opts[CURLOPT_CAINFO] = $caPath;
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $opts);
|
||||
$body = curl_exec($ch);
|
||||
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$ch = null;
|
||||
|
||||
if ($body === false || $httpCode < 200 || $httpCode >= 300) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$json = json_decode((string) $body, true);
|
||||
return is_array($json) ? $json : [];
|
||||
}
|
||||
|
||||
private function getCaBundlePath(): ?string
|
||||
{
|
||||
$candidates = [
|
||||
(string) ($_ENV['CURL_CA_BUNDLE_PATH'] ?? ''),
|
||||
(string) ini_get('curl.cainfo'),
|
||||
'C:/xampp/apache/bin/curl-ca-bundle.crt',
|
||||
'C:/xampp/php/extras/ssl/cacert.pem',
|
||||
'/etc/ssl/certs/ca-certificates.crt',
|
||||
];
|
||||
foreach ($candidates as $path) {
|
||||
if ($path !== '' && is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user