Files
portal-api/app/Console/Commands/CheckOverdueInvoices.php
T
2026-09-23 15:17:18 +07:00

83 lines
3.1 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Enums\Invoice\InvoiceStatus;
use App\Models\Invoice;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CheckOverdueInvoices extends Command
{
protected $signature = 'invoices:check-overdue {--dry-run : Preview invoices without updating data}';
protected $description = 'Mark unpaid invoices past due date as overdue.';
public function handle(): int
{
$today = now()->toDateString();
$dryRun = (bool) $this->option('dry-run');
$overdueByStatus = Invoice::query()
->whereNotNull('due_date')
->whereDate('due_date', '<', $today)
->selectRaw('status, count(*) as total')
->groupBy('status')
->orderBy('status')
->get();
if ($overdueByStatus->isNotEmpty()) {
$this->line('invoices:check-overdue | Past-due invoices by current status:');
foreach ($overdueByStatus as $row) {
$label = InvoiceStatus::tryFrom((int) $row->status)?->label() ?? 'Không xác định';
$this->line(" - {$label} ({$row->status}): {$row->total}");
}
}
$invoices = Invoice::query()
->with('order:id,status,customer_id')
->whereNotNull('due_date')
->whereDate('due_date', '<', $today)
->whereIn('status', [InvoiceStatus::UNPAID->value, InvoiceStatus::OVERDUE->value])
->get();
$this->info("invoices:check-overdue | Found {$invoices->count()} invoice(s) due before {$today}.");
$updatedInvoices = 0;
foreach ($invoices as $invoice) {
$needsInvoiceUpdate = (int) $invoice->status !== InvoiceStatus::OVERDUE->value;
$this->line(sprintf(
' [%s] Invoice #%s due %s%s',
$dryRun ? 'dry-run' : 'check',
$invoice->invoice_number,
$invoice->due_date?->format('Y-m-d') ?? '-',
$invoice->order_id ? " | order #{$invoice->order_id}" : ''
));
if ($dryRun || ! $needsInvoiceUpdate) {
continue;
}
// Chỉ đổi trạng thái hoá đơn. Trước đây command còn đẩy order về PENDING, nhưng hoá đơn
// gia hạn dùng lại order_id gốc nên một kỳ gia hạn quá hạn sẽ kéo đơn đang chạy về
// "Chờ xử lý" — vừa hiển thị sai, vừa khiến hasPendingOrder() khoá khách đặt đơn mới.
DB::transaction(function () use ($invoice, &$updatedInvoices) {
$invoice->update(['status' => InvoiceStatus::OVERDUE->value]);
$updatedInvoices++;
});
Log::info('Invoice marked overdue', [
'invoice_id' => $invoice->id,
'invoice_number' => $invoice->invoice_number,
'order_id' => $invoice->order_id,
]);
}
$this->info("invoices:check-overdue | Updated {$updatedInvoices} invoice(s).");
return Command::SUCCESS;
}
}