83 lines
3.1 KiB
PHP
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;
|
|
}
|
|
}
|