Feature: Payment resolver, Payment Provider, Completing Stripe Webhooks, Wiring Payments to checkout service
This commit is contained in:
@@ -2,25 +2,62 @@
|
||||
|
||||
namespace Modules\Core\Order\Listeners;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Lunar\Models\Order;
|
||||
use Modules\Core\Payment\Events\OrderPaymentStatusResolved;
|
||||
use Modules\Core\Checkout\Events\OrderPlaced;
|
||||
use Modules\Core\Payment\Events\PaymentAuthorized;
|
||||
use Modules\Core\Payment\Events\PaymentCaptured;
|
||||
|
||||
/**
|
||||
* The only place an Order's status column is written in reaction to a
|
||||
* payment outcome — Payment dispatches OrderPaymentStatusResolved with
|
||||
* what the status should become, never touching the Order model itself;
|
||||
* this listener, living in Order's own module, is what applies it.
|
||||
* payment outcome. Registered against BOTH PaymentCaptured and
|
||||
* PaymentAuthorized (see OrderServiceProvider) — same handler either way,
|
||||
* since both carry the same {type, result, context} shape and only differ
|
||||
* in which config key decides the resulting status.
|
||||
*
|
||||
* Reads $event->context['order_id'] to find which Order this outcome
|
||||
* belongs to — Payment has no concept of an Order, so this is the one
|
||||
* place that context key gets consumed on the Order side (Payment's own
|
||||
* StripePaymentDriver reads $context['order_id'] independently, for its
|
||||
* own unrelated correlation need — see that class's rememberIntent()).
|
||||
*
|
||||
* Loads and saves the model (not a bulk ::whereKey()->update()) so
|
||||
* Order::observe()'s updated() hook fires and OrderStatusUpdated goes out
|
||||
* the same as any other status write — see that event's own docblock for
|
||||
* why it's meant to fire "regardless of what wrote it."
|
||||
*
|
||||
* Dispatches Checkout\Events\OrderPlaced itself, once placed_at is set —
|
||||
* see that event's own docblock for why this, not CheckoutService, is now
|
||||
* the dispatch point.
|
||||
*/
|
||||
class ApplyResolvedPaymentStatus
|
||||
{
|
||||
public function handle(OrderPaymentStatusResolved $event): void
|
||||
public function handle(PaymentCaptured|PaymentAuthorized $event): void
|
||||
{
|
||||
$order = Order::findOrFail($event->orderId);
|
||||
$order->update(['status' => $event->status]);
|
||||
$orderId = $event->context['order_id'] ?? null;
|
||||
|
||||
if ($orderId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = Order::findOrFail($orderId);
|
||||
|
||||
$configKey = $event instanceof PaymentCaptured ? 'captured_status' : 'authorized_status';
|
||||
$status = config("lunar.payments.types.{$event->type}.{$configKey}");
|
||||
|
||||
if ($status === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wasPlaced = ! blank($order->placed_at);
|
||||
|
||||
$order->update([
|
||||
'status' => $status,
|
||||
'placed_at' => $order->placed_at ?? now(),
|
||||
]);
|
||||
|
||||
if (! $wasPlaced) {
|
||||
Event::dispatch(new OrderPlaced($order));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user