Feat: Creating PaymentMethods, Setting Fees, Availabilities
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Checkout\Events;
|
||||
|
||||
use Lunar\Models\Cart;
|
||||
|
||||
/**
|
||||
* Dispatched by CheckoutService::selectPaymentMethod() — carries the plain
|
||||
* type key (e.g. 'cash-on-delivery', 'stripe'), same convention as
|
||||
* CartService's events (a plain reference the listener resolves further
|
||||
* itself, rather than an already-resolved object) since a payment type key
|
||||
* has nothing further to eagerly resolve the way a ShippingOption does.
|
||||
*/
|
||||
class PaymentMethodSelected
|
||||
{
|
||||
public function __construct(
|
||||
public readonly Cart $cart,
|
||||
public readonly string $type,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Core\Checkout\Exceptions;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Thrown by CheckoutService::selectPaymentMethod()/confirmPayment() when
|
||||
* $type doesn't resolve to a registered Modules\Core\Checkout\Contracts\
|
||||
* PaymentDriver (config('payment.drivers')) — same reasoning as
|
||||
* InvalidShippingOptionException: nothing here has a matching Lunar
|
||||
* exception type to reuse, so this is the boboko-owned signal instead of a
|
||||
* silent no-op or an opaque container-resolution error.
|
||||
*/
|
||||
class UnknownPaymentTypeException extends RuntimeException
|
||||
{
|
||||
public function __construct(public readonly string $type)
|
||||
{
|
||||
parent::__construct("The payment type \"{$type}\" is not registered.");
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,14 @@ use Lunar\Facades\ShippingManifest;
|
||||
use Lunar\Models\Cart;
|
||||
use Lunar\Models\Order;
|
||||
use Modules\Core\Cart\Services\CartService;
|
||||
use Modules\Core\Checkout\Contracts\PaymentDriver;
|
||||
use Modules\Core\Checkout\Events\BillingAddressSet;
|
||||
use Modules\Core\Checkout\Events\OrderPlaced;
|
||||
use Modules\Core\Checkout\Events\PaymentMethodSelected;
|
||||
use Modules\Core\Checkout\Events\ShippingAddressSet;
|
||||
use Modules\Core\Checkout\Events\ShippingOptionSelected;
|
||||
use Modules\Core\Checkout\Exceptions\InvalidShippingOptionException;
|
||||
use Modules\Core\Checkout\Exceptions\UnknownPaymentTypeException;
|
||||
|
||||
/**
|
||||
* Storefront-facing checkout operations, mirroring
|
||||
@@ -123,4 +126,63 @@ class CheckoutService
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records which payment type the shopper picked (Cart::meta
|
||||
* ['payment_method']) — read by e.g. Modules\Core\Payment\Pipelines\
|
||||
* Cart\ApplyCashOnDeliveryFee to add that type's own cart-total
|
||||
* adjustments before the shopper reaches placeOrder()/confirmPayment().
|
||||
* Does not itself call a PaymentDriver — selecting a method and
|
||||
* confirming payment against it are deliberately separate steps, same
|
||||
* as selecting a shipping option happens before placing the order.
|
||||
*
|
||||
* @throws UnknownPaymentTypeException if $type has no registered
|
||||
* PaymentDriver (config('lunar.payments.types.<type>.payment_driver'))
|
||||
*/
|
||||
public function selectPaymentMethod(string $type): Cart
|
||||
{
|
||||
$this->paymentDriverFor($type);
|
||||
|
||||
$cart = $this->cart->currentOrCreate();
|
||||
$cart->meta = [...$cart->meta->toArray(), 'payment_method' => $type];
|
||||
$cart->save();
|
||||
|
||||
Event::dispatch(new PaymentMethodSelected($cart, $type));
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves $type's registered PaymentDriver and calls confirm() —
|
||||
* the driver decides whether/when the order actually gets placed (see
|
||||
* Modules\Core\Checkout\Contracts\PaymentDriver's docblock). $data
|
||||
* carries whatever that driver needs (Stripe's payment_intent id, a
|
||||
* future redirect-based provider's callback payload).
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @throws UnknownPaymentTypeException if $type has no registered driver
|
||||
* @throws \Lunar\Exceptions\FingerprintMismatchException
|
||||
* @throws \Lunar\Exceptions\Carts\CartException
|
||||
*/
|
||||
public function confirmPayment(string $type, string $fingerprint, array $data = []): Order
|
||||
{
|
||||
$driver = $this->paymentDriverFor($type);
|
||||
|
||||
return $driver->confirm($this->cart->currentOrCreate(), $fingerprint, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnknownPaymentTypeException
|
||||
*/
|
||||
private function paymentDriverFor(string $type): PaymentDriver
|
||||
{
|
||||
$driverClass = config("lunar.payments.types.{$type}.payment_driver");
|
||||
|
||||
if (! $driverClass) {
|
||||
throw new UnknownPaymentTypeException($type);
|
||||
}
|
||||
|
||||
return app($driverClass);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user