2026-06-14 21:32:07 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Notifications;
|
|
|
|
|
|
|
|
|
|
use App\Contracts\Repositories\OrderRepository;
|
|
|
|
|
use App\Dto\IcsContentDto;
|
|
|
|
|
use App\Jobs\SendMissingOrderReminderJob;
|
|
|
|
|
use App\Models\Employee;
|
|
|
|
|
use App\Services\IcsGeneratorService;
|
|
|
|
|
use Carbon\CarbonImmutable;
|
|
|
|
|
use Carbon\CarbonInterface;
|
|
|
|
|
use Domain\Services\PickupSchedulingService;
|
|
|
|
|
use Illuminate\Bus\Queueable;
|
|
|
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
|
|
|
use Illuminate\Notifications\Messages\MailMessage;
|
|
|
|
|
use Illuminate\Notifications\Notification;
|
2026-10-28 08:53:34 +01:00
|
|
|
use Illuminate\Support\Facades\Config;
|
2026-06-14 21:32:07 +02:00
|
|
|
|
|
|
|
|
class MissingOrderReminderNotification extends Notification implements ShouldQueue
|
|
|
|
|
{
|
|
|
|
|
use Queueable;
|
|
|
|
|
|
|
|
|
|
private readonly string $appName;
|
|
|
|
|
|
|
|
|
|
private readonly string $appUrl;
|
|
|
|
|
|
|
|
|
|
private readonly string $appHost;
|
|
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
|
private readonly CarbonInterface $pickupDay
|
|
|
|
|
) {
|
2026-10-28 08:53:34 +01:00
|
|
|
$appUrl = Config::string('app.url');
|
2026-06-14 21:32:07 +02:00
|
|
|
$appHost = parse_url($appUrl, \PHP_URL_HOST);
|
|
|
|
|
|
|
|
|
|
if (empty($appHost)) {
|
|
|
|
|
throw new \UnexpectedValueException('Invalid app URL configuration');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->appUrl = $appUrl;
|
|
|
|
|
$this->appHost = $appHost;
|
2026-10-28 08:53:34 +01:00
|
|
|
$this->appName = Config::string('app.name', 'La Boutique de Cocotte');
|
2026-06-14 21:32:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the notification should be sent.
|
|
|
|
|
*/
|
|
|
|
|
public function shouldSend(Employee $notifiable, string $channel): bool
|
|
|
|
|
{
|
|
|
|
|
/** @var OrderRepository $orderRepository */
|
|
|
|
|
$orderRepository = app(OrderRepository::class);
|
|
|
|
|
|
|
|
|
|
return ! $orderRepository->hasValidatedOrderForPickupDay(
|
|
|
|
|
$notifiable->matricule,
|
|
|
|
|
$this->pickupDay
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<int, string>
|
|
|
|
|
*/
|
|
|
|
|
public function via(mixed $notifiable): array
|
|
|
|
|
{
|
|
|
|
|
return ['mail'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function toMail(mixed $notifiable): MailMessage
|
|
|
|
|
{
|
|
|
|
|
/** @var Employee $notifiable */
|
|
|
|
|
$icsGenerator = app(IcsGeneratorService::class);
|
|
|
|
|
$schedulingService = app(PickupSchedulingService::class);
|
|
|
|
|
|
|
|
|
|
$cutoffDate = $schedulingService->getPeriodForPickupDate($this->pickupDay)->getStartDate();
|
|
|
|
|
|
|
|
|
|
$closureTime = $cutoffDate->format('G') . 'h';
|
|
|
|
|
$reminderDay = $cutoffDate->translatedFormat('l');
|
|
|
|
|
$reminderTime = $cutoffDate->copy()->subHours(2)->format('G') . 'h';
|
|
|
|
|
|
|
|
|
|
// The reminder event starts 2 hours before the cutoff on the cutoff day
|
|
|
|
|
$eventStart = CarbonImmutable::instance($cutoffDate)->subHours(2);
|
|
|
|
|
$eventEnd = $eventStart->addMinutes(15);
|
|
|
|
|
|
|
|
|
|
$icsContent = $this->generateIcsContent(
|
|
|
|
|
$icsGenerator,
|
|
|
|
|
$eventStart,
|
|
|
|
|
$eventEnd,
|
|
|
|
|
$closureTime
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (new MailMessage())
|
|
|
|
|
->subject(trans(':time before order taking closes - :appname', [
|
|
|
|
|
'time' => SendMissingOrderReminderJob::HOURS_BEFORE_CUTOFF . 'h',
|
|
|
|
|
'appname' => $this->appName,
|
|
|
|
|
]))
|
|
|
|
|
->markdown('emails.missing-order-reminder', [
|
|
|
|
|
'employee' => $notifiable,
|
|
|
|
|
'deliveryDate' => $this->pickupDay->translatedFormat('d/m/Y'),
|
|
|
|
|
'closureTime' => $closureTime,
|
|
|
|
|
'reminderDay' => $reminderDay,
|
|
|
|
|
'reminderTime' => $reminderTime,
|
|
|
|
|
'appHost' => $this->appHost,
|
|
|
|
|
'appUrl' => $this->appUrl,
|
|
|
|
|
])
|
|
|
|
|
->attachData($icsContent, 'rappel-commande.ics', [
|
|
|
|
|
'mime' => 'text/calendar',
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function generateIcsContent(
|
|
|
|
|
IcsGeneratorService $icsGenerator,
|
|
|
|
|
CarbonInterface $eventStart,
|
|
|
|
|
CarbonInterface $eventEnd,
|
|
|
|
|
string $closureTime
|
|
|
|
|
): string {
|
|
|
|
|
|
|
|
|
|
$eventDto = new IcsContentDto(
|
|
|
|
|
uid: 'reminder-' . $eventStart->format('Y-m-d') . '@' . $this->appHost,
|
|
|
|
|
summary: trans('Place my order :appname', [
|
|
|
|
|
'appname' => $this->appName,
|
|
|
|
|
]),
|
|
|
|
|
description: trans('Remember to validate your order before :closureTime on :url', [
|
|
|
|
|
'closureTime' => $closureTime,
|
|
|
|
|
'url' => $this->appHost,
|
|
|
|
|
]),
|
|
|
|
|
startsAt: $eventStart,
|
|
|
|
|
endsAt: $eventEnd,
|
|
|
|
|
url: $this->appUrl
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $icsGenerator->generate($eventDto);
|
|
|
|
|
}
|
|
|
|
|
}
|