134 lines
4.6 KiB
PHP
134 lines
4.6 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace Modules\Core\Shipping\Carriers\Acs;
|
||
|
|
|
||
|
|
use Illuminate\Support\Collection;
|
||
|
|
use Lunar\Models\Order;
|
||
|
|
use Modules\Core\Shipping\Contracts\CarrierFulfillmentInterface;
|
||
|
|
use Modules\Core\Shipping\Contracts\SupportsManifestBatching;
|
||
|
|
use Modules\Core\Shipping\DataTransferObjects\ManifestResult;
|
||
|
|
use Modules\Core\Shipping\Models\Shipment;
|
||
|
|
|
||
|
|
class AcsFulfillmentService implements CarrierFulfillmentInterface, SupportsManifestBatching
|
||
|
|
{
|
||
|
|
public function __construct(
|
||
|
|
private readonly AcsClient $client,
|
||
|
|
private readonly AreaResolver $areaResolver,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
public function createShipment(Order $order, array $overrides = []): Shipment
|
||
|
|
{
|
||
|
|
$address = $order->shippingAddress;
|
||
|
|
$destination = $this->areaResolver->resolve($address->postcode);
|
||
|
|
|
||
|
|
$response = $this->client->call('ACS_Create_Voucher', array_merge([
|
||
|
|
'Pickup_Date' => now()->toDateString(),
|
||
|
|
'Sender' => config('acs.sender.name'),
|
||
|
|
'Recipient_Name' => trim("{$address->first_name} {$address->last_name}"),
|
||
|
|
'Recipient_Address' => $address->line_one,
|
||
|
|
'Recipient_Zipcode' => $address->postcode,
|
||
|
|
'Recipient_Region' => $address->city,
|
||
|
|
'Recipient_Phone' => $address->contact_phone,
|
||
|
|
'Recipient_Country' => 'GR',
|
||
|
|
'Acs_Station_Branch_Destination' => $destination->branchId,
|
||
|
|
'Billing_Code' => config('acs.billing_code'),
|
||
|
|
'Charge_Type' => 2,
|
||
|
|
'Item_Quantity' => 1,
|
||
|
|
'Weight' => 0.5,
|
||
|
|
], $overrides))->throwIfError();
|
||
|
|
|
||
|
|
$voucherNo = (string) $response->valueOutput['Voucher_No'];
|
||
|
|
|
||
|
|
$shipment = Shipment::create([
|
||
|
|
'order_id' => $order->id,
|
||
|
|
'carrier' => 'acs',
|
||
|
|
'tracking_reference' => $voucherNo,
|
||
|
|
'meta' => [
|
||
|
|
'station_destination' => $destination->stationId,
|
||
|
|
'weight' => $overrides['Weight'] ?? 0.5,
|
||
|
|
'pickup_date' => now()->toDateString(),
|
||
|
|
],
|
||
|
|
]);
|
||
|
|
|
||
|
|
if (($overrides['Item_Quantity'] ?? 1) > 1) {
|
||
|
|
$this->persistMultipartVouchers($shipment);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $shipment;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function printLabel(Shipment $shipment): string
|
||
|
|
{
|
||
|
|
$response = $this->client->call('ACS_Print_Voucher', [
|
||
|
|
'Voucher_No' => $shipment->tracking_reference,
|
||
|
|
'Print_Type' => 2,
|
||
|
|
'Start_Position' => 1,
|
||
|
|
])->throwIfError();
|
||
|
|
|
||
|
|
$shipment->update(['label_printed_at' => now()]);
|
||
|
|
|
||
|
|
return $response->valueOutput[$shipment->tracking_reference] ?? '';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function cancelShipment(Shipment $shipment): void
|
||
|
|
{
|
||
|
|
if ($shipment->manifest_reference) {
|
||
|
|
throw new \RuntimeException('Cannot cancel a shipment already included in an issued manifest.');
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->client->call('ACS_Delete_Voucher', [
|
||
|
|
'Voucher_No' => $shipment->tracking_reference,
|
||
|
|
])->throwIfError();
|
||
|
|
|
||
|
|
$shipment->update(['cancelled_at' => now()]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function pendingForManifest(): Collection
|
||
|
|
{
|
||
|
|
return Shipment::query()
|
||
|
|
->where('carrier', 'acs')
|
||
|
|
->whereNull('manifest_reference')
|
||
|
|
->whereNull('cancelled_at')
|
||
|
|
->get();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function issueManifest(Collection $shipments): ManifestResult
|
||
|
|
{
|
||
|
|
$unprinted = $shipments->whereNull('label_printed_at');
|
||
|
|
|
||
|
|
if ($unprinted->isNotEmpty()) {
|
||
|
|
return ManifestResult::blocked($unprinted, 'unprinted');
|
||
|
|
}
|
||
|
|
|
||
|
|
$response = $this->client->call('ACS_Issue_Pickup_List', [
|
||
|
|
'Pickup_Date' => now()->toDateString(),
|
||
|
|
'MyData' => null,
|
||
|
|
])->throwIfError();
|
||
|
|
|
||
|
|
$pickupListNo = (string) $response->valueOutput['PickupList_No'];
|
||
|
|
|
||
|
|
$shipments->each(fn (Shipment $shipment) => $shipment->update([
|
||
|
|
'manifest_reference' => $pickupListNo,
|
||
|
|
]));
|
||
|
|
|
||
|
|
return ManifestResult::success($pickupListNo, $shipments);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function persistMultipartVouchers(Shipment $mainShipment): void
|
||
|
|
{
|
||
|
|
$response = $this->client->call('ACS_Get_Multipart_Vouchers', [
|
||
|
|
'Main_Voucher_No' => $mainShipment->tracking_reference,
|
||
|
|
])->throwIfError();
|
||
|
|
|
||
|
|
foreach ($response->tableOutput['Table_Data'] ?? [] as $row) {
|
||
|
|
Shipment::create([
|
||
|
|
'order_id' => $mainShipment->order_id,
|
||
|
|
'carrier' => 'acs',
|
||
|
|
'tracking_reference' => $row['MultiPart_Voucher_No'],
|
||
|
|
'parent_reference' => $mainShipment->tracking_reference,
|
||
|
|
'meta' => $mainShipment->meta?->toArray() ?? [],
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|