23-01-2026
This commit is contained in:
parent
a939cd51ef
commit
a8b395e20d
248 changed files with 29342 additions and 4805 deletions
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
namespace Acme\Dhl\Services;
|
||||
|
||||
use Acme\Dhl\Support\DhlClient;
|
||||
use Acme\Dhl\Jobs\CreateShipmentJob;
|
||||
use Acme\Dhl\Models\DhlShipment;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Acme\Dhl\Support\DhlClient;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use InvalidArgumentException;
|
||||
use Exception;
|
||||
use Acme\Dhl\Jobs\CreateShipmentJob;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* DHL Shipping Service for creating and managing shipment labels
|
||||
|
|
@ -22,8 +22,9 @@ class ShippingService
|
|||
/**
|
||||
* Create a new DHL shipment label
|
||||
*
|
||||
* @param array $orderData Order and shipping data
|
||||
* @param array $orderData Order and shipping data
|
||||
* @return array Shipment details including number and label path
|
||||
*
|
||||
* @throws InvalidArgumentException When required data is missing
|
||||
* @throws Exception When API request fails
|
||||
*/
|
||||
|
|
@ -33,6 +34,7 @@ class ShippingService
|
|||
$validatedData = $this->validateOrderData($orderData);
|
||||
if (config('dhl.use_queue')) {
|
||||
CreateShipmentJob::dispatch($validatedData);
|
||||
|
||||
return ['queued' => true];
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +45,7 @@ class ShippingService
|
|||
Log::info('[DHL API] Sending payload to DHL', [
|
||||
'endpoint' => '/parcel/de/shipping/v2/orders',
|
||||
'payload' => $payload,
|
||||
'payload_json' => json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
'payload_json' => json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
|
||||
try {
|
||||
|
|
@ -56,12 +58,12 @@ class ShippingService
|
|||
$response = $this->client->request('post', '/parcel/de/shipping/v2/orders', $payload, $query);
|
||||
|
||||
Log::info('[DHL API] Response received', [
|
||||
'response' => $response
|
||||
'response' => $response,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
Log::error('[DHL API] Request failed', [
|
||||
'error' => $e->getMessage(),
|
||||
'payload' => $payload
|
||||
'payload' => $payload,
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
|
|
@ -78,7 +80,7 @@ class ShippingService
|
|||
'shipmentNumber' => $shipmentNumber,
|
||||
'label_path' => $labelPath,
|
||||
'shipment' => $shipment,
|
||||
'raw' => $response
|
||||
'raw' => $response,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
|
@ -86,8 +88,9 @@ class ShippingService
|
|||
/**
|
||||
* Cancel an existing DHL shipment
|
||||
*
|
||||
* @param string $shipmentNumber DHL shipment number
|
||||
* @param string $shipmentNumber DHL shipment number
|
||||
* @return bool Success status
|
||||
*
|
||||
* @throws Exception When cancellation fails
|
||||
*/
|
||||
public function cancelLabel(string $shipmentNumber): bool
|
||||
|
|
@ -95,14 +98,48 @@ class ShippingService
|
|||
if (empty($shipmentNumber)) {
|
||||
throw new InvalidArgumentException('Shipment number is required');
|
||||
}
|
||||
|
||||
$shipment = DhlShipment::where('dhl_shipment_no', $shipmentNumber)->first();
|
||||
if (!$shipment || !$shipment->canCancel()) {
|
||||
throw new InvalidArgumentException('Shipment cannot be canceled');
|
||||
if (! $shipment) {
|
||||
throw new InvalidArgumentException('Shipment not found in database: ' . $shipmentNumber);
|
||||
}
|
||||
|
||||
if (! $shipment->canCancel()) {
|
||||
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}"
|
||||
]);
|
||||
|
||||
try {
|
||||
$response = $this->client->request('delete', "/parcel/de/shipping/v2/orders/{$shipmentNumber}");
|
||||
|
||||
Log::info('[DHL Package] Shipment cancellation response', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'response' => $response
|
||||
]);
|
||||
|
||||
$shipment->update(['status' => 'canceled']);
|
||||
Log::info('[DHL Package] Canceled shipment successfully', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'shipment_id' => $shipment->id
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('[DHL Package] Shipment cancellation failed', [
|
||||
'shipmentNumber' => $shipmentNumber,
|
||||
'shipment_id' => $shipment->id,
|
||||
'error' => $e->getMessage(),
|
||||
'error_class' => get_class($e)
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
$this->client->request('delete', "/parcel/de/shipping/v2/orders/{$shipmentNumber}");
|
||||
$shipment->update(['status' => 'canceled']);
|
||||
Log::info('Canceled shipment', ['shipmentNumber' => $shipmentNumber]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -133,17 +170,18 @@ class ShippingService
|
|||
'shipper.email' => 'nullable|email|max:100',
|
||||
'shipper.phone' => 'nullable|string|max:20',
|
||||
|
||||
// Consignee validation (recipient)
|
||||
// Consignee validation (recipient)
|
||||
'consignee' => 'required|array',
|
||||
'consignee.name' => 'required|string|max:50',
|
||||
'consignee.name2' => 'nullable|string|max:50',
|
||||
'consignee.street' => 'required|string|max:50',
|
||||
'consignee.houseNumber' => 'required|string|max:10',
|
||||
'consignee.houseNumber' => 'required_without:consignee.postNumber|string|max:10',
|
||||
'consignee.postalCode' => 'required|string|max:10',
|
||||
'consignee.city' => 'required|string|max:50',
|
||||
'consignee.country' => 'required|string|size:2',
|
||||
'consignee.email' => 'nullable|email|max:100',
|
||||
'consignee.phone' => 'nullable|string|max:20',
|
||||
'consignee.postNumber' => 'nullable|string|max:20', // DHL Postnummer für Packstation/Paketbox
|
||||
|
||||
// Optional dimensions
|
||||
'dimensions' => 'nullable|array',
|
||||
|
|
@ -173,7 +211,7 @@ class ShippingService
|
|||
$data['shipper'] = $this->parseAddressFields($data['shipper']);
|
||||
}
|
||||
|
||||
// Process consignee address
|
||||
// Process consignee address
|
||||
if (isset($data['consignee'])) {
|
||||
$data['consignee'] = $this->parseAddressFields($data['consignee']);
|
||||
}
|
||||
|
|
@ -187,7 +225,7 @@ class ShippingService
|
|||
private function parseAddressFields(array $addressData): array
|
||||
{
|
||||
// If houseNumber is already provided, use it
|
||||
if (!empty($addressData['houseNumber'])) {
|
||||
if (! empty($addressData['houseNumber'])) {
|
||||
return $addressData;
|
||||
}
|
||||
|
||||
|
|
@ -207,14 +245,14 @@ class ShippingService
|
|||
Log::info('Parsed German address', [
|
||||
'original' => $street,
|
||||
'parsed_street' => $parsed['street'],
|
||||
'parsed_houseNumber' => $parsed['houseNumber']
|
||||
'parsed_houseNumber' => $parsed['houseNumber'],
|
||||
]);
|
||||
} elseif (!$parsed['houseNumber']) {
|
||||
} elseif (! $parsed['houseNumber']) {
|
||||
// If we can't parse house number, use a default
|
||||
$addressData['houseNumber'] = '1';
|
||||
|
||||
Log::warning('Could not parse house number from address, using default', [
|
||||
'street' => $street
|
||||
'street' => $street,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -234,7 +272,7 @@ class ShippingService
|
|||
$patterns = [
|
||||
// "Musterstraße 123a" -> street: "Musterstraße", number: "123a"
|
||||
'/^(.+?)\s+([0-9]+[a-zA-Z]?)\s*$/',
|
||||
// "Am Markt 1-3" -> street: "Am Markt", number: "1-3"
|
||||
// "Am Markt 1-3" -> street: "Am Markt", number: "1-3"
|
||||
'/^(.+?)\s+([0-9]+[-\/][0-9]+[a-zA-Z]?)\s*$/',
|
||||
// "Muster Str. 123" -> street: "Muster Str.", number: "123"
|
||||
'/^(.+?)\s+([0-9]+)\s*$/',
|
||||
|
|
@ -244,7 +282,7 @@ class ShippingService
|
|||
if (preg_match($pattern, $address, $matches)) {
|
||||
return [
|
||||
'street' => trim($matches[1]),
|
||||
'houseNumber' => trim($matches[2])
|
||||
'houseNumber' => trim($matches[2]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -252,13 +290,13 @@ class ShippingService
|
|||
// If no pattern matches, return original street with empty house number
|
||||
return [
|
||||
'street' => $address,
|
||||
'houseNumber' => null
|
||||
'houseNumber' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build DHL API v2 payload from order data
|
||||
*
|
||||
*
|
||||
* Structure follows official DHL API v2 createOrders specification:
|
||||
* https://developer.dhl.com/api-reference/parcel-de-shipping-post-parcel-germany-v2
|
||||
*/
|
||||
|
|
@ -276,48 +314,36 @@ class ShippingService
|
|||
// Shipper information (sender) - separate street and house number as per official spec
|
||||
'shipper' => array_filter([
|
||||
'name1' => $orderData['shipper']['name'] ?? '',
|
||||
'name2' => !empty($orderData['shipper']['name2']) ? $orderData['shipper']['name2'] : null,
|
||||
'name2' => ! empty($orderData['shipper']['name2']) ? $orderData['shipper']['name2'] : null,
|
||||
'addressStreet' => $orderData['shipper']['street'] ?? '',
|
||||
'addressHouse' => $orderData['shipper']['houseNumber'] ?? null,
|
||||
'postalCode' => $orderData['shipper']['postalCode'] ?? '',
|
||||
'city' => $orderData['shipper']['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($orderData['shipper']['country'] ?? 'DE'),
|
||||
'email' => !empty($orderData['shipper']['email']) ? $orderData['shipper']['email'] : null,
|
||||
'phone' => !empty($orderData['shipper']['phone']) ? $orderData['shipper']['phone'] : null,
|
||||
'email' => ! empty($orderData['shipper']['email']) ? $orderData['shipper']['email'] : null,
|
||||
'phone' => ! empty($orderData['shipper']['phone']) ? $orderData['shipper']['phone'] : null,
|
||||
], function ($value) {
|
||||
return $value !== null;
|
||||
}),
|
||||
|
||||
// Consignee information (recipient) - separate street and house number as per official spec
|
||||
'consignee' => array_filter([
|
||||
'name1' => $orderData['consignee']['name'] ?? '',
|
||||
'name2' => !empty($orderData['consignee']['name2']) ? $orderData['consignee']['name2'] : null,
|
||||
'addressStreet' => $orderData['consignee']['street'] ?? '',
|
||||
'addressHouse' => $orderData['consignee']['houseNumber'] ?? null,
|
||||
'postalCode' => $orderData['consignee']['postalCode'] ?? '',
|
||||
'city' => $orderData['consignee']['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($orderData['consignee']['country'] ?? 'DE'),
|
||||
'email' => !empty($orderData['consignee']['email']) ? $orderData['consignee']['email'] : null,
|
||||
'phone' => !empty($orderData['consignee']['phone']) ? $orderData['consignee']['phone'] : null,
|
||||
], function ($value) {
|
||||
return $value !== null;
|
||||
}),
|
||||
// Consignee information (recipient)
|
||||
'consignee' => $this->buildConsigneePayload($orderData['consignee']),
|
||||
|
||||
'details' => [
|
||||
'weight' => [
|
||||
'value' => ($orderData['weight_kg'] ?? 1.0) * 1000, // Convert kg to grams
|
||||
'uom' => 'g'
|
||||
]
|
||||
'uom' => 'g',
|
||||
],
|
||||
],
|
||||
|
||||
'print' => [
|
||||
'format' => $orderData['label_format'] ?? config('dhl.label_format', 'PDF')
|
||||
]
|
||||
]]
|
||||
'format' => $orderData['label_format'] ?? config('dhl.label_format', 'PDF'),
|
||||
],
|
||||
]],
|
||||
];
|
||||
|
||||
// Add dimensions if provided (convert cm to mm)
|
||||
if (!empty($orderData['dimensions'])) {
|
||||
if (! empty($orderData['dimensions'])) {
|
||||
$payload['shipments'][0]['details']['dim'] = [
|
||||
'uom' => 'mm',
|
||||
'length' => ($orderData['dimensions']['length'] ?? 30) * 10, // cm to mm
|
||||
|
|
@ -327,13 +353,182 @@ class ShippingService
|
|||
}
|
||||
|
||||
// Add custom reference if provided
|
||||
if (!empty($orderData['reference'])) {
|
||||
if (! empty($orderData['reference'])) {
|
||||
$payload['shipments'][0]['refNo'] = $orderData['reference'];
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build consignee payload - handles both regular addresses and Packstation/Paketbox
|
||||
*
|
||||
* @param array $consignee Consignee data from order
|
||||
* @return array Formatted consignee payload for DHL API
|
||||
*/
|
||||
private function buildConsigneePayload(array $consignee): array
|
||||
{
|
||||
// Check if this is a Packstation/Paketbox delivery (has postNumber)
|
||||
if (! empty($consignee['postNumber'])) {
|
||||
return $this->buildPackstationConsignee($consignee);
|
||||
}
|
||||
|
||||
// Regular address
|
||||
return array_filter([
|
||||
'name1' => $consignee['name'] ?? '',
|
||||
'name2' => ! empty($consignee['name2']) ? $consignee['name2'] : null,
|
||||
'addressStreet' => $consignee['street'] ?? '',
|
||||
'addressHouse' => $consignee['houseNumber'] ?? null,
|
||||
'postalCode' => $consignee['postalCode'] ?? '',
|
||||
'city' => $consignee['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($consignee['country'] ?? 'DE'),
|
||||
'email' => ! empty($consignee['email']) ? $consignee['email'] : null,
|
||||
'phone' => ! empty($consignee['phone']) ? $consignee['phone'] : null,
|
||||
], function ($value) {
|
||||
return $value !== null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Packstation/Paketbox consignee payload
|
||||
*
|
||||
* DHL API v2 uses the Locker schema for Packstation deliveries:
|
||||
* - name: Recipient name (max 50 chars)
|
||||
* - lockerID: Integer 100-999 (3-digit Packstation number)
|
||||
* - postNumber: String 6-10 digits (DHL Postnummer)
|
||||
* - postalCode, city, country: Location of the Packstation
|
||||
*
|
||||
* The street field should contain "Packstation XXX" or "Paketbox XXX"
|
||||
*
|
||||
* @see https://developer.dhl.com/api-reference/parcel-de-shipping-post-parcel-germany-v2#/components/schemas/Locker
|
||||
*
|
||||
* @param array $consignee Consignee data with postNumber
|
||||
* @return array Formatted Locker consignee payload for DHL API
|
||||
*/
|
||||
private function buildPackstationConsignee(array $consignee): array
|
||||
{
|
||||
// Extract locker number from multiple sources:
|
||||
// 1. From street field (e.g., "Packstation 145" -> "145")
|
||||
// 2. From houseNumber field (e.g., houseNumber: "145")
|
||||
// 3. Combined: street "Packstation" + houseNumber "145"
|
||||
$lockerNumber = $this->extractLockerNumber(
|
||||
$consignee['street'] ?? '',
|
||||
$consignee['houseNumber'] ?? ''
|
||||
);
|
||||
|
||||
// Convert to integer for DHL API (lockerID must be int 100-999)
|
||||
$lockerID = (int) $lockerNumber;
|
||||
|
||||
Log::info('Building Packstation consignee payload (Locker schema)', [
|
||||
'postNumber' => $consignee['postNumber'],
|
||||
'lockerID' => $lockerID,
|
||||
'originalStreet' => $consignee['street'] ?? '',
|
||||
'originalHouseNumber' => $consignee['houseNumber'] ?? '',
|
||||
]);
|
||||
|
||||
// Validate lockerID: must be integer between 100 and 999
|
||||
if ($lockerID < 100 || $lockerID > 999) {
|
||||
Log::error('Invalid Packstation lockerID - must be 100-999', [
|
||||
'lockerID' => $lockerID,
|
||||
'original_input' => $lockerNumber,
|
||||
'street' => $consignee['street'] ?? '',
|
||||
'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 .= '• Beispiel: Packstation 145, PLZ 12345, Postnummer 1234567890';
|
||||
|
||||
throw new \InvalidArgumentException($errorMessage);
|
||||
}
|
||||
|
||||
// Validate postNumber: must be 6-10 digits
|
||||
$postNumber = $consignee['postNumber'] ?? '';
|
||||
if (! preg_match('/^[0-9]{6,10}$/', $postNumber)) {
|
||||
Log::error('Invalid DHL Postnummer - must be 6-10 digits', [
|
||||
'postNumber' => $postNumber,
|
||||
]);
|
||||
throw new \InvalidArgumentException(
|
||||
'DHL Postnummer muss 6-10 Ziffern enthalten. Bitte prüfen Sie die Postnummer.'
|
||||
);
|
||||
}
|
||||
|
||||
// DHL Locker schema - flat structure, not nested
|
||||
return array_filter([
|
||||
'name' => $consignee['name'] ?? '',
|
||||
'lockerID' => $lockerID,
|
||||
'postNumber' => $postNumber,
|
||||
'postalCode' => $consignee['postalCode'] ?? '',
|
||||
'city' => $consignee['city'] ?? '',
|
||||
'country' => $this->convertCountryCode($consignee['country'] ?? 'DE'),
|
||||
], function ($value) {
|
||||
return $value !== null && $value !== '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract locker number from address string or houseNumber field
|
||||
*
|
||||
* Examples:
|
||||
* - "Packstation 145" -> "145"
|
||||
* - "Paketbox 123" -> "123"
|
||||
* - "PACKSTATION 987" -> "987"
|
||||
* - street: "Packstation", houseNumber: "145" -> "145"
|
||||
*
|
||||
* @param string $address Address containing Packstation/Paketbox number
|
||||
* @param string $houseNumber Optional house number field (may contain locker number)
|
||||
* @return string The extracted locker number
|
||||
*/
|
||||
private function extractLockerNumber(string $address, string $houseNumber = ''): string
|
||||
{
|
||||
// Match patterns like "Packstation 145", "Paketbox 123", etc.
|
||||
if (preg_match('/(?:packstation|paketbox)\s*(\d+)/i', $address, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// If address is just "Packstation" or "Paketbox" without number,
|
||||
// check if houseNumber contains the locker number
|
||||
if (preg_match('/^(?:packstation|paketbox)$/i', trim($address)) && ! empty($houseNumber)) {
|
||||
// houseNumber might be the locker number directly
|
||||
if (preg_match('/^\d+$/', trim($houseNumber))) {
|
||||
Log::info('Using houseNumber as locker number', [
|
||||
'address' => $address,
|
||||
'houseNumber' => $houseNumber,
|
||||
]);
|
||||
|
||||
return trim($houseNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// If no pattern matches, try to extract any number from the address string
|
||||
if (preg_match('/(\d+)/', $address, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// Last resort: check if houseNumber contains any number
|
||||
if (! empty($houseNumber) && preg_match('/(\d+)/', $houseNumber, $matches)) {
|
||||
Log::info('Extracted locker number from houseNumber field', [
|
||||
'address' => $address,
|
||||
'houseNumber' => $houseNumber,
|
||||
'extracted' => $matches[1],
|
||||
]);
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// Fallback: return empty string (will trigger validation error with helpful message)
|
||||
Log::warning('Could not extract locker number from address', [
|
||||
'address' => $address,
|
||||
'houseNumber' => $houseNumber,
|
||||
]);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 2-letter country code to 3-letter country code for DHL API
|
||||
*/
|
||||
|
|
@ -374,8 +569,9 @@ class ShippingService
|
|||
Log::info('Using DHL test billing number (sandbox mode)', [
|
||||
'product_code' => $productCode,
|
||||
'billing_number' => $testBillingNumber,
|
||||
'test_mode' => true
|
||||
'test_mode' => true,
|
||||
]);
|
||||
|
||||
return $testBillingNumber;
|
||||
}
|
||||
|
||||
|
|
@ -386,15 +582,16 @@ class ShippingService
|
|||
if ($accountNumber) {
|
||||
Log::info('Using DHL account number from database settings', [
|
||||
'product_code' => $productCode,
|
||||
'account_number' => $accountNumber
|
||||
'account_number' => $accountNumber,
|
||||
]);
|
||||
|
||||
return $accountNumber;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::warning('Could not load DHL account number from settings', [
|
||||
'product_code' => $productCode,
|
||||
'setting_key' => $settingKey,
|
||||
'error' => $e->getMessage()
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -403,8 +600,9 @@ class ShippingService
|
|||
if ($accountNumber) {
|
||||
Log::info('Using DHL account number from config file', [
|
||||
'product_code' => $productCode,
|
||||
'account_number' => $accountNumber
|
||||
'account_number' => $accountNumber,
|
||||
]);
|
||||
|
||||
return $accountNumber;
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +611,7 @@ class ShippingService
|
|||
|
||||
Log::warning('Using default billing number for product code', [
|
||||
'product_code' => $productCode,
|
||||
'billing_number' => $defaultBillingNumber
|
||||
'billing_number' => $defaultBillingNumber,
|
||||
]);
|
||||
|
||||
return $defaultBillingNumber;
|
||||
|
|
@ -471,6 +669,10 @@ class ShippingService
|
|||
$lastname = $consignee['lastname'] ?? '';
|
||||
}
|
||||
|
||||
// Extract email and postnumber
|
||||
$email = $consignee['email'] ?? '';
|
||||
$postnumber = $consignee['postNumber'] ?? $consignee['postnumber'] ?? '';
|
||||
|
||||
// Prepare complete recipient address as JSON
|
||||
$recipientData = [
|
||||
'firstname' => $firstname,
|
||||
|
|
@ -481,8 +683,9 @@ class ShippingService
|
|||
'postalCode' => $consignee['postalCode'] ?? '',
|
||||
'city' => $consignee['city'] ?? '',
|
||||
'country' => $consignee['country'] ?? '',
|
||||
'email' => $consignee['email'] ?? '',
|
||||
'email' => $email,
|
||||
'phone' => $consignee['phone'] ?? '',
|
||||
'postnumber' => $postnumber,
|
||||
];
|
||||
|
||||
return DhlShipment::create([
|
||||
|
|
@ -502,7 +705,9 @@ class ShippingService
|
|||
'firstname' => $firstname,
|
||||
'lastname' => $lastname,
|
||||
'company' => $consignee['name2'] ?? '',
|
||||
'recipient' => $recipientData
|
||||
'email' => $email,
|
||||
'postnumber' => $postnumber,
|
||||
'recipient' => $recipientData,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -511,8 +716,9 @@ class ShippingService
|
|||
*/
|
||||
private function saveLabelFile(DhlShipment $shipment, ?string $labelBase64, string $format): ?string
|
||||
{
|
||||
if (!$labelBase64) {
|
||||
if (! $labelBase64) {
|
||||
Log::warning('No label data received for shipment', ['shipmentId' => $shipment->id]);
|
||||
|
||||
return null;
|
||||
}
|
||||
$path = 'dhl/labels/' . $shipment->dhl_shipment_no . '.' . strtolower($format);
|
||||
|
|
@ -527,10 +733,11 @@ class ShippingService
|
|||
usleep(1000000); // 1 second in microseconds
|
||||
}
|
||||
}
|
||||
if (!$success) {
|
||||
if (! $success) {
|
||||
throw new \Exception('Failed to save label after 3 attempts');
|
||||
}
|
||||
$shipment->update(['label_path' => $path]);
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue