Skip to content

Commit f30cf4d

Browse files
committed
Add --catch-up
1 parent 5e5a8e1 commit f30cf4d

File tree

1 file changed

+35
-16
lines changed

1 file changed

+35
-16
lines changed

app/Console/Commands/SendLicenseExpiryWarnings.php

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,22 @@
88

99
class SendLicenseExpiryWarnings extends Command
1010
{
11-
protected $signature = 'licenses:send-expiry-warnings';
11+
protected $signature = 'licenses:send-expiry-warnings {--catch-up : Send missed warnings for licenses within warning windows}';
1212

1313
protected $description = 'Send expiry warning emails for licenses that are expiring soon';
1414

1515
public function handle(): int
1616
{
1717
$warningDays = [30, 7, 1];
1818
$totalSent = 0;
19+
$catchUp = $this->option('catch-up');
20+
21+
if ($catchUp) {
22+
$this->info('Running in catch-up mode - sending missed warnings...');
23+
}
1924

2025
foreach ($warningDays as $days) {
21-
$sent = $this->sendWarningsForDays($days);
26+
$sent = $this->sendWarningsForDays($days, $catchUp);
2227
$totalSent += $sent;
2328

2429
$this->info("Sent {$sent} warning emails for licenses expiring in {$days} day(s)");
@@ -29,24 +34,38 @@ public function handle(): int
2934
return Command::SUCCESS;
3035
}
3136

32-
private function sendWarningsForDays(int $days): int
37+
private function sendWarningsForDays(int $days, bool $catchUp = false): int
3338
{
34-
$targetDate = now()->addDays($days)->startOfDay();
3539
$sent = 0;
3640

37-
// Find licenses that:
38-
// 1. Expire on the target date
39-
// 2. Don't have an active subscription (legacy licenses)
40-
// 3. Haven't been sent a warning for this specific day count recently
41-
$licenses = License::query()
42-
->whereDate('expires_at', $targetDate)
41+
$query = License::query()
4342
->whereNull('subscription_item_id') // Legacy licenses without subscriptions
44-
->whereDoesntHave('expiryWarnings', function ($query) use ($days) {
45-
$query->where('warning_days', $days)
46-
->where('sent_at', '>=', now()->subHours(23)); // Prevent duplicate emails within 23 hours
47-
})
48-
->with('user')
49-
->get();
43+
->with('user');
44+
45+
if ($catchUp) {
46+
// Catch-up mode: find licenses that are within the warning window but haven't received this warning yet
47+
// For 30-day: expires within 30 days (but more than 7 days to avoid overlap)
48+
// For 7-day: expires within 7 days (but more than 1 day)
49+
// For 1-day: expires within 1 day (but hasn't expired yet)
50+
$warningThresholds = [30 => 7, 7 => 1, 1 => 0];
51+
$lowerBound = $warningThresholds[$days] ?? 0;
52+
53+
$query->where('expires_at', '>', now()->addDays($lowerBound)->startOfDay())
54+
->where('expires_at', '<=', now()->addDays($days)->endOfDay())
55+
->whereDoesntHave('expiryWarnings', function ($q) use ($days) {
56+
$q->where('warning_days', $days);
57+
});
58+
} else {
59+
// Normal mode: only licenses expiring on the exact target date
60+
$targetDate = now()->addDays($days)->startOfDay();
61+
$query->whereDate('expires_at', $targetDate)
62+
->whereDoesntHave('expiryWarnings', function ($q) use ($days) {
63+
$q->where('warning_days', $days)
64+
->where('sent_at', '>=', now()->subHours(23)); // Prevent duplicate emails within 23 hours
65+
});
66+
}
67+
68+
$licenses = $query->get();
5069

5170
foreach ($licenses as $license) {
5271
if ($license->user) {

0 commit comments

Comments
 (0)