Chore: Updates to Notifications
This commit is contained in:
@@ -5,6 +5,7 @@ namespace Modules\Core\Checkout\Services;
|
|||||||
use Lunar\Exceptions\FingerprintMismatchException;
|
use Lunar\Exceptions\FingerprintMismatchException;
|
||||||
use Lunar\Exceptions\Carts\CartException;
|
use Lunar\Exceptions\Carts\CartException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Lunar\Base\Addressable;
|
use Lunar\Base\Addressable;
|
||||||
use Lunar\DataTypes\ShippingOption;
|
use Lunar\DataTypes\ShippingOption;
|
||||||
@@ -431,6 +432,22 @@ class CheckoutService
|
|||||||
'terms_accepted' => true,
|
'terms_accepted' => true,
|
||||||
'terms_accepted_at' => now()->toIso8601String(),
|
'terms_accepted_at' => now()->toIso8601String(),
|
||||||
'terms_accepted_policy_version' => $policyVersion,
|
'terms_accepted_policy_version' => $policyVersion,
|
||||||
|
// Order.locale doesn't exist as a column — saved here so every
|
||||||
|
// order notification (OrderPaymentResolutionService/
|
||||||
|
// MarkOrderPlacedOnDeferredPayment fire OrderPlaced synchronously
|
||||||
|
// in THIS request, but a later one — e.g. a Stripe 3-D Secure
|
||||||
|
// webhook, or a staff status change from Filament — has no
|
||||||
|
// request-scoped locale of its own) can render in the locale the
|
||||||
|
// shopper actually checked out in, not whatever locale (or none)
|
||||||
|
// happens to be active when the notification is sent. See
|
||||||
|
// NotificationRegistry::register(), which reads this back.
|
||||||
|
'locale' => App::getLocale(),
|
||||||
|
// Lunar copies the discount onto Order.discount_breakdown but not
|
||||||
|
// the coupon CODE itself — that stays on the cart row, which may
|
||||||
|
// since have been cleared/reused for a new cart. Copied here so
|
||||||
|
// the confirmation email always shows what code THIS order was
|
||||||
|
// actually placed with.
|
||||||
|
'coupon_code' => $cart->coupon_code,
|
||||||
];
|
];
|
||||||
$order->save();
|
$order->save();
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,17 @@ class NotificationRegistry
|
|||||||
if (isset($event->delaySeconds) && $event->delaySeconds > 0) {
|
if (isset($event->delaySeconds) && $event->delaySeconds > 0) {
|
||||||
$notification->delay($event->delaySeconds);
|
$notification->delay($event->delaySeconds);
|
||||||
}
|
}
|
||||||
|
// Every order-notification event carries ->order, whose
|
||||||
|
// ->meta['locale'] was saved at checkout (Checkout\
|
||||||
|
// Services\CheckoutService::initiatePayment()) — the
|
||||||
|
// request that actually sends this may have no locale of
|
||||||
|
// its own (a payment webhook, a queued job, a staff
|
||||||
|
// action from Filament), so this is the only reliable
|
||||||
|
// source. Falls back to the app default for an order
|
||||||
|
// placed before this existed.
|
||||||
|
if (isset($event->order) && $locale = $event->order->meta['locale'] ?? null) {
|
||||||
|
$notification->locale($locale);
|
||||||
|
}
|
||||||
$notification->notifiable()->notify($notification);
|
$notification->notifiable()->notify($notification);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
report($e);
|
report($e);
|
||||||
|
|||||||
@@ -7,8 +7,23 @@ use Illuminate\Notifications\Messages\MailMessage;
|
|||||||
use Illuminate\Support\Facades\Notification as NotificationFacade;
|
use Illuminate\Support\Facades\Notification as NotificationFacade;
|
||||||
use Modules\Core\Notification\BaseNotification;
|
use Modules\Core\Notification\BaseNotification;
|
||||||
use Modules\Core\Order\Events\OrderCaptured;
|
use Modules\Core\Order\Events\OrderCaptured;
|
||||||
|
use Modules\Core\Order\Services\OrderStatusFlow;
|
||||||
use Modules\Core\Order\Support\OrderReferenceDisplay;
|
use Modules\Core\Order\Support\OrderReferenceDisplay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Payment captured" is only a meaningful, distinct update for a bank
|
||||||
|
* transfer order — placing that order and paying for it are genuinely two
|
||||||
|
* separate moments (Order::paid stays false at checkout; a shopper is
|
||||||
|
* told their order is confirmed and awaiting a wire, then separately told
|
||||||
|
* once staff mark it paid). For every other payment method (card,
|
||||||
|
* authorize-then-capture, COD), placing the order already means the
|
||||||
|
* shopper did everything they need to on their end — a card payment is
|
||||||
|
* captured in the very same request that places the order, so a second
|
||||||
|
* "payment captured" email would just repeat what OrderPlacedNotification
|
||||||
|
* already said. See OrderStatusFlow's own docblock for why payment method
|
||||||
|
* never affects the order's status SEQUENCE, only this kind of business
|
||||||
|
* decision about which events actually matter to the shopper.
|
||||||
|
*/
|
||||||
class OrderCapturedNotification extends BaseNotification
|
class OrderCapturedNotification extends BaseNotification
|
||||||
{
|
{
|
||||||
public function __construct(private readonly OrderCaptured $event) {}
|
public function __construct(private readonly OrderCaptured $event) {}
|
||||||
@@ -25,6 +40,10 @@ class OrderCapturedNotification extends BaseNotification
|
|||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
{
|
{
|
||||||
|
if (! app(OrderStatusFlow::class)->isBankTransfer($this->event->order)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
return ['mail'];
|
return ['mail'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +65,7 @@ class OrderCapturedNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Payment captured for your order :reference', ['reference' => $reference]))
|
->subject(__('Payment captured for your order :reference', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.captured', [
|
->view('core::order.notifications.captured', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
'amount' => $this->event->transaction->amount->formatted,
|
'amount' => $this->event->transaction->amount->formatted,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class OrderCompletedNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Your order :reference is complete', ['reference' => $reference]))
|
->subject(__('Your order :reference is complete', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.completed', [
|
->view('core::order.notifications.completed', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class OrderDeliveredNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Your order :reference has been delivered', ['reference' => $reference]))
|
->subject(__('Your order :reference has been delivered', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.delivered', [
|
->view('core::order.notifications.delivered', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class OrderDispatchedNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Your order :reference is on its way', ['reference' => $reference]))
|
->subject(__('Your order :reference is on its way', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.dispatched', [
|
->view('core::order.notifications.dispatched', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class OrderPickupReadyNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Your order :reference is ready for pickup', ['reference' => $reference]))
|
->subject(__('Your order :reference is ready for pickup', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.pickup-ready', [
|
->view('core::order.notifications.pickup-ready', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class OrderPlacedNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Your order :reference is confirmed', ['reference' => $reference]))
|
->subject(__('Your order :reference is confirmed', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.placed', [
|
->view('core::order.notifications.placed', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
'total' => $order->total->formatted,
|
'total' => $order->total->formatted,
|
||||||
'lines' => $order->lines,
|
'lines' => $order->lines,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class OrderRefundedNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('A refund has been issued for your order :reference', ['reference' => $reference]))
|
->subject(__('A refund has been issued for your order :reference', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.refunded', [
|
->view('core::order.notifications.refunded', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
'amount' => $this->event->transaction->amount->formatted,
|
'amount' => $this->event->transaction->amount->formatted,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class OrderStatusUpdatedNotification extends BaseNotification
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Your order :reference has been updated', ['reference' => $reference]))
|
->subject(__('Your order :reference has been updated', ['reference' => $reference]))
|
||||||
->view('core::order.notifications.status-updated', [
|
->view('core::order.notifications.status-updated', [
|
||||||
|
'order' => $order,
|
||||||
'reference' => $reference,
|
'reference' => $reference,
|
||||||
'statusLabel' => config("lunar.orders.statuses.{$order->status}.label", $order->status),
|
'statusLabel' => config("lunar.orders.statuses.{$order->status}.label", $order->status),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace Modules\Core\Store\Services;
|
|||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Lunar\Models\Language;
|
use Lunar\Models\Language;
|
||||||
|
use Lunar\Models\Order;
|
||||||
|
use Modules\Core\Order\Services\OrderStatusFlow;
|
||||||
use Modules\Core\Store\Events\StoreDetailsUpdated;
|
use Modules\Core\Store\Events\StoreDetailsUpdated;
|
||||||
use Modules\Core\Store\Models\StoreDetails;
|
use Modules\Core\Store\Models\StoreDetails;
|
||||||
|
|
||||||
@@ -35,6 +37,24 @@ class StoreDetailsService
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null for any non-bank-transfer order — the confirmation email only
|
||||||
|
* shows this block when there's actually a wire to send (see
|
||||||
|
* BankTransferPaymentDriver's own docblock for why a bank transfer
|
||||||
|
* order stays at 'awaiting_payment' until staff confirm the wire
|
||||||
|
* arrived). Null also when the store hasn't filled the field in for
|
||||||
|
* $locale, so the caller's own @if($bankTransferInstructions) guard
|
||||||
|
* covers both cases identically.
|
||||||
|
*/
|
||||||
|
public function bankTransferInstructionsFor(Order $order, string $locale): ?string
|
||||||
|
{
|
||||||
|
if (! app(OrderStatusFlow::class)->isBankTransfer($order)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->current()->translate('bank_transfer_instructions', $locale) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
public function update(array $attributes): StoreDetails
|
public function update(array $attributes): StoreDetails
|
||||||
{
|
{
|
||||||
$storeDetails = $this->firstOrCreate();
|
$storeDetails = $this->firstOrCreate();
|
||||||
|
|||||||
Reference in New Issue
Block a user