# HQLAND - TRẠNG THÁI CODEBASE & LỘ TRÌNH PHÁT TRIỂN > File này được tạo để lưu trữ ngữ cảnh dự án cho các phiên làm việc sau. > **Cập nhật:** 24/04/2026 > **Dự án:** HQLand - Hệ thống quản lý Bất động sản > **Stack:** Laravel 13 + Filament v5.5 (Schemas Architecture) + PostgreSQL + UUID --- ## 1. THÔNG TIN KẾT NỐI DATABASE (CRITICAL) ### Database Chính (Production Data) - **Connection:** pgsql - **Host:** pgsql (trong Docker), 127.0.0.1 (từ Host machine) - **Port:** 5432 - **Database:** laravel - **Username:** sail - **Password:** password - **Dữ liệu hiện có:** 120 khách hàng, 45 sản phẩm, 139 hợp đồng ### Database Thử Nghiệm - **Database:** laravel_testing (đã tạo) - **Cách chạy test:** `DB_HOST=127.0.0.1 ./vendor/bin/pest` - **Cách chạy artisan:** `DB_HOST=127.0.0.1 php artisan tinker` ### Quy tắc VÀNG - **TUYỆT ĐỐI KHÔNG** dùng `migrate:fresh` trên database chính. - Tài khoản admin: `admin@phuongtc.com` / `1Qazxsw2@!321` - Dữ liệu Excel đã import là tài sản quý - không xóa. --- ## 2. KIẾN TRÚC KỸ THUẬT ### Tech Stack | Thành phần | Phiên bản / Công nghệ | |------------|----------------------| | Framework | Laravel 13.x | | PHP | 8.3 | | Admin Panel | Filament v5.5 | | Kiến trúc UI | **Schemas Architecture** (Tách Form/Table ra khỏi Resource) | | Database | PostgreSQL | | Khóa chính | UUID (100% các bảng) | | Excel | PhpSpreadsheet 5.7 | | Testing | Pest PHP 4.6 | ### Quy chuẩn Code 1. **LUÔN** dùng `Schemas` class. **KHÔNG** định nghĩa inline trong Resource. 2. `Grid` và `Section` nằm trong `Filament\Schemas\Components`. 3. Khi render HTML động trong Form, dùng **Inline Styles** thay vì Tailwind class. 4. Mọi trường JSONB trong Model phải khai báo trong `$casts = ['field' => 'array']`. 5. Naming database: **snake_case** cho mọi bảng và cột. --- ## 3. CẤU TRÚC MODULE HIỆN TẠI ### 3.1. Warehouse (Kho hàng) **Models:** `Project`, `Product` **Project:** - `code`, `name`, `type`, `address` - `payment_template_id` (relationship với PaymentTemplate) **Product:** - `code`, `project_id`, `product_type` (LAND | APARTMENT) - `area`, `price_per_unit`, `total_price` - `qsdd_value`, `foundation_temp_value`, `contract_temp_value` - `infrastructure_status` (JSONB) - `custom_data` (JSONB): block, building_density, legal_status_raw - `status` **Filament Resources:** - `ProjectResource` → `ProjectForm` (Schemas) - `ProductResource` --- ### 3.2. CRM (Khách hàng) **Model:** `Customer` **Cấu trúc:** - `type`: INDIVIDUAL | COMPANY - `full_name`, `cmnd_cccd`, `tax_code`, `title` - `phone`, `secondary_phones` (JSONB) - `email`, `dob` - `permanent_address`, `contact_address` (lưu cứng, không JSON) - `id_issue_date`, `id_issue_place` - `representative_id` (self-referencing, cho công ty) **Quan hệ:** - `representedCompanies()`: Công ty mà khách hàng đại diện - `representative()`: Ngườ đại diện của công ty - `contracts()`: belongsToMany qua `contract_customers` **Filament Resources:** - `CustomerResource` → `CustomerForm` + `CustomersTable` (Schemas) - Form hỗ trợ chuyển đổi INDIVIDUAL/COMPANY động (live) - Copy địa chỉ thường trú → liên hệ (suffixAction) --- ### 3.3. Contracts (Hợp đồng & Tài chính) **Model:** `Contract` **Cấu trúc:** - `contract_number`, `contract_type` (HĐMB | HĐGV | HĐDC) - `product_id`, `status` - `signing_date`, `sale_date`, `hql_confirmation_date` - `land_value`, `foundation_value`, `total_value`, `total_value_with_foundation` - `paid_amount`, `remaining_amount`, `excess_amount` - `discount_details` (JSONB) - `brokerage_name`, `stored_contract_count`, `filing_note` - `transfer_order`: 0 = chủ hiện tại, 1 = F0, 2+ = F1, F2... **Logic tự động trong Model (booted):** - `total_value` = `land_value` + `foundation_value` (nếu có giá trị) - Fallback: lấy từ `product.total_price` khi tạo mới - `remaining_amount` = `total_value` - `paid_amount` **Quan hệ:** - `product()`, `customers()` (belongsToMany qua contract_customers) - `appendices()`, `paymentSchedule()`, `scheduleItems()` (HasManyThrough) - `payments()`, `paymentFines()` **Filament Resources:** - `ContractResource` → `ContractForm` + `ContractsTable` - Action "Tạo lịch TT" trong Table (gọi `ContractScheduleService`) - Form có tính toán live: land_value + foundation_value = total_value - Hiển thị discount_details dạng grid inline style --- ### 3.4. Finance (Tài chính & Thu tiền) **Models:** `PaymentTemplate`, `PaymentSchedule`, `PaymentScheduleItem`, `Payment`, `PaymentFine` **PaymentTemplate:** - `project_id`, `name`, `is_default` - `items()`: các đợt thanh toán mẫu **PaymentSchedule:** - `contract_id`, `template_id` - `items()`: các đợt thanh toán thực tế **PaymentScheduleItem:** - `schedule_id` (hoặc `template_id` - dùng chung bảng) - `installment_no`, `type` (PaymentType enum), `percentage`, `amount`, `due_date` - `days_after_signing`, `days_after_previous` **Payment:** - `contract_id`, `schedule_item_id`, `amount`, `paid_date` - `method`, `receipt_number`, `metadata` (JSONB) **PaymentObserver (TỰ ĐỘNG):** - Khi tạo/sửa/xóa Payment: 1. Tính lại `contract.paid_amount` = SUM(payments) 2. Tính lại `remaining_amount` và `excess_amount` 3. Nếu có `excess_amount` > 0: **Tự động khấu trừ** vào đợt thanh toán tiếp theo chưa đủ tiền (tạo Payment auto) **Filament Resources:** - `PaymentResource` → `PaymentForm` + `PaymentsTable` - Form chọn Contract → chọn Đợt thanh toán (cascade) - Table có filter theo phương thức và ngày thu --- ## 4. CÁC COMMAND IMPORT DỮ LIỆU ### `import:products-excel {file=sanpham.xlsx}` - Import sản phẩm vào dự án "Hà Quang 1" - Tự động parse hạ tầng từ chuỗi "Key: Value - Key2: Value2" - Tạo custom_data (block, building_density...) ### `import:customers-excel {file=khachhang.xlsx}` - Import khách hàng cá nhân - Tách nhiều số điện thoại (dấu phẩy, gạch chéo, xuống dòng) - Parse ngày tháng Excel (số serial hoặc chuỗi) - Tự động tạo mẫu Công ty + Ngườ đại diện (Công ty TNHH BĐS Thịnh Vượng) ### `import:contracts-complex {hopdong=hopdong.xlsx} {hdkh=Hd_kh.xlsx}` - Logic "Bắc cầu" 2 file: 1. `hopdong.xlsx`: Dữ liệu tài chính (theo Số HĐMB) 2. `Hd_kh.xlsx`: Liên kết Khách hàng - Lô đất - Thứ tự chuyển nhượng - Tìm mapping giữa mã lô và số HĐMB (str_contains) - Tạo/cập nhật Contract + liên kết pivot `contract_customers` ### Các file Excel quan trọng (KHÔNG ĐƯỢC XÓA) - `hopdong.xlsx` - Dữ liệu hợp đồng tài chính - `Hd_kh.xlsx` - Liên kết hợp đồng-khách hàng - `khachhang.xlsx` - Danh sách khách hàng - `sanpham.xlsx` - Danh sách sản phẩm/lô đất --- ## 5. TÌNH TRẠNG CÁC PHẦN ĐÃ LÀM / ĐANG DỞ ### 5.1. Đã hoàn thành - [x] Kiến trúc Schemas cho tất cả Resources - [x] Import Customers, Products, Contracts từ Excel - [x] Mở rộng bảng customers (type, representative, addresses...) - [x] Mở rộng bảng contracts (land_value, foundation_value, discount_details...) - [x] ContractScheduleService - Tạo lịch thanh toán từ template - [x] PaymentObserver - Tự động tính toán tài chính + khấu trừ dư - [x] PaymentResource (Form + Table) - [x] Test: ContractFinanceFlowTest (PASS) - [x] Cấu hình PHPUnit dùng PostgreSQL testing database ### 5.2. Đang dở / Cần tiếp tục - [ ] **ContractForm:** `payment_template_id` đang `dehydrated(false)` - chưa tự động tạo lịch khi tạo hợp đồng mới từ form (hiện chỉ có trong CreateContract page sau khi submit) - [ ] **PaymentsTable:** Chưa có cột trạng thái đối soát (so sánh với schedule_item amount) - [ ] **Module Chiết khấu (Discounts):** Chưa có engine tính toán tự động dựa trên `discount_details` - [ ] **PaymentFine:** Model đã có nhưng chưa có Resource/Form - [ ] **Appendix & Settlement:** Chưa có Filament Resources - [ ] **Báo cáo:** Chưa có Dashboard thống kê - [ ] **Tự động hóa lịch trình cho 139 HĐ:** Cần command hoặc action để generate schedule hàng loạt ### 5.3. Vấn đề kỹ thuật cần xử lý - [ ] `payment_template_id` trong ContractForm cần hook `afterCreate` hoặc đổi thành dehydrated + xử lý trong CreateContract - [ ] PaymentsTable nên hiển thị `scheduleItem.type` và trạng thái đối soát - [ ] ContractTable có thể thêm cột `paid_amount` / `remaining_amount` (đã có trong Resource nhưng chưa commit staged) - [ ] Cần kiểm tra logic `updateOrCreate` trong ImportContractsComplex với nhiều khách hàng cùng 1 hợp đồng --- ## 6. LỘ TRÌNH PHÁT TRIỂN TIẾP THEO (ĐỀ XUẤT) ### Giai đoạn 1: Hoàn thiện Core Finance (Ưu tiên CAO) 1. **Fix ContractForm:** Cho phép chọn template và tự động tạo lịch thanh toán ngay khi tạo hợp đồng 2. **Hoàn thiện PaymentForm:** Thêm validation số tiền không vượt quá công nợ đợt 3. **Cập nhật PaymentsTable:** Thêm cột "Đợt TT", "Trạng thái đối soát", "Còn thiếu" 4. **Command generate schedule hàng loạt:** `php artisan contracts:generate-schedules` cho 139 hợp đồng đã import ### Giai đoạn 2: Module Bổ sung (Ưu tiên TRUNG BÌNH) 5. **PaymentFine Resource:** Quản lý tiền phạt chậm thanh toán 6. **Appendix Resource:** Quản lý phụ lục hợp đồng 7. **Settlement Resource:** Quản lý thanh lý hợp đồng 8. **Discount Engine:** Tính toán tự động chiết khấu từ `discount_details` vào giá trị hợp đồng ### Giai đoạn 3: Báo cáo & Tối ưu (Ưu tiên THẤP) 9. **Dashboard Tài chính:** Tổng doanh thu, dòng tiền dự kiến, công nợ phải thu 10. **Báo cáo theo Dự án:** Thống kê bán hàng, thanh toán theo từng dự án 11. **Export Excel:** Xuất báo cáo công nợ khách hàng 12. **Notification:** Cảnh báo đợt thanh toán sắp đến hạn --- ## 7. CÂU LỆNH THƯỜNG DÙNG ```bash # Chạy test DB_HOST=127.0.0.1 ./vendor/bin/pest # Chạy test cụ thể DB_HOST=127.0.0.1 ./vendor/bin/pest --filter="ContractFinanceFlowTest" # Import dữ liệu db:host=127.0.0.1 php artisan import:products-excel db:host=127.0.0.1 php artisan import:customers-excel db:host=127.0.0.1 php artisan import:contracts-complex # Tinker DB_HOST=127.0.0.1 php artisan tinker # Migrate (KHÔNG dùng fresh!) DB_HOST=127.0.0.1 php artisan migrate ``` --- ## 8. DANH SÁCH FILE ĐÃ THAY ĐỔI (Git Status) ### Staged (Sẵn sàng commit) - `HQLAND_PROJECT_BLUEPRINT.md` - `analyze_contracts.php`, `analyze_excel.php`, `analyze_khachhang.php` - `app/Console/Commands/ImportContractsComplex.php` - `app/Console/Commands/ImportCustomersExcel.php` - `app/Console/Commands/ImportProductsExcel.php` - `app/Filament/Resources/Contracts/Schemas/ContractForm.php` - `app/Filament/Resources/Contracts/Tables/ContractsTable.php` - `app/Filament/Resources/Customers/CustomerResource.php` - `app/Filament/Resources/Customers/Schemas/CustomerForm.php` - `app/Filament/Resources/Customers/Tables/CustomersTable.php` - `app/Filament/Resources/Products/Schemas/ProductForm.php` - `app/Models/Contract.php` - `app/Models/Customer.php` - `composer.json`, `composer.lock` - `database/migrations/2026_04_23_081206_update_customers_table_for_real_estate.php` - `database/migrations/2026_04_23_094837_expand_contracts_table_for_finance.php` - `tests/Feature/ContractFinanceFlowTest.php` - `tests/Feature/ProductResourceTest.php` ### Unstaged (Đang chỉnh sửa, chưa xong) - `.gitignore` - `analyze_contracts.php` - `app/Filament/Resources/Contracts/ContractResource.php` (thêm action Tạo lịch TT) - `app/Filament/Resources/Contracts/Pages/CreateContract.php` (refactor dùng Service) - `app/Filament/Resources/Contracts/Schemas/ContractForm.php` - `app/Filament/Resources/Projects/ProjectResource.php` (refactor sang Schemas) - `app/Filament/Resources/Projects/Schemas/ProjectForm.php` - `app/Models/Contract.php` (booted logic tài chính) - `app/Providers/AppServiceProvider.php` (đăng ký PaymentObserver) - `composer.json` (xóa script tạo SQLite) - `config/database.php` (default về pgsql) - `database/factories/CustomerFactory.php` - `phpunit.xml` (cấu hình PostgreSQL testing) ### Untracked (File mới chưa add) - `app/Filament/Resources/Payments/` (PaymentResource, Form, Table, Pages) - `app/Observers/PaymentObserver.php` - `app/Services/ContractScheduleService.php` --- *File này cần được cập nhật mỗi khi có thay đổi lớn trong kiến trúc hoặc lộ trình phát triển.*