diff --git a/app/Jobs/SendPaymentFailedReminderJob.php b/app/Jobs/SendPaymentFailedReminderJob.php new file mode 100644 index 0000000..28cee69 --- /dev/null +++ b/app/Jobs/SendPaymentFailedReminderJob.php @@ -0,0 +1,44 @@ +onQueue('notifications'); + } + + public function handle(): void + { + $user = User::find($this->userId); + + if ($user === null) { + return; + } + + if ($user->grace_period_until === null) { + return; + } + + $mailable = match ($this->day) { + 3 => new PaymentFailedDay3Reminder($user), + 5 => new PaymentFailedDay5Reminder($user), + default => throw new InvalidArgumentException("Unsupported reminder day: {$this->day}"), + }; + + Mail::to($user->email)->send($mailable); + } +} diff --git a/tests/Feature/Payments/SendPaymentFailedReminderJobTest.php b/tests/Feature/Payments/SendPaymentFailedReminderJobTest.php new file mode 100644 index 0000000..35dc787 --- /dev/null +++ b/tests/Feature/Payments/SendPaymentFailedReminderJobTest.php @@ -0,0 +1,54 @@ +create(['grace_period_until' => now()->addDays(2)]); + + (new SendPaymentFailedReminderJob($user->id, 3))->handle(); + + Mail::assertSent(PaymentFailedDay3Reminder::class, fn ($mail) => $mail->hasTo($user->email)); +}); + +it('sends the day-5 mailable when grace_period_until is still set', function (): void { + Mail::fake(); + $user = User::factory()->create(['grace_period_until' => now()->addDay()]); + + (new SendPaymentFailedReminderJob($user->id, 5))->handle(); + + Mail::assertSent(PaymentFailedDay5Reminder::class, fn ($mail) => $mail->hasTo($user->email)); +}); + +it('silently skips the day-3 mailable when grace has been cleared', function (): void { + Mail::fake(); + $user = User::factory()->create(['grace_period_until' => null]); + + (new SendPaymentFailedReminderJob($user->id, 3))->handle(); + + Mail::assertNothingSent(); +}); + +it('silently skips the day-5 mailable when grace has been cleared', function (): void { + Mail::fake(); + $user = User::factory()->create(['grace_period_until' => null]); + + (new SendPaymentFailedReminderJob($user->id, 5))->handle(); + + Mail::assertNothingSent(); +}); + +it('silently skips when the user no longer exists', function (): void { + Mail::fake(); + + (new SendPaymentFailedReminderJob(999999, 3))->handle(); + + Mail::assertNothingSent(); +});