262 lines
9.5 KiB
PHP
262 lines
9.5 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use Acme\Dhl\Models\DhlShipment;
|
|
use Acme\Dhl\Services\ReturnsService;
|
|
use Acme\Dhl\Support\DhlClient;
|
|
use App\Http\Controllers\SettingController;
|
|
use Exception;
|
|
use Illuminate\Bus\Queueable as BusQueueable;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
/**
|
|
* Job to create DHL return labels asynchronously
|
|
*
|
|
* This job handles the creation of DHL return labels in the background,
|
|
* preventing API timeouts and improving user experience.
|
|
*/
|
|
class CreateReturnLabelJob implements ShouldQueue
|
|
{
|
|
use BusQueueable, Dispatchable, InteractsWithQueue, SerializesModels;
|
|
|
|
/**
|
|
* @var DhlShipment
|
|
*/
|
|
public $originalShipment;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
public $options;
|
|
|
|
/**
|
|
* The number of times the job may be attempted.
|
|
*
|
|
* @var int
|
|
*/
|
|
public $tries = 3;
|
|
|
|
/**
|
|
* The maximum number of seconds the job can run before timing out.
|
|
*
|
|
* @var int
|
|
*/
|
|
public $timeout = 120;
|
|
|
|
/**
|
|
* Create a new job instance.
|
|
*/
|
|
public function __construct(DhlShipment $originalShipment, array $options = [])
|
|
{
|
|
$this->originalShipment = $originalShipment;
|
|
$this->options = $options;
|
|
|
|
// Set queue name based on priority
|
|
if (isset($options['priority']) && $options['priority'] === 'high') {
|
|
$this->onQueue('high-priority');
|
|
} else {
|
|
$this->onQueue('dhl-returns');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute the job.
|
|
*/
|
|
public function handle(): void
|
|
{
|
|
try {
|
|
Log::info('[DHL Queue] Starting return label creation job', [
|
|
'original_shipment_id' => $this->originalShipment->id,
|
|
'original_shipment_number' => $this->originalShipment->dhl_shipment_no,
|
|
'attempt' => $this->attempts(),
|
|
]);
|
|
|
|
// Get DHL configuration
|
|
$settingController = new SettingController;
|
|
$dhlConfig = $settingController->getDhlConfig();
|
|
|
|
// Initialize DHL client
|
|
$dhlClient = new DhlClient(
|
|
$dhlConfig['base_url'],
|
|
$dhlConfig['api_key'],
|
|
$dhlConfig['username'],
|
|
$dhlConfig['password']
|
|
);
|
|
|
|
// Use ReturnsService instead of ShippingService
|
|
$returnsService = new ReturnsService($dhlClient);
|
|
|
|
// Prepare return label data from original shipment
|
|
$returnData = $this->prepareReturnLabelData($dhlConfig);
|
|
|
|
Log::info('[DHL Queue] Prepared return data', [
|
|
'returnData' => $returnData,
|
|
]);
|
|
|
|
// Create the return label using ReturnsService (with automatic fallback)
|
|
$result = $returnsService->createReturn($returnData);
|
|
|
|
Log::info('[DHL Queue] Return label created successfully', [
|
|
'original_shipment_id' => $this->originalShipment->id,
|
|
'return_shipment_number' => $result['returnNumber'] ?? 'N/A',
|
|
]);
|
|
} catch (Exception $e) {
|
|
Log::error('[DHL Queue] Return label creation failed', [
|
|
'original_shipment_id' => $this->originalShipment->id,
|
|
'error' => $e->getMessage(),
|
|
'attempt' => $this->attempts(),
|
|
'max_tries' => $this->tries,
|
|
]);
|
|
|
|
// If this is the final attempt, mark as permanently failed
|
|
if ($this->attempts() >= $this->tries) {
|
|
Log::error('[DHL Queue] Return label creation permanently failed', [
|
|
'original_shipment_id' => $this->originalShipment->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
|
|
throw $e; // Re-throw to trigger retry mechanism
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prepare return label data based on original shipment
|
|
*/
|
|
private function prepareReturnLabelData(array $dhlConfig): array
|
|
{
|
|
$order = $this->originalShipment->shoppingOrder;
|
|
$recipient = $this->originalShipment->recipient ?? [];
|
|
|
|
// Check if this is a Packstation delivery - use billing address as return sender
|
|
$hasPostNumber = ! empty($recipient['postnumber'] ?? $recipient['postNumber'] ?? '');
|
|
|
|
if ($hasPostNumber) {
|
|
Log::info('[DHL Queue] Packstation detected - using billing address for return sender', [
|
|
'shipment_id' => $this->originalShipment->id,
|
|
'order_id' => $order->id,
|
|
]);
|
|
|
|
// Load billing address from order
|
|
$shippingUser = $order->shopping_user;
|
|
$shipperAddress = $this->getBillingAddressForReturn($shippingUser, $recipient);
|
|
} else {
|
|
// Use original recipient address (normal delivery)
|
|
$shipperAddress = [
|
|
'name' => trim(($recipient['firstname'] ?? '').' '.($recipient['lastname'] ?? '')),
|
|
'name2' => $recipient['company'] ?? '',
|
|
'street' => $recipient['street'] ?? '',
|
|
'houseNumber' => $recipient['houseNumber'] ?? '',
|
|
'postalCode' => $recipient['postalCode'] ?? '',
|
|
'city' => $recipient['city'] ?? '',
|
|
'country' => $recipient['country'] ?? 'DEU',
|
|
'email' => $recipient['email'] ?? '',
|
|
'phone' => $recipient['phone'] ?? '',
|
|
];
|
|
}
|
|
|
|
return [
|
|
'order_id' => $order->id,
|
|
'original_shipment_id' => $this->originalShipment->id,
|
|
'weight_kg' => $this->originalShipment->weight_kg,
|
|
'label_format' => $this->originalShipment->label_format ?? 'PDF',
|
|
|
|
// Shipper: Customer sends back to us (using billing address for Packstation)
|
|
'shipper' => $shipperAddress,
|
|
|
|
// Consignee: Our warehouse (from settings)
|
|
'consignee' => [
|
|
'name' => $dhlConfig['sender']['company'] ?? 'mivita care gmbh',
|
|
'name2' => $dhlConfig['sender']['name'] ?? '',
|
|
'street' => $dhlConfig['sender']['street'] ?? 'Leinfeld',
|
|
'houseNumber' => $dhlConfig['sender']['house_number'] ?? '2',
|
|
'postalCode' => $dhlConfig['sender']['postalCode'] ?? '87755',
|
|
'city' => $dhlConfig['sender']['city'] ?? 'Kirchhaslach',
|
|
'country' => $dhlConfig['sender']['country'] ?? 'DEU',
|
|
'email' => $dhlConfig['sender']['email'] ?? 'versand@mivita.care',
|
|
'phone' => $dhlConfig['sender']['phone'] ?? '+49 123 456789',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get billing address for return label (used when original delivery was to Packstation)
|
|
*/
|
|
private function getBillingAddressForReturn($shippingUser, array $recipient): array
|
|
{
|
|
if (! $shippingUser) {
|
|
Log::warning('[DHL Queue] No shipping user found, using recipient data', [
|
|
'recipient' => $recipient,
|
|
]);
|
|
|
|
// Fallback: use recipient data but without Packstation fields
|
|
return [
|
|
'name' => trim(($recipient['firstname'] ?? '').' '.($recipient['lastname'] ?? '')),
|
|
'name2' => $recipient['company'] ?? '',
|
|
'street' => 'Adresse fehlt',
|
|
'houseNumber' => '',
|
|
'postalCode' => $recipient['postalCode'] ?? '',
|
|
'city' => $recipient['city'] ?? '',
|
|
'country' => $recipient['country'] ?? 'DEU',
|
|
'email' => $recipient['email'] ?? '',
|
|
'phone' => $recipient['phone'] ?? '',
|
|
];
|
|
}
|
|
|
|
// Parse billing address to extract street and house number
|
|
$billingAddress = trim($shippingUser->billing_address ?? '');
|
|
$street = $billingAddress;
|
|
$houseNumber = '';
|
|
|
|
// Try to extract house number from address
|
|
if (preg_match('/^(.+?)\s+(\d+[a-zA-Z]?[-\/\d]*)$/u', $billingAddress, $matches)) {
|
|
$street = trim($matches[1]);
|
|
$houseNumber = trim($matches[2]);
|
|
}
|
|
|
|
return [
|
|
'name' => trim(($shippingUser->billing_firstname ?? '').' '.($shippingUser->billing_lastname ?? '')),
|
|
'name2' => $shippingUser->billing_company ?? '',
|
|
'street' => $street,
|
|
'houseNumber' => $houseNumber,
|
|
'postalCode' => $shippingUser->billing_zipcode ?? '',
|
|
'city' => $shippingUser->billing_city ?? '',
|
|
'country' => $shippingUser->billing_country?->code ?? 'DEU',
|
|
'email' => $shippingUser->billing_email ?? '',
|
|
'phone' => $shippingUser->billing_phone ?? '',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Handle a job failure.
|
|
*/
|
|
public function failed(Exception $exception): void
|
|
{
|
|
Log::error('[DHL Queue] CreateReturnLabelJob permanently failed', [
|
|
'original_shipment_id' => $this->originalShipment->id,
|
|
'original_shipment_number' => $this->originalShipment->dhl_shipment_no,
|
|
'error' => $exception->getMessage(),
|
|
'trace' => $exception->getTraceAsString(),
|
|
]);
|
|
|
|
// You could implement additional failure handling here:
|
|
// - Send notification to admin
|
|
// - Create manual task for staff to handle return label creation
|
|
// - Update original shipment to mark return label creation failed
|
|
}
|
|
|
|
/**
|
|
* Determine the time at which the job should timeout.
|
|
*
|
|
* @return \DateTime
|
|
*/
|
|
public function retryUntil()
|
|
{
|
|
return now()->addHours(2);
|
|
}
|
|
}
|