diff --git a/app/Console/Commands/CertificateGenerateWindow.php b/app/Console/Commands/CertificateGenerateWindow.php index 4d4c516bc..178a4dbae 100644 --- a/app/Console/Commands/CertificateGenerateWindow.php +++ b/app/Console/Commands/CertificateGenerateWindow.php @@ -11,16 +11,18 @@ class CertificateGenerateWindow extends Command protected $signature = 'certificate:generate-window {--edition=2025 : Target edition year} {--type=all : excellence|super-organiser|all} - {--limit=500 : Max recipients to process per type in this run} - {--include-failed : Include rows with previous generation errors}'; + {--limit=500 : Max recipients to process per type per batch} + {--include-failed : Include rows with previous generation errors} + {--once : Run only one batch per type then stop (default: run until no pending left)}'; - protected $description = 'Generate certificates in controlled windows (e.g. 500 at a time); use --type=all for both certs'; + protected $description = 'Generate certificates in batches; runs until no pending left (use --once for single batch)'; public function handle(): int { $edition = (int) $this->option('edition'); $limit = max(1, (int) $this->option('limit')); $includeFailed = (bool) $this->option('include-failed'); + $once = (bool) $this->option('once'); $typeInput = strtolower(trim((string) $this->option('type'))); $types = $this->resolveTypes($typeInput); if ($types === null) { @@ -30,22 +32,21 @@ public function handle(): int $totalOk = 0; $totalFailed = 0; - $any = false; + $batchCount = 0; foreach ($types as $type) { - $result = $this->generateWindowForType($edition, $type, $limit, $includeFailed); - $totalOk += $result['ok']; - $totalFailed += $result['failed']; - if ($result['processed'] > 0) { - $any = true; - } + do { + $result = $this->generateWindowForType($edition, $type, $limit, $includeFailed); + $totalOk += $result['ok']; + $totalFailed += $result['failed']; + if ($result['processed'] > 0) { + $batchCount++; + } + } while (! $once && $result['processed'] > 0); } $this->newLine(); - $this->info("Generate window(s) complete. Total success: {$totalOk}, Total failed: {$totalFailed}."); - if ($any) { - $this->line('Run the same command again to process the next batch.'); - } + $this->info("Generate complete. Batches: {$batchCount}, Total success: {$totalOk}, Total failed: {$totalFailed}."); return self::SUCCESS; } diff --git a/app/Console/Commands/CertificateSendWindow.php b/app/Console/Commands/CertificateSendWindow.php index 341084229..e058bde7c 100644 --- a/app/Console/Commands/CertificateSendWindow.php +++ b/app/Console/Commands/CertificateSendWindow.php @@ -14,16 +14,18 @@ class CertificateSendWindow extends Command protected $signature = 'certificate:send-window {--edition=2025 : Target edition year} {--type=all : excellence|super-organiser|all} - {--limit=500 : Max recipients to send per type in this run} - {--include-send-failed : Include rows that previously failed sending}'; + {--limit=500 : Max recipients to send per type per batch} + {--include-send-failed : Include rows that previously failed sending} + {--once : Run only one batch per type then stop (default: run until no recipients left)}'; - protected $description = 'Send certificate emails in controlled windows (e.g. 500 at a time); use --type=all for both certs'; + protected $description = 'Send certificate emails in batches; runs until no recipients left (use --once for single batch)'; public function handle(): int { $edition = (int) $this->option('edition'); $limit = max(1, (int) $this->option('limit')); $includeSendFailed = (bool) $this->option('include-send-failed'); + $once = (bool) $this->option('once'); $typeInput = strtolower(trim((string) $this->option('type'))); $types = $this->resolveTypes($typeInput); if ($types === null) { @@ -33,22 +35,22 @@ public function handle(): int $totalQueued = 0; $totalFailed = 0; - $any = false; + $batchCount = 0; foreach ($types as $type) { - $result = $this->sendWindowForType($edition, $type, $limit, $includeSendFailed); - $totalQueued += $result['queued']; - $totalFailed += $result['failed']; - if ($result['processed'] > 0) { - $any = true; - } + do { + $result = $this->sendWindowForType($edition, $type, $limit, $includeSendFailed); + $totalQueued += $result['queued']; + $totalFailed += $result['failed']; + if ($result['processed'] > 0) { + $batchCount++; + } + } while (! $once && $result['processed'] > 0); } $this->newLine(); - $this->info("Send window(s) complete. Total queued: {$totalQueued}, Total failed: {$totalFailed}."); - if ($any) { - $this->line('Run the same command again to process the next batch (or ensure queue worker is running: php artisan queue:work).'); - } + $this->info("Send complete. Batches: {$batchCount}, Total queued: {$totalQueued}, Total failed: {$totalFailed}."); + $this->line('Ensure queue worker is running to deliver: php artisan queue:work'); return self::SUCCESS; }