Fix: Correct shipment resolving
This commit is contained in:
@@ -22,11 +22,13 @@ use Modules\Core\Checkout\Exceptions\InvalidShippingOptionException;
|
||||
use Modules\Core\Checkout\Exceptions\NoShippingAddressException;
|
||||
use Modules\Core\Checkout\Exceptions\TermsNotAcceptedException;
|
||||
use Modules\Core\Checkout\Exceptions\UnknownPaymentTypeException;
|
||||
use Lunar\Shipping\Facades\Shipping;
|
||||
use Modules\Core\Payment\Contracts\RequiresFulfillmentType;
|
||||
use Modules\Core\Payment\DTOs\PaymentResult;
|
||||
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\FulfillmentType;
|
||||
|
||||
/**
|
||||
@@ -254,42 +256,59 @@ class CheckoutService
|
||||
* a courier delivery makes no sense (no staff member present at
|
||||
* handoff to take cash), and cash-on-delivery alongside store
|
||||
* pickup is equally meaningless (OfflinePaymentDriver already
|
||||
* covers that in-person moment). A cart with no shipping option
|
||||
* selected yet imposes no constraint here — every method is
|
||||
* offered until a fulfillment type is actually known, the same
|
||||
* leniency setShippingAddress()'s own docblock describes for
|
||||
* required-field enforcement happening at the payment gate, not
|
||||
* mid-checkout.
|
||||
* covers that in-person moment).
|
||||
* 5. for cash-on-delivery specifically, the cart's currently selected
|
||||
* shipping method's own driver implements Modules\Core\Shipping\
|
||||
* Contracts\SupportsCashCollection — "carrier" alone
|
||||
* (RequiresFulfillmentType) isn't precise enough, since an
|
||||
* unattended parcel locker network (Modules\Core\Shipping\
|
||||
* Carriers\BoxNow\BoxNowRateDriver) is a carrier delivery with
|
||||
* nobody there to collect cash, unlike an actual courier
|
||||
* (Modules\Core\Shipping\Carriers\Acs\AcsRateDriver).
|
||||
* Checks 4 and 5 both impose no constraint when the cart has no
|
||||
* shipping option selected yet — every method is offered until a
|
||||
* shipping method is actually known, the same leniency
|
||||
* setShippingAddress()'s own docblock describes for required-field
|
||||
* enforcement happening at the payment gate, not mid-checkout.
|
||||
*
|
||||
* @return Collection<int, PaymentMethod>
|
||||
*/
|
||||
public function getPaymentMethods(): Collection
|
||||
{
|
||||
$fulfillmentType = $this->currentFulfillmentType();
|
||||
$shippingMethod = $this->currentShippingMethod();
|
||||
$fulfillmentType = $shippingMethod ? FulfillmentType::resolve($shippingMethod) : null;
|
||||
|
||||
return $this->paymentMethods->all()
|
||||
->filter(fn (PaymentMethod $method) => $method->enabled && $method->driver_missing_at === null)
|
||||
->filter(function (PaymentMethod $method) use ($fulfillmentType) {
|
||||
->filter(function (PaymentMethod $method) use ($fulfillmentType, $shippingMethod) {
|
||||
$driver = $this->paymentDrivers->resolve($method->driver);
|
||||
|
||||
if (! $driver?->isConfigured()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($fulfillmentType === null || ! $driver instanceof RequiresFulfillmentType) {
|
||||
return true;
|
||||
if ($fulfillmentType !== null && $driver instanceof RequiresFulfillmentType
|
||||
&& $driver->requiredFulfillmentType() !== $fulfillmentType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $driver->requiredFulfillmentType() === $fulfillmentType;
|
||||
// collect(...)->get() rather than Shipping::driver(), which
|
||||
// throws for an unregistered key — a stale ShippingMethod
|
||||
// row (e.g. still pointing at a removed generic driver)
|
||||
// must fail this check quietly, the same as any other
|
||||
// driver this module doesn't recognize.
|
||||
if ($shippingMethod !== null && $method->driver === 'cash-on-delivery') {
|
||||
$shippingDriver = collect(Shipping::getSupportedDrivers())->get($shippingMethod->driver);
|
||||
|
||||
return $shippingDriver instanceof SupportsCashCollection && $shippingDriver->collectsCash();
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 'carrier'|'store_pickup'|null null when the cart has no
|
||||
* shipping option selected yet
|
||||
*/
|
||||
private function currentFulfillmentType(): ?string
|
||||
private function currentShippingMethod(): ?ShippingMethod
|
||||
{
|
||||
$identifier = $this->cart->currentOrCreate()->shippingAddress?->shipping_option;
|
||||
|
||||
@@ -297,9 +316,7 @@ class CheckoutService
|
||||
return null;
|
||||
}
|
||||
|
||||
$method = ShippingMethod::where('code', $identifier)->first();
|
||||
|
||||
return $method ? FulfillmentType::resolve($method) : null;
|
||||
return ShippingMethod::where('code', $identifier)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user