27-05-2026 Update DHL Modul v2.0
This commit is contained in:
parent
53bdba33cd
commit
036595be94
41 changed files with 3346 additions and 310 deletions
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Acme\Dhl\Exceptions;
|
||||
|
||||
class DhlAddressValidationException extends DhlValidationException
|
||||
{
|
||||
//
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ class DhlShipment extends Model
|
|||
'order_id',
|
||||
'dhl_shipment_no',
|
||||
'routing_code',
|
||||
'reference',
|
||||
'type',
|
||||
'related_shipment_id',
|
||||
'product_code',
|
||||
|
|
@ -60,6 +61,15 @@ class DhlShipment extends Model
|
|||
'unknown' => 'unknown',
|
||||
];
|
||||
|
||||
public const TRACKING_EMAIL_TRIGGER_STATUSES = [
|
||||
'in_transit',
|
||||
'out_for_delivery',
|
||||
];
|
||||
|
||||
public const LEGACY_STATUS_ALIASES = [
|
||||
'cancelled' => 'canceled',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the tracking events for this shipment
|
||||
*/
|
||||
|
|
@ -164,7 +174,9 @@ class DhlShipment extends Model
|
|||
*/
|
||||
public function getStatusTranslation(): string
|
||||
{
|
||||
return __('dhl.status.'.$this->status, [], $this->status);
|
||||
$status = self::normalizeStatus($this->status);
|
||||
|
||||
return __('dhl.status.'.$status, [], $status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -172,9 +184,20 @@ class DhlShipment extends Model
|
|||
*/
|
||||
public static function getStatusTranslationFor(string $status): string
|
||||
{
|
||||
$status = self::normalizeStatus($status);
|
||||
|
||||
return __('dhl.status.'.$status, [], $status);
|
||||
}
|
||||
|
||||
public static function normalizeStatus(?string $status): string
|
||||
{
|
||||
if ($status === null || $status === '') {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
return self::LEGACY_STATUS_ALIASES[$status] ?? $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translated type for current locale
|
||||
*/
|
||||
|
|
@ -234,23 +257,92 @@ class DhlShipment extends Model
|
|||
return $this->tracking_email_sent_at !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function getTrackingEmailHistory(): array
|
||||
{
|
||||
$history = data_get($this->api_response_data ?? [], 'tracking_email_history', []);
|
||||
|
||||
if (! is_array($history)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_values(array_reverse($history));
|
||||
}
|
||||
|
||||
public function shouldTriggerTrackingEmail(?string $previousStatus): bool
|
||||
{
|
||||
$currentStatus = self::normalizeStatus($this->status);
|
||||
$previousStatus = self::normalizeStatus($previousStatus);
|
||||
|
||||
return in_array($currentStatus, self::TRACKING_EMAIL_TRIGGER_STATUSES, true)
|
||||
&& $currentStatus !== $previousStatus
|
||||
&& ! $this->wasTrackingEmailSent()
|
||||
&& $this->canSendTrackingEmail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark tracking email as sent
|
||||
*/
|
||||
public function markTrackingEmailSent(string $type = 'manual'): void
|
||||
public function markTrackingEmailSent(string $type = 'manual', ?string $recipientEmail = null, ?iterable $includedShipments = null): void
|
||||
{
|
||||
$apiResponseData = $this->api_response_data ?? [];
|
||||
$history = data_get($apiResponseData, 'tracking_email_history', []);
|
||||
|
||||
if (! is_array($history)) {
|
||||
$history = [];
|
||||
}
|
||||
|
||||
$history[] = [
|
||||
'sent_at' => now()->toISOString(),
|
||||
'type' => $type,
|
||||
'recipient_email' => $recipientEmail,
|
||||
'status' => self::normalizeStatus($this->status),
|
||||
'tracking_status' => $this->tracking_status,
|
||||
'dhl_shipment_no' => $this->dhl_shipment_no,
|
||||
'included_shipment_ids' => $this->extractIncludedShipmentIds($includedShipments),
|
||||
];
|
||||
|
||||
data_set($apiResponseData, 'tracking_email_history', $history);
|
||||
|
||||
$this->update([
|
||||
'tracking_email_sent_at' => now(),
|
||||
'tracking_email_type' => $type,
|
||||
'api_response_data' => $apiResponseData,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int|string>
|
||||
*/
|
||||
private function extractIncludedShipmentIds(?iterable $includedShipments): array
|
||||
{
|
||||
if ($includedShipments === null) {
|
||||
return [$this->id];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
foreach ($includedShipments as $shipment) {
|
||||
if ($shipment instanceof self && $shipment->id !== null) {
|
||||
$ids[] = $shipment->id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids ?: [$this->id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status badge class for Bootstrap
|
||||
*/
|
||||
public function getStatusBadgeClass(): string
|
||||
{
|
||||
return match ($this->status) {
|
||||
return self::getStatusBadgeClassFor($this->status);
|
||||
}
|
||||
|
||||
public static function getStatusBadgeClassFor(?string $status): string
|
||||
{
|
||||
return match (self::normalizeStatus($status)) {
|
||||
'created', 'pending' => 'secondary',
|
||||
'in_transit' => 'info',
|
||||
'out_for_delivery' => 'primary',
|
||||
|
|
@ -266,13 +358,13 @@ class DhlShipment extends Model
|
|||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->whereNotIn('status', ['delivered', 'canceled', 'returned', 'failed']);
|
||||
return $query->whereNotIn('status', self::TERMINAL_STATUSES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminal statuses where tracking is considered complete
|
||||
*/
|
||||
public const TERMINAL_STATUSES = ['delivered', 'canceled', 'returned', 'failed'];
|
||||
public const TERMINAL_STATUSES = ['delivered', 'canceled', 'cancelled', 'returned', 'failed'];
|
||||
|
||||
/**
|
||||
* Tracking interval per status (in hours).
|
||||
|
|
@ -345,7 +437,7 @@ class DhlShipment extends Model
|
|||
*/
|
||||
public function scopeNeedsTrackingEmail($query)
|
||||
{
|
||||
return $query->where('status', 'in_transit')
|
||||
return $query->whereIn('status', self::TRACKING_EMAIL_TRIGGER_STATUSES)
|
||||
->whereNull('tracking_email_sent_at');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
namespace Acme\Dhl\Services;
|
||||
|
||||
use Acme\Dhl\Exceptions\DhlAddressValidationException;
|
||||
use Acme\Dhl\Exceptions\DhlValidationException;
|
||||
use Acme\Dhl\Jobs\CreateShipmentJob;
|
||||
use Acme\Dhl\Models\DhlShipment;
|
||||
use Acme\Dhl\Support\DhlClient;
|
||||
use App\Services\DhlProductResolver;
|
||||
use App\Services\DhlShipmentWeightCalculator;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -53,6 +57,7 @@ class ShippingService
|
|||
$query = array_filter([
|
||||
'printFormat' => $validatedData['print_format'] ?? null,
|
||||
'retourePrintFormat' => $validatedData['retoure_print_format'] ?? null,
|
||||
'mustEncode' => $this->shouldUseMustEncode($validatedData) ? 'true' : null,
|
||||
]);
|
||||
|
||||
$response = $this->client->request('post', '/parcel/de/shipping/v2/orders', $payload, $query);
|
||||
|
|
@ -60,6 +65,13 @@ class ShippingService
|
|||
Log::info('[DHL API] Response received', [
|
||||
'response' => $response,
|
||||
]);
|
||||
$this->assertSuccessfulShipmentResponse($response, $this->shouldUseMustEncode($validatedData));
|
||||
} catch (DhlValidationException $e) {
|
||||
if ($this->shouldUseMustEncode($validatedData) && $this->looksLikeAddressValidationError($e->getMessage())) {
|
||||
throw new DhlAddressValidationException($this->normalizeDhlAddressValidationMessage($e->getMessage()), (int) $e->getCode(), $e);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL API] Request failed', [
|
||||
'error' => $e->getMessage(),
|
||||
|
|
@ -101,18 +113,18 @@ class ShippingService
|
|||
|
||||
$shipment = DhlShipment::where('dhl_shipment_no', $shipmentNumber)->first();
|
||||
if (! $shipment) {
|
||||
throw new InvalidArgumentException('Shipment not found in database: ' . $shipmentNumber);
|
||||
throw new InvalidArgumentException('Shipment not found in database: '.$shipmentNumber);
|
||||
}
|
||||
|
||||
if (! $shipment->canCancel()) {
|
||||
throw new InvalidArgumentException('Shipment cannot be canceled (current status: ' . $shipment->status . ')');
|
||||
throw new InvalidArgumentException('Shipment cannot be canceled (current status: '.$shipment->status.')');
|
||||
}
|
||||
|
||||
Log::info('[DHL Package] Attempting to cancel shipment', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'shipment_id' => $shipment->id,
|
||||
'status' => $shipment->status,
|
||||
'endpoint' => "/parcel/de/shipping/v2/orders/{$shipmentNumber}"
|
||||
'endpoint' => "/parcel/de/shipping/v2/orders/{$shipmentNumber}",
|
||||
]);
|
||||
|
||||
try {
|
||||
|
|
@ -120,28 +132,78 @@ class ShippingService
|
|||
|
||||
Log::info('[DHL Package] Shipment cancellation response', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'response' => $response
|
||||
'response' => $response,
|
||||
]);
|
||||
|
||||
$shipment->update(['status' => 'canceled']);
|
||||
$this->recordCancellationSuccess($shipment, $response);
|
||||
Log::info('[DHL Package] Canceled shipment successfully', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'shipment_id' => $shipment->id
|
||||
'shipment_id' => $shipment->id,
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->recordCancellationFailure($shipment, $e);
|
||||
|
||||
Log::error('[DHL Package] Shipment cancellation failed', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'shipment_id' => $shipment->id,
|
||||
'error' => $e->getMessage(),
|
||||
'error_class' => get_class($e)
|
||||
'error_class' => get_class($e),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function recordCancellationSuccess(DhlShipment $shipment, array $response): void
|
||||
{
|
||||
$apiResponseData = $shipment->api_response_data ?? [];
|
||||
$apiResponseData['cancellation'] = [
|
||||
'status' => 'success',
|
||||
'response' => $response,
|
||||
'occurred_at' => now()->toISOString(),
|
||||
];
|
||||
|
||||
$shipment->update([
|
||||
'status' => 'canceled',
|
||||
'api_response_data' => $apiResponseData,
|
||||
]);
|
||||
}
|
||||
|
||||
private function recordCancellationFailure(DhlShipment $shipment, \Exception $exception): void
|
||||
{
|
||||
$apiResponseData = $shipment->api_response_data ?? [];
|
||||
$apiResponseData['cancellation_error'] = [
|
||||
'status' => 'failed',
|
||||
'http_status' => $this->extractHttpStatus($exception->getMessage()),
|
||||
'dhl_code' => $this->extractDhlErrorCode($exception->getMessage()),
|
||||
'detail' => $exception->getMessage(),
|
||||
'exception_class' => $exception::class,
|
||||
'occurred_at' => now()->toISOString(),
|
||||
];
|
||||
|
||||
$shipment->update(['api_response_data' => $apiResponseData]);
|
||||
}
|
||||
|
||||
private function extractHttpStatus(string $message): ?int
|
||||
{
|
||||
if (preg_match('/\b([45][0-9]{2})\b/', $message, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function extractDhlErrorCode(string $message): ?string
|
||||
{
|
||||
if (preg_match('/\b([A-Z]{2}-[A-Za-z0-9_-]+)\b/', $message, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate required order data according to DHL API v2 specification
|
||||
*/
|
||||
|
|
@ -153,10 +215,11 @@ class ShippingService
|
|||
$validator = Validator::make($data, [
|
||||
'order_id' => 'nullable|integer',
|
||||
'weight_kg' => 'required|numeric|min:0.1|max:31.5', // DHL weight limit
|
||||
'product_code' => 'nullable|string|in:V01PAK,V53PAK,V62WP,V07PAK',
|
||||
'product_code' => 'nullable|string|in:V01PAK,V53PAK,V62KP,V07PAK',
|
||||
'label_format' => 'nullable|string|in:PDF,ZPL',
|
||||
'print_format' => 'nullable|string', // Values like A4, 910-300-700 etc.
|
||||
'retoure_print_format' => 'nullable|string',
|
||||
'print_only_if_codeable' => 'nullable|boolean',
|
||||
|
||||
// Shipper validation (sender)
|
||||
'shipper' => 'required|array',
|
||||
|
|
@ -198,7 +261,81 @@ class ShippingService
|
|||
throw new InvalidArgumentException($validator->errors()->first());
|
||||
}
|
||||
|
||||
return $validator->validated();
|
||||
$validated = $validator->validated();
|
||||
(new DhlShipmentWeightCalculator)->assertWithinProductLimit(
|
||||
(float) $validated['weight_kg'],
|
||||
$validated['product_code'] ?? null
|
||||
);
|
||||
|
||||
return $validated;
|
||||
}
|
||||
|
||||
private function shouldUseMustEncode(array $orderData): bool
|
||||
{
|
||||
return (bool) ($orderData['print_only_if_codeable'] ?? config('dhl.print_only_if_codeable', true))
|
||||
&& strtoupper((string) ($orderData['consignee']['country'] ?? '')) === DhlProductResolver::DOMESTIC_COUNTRY;
|
||||
}
|
||||
|
||||
private function assertSuccessfulShipmentResponse(array $response, bool $mustEncodeEnabled): void
|
||||
{
|
||||
$itemStatusCode = (int) (data_get($response, 'items.0.sstatus.statusCode')
|
||||
?? data_get($response, 'items.0.sstatus.status')
|
||||
?? data_get($response, 'status.statusCode')
|
||||
?? data_get($response, 'status.status')
|
||||
?? 200);
|
||||
|
||||
if ($itemStatusCode < 400 && $this->extractShipmentNumber($response) !== null && $this->extractLabelData($response) !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = $this->extractResponseErrorMessage($response) ?: 'DHL hat kein Versandlabel erstellt.';
|
||||
|
||||
if ($mustEncodeEnabled || $this->looksLikeAddressValidationError($message)) {
|
||||
throw new DhlAddressValidationException($this->normalizeDhlAddressValidationMessage($message));
|
||||
}
|
||||
|
||||
throw new DhlValidationException($message);
|
||||
}
|
||||
|
||||
private function extractResponseErrorMessage(array $response): ?string
|
||||
{
|
||||
$message = data_get($response, 'items.0.sstatus.detail')
|
||||
?? data_get($response, 'items.0.sstatus.title')
|
||||
?? data_get($response, 'status.detail')
|
||||
?? data_get($response, 'status.title')
|
||||
?? data_get($response, 'detail')
|
||||
?? data_get($response, 'message');
|
||||
|
||||
$validationMessages = data_get($response, 'items.0.validationMessages', []);
|
||||
if (is_array($validationMessages) && $validationMessages !== []) {
|
||||
$messages = [];
|
||||
foreach ($validationMessages as $validationMessage) {
|
||||
$messages[] = $validationMessage['validationMessage']
|
||||
?? $validationMessage['message']
|
||||
?? $validationMessage['property']
|
||||
?? null;
|
||||
}
|
||||
|
||||
$messages = array_values(array_filter($messages));
|
||||
if ($messages !== []) {
|
||||
$message = implode('; ', $messages);
|
||||
}
|
||||
}
|
||||
|
||||
return $message ? (string) $message : null;
|
||||
}
|
||||
|
||||
private function looksLikeAddressValidationError(string $message): bool
|
||||
{
|
||||
return (bool) preg_match('/address|adresse|anschrift|leitcod|routing|route|codeable|codable|encodable|mustEncode|postal|postleitzahl|street|straße|strasse|house|hausnummer|city|ort/i', $message);
|
||||
}
|
||||
|
||||
private function normalizeDhlAddressValidationMessage(string $message): string
|
||||
{
|
||||
$message = trim(preg_replace('/^DHL API validation error:\s*/i', '', $message));
|
||||
$message = $message !== '' ? $message : 'DHL kann diese Adresse nicht leitcodieren.';
|
||||
|
||||
return 'DHL kann diese Adresse nicht leitcodieren. Bitte Straße, Hausnummer, PLZ und Ort prüfen. DHL-Meldung: '.$message;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -302,8 +439,14 @@ class ShippingService
|
|||
*/
|
||||
private function buildShipmentPayload(array $orderData): array
|
||||
{
|
||||
$productCode = $orderData['product_code'] ?? config('dhl.default_product', 'V01PAK');
|
||||
$billingNumber = $this->getBillingNumberForProduct($productCode);
|
||||
$resolver = new DhlProductResolver;
|
||||
$destination = $resolver->resolveForShipment(
|
||||
$orderData['consignee']['country'] ?? '',
|
||||
$orderData['product_code'] ?? null,
|
||||
config('dhl.default_product', 'V01PAK')
|
||||
);
|
||||
$productCode = $destination['product_code'];
|
||||
$billingNumber = $resolver->assertBillingNumber($productCode, $this->getBillingNumberForProduct($productCode));
|
||||
|
||||
$payload = [
|
||||
'profile' => config('dhl.profile', 'STANDARD_GRUPPENPROFIL'),
|
||||
|
|
@ -319,7 +462,7 @@ class ShippingService
|
|||
'addressHouse' => $orderData['shipper']['houseNumber'] ?? null,
|
||||
'postalCode' => $orderData['shipper']['postalCode'] ?? '',
|
||||
'city' => $orderData['shipper']['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($orderData['shipper']['country'] ?? 'DE'),
|
||||
'country' => $this->convertCountryCode($orderData['shipper']['country'] ?? ''),
|
||||
'email' => ! empty($orderData['shipper']['email']) ? $orderData['shipper']['email'] : null,
|
||||
'phone' => ! empty($orderData['shipper']['phone']) ? $orderData['shipper']['phone'] : null,
|
||||
], function ($value) {
|
||||
|
|
@ -381,7 +524,7 @@ class ShippingService
|
|||
'addressHouse' => $consignee['houseNumber'] ?? null,
|
||||
'postalCode' => $consignee['postalCode'] ?? '',
|
||||
'city' => $consignee['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($consignee['country'] ?? 'DE'),
|
||||
'country' => $this->convertCountryCode($consignee['country'] ?? ''),
|
||||
'email' => ! empty($consignee['email']) ? $consignee['email'] : null,
|
||||
'phone' => ! empty($consignee['phone']) ? $consignee['phone'] : null,
|
||||
], function ($value) {
|
||||
|
|
@ -435,12 +578,12 @@ class ShippingService
|
|||
'houseNumber' => $consignee['houseNumber'] ?? '',
|
||||
]);
|
||||
|
||||
$errorMessage = 'PACKSTATION-FEHLER: Die Packstation-Nummer muss 3-stellig sein (100-999).' . PHP_EOL . PHP_EOL;
|
||||
$errorMessage .= 'Eingegeben wurde: "' . $lockerNumber . '"' . PHP_EOL . PHP_EOL;
|
||||
$errorMessage .= 'HINWEISE:' . PHP_EOL;
|
||||
$errorMessage .= '• Straße/Nr.: "Packstation 145" (nicht "Packstation 12345")' . PHP_EOL;
|
||||
$errorMessage .= '• Die Packstation-NUMMER ist die 3-stellige Nummer auf dem gelben DHL-Schild' . PHP_EOL;
|
||||
$errorMessage .= '• Die 5-10-stellige POSTNUMMER ist etwas anderes (kommt ins separate Feld!)' . PHP_EOL;
|
||||
$errorMessage = 'PACKSTATION-FEHLER: Die Packstation-Nummer muss 3-stellig sein (100-999).'.PHP_EOL.PHP_EOL;
|
||||
$errorMessage .= 'Eingegeben wurde: "'.$lockerNumber.'"'.PHP_EOL.PHP_EOL;
|
||||
$errorMessage .= 'HINWEISE:'.PHP_EOL;
|
||||
$errorMessage .= '• Straße/Nr.: "Packstation 145" (nicht "Packstation 12345")'.PHP_EOL;
|
||||
$errorMessage .= '• Die Packstation-NUMMER ist die 3-stellige Nummer auf dem gelben DHL-Schild'.PHP_EOL;
|
||||
$errorMessage .= '• Die 5-10-stellige POSTNUMMER ist etwas anderes (kommt ins separate Feld!)'.PHP_EOL;
|
||||
$errorMessage .= '• Beispiel: Packstation 145, PLZ 12345, Postnummer 1234567890';
|
||||
|
||||
throw new \InvalidArgumentException($errorMessage);
|
||||
|
|
@ -464,7 +607,7 @@ class ShippingService
|
|||
'postNumber' => $postNumber,
|
||||
'postalCode' => $consignee['postalCode'] ?? '',
|
||||
'city' => $consignee['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($consignee['country'] ?? 'DE'),
|
||||
'country' => $this->convertCountryCode($consignee['country'] ?? ''),
|
||||
], function ($value) {
|
||||
return $value !== null && $value !== '';
|
||||
});
|
||||
|
|
@ -534,25 +677,7 @@ class ShippingService
|
|||
*/
|
||||
private function convertCountryCode(string $countryCode): string
|
||||
{
|
||||
$countryMap = [
|
||||
'DE' => 'DEU',
|
||||
'AT' => 'AUT',
|
||||
'CH' => 'CHE',
|
||||
'US' => 'USA',
|
||||
'GB' => 'GBR',
|
||||
'FR' => 'FRA',
|
||||
'IT' => 'ITA',
|
||||
'ES' => 'ESP',
|
||||
'NL' => 'NLD',
|
||||
'BE' => 'BEL',
|
||||
'PL' => 'POL',
|
||||
'CZ' => 'CZE',
|
||||
'DK' => 'DNK',
|
||||
'SE' => 'SWE',
|
||||
'NO' => 'NOR',
|
||||
];
|
||||
|
||||
return $countryMap[strtoupper($countryCode)] ?? 'DEU';
|
||||
return (new DhlProductResolver)->toDhlCountryCode($countryCode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -576,8 +701,9 @@ class ShippingService
|
|||
}
|
||||
|
||||
// Try to get from admin settings via Setting model first (database settings override config)
|
||||
$settingKey = 'dhl_account_'.strtolower($productCode);
|
||||
|
||||
try {
|
||||
$settingKey = 'dhl_account_' . strtolower($productCode);
|
||||
$accountNumber = \App\Models\Setting::getContentBySlug($settingKey);
|
||||
if ($accountNumber) {
|
||||
Log::info('Using DHL account number from database settings', [
|
||||
|
|
@ -692,6 +818,7 @@ class ShippingService
|
|||
'order_id' => $orderData['order_id'] ?? null,
|
||||
'dhl_shipment_no' => $shipmentNumber,
|
||||
'routing_code' => $this->extractRoutingCode($response),
|
||||
'reference' => $payload['shipments'][0]['refNo'] ?? null,
|
||||
'type' => 'outbound',
|
||||
'product_code' => $payload['shipments'][0]['product'],
|
||||
'billing_number' => $payload['shipments'][0]['billingNumber'],
|
||||
|
|
@ -721,7 +848,7 @@ class ShippingService
|
|||
|
||||
return null;
|
||||
}
|
||||
$path = 'dhl/labels/' . $shipment->dhl_shipment_no . '.' . strtolower($format);
|
||||
$path = 'dhl/labels/'.$shipment->dhl_shipment_no.'.'.strtolower($format);
|
||||
$success = false;
|
||||
for ($attempt = 1; $attempt <= 3; $attempt++) {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue