Fix: Resolving box now by instance, not by type. Also, fixing bug where missing shipping driver would break checkout
This commit is contained in:
@@ -29,6 +29,7 @@ use Modules\Core\Payment\Models\PaymentMethod;
|
||||
use Modules\Core\Payment\Services\PaymentDriverRegistry;
|
||||
use Modules\Core\Payment\Services\PaymentMethodCache;
|
||||
use Modules\Core\Shipping\Contracts\SupportsCashCollection;
|
||||
use Modules\Core\Shipping\Support\BoxNowShipping;
|
||||
use Modules\Core\Shipping\Support\FulfillmentType;
|
||||
|
||||
/**
|
||||
@@ -181,7 +182,7 @@ class CheckoutService
|
||||
// switches BACK to Box Now and it resurfaces as if still chosen,
|
||||
// possibly for a locker that no longer exists/fits. Cleared here,
|
||||
// the one place that knows the method just changed.
|
||||
if ($identifier !== 'box-now') {
|
||||
if (! BoxNowShipping::isOption($identifier)) {
|
||||
$address = $cart->shippingAddress;
|
||||
|
||||
if ($address && isset($address->meta['box_now_locker'])) {
|
||||
|
||||
@@ -19,6 +19,7 @@ use Modules\Core\Shipping\Enums\TrackingStatus;
|
||||
use Modules\Core\Shipping\Events\ShipmentStatusUpdatedByCarrier;
|
||||
use Modules\Core\Shipping\Filament\Resources\ShipmentResource;
|
||||
use Modules\Core\Shipping\Models\Shipment;
|
||||
use Modules\Core\Shipping\Support\BoxNowShipping;
|
||||
|
||||
/**
|
||||
* Adds a "Shipments" section to the order page's main column — previously
|
||||
@@ -224,7 +225,7 @@ class OrderShipmentsExtension extends ViewPageExtension
|
||||
{
|
||||
$parts = ['Created '.$record->created_at->format('Y-m-d H:i')];
|
||||
|
||||
if ($record->carrier === 'box-now' && $locker = $record->meta['locker_id'] ?? null) {
|
||||
if (BoxNowShipping::isDriver($record->carrier) && $locker = $record->meta['locker_id'] ?? null) {
|
||||
$parts[] = 'Locker '.$locker;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ use Modules\Core\Shipping\Contracts\SupportsVoucherLookup;
|
||||
use Modules\Core\Shipping\DTOs\ShipmentRequest;
|
||||
use Modules\Core\Shipping\Enums\ExtraService;
|
||||
use Modules\Core\Shipping\Models\Shipment;
|
||||
use Modules\Core\Shipping\Support\BoxNowShipping;
|
||||
use Modules\Core\Shipping\Support\WeightCalculator;
|
||||
use Throwable;
|
||||
|
||||
@@ -122,7 +123,7 @@ class OrderViewExtension extends ViewPageExtension
|
||||
->modalSubmitActionLabel('Create Shipment')
|
||||
->schema(function (Order $record) {
|
||||
$carrier = $this->service()->carrierFor($record);
|
||||
$isBoxNow = $carrier === 'box-now';
|
||||
$isBoxNow = BoxNowShipping::isDriver($carrier);
|
||||
$lockerId = $record->shippingAddress?->meta['box_now_locker']['locationId'] ?? null;
|
||||
|
||||
if ($carrier === 'manual') {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Shipping\Support;
|
||||
|
||||
use Lunar\Shipping\Facades\Shipping;
|
||||
use Lunar\Shipping\Models\ShippingMethod;
|
||||
use Modules\Core\Shipping\Carriers\BoxNow\BoxNowRateDriver;
|
||||
|
||||
/**
|
||||
* Whether something is Box Now — a checkout option, a shipping method, a
|
||||
* driver key — by checking that the driver is a BoxNowRateDriver, never by
|
||||
* comparing names: an option's identifier is the merchant-typed method
|
||||
* code (may well not be "box-now"), and the driver may be registered under
|
||||
* any key.
|
||||
*/
|
||||
class BoxNowShipping
|
||||
{
|
||||
public static function isOption(?string $identifier): bool
|
||||
{
|
||||
return $identifier !== null
|
||||
&& self::isMethod(ShippingMethod::where('code', $identifier)->first());
|
||||
}
|
||||
|
||||
public static function isMethod(?ShippingMethod $method): bool
|
||||
{
|
||||
return self::isDriver($method?->driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shipping driver key (a method's `driver`, a shipment's `carrier`)
|
||||
* that resolves to Box Now. getSupportedDrivers() rather than
|
||||
* Shipping::driver(), which throws for a key no longer registered.
|
||||
*/
|
||||
public static function isDriver(?string $driver): bool
|
||||
{
|
||||
return $driver !== null
|
||||
&& Shipping::getSupportedDrivers()->get($driver) instanceof BoxNowRateDriver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Codes of every Box Now shipping method — for marking options in bulk.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function codes(): array
|
||||
{
|
||||
return ShippingMethod::all()
|
||||
->filter(fn (ShippingMethod $method) => self::isMethod($method))
|
||||
->pluck('code')
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Shipping\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Lunar\Shipping\Facades\Shipping;
|
||||
use Lunar\Shipping\Resolvers\ShippingRateResolver;
|
||||
|
||||
/**
|
||||
* Lunar's rate resolver, minus rates whose shipping method points at a
|
||||
* driver that isn't registered anymore (e.g. a carrier commented out of
|
||||
* ShippingServiceProvider while its shipping method still exists). Lunar
|
||||
* would go on to call that driver to price the option and throw "Driver
|
||||
* [x] not supported", taking the whole checkout down; here the method is
|
||||
* simply not offered. It stays in the admin as it was.
|
||||
*/
|
||||
class RegisteredDriverRateResolver extends ShippingRateResolver
|
||||
{
|
||||
public function get(): Collection
|
||||
{
|
||||
$registered = Shipping::getSupportedDrivers();
|
||||
|
||||
return parent::get()
|
||||
->filter(fn ($rate) => $registered->has($rate->shippingMethod?->driver))
|
||||
->values();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Modules\Core\Shipping\Support;
|
||||
|
||||
use Lunar\Models\Contracts\Cart as CartContract;
|
||||
use Lunar\Shipping\Managers\ShippingManager as VendorShippingManager;
|
||||
use Lunar\Shipping\Resolvers\ShippingRateResolver;
|
||||
|
||||
/**
|
||||
* Drops lunarphp/table-rate-shipping's own generic drivers (free-shipping,
|
||||
@@ -28,6 +30,15 @@ use Lunar\Shipping\Managers\ShippingManager as VendorShippingManager;
|
||||
*/
|
||||
class ShippingManager extends VendorShippingManager
|
||||
{
|
||||
/**
|
||||
* Rates for a cart, leaving out shipping methods whose driver is no
|
||||
* longer registered (see RegisteredDriverRateResolver).
|
||||
*/
|
||||
public function shippingRates(?CartContract $cart = null): ShippingRateResolver
|
||||
{
|
||||
return new RegisteredDriverRateResolver($cart);
|
||||
}
|
||||
|
||||
public function getSupportedDrivers(): \Illuminate\Support\Collection
|
||||
{
|
||||
return collect($this->customCreators)
|
||||
|
||||
Reference in New Issue
Block a user