2026-07-19 00:50:51 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Modules\Core\Shipping\Carriers\Acs;
|
|
|
|
|
|
|
|
|
|
use Lunar\DataTypes\Price;
|
|
|
|
|
use Lunar\DataTypes\ShippingOption;
|
|
|
|
|
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
|
|
|
|
|
use Lunar\Shipping\Interfaces\ShippingRateInterface;
|
|
|
|
|
use Lunar\Shipping\Models\ShippingRate;
|
|
|
|
|
use Modules\Core\Shipping\Carriers\Acs\Exceptions\AcsApiException;
|
2026-07-19 02:24:10 +03:00
|
|
|
use Modules\Core\Shipping\Concerns\ResolvesFixedPricing;
|
2026-07-19 00:50:51 +03:00
|
|
|
use Modules\Core\Shipping\Contracts\SupportsLivePricing;
|
|
|
|
|
|
|
|
|
|
class AcsRateDriver implements ShippingRateInterface, SupportsLivePricing
|
|
|
|
|
{
|
2026-07-19 02:24:10 +03:00
|
|
|
use ResolvesFixedPricing;
|
|
|
|
|
|
2026-07-19 00:50:51 +03:00
|
|
|
public ShippingRate $shippingRate;
|
|
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
|
private readonly AcsClient $client,
|
|
|
|
|
private readonly AreaResolver $areaResolver,
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
public function name(): string
|
|
|
|
|
{
|
|
|
|
|
return 'ACS Courier';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function description(): string
|
|
|
|
|
{
|
|
|
|
|
return 'Live rate quote from ACS Courier.';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function resolve(ShippingOptionRequest $shippingOptionRequest): ?ShippingOption
|
|
|
|
|
{
|
|
|
|
|
$shippingRate = $shippingOptionRequest->shippingRate;
|
|
|
|
|
$shippingMethod = $shippingRate->shippingMethod;
|
|
|
|
|
$cart = $shippingOptionRequest->cart;
|
|
|
|
|
|
2026-07-19 02:24:10 +03:00
|
|
|
if (($shippingMethod->data['charge_by'] ?? 'cart_total') !== 'live') {
|
2026-07-19 00:50:51 +03:00
|
|
|
return $this->resolveFixedPrice($shippingRate, $shippingMethod, $cart);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-19 02:24:10 +03:00
|
|
|
$postcode = $cart->shippingAddress?->postcode;
|
2026-07-19 00:50:51 +03:00
|
|
|
|
2026-07-19 02:24:10 +03:00
|
|
|
if (! $postcode) {
|
2026-07-19 00:50:51 +03:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-19 02:24:10 +03:00
|
|
|
return $this->resolveLivePrice($shippingRate, $shippingMethod, $cart, $postcode);
|
2026-07-19 00:50:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function resolveLivePrice(ShippingRate $shippingRate, $shippingMethod, $cart, string $postcode): ?ShippingOption
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$destination = $this->areaResolver->resolve($postcode);
|
|
|
|
|
|
|
|
|
|
$response = $this->client->call('ACS_Price_Calculation', [
|
|
|
|
|
'Billing_Code' => config('acs.billing_code'),
|
|
|
|
|
'Acs_Station_Destination' => $destination->stationId,
|
|
|
|
|
'Weight' => $this->totalWeightInKg($cart),
|
|
|
|
|
'Pickup_Date' => now()->toDateString(),
|
|
|
|
|
'Charge_Type' => 2,
|
|
|
|
|
])->throwIfError();
|
|
|
|
|
} catch (AcsApiException $e) {
|
|
|
|
|
report($e);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$amount = (int) round(($response->valueOutput['Total_Ammount'] ?? 0) * 100);
|
|
|
|
|
|
|
|
|
|
return new ShippingOption(
|
|
|
|
|
name: $shippingMethod->name ?: $this->name(),
|
|
|
|
|
description: $shippingMethod->description ?: $this->description(),
|
|
|
|
|
identifier: $shippingRate->getIdentifier(),
|
|
|
|
|
price: new Price($amount, $cart->currency, 1),
|
|
|
|
|
taxClass: $shippingRate->getTaxClass(),
|
|
|
|
|
taxReference: $shippingRate->getTaxReference(),
|
|
|
|
|
meta: ['acs_station_destination' => $destination->stationId],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function on(ShippingRate $shippingRate): self
|
|
|
|
|
{
|
|
|
|
|
$this->shippingRate = $shippingRate;
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function totalWeightInKg($cart): float
|
|
|
|
|
{
|
|
|
|
|
$weight = 0.0;
|
|
|
|
|
|
|
|
|
|
foreach ($cart->lines->load('purchasable') as $line) {
|
|
|
|
|
$variant = $line->purchasable;
|
|
|
|
|
|
|
|
|
|
if (! $variant || ! $variant->weight_value) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$unit = $variant->weight_unit ?? 'kg';
|
|
|
|
|
$value = (float) $variant->weight_value;
|
|
|
|
|
|
|
|
|
|
$weight += match ($unit) {
|
|
|
|
|
'g' => $value / 1000,
|
|
|
|
|
'lb' => $value * 0.45359237,
|
|
|
|
|
'oz' => $value * 0.0283495231,
|
|
|
|
|
default => $value, // kg
|
|
|
|
|
} * $line->quantity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return max($weight, 0.5); // ACS minimum billable weight
|
|
|
|
|
}
|
|
|
|
|
}
|