|
|
|
|
@@ -0,0 +1,577 @@
|
|
|
|
|
<?php
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Modules\Shipments;
|
|
|
|
|
|
|
|
|
|
use App\Core\Exceptions\IntegrationConfigException;
|
|
|
|
|
use App\Core\Exceptions\ShipmentException;
|
|
|
|
|
use App\Modules\Orders\OrdersRepository;
|
|
|
|
|
use App\Modules\Settings\CompanySettingsRepository;
|
|
|
|
|
use App\Modules\Settings\InpostIntegrationRepository;
|
|
|
|
|
use RuntimeException;
|
|
|
|
|
use Throwable;
|
|
|
|
|
|
|
|
|
|
final class InpostShipmentService implements ShipmentProviderInterface
|
|
|
|
|
{
|
|
|
|
|
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,
|
|
|
|
|
private readonly ShipmentPackageRepository $packages,
|
|
|
|
|
private readonly CompanySettingsRepository $companySettings,
|
|
|
|
|
private readonly OrdersRepository $ordersRepository
|
|
|
|
|
) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function code(): string
|
|
|
|
|
{
|
|
|
|
|
return 'inpost';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<int, array<string, mixed>>
|
|
|
|
|
*/
|
|
|
|
|
public function getDeliveryServices(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
['id' => 'inpost_locker_standard', 'name' => 'InPost Paczkomat - Standard', 'type' => 'locker'],
|
|
|
|
|
['id' => 'inpost_courier_standard', 'name' => 'InPost Kurier - Standard', 'type' => 'courier'],
|
|
|
|
|
['id' => 'inpost_courier_express', 'name' => 'InPost Kurier - Express', 'type' => 'courier'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $formData
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
public function createShipment(int $orderId, array $formData): array
|
|
|
|
|
{
|
|
|
|
|
$order = $this->ordersRepository->findDetails($orderId);
|
|
|
|
|
if ($order === null) {
|
|
|
|
|
throw new ShipmentException('Zamowienie nie znalezione.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$token = $this->resolveToken();
|
|
|
|
|
$settings = $this->inpostRepository->getSettings();
|
|
|
|
|
$organizationId = trim((string) ($settings['organization_id'] ?? ''));
|
|
|
|
|
if ($organizationId === '') {
|
|
|
|
|
throw new IntegrationConfigException('Brak organization_id w konfiguracji InPost.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$company = $this->companySettings->getSettings();
|
|
|
|
|
$sender = $this->companySettings->getSenderAddress();
|
|
|
|
|
$this->validateSenderAddress($sender);
|
|
|
|
|
|
|
|
|
|
$receiver = $this->buildReceiverFromOrder($order, $formData);
|
|
|
|
|
$senderPayload = $this->buildSenderPayload($sender);
|
|
|
|
|
|
|
|
|
|
$serviceType = $this->resolveServiceType($formData, $settings);
|
|
|
|
|
$parcelPayload = $this->buildParcelPayload($formData, $settings, $company, $serviceType);
|
|
|
|
|
|
|
|
|
|
$apiPayload = [
|
|
|
|
|
'receiver' => $receiver,
|
|
|
|
|
'sender' => $senderPayload,
|
|
|
|
|
'parcels' => [$parcelPayload],
|
|
|
|
|
'service' => $serviceType,
|
|
|
|
|
'reference' => $this->buildReference($order, $orderId),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$codAmount = (float) ($formData['cod_amount'] ?? 0);
|
|
|
|
|
if ($codAmount > 0) {
|
|
|
|
|
$apiPayload['cod'] = [
|
|
|
|
|
'amount' => number_format($codAmount, 2, '.', ''),
|
|
|
|
|
'currency' => strtoupper(trim((string) ($formData['cod_currency'] ?? 'PLN'))),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$insuranceAmount = (float) ($formData['insurance_amount'] ?? 0);
|
|
|
|
|
if ($insuranceAmount <= 0 && !empty($settings['auto_insurance_value'])) {
|
|
|
|
|
$orderData = is_array($order['order'] ?? null) ? $order['order'] : [];
|
|
|
|
|
$totalWithTax = (float) ($orderData['total_with_tax'] ?? 0);
|
|
|
|
|
if ($totalWithTax > 0) {
|
|
|
|
|
$insuranceAmount = $totalWithTax;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($insuranceAmount > 0) {
|
|
|
|
|
$apiPayload['insurance'] = [
|
|
|
|
|
'amount' => number_format($insuranceAmount, 2, '.', ''),
|
|
|
|
|
'currency' => strtoupper(trim((string) ($formData['insurance_currency'] ?? 'PLN'))),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$labelFormat = trim((string) ($formData['label_format'] ?? ($settings['label_format'] ?? 'Pdf')));
|
|
|
|
|
|
|
|
|
|
$packageId = $this->packages->create([
|
|
|
|
|
'order_id' => $orderId,
|
|
|
|
|
'provider' => 'inpost',
|
|
|
|
|
'delivery_method_id' => $serviceType,
|
|
|
|
|
'credentials_id' => null,
|
|
|
|
|
'command_id' => null,
|
|
|
|
|
'status' => 'pending',
|
|
|
|
|
'carrier_id' => 'inpost',
|
|
|
|
|
'package_type' => $parcelPayload['dimensions'] ? 'PACKAGE' : 'LOCKER',
|
|
|
|
|
'weight_kg' => isset($parcelPayload['weight']['amount']) ? (float) $parcelPayload['weight']['amount'] : null,
|
|
|
|
|
'length_cm' => isset($parcelPayload['dimensions']['length']) ? (float) $parcelPayload['dimensions']['length'] : null,
|
|
|
|
|
'width_cm' => isset($parcelPayload['dimensions']['width']) ? (float) $parcelPayload['dimensions']['width'] : null,
|
|
|
|
|
'height_cm' => isset($parcelPayload['dimensions']['height']) ? (float) $parcelPayload['dimensions']['height'] : null,
|
|
|
|
|
'insurance_amount' => $insuranceAmount > 0 ? $insuranceAmount : null,
|
|
|
|
|
'insurance_currency' => $insuranceAmount > 0 ? strtoupper(trim((string) ($formData['insurance_currency'] ?? 'PLN'))) : null,
|
|
|
|
|
'cod_amount' => $codAmount > 0 ? $codAmount : null,
|
|
|
|
|
'cod_currency' => $codAmount > 0 ? strtoupper(trim((string) ($formData['cod_currency'] ?? 'PLN'))) : null,
|
|
|
|
|
'label_format' => $labelFormat,
|
|
|
|
|
'receiver_point_id' => trim((string) ($formData['receiver_point_id'] ?? '')),
|
|
|
|
|
'sender_point_id' => trim((string) ($formData['sender_point_id'] ?? '')),
|
|
|
|
|
'reference_number' => $apiPayload['reference'],
|
|
|
|
|
'payload_json' => $apiPayload,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$env = (string) ($settings['environment'] ?? 'sandbox');
|
|
|
|
|
$url = $this->apiBaseUrl($env) . '/organizations/' . rawurlencode($organizationId) . '/shipments';
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$response = $this->apiRequest('POST', $url, $token, $apiPayload);
|
|
|
|
|
} catch (Throwable $exception) {
|
|
|
|
|
$this->packages->update($packageId, [
|
|
|
|
|
'status' => 'error',
|
|
|
|
|
'error_message' => $exception->getMessage(),
|
|
|
|
|
]);
|
|
|
|
|
throw $exception;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$shipmentId = trim((string) ($response['id'] ?? ''));
|
|
|
|
|
$trackingNumber = trim((string) ($response['tracking_number'] ?? ''));
|
|
|
|
|
$status = strtolower(trim((string) ($response['status'] ?? 'created')));
|
|
|
|
|
|
|
|
|
|
$this->packages->update($packageId, [
|
|
|
|
|
'shipment_id' => $shipmentId !== '' ? $shipmentId : null,
|
|
|
|
|
'tracking_number' => $trackingNumber !== '' ? $trackingNumber : null,
|
|
|
|
|
'status' => $status === 'created' || $status === 'confirmed' ? 'created' : 'pending',
|
|
|
|
|
'payload_json' => $response,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'package_id' => $packageId,
|
|
|
|
|
'command_id' => $shipmentId,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
public function checkCreationStatus(int $packageId): array
|
|
|
|
|
{
|
|
|
|
|
$package = $this->packages->findById($packageId);
|
|
|
|
|
if ($package === null) {
|
|
|
|
|
throw new ShipmentException('Paczka nie znaleziona.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$shipmentId = trim((string) ($package['shipment_id'] ?? ''));
|
|
|
|
|
if ($shipmentId === '') {
|
|
|
|
|
return ['status' => 'error', 'error' => 'Brak shipment_id — przesylka nie zostala utworzona.'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$token = $this->resolveToken();
|
|
|
|
|
$settings = $this->inpostRepository->getSettings();
|
|
|
|
|
$env = (string) ($settings['environment'] ?? 'sandbox');
|
|
|
|
|
$url = $this->apiBaseUrl($env) . '/shipments/' . rawurlencode($shipmentId);
|
|
|
|
|
|
|
|
|
|
$response = $this->apiRequest('GET', $url, $token);
|
|
|
|
|
$status = strtolower(trim((string) ($response['status'] ?? '')));
|
|
|
|
|
$trackingNumber = trim((string) ($response['tracking_number'] ?? ''));
|
|
|
|
|
|
|
|
|
|
if (in_array($status, ['created', 'confirmed', 'dispatched', 'collected', 'delivered'], true)) {
|
|
|
|
|
$this->packages->update($packageId, [
|
|
|
|
|
'status' => 'created',
|
|
|
|
|
'tracking_number' => $trackingNumber !== '' ? $trackingNumber : null,
|
|
|
|
|
'payload_json' => $response,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'status' => 'created',
|
|
|
|
|
'shipment_id' => $shipmentId,
|
|
|
|
|
'tracking_number' => $trackingNumber,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (in_array($status, ['cancelled', 'expired'], true)) {
|
|
|
|
|
$this->packages->update($packageId, [
|
|
|
|
|
'status' => 'error',
|
|
|
|
|
'error_message' => 'Przesylka anulowana/wygasla (status: ' . $status . ')',
|
|
|
|
|
'payload_json' => $response,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return ['status' => 'error', 'error' => 'Przesylka: ' . $status];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ['status' => 'in_progress'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
public function downloadLabel(int $packageId, string $storagePath): array
|
|
|
|
|
{
|
|
|
|
|
$package = $this->packages->findById($packageId);
|
|
|
|
|
if ($package === null) {
|
|
|
|
|
throw new ShipmentException('Paczka nie znaleziona.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$shipmentId = trim((string) ($package['shipment_id'] ?? ''));
|
|
|
|
|
if ($shipmentId === '') {
|
|
|
|
|
throw new ShipmentException('Przesylka nie zostala jeszcze utworzona.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$token = $this->resolveToken();
|
|
|
|
|
$settings = $this->inpostRepository->getSettings();
|
|
|
|
|
$env = (string) ($settings['environment'] ?? 'sandbox');
|
|
|
|
|
$labelFormat = trim((string) ($package['label_format'] ?? ($settings['label_format'] ?? 'Pdf')));
|
|
|
|
|
|
|
|
|
|
$url = $this->apiBaseUrl($env) . '/shipments/' . rawurlencode($shipmentId) . '/label';
|
|
|
|
|
$queryParams = ['format' => $labelFormat, 'type' => 'normal'];
|
|
|
|
|
$url .= '?' . http_build_query($queryParams);
|
|
|
|
|
|
|
|
|
|
$binary = $this->apiRequestRaw('GET', $url, $token);
|
|
|
|
|
|
|
|
|
|
$dir = rtrim($storagePath, '/\\') . '/labels';
|
|
|
|
|
if (!is_dir($dir)) {
|
|
|
|
|
mkdir($dir, 0775, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$ext = strtolower($labelFormat) === 'zpl' ? 'zpl' : 'pdf';
|
|
|
|
|
$filename = 'label_' . $packageId . '_inpost_' . $shipmentId . '.' . $ext;
|
|
|
|
|
$filePath = $dir . '/' . $filename;
|
|
|
|
|
file_put_contents($filePath, $binary);
|
|
|
|
|
|
|
|
|
|
$updateFields = [
|
|
|
|
|
'status' => 'label_ready',
|
|
|
|
|
'label_path' => 'labels/' . $filename,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if (trim((string) ($package['tracking_number'] ?? '')) === '') {
|
|
|
|
|
try {
|
|
|
|
|
$detailsUrl = $this->apiBaseUrl($env) . '/shipments/' . rawurlencode($shipmentId);
|
|
|
|
|
$details = $this->apiRequest('GET', $detailsUrl, $token);
|
|
|
|
|
$trackingNumber = trim((string) ($details['tracking_number'] ?? ''));
|
|
|
|
|
if ($trackingNumber !== '') {
|
|
|
|
|
$updateFields['tracking_number'] = $trackingNumber;
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->packages->update($packageId, $updateFields);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'label_path' => 'labels/' . $filename,
|
|
|
|
|
'full_path' => $filePath,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function resolveToken(): string
|
|
|
|
|
{
|
|
|
|
|
$token = $this->inpostRepository->getDecryptedToken();
|
|
|
|
|
if ($token === null || trim($token) === '') {
|
|
|
|
|
throw new IntegrationConfigException('Brak tokenu API InPost. Skonfiguruj w Ustawienia > Integracje > InPost.');
|
|
|
|
|
}
|
|
|
|
|
return trim($token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function apiBaseUrl(string $environment): string
|
|
|
|
|
{
|
|
|
|
|
return strtolower(trim($environment)) === 'production'
|
|
|
|
|
? self::API_BASE_PRODUCTION
|
|
|
|
|
: self::API_BASE_SANDBOX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed>|null $body
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
private function apiRequest(string $method, string $url, string $token, ?array $body = null): array
|
|
|
|
|
{
|
|
|
|
|
$binary = $this->apiRequestRaw($method, $url, $token, $body, 'application/json');
|
|
|
|
|
$json = json_decode($binary, true);
|
|
|
|
|
if (!is_array($json)) {
|
|
|
|
|
throw new ShipmentException('Nieprawidlowa odpowiedz JSON z InPost API.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $json;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed>|null $body
|
|
|
|
|
*/
|
|
|
|
|
private function apiRequestRaw(
|
|
|
|
|
string $method,
|
|
|
|
|
string $url,
|
|
|
|
|
string $token,
|
|
|
|
|
?array $body = null,
|
|
|
|
|
string $accept = 'application/pdf'
|
|
|
|
|
): string {
|
|
|
|
|
$ch = curl_init($url);
|
|
|
|
|
if ($ch === false) {
|
|
|
|
|
throw new ShipmentException('Nie udalo sie zainicjowac polaczenia z InPost API.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$headers = [
|
|
|
|
|
'Authorization: Bearer ' . $token,
|
|
|
|
|
'Accept: ' . $accept,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$opts = [
|
|
|
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
|
|
|
CURLOPT_TIMEOUT => 30,
|
|
|
|
|
CURLOPT_CONNECTTIMEOUT => 10,
|
|
|
|
|
CURLOPT_SSL_VERIFYPEER => true,
|
|
|
|
|
CURLOPT_SSL_VERIFYHOST => 2,
|
|
|
|
|
CURLOPT_CUSTOMREQUEST => $method,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$caPath = $this->getCaBundlePath();
|
|
|
|
|
if ($caPath !== null) {
|
|
|
|
|
$opts[CURLOPT_CAINFO] = $caPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($body !== null) {
|
|
|
|
|
$jsonBody = json_encode($body, JSON_UNESCAPED_UNICODE);
|
|
|
|
|
$headers[] = 'Content-Type: application/json';
|
|
|
|
|
$opts[CURLOPT_POSTFIELDS] = $jsonBody;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$opts[CURLOPT_HTTPHEADER] = $headers;
|
|
|
|
|
curl_setopt_array($ch, $opts);
|
|
|
|
|
|
|
|
|
|
$responseBody = curl_exec($ch);
|
|
|
|
|
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
|
|
|
$curlError = curl_error($ch);
|
|
|
|
|
$ch = null;
|
|
|
|
|
|
|
|
|
|
if ($responseBody === false) {
|
|
|
|
|
throw new ShipmentException('Blad polaczenia z InPost API: ' . $curlError);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($httpCode < 200 || $httpCode >= 300) {
|
|
|
|
|
$errorMsg = $this->extractApiErrorMessage((string) $responseBody, $httpCode);
|
|
|
|
|
throw new ShipmentException($errorMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (string) $responseBody;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function extractApiErrorMessage(string $body, int $httpCode): string
|
|
|
|
|
{
|
|
|
|
|
$json = json_decode($body, true);
|
|
|
|
|
if (is_array($json)) {
|
|
|
|
|
$message = trim((string) ($json['message'] ?? ''));
|
|
|
|
|
if ($message !== '') {
|
|
|
|
|
return 'InPost API [HTTP ' . $httpCode . ']: ' . $message;
|
|
|
|
|
}
|
|
|
|
|
$details = $json['details'] ?? $json['error'] ?? null;
|
|
|
|
|
if (is_string($details) && trim($details) !== '') {
|
|
|
|
|
return 'InPost API [HTTP ' . $httpCode . ']: ' . trim($details);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 'InPost API zwrocilo blad HTTP ' . $httpCode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getCaBundlePath(): ?string
|
|
|
|
|
{
|
|
|
|
|
$envPath = (string) ($_ENV['CURL_CA_BUNDLE_PATH'] ?? '');
|
|
|
|
|
if ($envPath !== '' && is_file($envPath)) {
|
|
|
|
|
return $envPath;
|
|
|
|
|
}
|
|
|
|
|
$iniPath = (string) ini_get('curl.cainfo');
|
|
|
|
|
if ($iniPath !== '' && is_file($iniPath)) {
|
|
|
|
|
return $iniPath;
|
|
|
|
|
}
|
|
|
|
|
$candidates = [
|
|
|
|
|
'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 (is_file($path)) {
|
|
|
|
|
return $path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $orderDetails
|
|
|
|
|
* @param array<string, mixed> $formData
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
private function buildReceiverFromOrder(array $orderDetails, array $formData): array
|
|
|
|
|
{
|
|
|
|
|
$addresses = is_array($orderDetails['addresses'] ?? null) ? $orderDetails['addresses'] : [];
|
|
|
|
|
$deliveryAddr = null;
|
|
|
|
|
$customerAddr = null;
|
|
|
|
|
foreach ($addresses as $addr) {
|
|
|
|
|
$type = (string) ($addr['address_type'] ?? '');
|
|
|
|
|
if ($type === 'delivery') {
|
|
|
|
|
$deliveryAddr = $addr;
|
|
|
|
|
}
|
|
|
|
|
if ($type === 'customer') {
|
|
|
|
|
$customerAddr = $addr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$addr = $deliveryAddr ?? $customerAddr ?? [];
|
|
|
|
|
|
|
|
|
|
$name = trim((string) ($formData['receiver_name'] ?? ($addr['name'] ?? '')));
|
|
|
|
|
$company = trim((string) ($formData['receiver_company'] ?? ($addr['company_name'] ?? '')));
|
|
|
|
|
$phone = trim((string) ($formData['receiver_phone'] ?? ($addr['phone'] ?? '')));
|
|
|
|
|
$email = trim((string) ($formData['receiver_email'] ?? ($addr['email'] ?? '')));
|
|
|
|
|
|
|
|
|
|
$receiver = [
|
|
|
|
|
'name' => $name !== '' ? $name : ($company !== '' ? $company : 'Odbiorca'),
|
|
|
|
|
'phone' => $phone,
|
|
|
|
|
'email' => $email,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ($company !== '') {
|
|
|
|
|
$receiver['company_name'] = $company;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$street = trim((string) ($formData['receiver_street'] ?? ($addr['street_name'] ?? '')));
|
|
|
|
|
$city = trim((string) ($formData['receiver_city'] ?? ($addr['city'] ?? '')));
|
|
|
|
|
$postalCode = trim((string) ($formData['receiver_postal_code'] ?? ($addr['zip_code'] ?? '')));
|
|
|
|
|
$countryCode = strtoupper(trim((string) ($formData['receiver_country_code'] ?? ($addr['country'] ?? 'PL'))));
|
|
|
|
|
|
|
|
|
|
$receiver['address'] = [
|
|
|
|
|
'street' => $street,
|
|
|
|
|
'city' => $city,
|
|
|
|
|
'post_code' => $postalCode,
|
|
|
|
|
'country_code' => $countryCode,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return $receiver;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $sender
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
private function buildSenderPayload(array $sender): array
|
|
|
|
|
{
|
|
|
|
|
$name = trim((string) ($sender['name'] ?? ''));
|
|
|
|
|
$company = trim((string) ($sender['company'] ?? ''));
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'name' => $name !== '' ? $name : ($company !== '' ? $company : 'Nadawca'),
|
|
|
|
|
'company_name' => $company !== '' ? $company : null,
|
|
|
|
|
'phone' => trim((string) ($sender['phone'] ?? '')),
|
|
|
|
|
'email' => trim((string) ($sender['email'] ?? '')),
|
|
|
|
|
'address' => [
|
|
|
|
|
'street' => trim((string) ($sender['street'] ?? '')),
|
|
|
|
|
'city' => trim((string) ($sender['city'] ?? '')),
|
|
|
|
|
'post_code' => trim((string) ($sender['postalCode'] ?? '')),
|
|
|
|
|
'country_code' => strtoupper(trim((string) ($sender['countryCode'] ?? 'PL'))),
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $formData
|
|
|
|
|
* @param array<string, mixed> $settings
|
|
|
|
|
*/
|
|
|
|
|
private function resolveServiceType(array $formData, array $settings): string
|
|
|
|
|
{
|
|
|
|
|
$deliveryMethodId = trim((string) ($formData['delivery_method_id'] ?? ''));
|
|
|
|
|
if ($deliveryMethodId !== '') {
|
|
|
|
|
return $deliveryMethodId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$pointId = trim((string) ($formData['receiver_point_id'] ?? ''));
|
|
|
|
|
if ($pointId !== '') {
|
|
|
|
|
return 'inpost_locker_standard';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$dispatchMethod = (string) ($settings['default_dispatch_method'] ?? 'pop');
|
|
|
|
|
if ($dispatchMethod === 'parcel_locker') {
|
|
|
|
|
return 'inpost_locker_standard';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 'inpost_courier_standard';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $formData
|
|
|
|
|
* @param array<string, mixed> $settings
|
|
|
|
|
* @param array<string, mixed> $company
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
private function buildParcelPayload(array $formData, array $settings, array $company, string $serviceType): array
|
|
|
|
|
{
|
|
|
|
|
$isLocker = str_contains($serviceType, 'locker');
|
|
|
|
|
|
|
|
|
|
if ($isLocker) {
|
|
|
|
|
$size = trim((string) ($formData['locker_size'] ?? ($settings['default_locker_size'] ?? 'small')));
|
|
|
|
|
if (!in_array($size, ['small', 'medium', 'large'], true)) {
|
|
|
|
|
$size = 'small';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$targetPointId = trim((string) ($formData['receiver_point_id'] ?? ''));
|
|
|
|
|
|
|
|
|
|
$parcel = [
|
|
|
|
|
'template' => $size,
|
|
|
|
|
];
|
|
|
|
|
if ($targetPointId !== '') {
|
|
|
|
|
$parcel['target_point'] = $targetPointId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $parcel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$lengthCm = (float) ($formData['length_cm'] ?? ($settings['default_courier_length'] ?? $company['default_package_length_cm'] ?? 20));
|
|
|
|
|
$widthCm = (float) ($formData['width_cm'] ?? ($settings['default_courier_width'] ?? $company['default_package_width_cm'] ?? 15));
|
|
|
|
|
$heightCm = (float) ($formData['height_cm'] ?? ($settings['default_courier_height'] ?? $company['default_package_height_cm'] ?? 8));
|
|
|
|
|
$weightKg = (float) ($formData['weight_kg'] ?? ($company['default_package_weight_kg'] ?? 1));
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'dimensions' => [
|
|
|
|
|
'length' => $lengthCm,
|
|
|
|
|
'width' => $widthCm,
|
|
|
|
|
'height' => $heightCm,
|
|
|
|
|
'unit' => 'mm',
|
|
|
|
|
],
|
|
|
|
|
'weight' => [
|
|
|
|
|
'amount' => $weightKg,
|
|
|
|
|
'unit' => 'kg',
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $orderDetails
|
|
|
|
|
*/
|
|
|
|
|
private function buildReference(array $orderDetails, int $orderId): string
|
|
|
|
|
{
|
|
|
|
|
$orderData = is_array($orderDetails['order'] ?? null) ? $orderDetails['order'] : [];
|
|
|
|
|
$sourceOrderId = trim((string) ($orderData['source_order_id'] ?? ''));
|
|
|
|
|
|
|
|
|
|
return $sourceOrderId !== '' ? $sourceOrderId : (string) $orderId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<string, mixed> $sender
|
|
|
|
|
*/
|
|
|
|
|
private function validateSenderAddress(array $sender): void
|
|
|
|
|
{
|
|
|
|
|
$required = ['street', 'city', 'postalCode', 'phone', 'email'];
|
|
|
|
|
foreach ($required as $field) {
|
|
|
|
|
if (trim((string) ($sender[$field] ?? '')) === '') {
|
|
|
|
|
throw new IntegrationConfigException('Uzupelnij dane nadawcy w Ustawienia > Dane firmy (brak: ' . $field . ').');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$name = trim((string) ($sender['name'] ?? ''));
|
|
|
|
|
$company = trim((string) ($sender['company'] ?? ''));
|
|
|
|
|
if ($name === '' && $company === '') {
|
|
|
|
|
throw new IntegrationConfigException('Uzupelnij dane nadawcy w Ustawienia > Dane firmy (brak nazwy/firmy).');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|