option('force'); $query = Contract::query() ->whereNotNull('signing_date') ->when(! $force, fn ($q) => $q->whereDoesntHave('paymentSchedule')); $total = $query->count(); if ($total === 0) { $this->info('Không có hợp đồng nào cần tạo lịch thanh toán.'); return 0; } $this->info("Tìm thấy {$total} hợp đồng cần tạo lịch thanh toán..."); $success = 0; $skipped = 0; $errors = []; $query->chunk(50, function ($contracts) use (&$success, &$skipped, &$errors) { foreach ($contracts as $contract) { try { // Xác định template $template = $contract->paymentTemplate; if (! $template) { $template = $contract->product?->project?->paymentTemplate; } if (! $template) { $skipped++; $this->warn("Bỏ qua HĐ {$contract->contract_number}: Không tìm thấy mẫu thanh toán."); continue; } ContractScheduleService::generateFromTemplate($contract, $template); $success++; $this->info("[OK] HĐ {$contract->contract_number} - Đã tạo lịch từ mẫu '{$template->name}'."); } catch (\Exception $e) { $errors[] = "HĐ {$contract->contract_number}: " . $e->getMessage(); $this->error("[LỖI] HĐ {$contract->contract_number}: " . $e->getMessage()); } } }); $this->newLine(); $this->info("===== KẾT QUẢ ====="); $this->info("Thành công: {$success}"); $this->info("Bỏ qua: {$skipped}"); if (count($errors) > 0) { $this->error("Lỗi: " . count($errors)); foreach ($errors as $err) { $this->error(" - {$err}"); } } return 0; } }