169 lines
7.1 KiB
PHP
169 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use App\Models\Contract;
|
|
use App\Models\Product;
|
|
use App\Models\Customer;
|
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ImportContractsComplex extends Command
|
|
{
|
|
protected $signature = 'import:contracts-complex {hopdong=hopdong.xlsx} {hdkh=Hd_kh.xlsx}';
|
|
protected $description = 'Import hợp đồng và liên kết khách hàng từ 2 file Excel';
|
|
|
|
public function handle()
|
|
{
|
|
$fileHopDong = $this->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)
|
|
// syncWithoutDetaching đảm bảo nhiều KH cùng 1 HĐ không bị ghi đè lẫn nhau
|
|
$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;
|
|
}
|
|
}
|
|
}
|