108 lines
4.3 KiB
PHP
108 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace Modules\Core\Order\Notifications;
|
|
|
|
use Illuminate\Notifications\AnonymousNotifiable;
|
|
use Illuminate\Notifications\Messages\MailMessage;
|
|
use Illuminate\Support\Facades\Notification as NotificationFacade;
|
|
use Modules\Core\Notification\BaseNotification;
|
|
use Modules\Core\Order\Commands\CloseExpiredReturnWindows;
|
|
use Modules\Core\Order\Events\OrderStatusUpdated;
|
|
use Modules\Core\Order\Listeners\AdvanceFulfillmentOnCarrierCheckpoint;
|
|
use Modules\Core\Order\Listeners\AdvanceFulfillmentOnDelivered;
|
|
use Modules\Core\Order\Listeners\CompleteOrderOnPickedUp;
|
|
use Modules\Core\Order\Services\OrderFulfillmentService;
|
|
use Modules\Core\Order\Services\OrderStatusFlow;
|
|
use Modules\Core\Order\Support\OrderReferenceDisplay;
|
|
|
|
class OrderStatusUpdatedNotification extends BaseNotification
|
|
{
|
|
public function __construct(private readonly OrderStatusUpdated $event) {}
|
|
|
|
public static function getKey(): string
|
|
{
|
|
return 'order.status_updated.customer.mail';
|
|
}
|
|
|
|
public static function listensTo(): string
|
|
{
|
|
return OrderStatusUpdated::class;
|
|
}
|
|
|
|
/**
|
|
* Writes that send their own, richer email for the new status — the
|
|
* generic one stays out of those, or the customer gets two. The same
|
|
* status written any other way (staff's "Update Status", which fires
|
|
* none of those events) still gets the generic email.
|
|
*/
|
|
private const OWN_EMAIL = [
|
|
'ready_for_pickup' => [OrderFulfillmentService::class.'::markReady'], // OrderPickupReadyNotification
|
|
'dispatched' => [AdvanceFulfillmentOnCarrierCheckpoint::class], // OrderDispatchedNotification
|
|
'delivered' => [AdvanceFulfillmentOnDelivered::class], // OrderDeliveredNotification
|
|
'completed' => [CompleteOrderOnPickedUp::class, CloseExpiredReturnWindows::class], // OrderCompletedNotification
|
|
];
|
|
|
|
/**
|
|
* Suppressed when a dedicated notification covers this write (see
|
|
* OWN_EMAIL). Returning no channels is the standard Laravel way to
|
|
* suppress a notification outright.
|
|
*
|
|
* Also suppressed for the order's very first transition off
|
|
* 'awaiting_payment' — for every payment method except bank transfer,
|
|
* that transition happens in the SAME request as checkout itself
|
|
* (Modules\Core\Order\Services\OrderPaymentResolutionService::
|
|
* resolveCaptureOrAuthorization()/resolveDeferredPayment(), both
|
|
* called synchronously alongside Checkout\Events\OrderPlaced), so it's
|
|
* not new information — the shopper was already told their order is
|
|
* confirmed by Modules\Core\Order\Notifications\
|
|
* OrderPlacedNotification moments earlier. A bank transfer order is
|
|
* the one genuine exception: it sits at 'awaiting_payment' until
|
|
* staff separately mark it paid (Modules\Core\Order\Services\
|
|
* OrderFulfillmentService::markPaid()), a real, later event the
|
|
* shopper does need to hear about — see OrderStatusFlow's own
|
|
* docblock for why bank transfer is the only payment method where
|
|
* placement and payment aren't the same moment.
|
|
*/
|
|
public function via(object $notifiable): array
|
|
{
|
|
if (in_array($this->event->causeClass, self::OWN_EMAIL[$this->event->newStatus] ?? [], true)) {
|
|
return [];
|
|
}
|
|
|
|
if ($this->event->previousStatus === 'awaiting_payment'
|
|
&& ! app(OrderStatusFlow::class)->isBankTransfer($this->event->order)) {
|
|
return [];
|
|
}
|
|
|
|
return ['mail'];
|
|
}
|
|
|
|
public function notifiable(): AnonymousNotifiable
|
|
{
|
|
$order = $this->event->order;
|
|
|
|
$email = $order->billingAddress?->contact_email ?? $order->shippingAddress?->contact_email;
|
|
|
|
return NotificationFacade::route('mail', $email);
|
|
}
|
|
|
|
public function toMail(object $notifiable): MailMessage
|
|
{
|
|
$order = $this->event->order;
|
|
|
|
$reference = OrderReferenceDisplay::resolve($order);
|
|
$statusLabel = config("lunar.orders.statuses.{$order->status}.label", $order->status);
|
|
|
|
return (new MailMessage)
|
|
->subject(__('Your order :reference is now :status', [
|
|
'reference' => $reference,
|
|
'status' => $statusLabel,
|
|
]))
|
|
->view('core::order.notifications.status-updated', [
|
|
'order' => $order,
|
|
'reference' => $reference,
|
|
'statusLabel' => $statusLabel,
|
|
]);
|
|
}
|
|
}
|