Feature: Add Box Now locker delivery integration

Box Now rate driver (fixed pricing only — no live pricing API) and fulfillment service (delivery request creation, label printing, cancellation). Unlike ACS, Box Now books courier pickup automatically on delivery request creation, so no manifest/pickup-list step is implemented. Storefront locker selection is not yet built; createShipment() expects the chosen locker's locationId to be supplied by the caller.
This commit is contained in:
2026-07-19 00:51:23 +03:00
parent 89255687a1
commit 37c2e1194c
5 changed files with 310 additions and 0 deletions
@@ -0,0 +1,61 @@
<?php
namespace Modules\Core\Shipping\Carriers\BoxNow;
use Lunar\DataTypes\ShippingOption;
use Lunar\Facades\Pricing;
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
use Lunar\Shipping\Interfaces\ShippingRateInterface;
use Lunar\Shipping\Models\ShippingRate;
/**
* Box Now has no pricing API, so this always resolves the admin-configured
* price/price-breaks on the ShippingRate — the same mechanism the built-in
* flat-rate driver uses. Unlike AcsRateDriver, this does not implement
* SupportsLivePricing: there is nothing to toggle between.
*/
class BoxNowRateDriver implements ShippingRateInterface
{
public ShippingRate $shippingRate;
public function name(): string
{
return 'Box Now Locker Delivery';
}
public function description(): string
{
return 'Deliver to a Box Now parcel locker.';
}
public function resolve(ShippingOptionRequest $shippingOptionRequest): ?ShippingOption
{
$shippingRate = $shippingOptionRequest->shippingRate;
$shippingMethod = $shippingRate->shippingMethod;
$cart = $shippingOptionRequest->cart;
$subTotal = $cart->lines->sum('subTotal.value');
$pricing = Pricing::for($shippingRate)->qty($subTotal)->get();
if (! $pricing->matched) {
return null;
}
return new ShippingOption(
name: $shippingMethod->name ?: $this->name(),
description: $shippingMethod->description ?: $this->description(),
identifier: $shippingRate->getIdentifier(),
price: $pricing->matched->price,
taxClass: $shippingRate->getTaxClass(),
taxReference: $shippingRate->getTaxReference(),
);
}
public function on(ShippingRate $shippingRate): self
{
$this->shippingRate = $shippingRate;
return $this;
}
}