argument('hopdong'); $fileHdKh = $this->argument('hdkh'); if (!file_exists($fileHopDong) || !file_exists($fileHdKh)) { $this->error("Không tìm thấy một trong hai file Excel."); return 1; } // BƯỚC 1: ĐỌC FILE HOPDONG.XLSX ĐỂ LẤY DỮ LIỆU TÀI CHÍNH $this->info("Đang xử lý dữ liệu tài chính từ hopdong.xlsx..."); $sheetFinance = IOFactory::load($fileHopDong)->getActiveSheet(); $rowsFinance = $sheetFinance->toArray(); $financeMap = []; foreach ($rowsFinance as $idx => $row) { if ($idx === 0 || empty($row[2])) continue; // Bỏ qua header hoặc Số HĐMB trống $contractNumber = trim($row[2]); $financeMap[$contractNumber] = [ 'signing_date' => $this->parseExcelDate($row[1]), 'sale_date' => $this->parseExcelDate($row[3]), 'hql_confirmation_date' => $this->parseExcelDate($row[4]), 'brokerage_name' => $row[5], 'land_value' => $this->parseMoney($row[9]), 'foundation_value' => $this->parseMoney($row[10]), 'total_value_with_foundation' => $this->parseMoney($row[11]), 'stored_contract_count' => (int)$row[23], 'filing_note' => $row[26], 'discounts' => [ 'open_sale' => $row[13], 'multi_lot' => $row[14], 'wholesale' => $row[15], 'ctv' => $row[16], 'full_payment' => $row[17], 'total_percentage' => $row[18], 'total_amount' => $this->parseMoney($row[19]), ] ]; } // BƯỚC 2: ĐỌC FILE HD_KH.XLSX ĐỂ TẠO HỢP ĐỒNG VÀ LIÊN KẾT $this->info("Đang xử lý liên kết khách hàng từ Hd_kh.xlsx..."); $sheetLink = IOFactory::load($fileHdKh)->getActiveSheet(); $rowsLink = $sheetLink->toArray(); $count = 0; DB::beginTransaction(); try { foreach ($rowsLink as $idx => $row) { if ($idx === 0 || empty($row[2])) continue; // Bỏ qua header hoặc Mã Lô trống $plotCode = trim($row[2]); $customerCmnd = trim($row[5]); $transferOrder = (int)$row[3]; // Tìm sản phẩm $product = Product::where('code', $plotCode)->first(); if (!$product) { $this->warn("Bỏ qua: Không tìm thấy Lô {$plotCode} trong database."); continue; } // Tìm khách hàng $customer = Customer::where('cmnd_cccd', $customerCmnd)->first(); if (!$customer) { $this->warn("Bỏ qua: Không tìm thấy Khách hàng CMND {$customerCmnd} ({$row[6]})."); continue; } // Logic tìm Hợp đồng tương ứng trong financeMap // Vì hopdong.xlsx không có mã lô, ta sẽ tìm trong financeMap xem Số HĐMB nào có chứa mã lô này $targetContractNumber = null; $financeData = null; foreach ($financeMap as $number => $data) { if (str_contains($number, $plotCode)) { $targetContractNumber = $number; $financeData = $data; break; } } if (!$targetContractNumber) { $this->warn("Lô {$plotCode}: Không tìm thấy thông tin tài chính trong hopdong.xlsx. Sẽ dùng mã tạm."); $targetContractNumber = "HD-TEMP-" . $plotCode . "-" . $transferOrder; } // Tạo/Cập nhật Hợp đồng $contract = Contract::updateOrCreate( ['contract_number' => $targetContractNumber], [ 'product_id' => $product->id, 'signing_date' => $financeData['signing_date'] ?? null, 'total_value' => $financeData['total_value_with_foundation'] ?? 0, 'land_value' => $financeData['land_value'] ?? 0, 'foundation_value' => $financeData['foundation_value'] ?? 0, 'total_value_with_foundation' => $financeData['total_value_with_foundation'] ?? 0, 'discount_details' => $financeData['discounts'] ?? [], 'brokerage_name' => $financeData['brokerage_name'] ?? null, 'sale_date' => $financeData['sale_date'] ?? null, 'hql_confirmation_date' => $financeData['hql_confirmation_date'] ?? null, 'stored_contract_count' => $financeData['stored_contract_count'] ?? 0, 'filing_note' => $financeData['filing_note'] ?? null, 'transfer_order' => $transferOrder, 'contract_type' => 'HĐMB', 'status' => 'Đang hiệu lực', // Tạm thời set mặc định ] ); // Liên kết khách hàng (Pivot) $contract->customers()->syncWithoutDetaching([ $customer->id => [ 'role' => $row[7] ?? 'Chủ SH', 'transfer_order' => $transferOrder ] ]); $count++; } DB::commit(); $this->info("Thành công! Đã tạo và liên kết {$count} bản ghi hợp đồng."); } catch (\Exception $e) { DB::rollBack(); $this->error("Lỗi: " . $e->getMessage()); } return 0; } private function parseMoney($value) { if (empty($value)) return 0; return (float) str_replace([',', ' '], '', $value); } private function parseExcelDate($value) { if (empty($value)) return null; try { if (is_numeric($value)) { return Carbon::instance(ExcelDate::excelToDateTimeObject($value))->format('Y-m-d'); } return Carbon::parse(str_replace('/', '-', $value))->format('Y-m-d'); } catch (\Exception $e) { return null; } } }