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') ->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; $updatedOrders = 0; foreach ($invoices as $invoice) { $needsInvoiceUpdate = (int) $invoice->status !== InvoiceStatus::OVERDUE->value; $order = $invoice->order; $needsOrderUpdate = $order && ! in_array((int) $order->status, [OrderStatus::PENDING->value, OrderStatus::CANCELLED->value], true); $this->line(sprintf( ' [%s] Invoice #%s due %s%s', $dryRun ? 'dry-run' : 'check', $invoice->invoice_number, $invoice->due_date?->format('Y-m-d') ?? '-', $order ? " | order #{$invoice->order_id}" : '' )); if ($dryRun || (! $needsInvoiceUpdate && ! $needsOrderUpdate)) { continue; } DB::transaction(function () use ($invoice, $order, $needsInvoiceUpdate, $needsOrderUpdate, &$updatedInvoices, &$updatedOrders) { if ($needsInvoiceUpdate) { $invoice->update(['status' => InvoiceStatus::OVERDUE->value]); $updatedInvoices++; } if ($needsOrderUpdate && $order) { $order->update(['status' => OrderStatus::PENDING->value]); $updatedOrders++; } }); 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), {$updatedOrders} order(s)."); return Command::SUCCESS; } }