Feature: Abstraction on Payments based on their operations

This commit is contained in:
2026-09-03 16:01:33 +03:00
parent 0fa2188146
commit a987a2d57c
25 changed files with 497 additions and 381 deletions
-62
View File
@@ -1,62 +0,0 @@
<?php
namespace Modules\Core\Checkout\Contracts;
use Lunar\Exceptions\FingerprintMismatchException;
use Lunar\Exceptions\Carts\CartException;
use Lunar\Models\Cart;
use Lunar\Models\Order;
/**
* A boboko-owned payment driver — wraps a payment gateway's own confirmation
* mechanics (Stripe's synchronous authorize() call, a redirect-based
* provider's async callback/webhook, anything else) behind one uniform
* moment: "payment is confirmed, place the order."
*
* confirm() is the only thing a driver is required to do: once it has,
* by whatever mechanism is native to that gateway, independently decided
* the payment succeeded, it calls Modules\Core\Checkout\Services\
* CheckoutService::placeOrder($fingerprint) itself — no driver ever calls
* Lunar\Models\Cart::createOrder() directly. This is what lets the
* storefront checkout sequence stay uniform regardless of which provider is
* active: set addresses, select shipping, hand off to whichever driver is
* configured, and the driver decides when (or whether) the order actually
* gets created. See docs/checkout.md / docs/payments.md.
*/
interface PaymentDriver
{
/**
* Whether this driver can actually be used right now — e.g. Stripe
* checking its own API key is present, an offline-style driver always
* returning true since it has no external dependency. Independent of
* Modules\Core\Payment\Models\PaymentMethod::enabled (the admin
* on/off toggle) — CheckoutService::getPaymentMethods() combines both:
* a type is only offered to the storefront if it's administratively
* enabled AND its driver reports itself configured.
*/
public function isConfigured(): bool;
/**
* $type is the payment type key being confirmed (e.g. 'cash-in-hand',
* 'cash-on-delivery', 'stripe') — passed through even though most
* drivers only ever serve one type, because a driver shared across
* several types (e.g. one "no real confirmation" offline driver behind
* both cash-in-hand and cash-on-delivery) needs it to look up that
* type's own config (e.g. its 'authorized' status) rather than another
* type's.
*
* $data carries whatever the gateway needs to confirm this specific
* payment (Stripe: ['payment_intent' => $id], a redirect-based
* provider: its callback payload) — passed explicitly by the caller
* (a controller, a webhook job) rather than a driver reaching into the
* global request(), so confirm() works the same whether it's called
* from a synchronous HTTP request or an async webhook/job with no
* active request at all.
*
* @param array<string, mixed> $data
*
* @throws FingerprintMismatchException
* @throws CartException
*/
public function confirm(Cart $cart, string $type, string $fingerprint, array $data): Order;
}
-36
View File
@@ -1,36 +0,0 @@
<?php
namespace Modules\Core\Checkout\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Lunar\Models\Cart;
/**
* Dispatched by a PaymentDriver once it has independently decided (by
* whatever mechanism is native to its gateway) that payment succeeded —
* the event-driven counterpart to what used to be a direct
* CheckoutService::placeOrder() call from inside confirm(). Listened to by
* CheckoutService itself, which places the order and dispatches
* OrderPlaced.
*
* $type/$data are carried through for the same reason PaymentDriver::
* confirm() takes them — a driver-specific post-placement step (e.g.
* OfflinePaymentDriver's status mapping, StripePaymentDriver's
* UpdateOrderFromIntent) still needs them, but can no longer receive the
* placed Order as a return value. Each driver instead listens for
* OrderPlaced and checks $order->meta['payment_method'] against its own
* type(s) to recognize which OrderPlaced is its own — carrying $fingerprint
* here too lets a driver correlate its own OrderPlaced listener call back
* to the specific confirmation that triggered it, if it needs to.
*/
class PaymentConfirmed
{
use Dispatchable;
public function __construct(
public readonly Cart $cart,
public readonly string $type,
public readonly string $fingerprint,
public readonly array $data = [],
) {}
}