Files
hqland-app/AGENTS.md

375 lines
16 KiB
Markdown

# 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``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)
- `paymentTemplate()` (belongsTo PaymentTemplate)
- `appendices()`, `paymentSchedule()`, `scheduleItems()` (HasManyThrough)
- `payments()`, `paymentFines()`
**Accessor:**
- `final_value`: Giá trị sau chiết khấu (tính từ `DiscountEngine`)
**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``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)
- Validation số tiền không vượt quá công nợ đợt / công nợ HĐ
- Table có filter theo phương thức và ngày thu
- Cột đối soát: Đủ / Thiếu / Thừa (tính tổng payments của đợt)
- Cột còn thiếu tiền theo đợt
- `PaymentFineResource` → Quản lý tiền phạt chậm thanh toán
- `AppendixResource` → Quản lý phụ lục hợp đồng
- `SettlementResource` → Quản lý quyết toán & sổ đỏ
---
### 3.5. Form Templates (Biểu mẫu in ấn)
**Kiến trúc:** Mail Merge Engine - Word-style template với merge fields.
**Models:** `FormTemplate`, `FormField`, `FormPrintLog`
**FormTemplate:**
- `name`, `code`, `target_model` (Contract/Product/Customer)
- `html_template`: Nội dung HTML với placeholder `{{ma_truong}}`
- `paper_size`: A4/A5/Letter
**FormField (Merge Fields):**
- `code`: Tên biến trong template (ví dụ: `ten_khach_hang`)
- `source_type`: `db_column` | `db_relation` | `formula` | `input` | `static`
- `source_config`: JSON cấu hình (tên cột, công thức, relation path...)
- `format`: `text` | `number` | `currency` | `date` | `percent`
- `decimal_places`: Số chữ số thập phân
**Cách hoạt động:**
1. Admin tạo template HTML, chèn `{{ten_khach_hang}}`
2. Định nghĩa FormField: `ten_khach_hang` lấy từ `contract.customers.0.full_name`
3. Khi in: `MailMergeService::render()` evaluate tất cả fields → thay vào template
4. Snapshot được lưu vào `FormPrintLog`
**Filament Resource:**
- `FormTemplateResource` → CRUD biểu mẫu với Repeater fields
**Services:**
- `MailMergeService::evaluateFields()` - Tính toán giá trị tất cả fields
- `MailMergeService::render()` - Render HTML cuối cùng
- `MailMergeService::savePrintLog()` - Lưu snapshot + rendered HTML
---
## 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)
### `contracts:generate-schedules {--force}`
- Tự động tạo lịch thanh toán cho các hợp đồng chưa có lịch
- Ưu tiên `contract.payment_template_id`, fallback lấy từ `product.project.paymentTemplate`
- Option `--force` để tạo lại lịch cho HĐ đã có schedule
### `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
- [x] **Fix ContractForm:** `payment_template_id` đã lưu vào DB, tự động tạo lịch khi tạo HĐ mới
- [x] **PaymentForm validation:** Không cho phép thu quá công nợ đợt / HĐ
- [x] **PaymentsTable:** Thêm cột Loại đợt, Trạng thái đối soát, Còn thiếu
- [x] **Command generate schedule hàng loạt:** `php artisan contracts:generate-schedules`
- [x] **PaymentFine Resource:** Form + Table đầy đủ
- [x] **Appendix Resource:** Form + Table đầy đủ
- [x] **Settlement Resource:** Form + Table đầy đủ
- [x] **Discount Engine:** Tính toán tự động chiết khấu + hiển thị `final_value` trong ContractForm
- [x] **Calculation Pipeline:** Kiến trúc tính toán tường minh (Step-by-step) với làm tròn tại mỗi bước
- [x] **Form Templates:** Mail Merge Engine cho phiếu tính giá, HĐ, phụ lục - Admin tự tạo template
### 5.2. Đang dở / Cần tiếp tục
- [x] **Dashboard thống kê:** Đã tạo `ContractStatsOverview` + `UpcomingPaymentsTable`
- [ ] **Notification:** Cảnh báo đợt thanh toán sắp đến hạn (chưa có hệ thống notification)
### 5.3. Vấn đề kỹ thuật ĐÃ XỬ LÝ
- [x] ContractTable đã thêm cột `paid_amount` / `remaining_amount`, chuyển sang dùng `ContractsTable` Schemas
- [x] Logic `syncWithoutDetaching` trong ImportContractsComplex đảm bảo nhiều KH cùng 1 HĐ không bị ghi đè
- [x] Fix N+1 query ở `PaymentScheduleItem::getPaidAmountAttribute()` (dùng `relationLoaded`)
- [x] Fix PaymentForm validation khi edit (`instanceof Payment` thay vì truthy check)
- [x] Fix ContractForm `final_value_display` hiển thị được cả khi create (dùng `$get` state)
---
## 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 MỚI / THAY ĐỔI TRONG PHIÊN NÀY
### Migrations mới
- `database/migrations/2026_04_24_083000_add_payment_template_id_to_contracts.php`
- `database/migrations/2026_04_28_013900_add_calculation_log_to_contracts.php`
- `database/migrations/2026_04_28_020000_create_form_templates_tables.php`
### Services mới
- `app/Services/DiscountEngine.php` - Tính toán chiết khấu
- `app/Services/Calculation/` - Calculation Pipeline (RoundingRule, CalculationStep, CalculationResult, CalculationPipeline, PriceCalculationService)
- `app/Services/Forms/MailMergeService.php` - Engine xử lý biểu mẫu in ấn
- `app/Console/Commands/GenerateContractSchedules.php` - Command tạo lịch hàng loạt
### Filament Resources mới
- `app/Filament/Resources/PaymentFines/` (Resource + Form + Table + Pages)
- `app/Filament/Resources/Appendices/` (Resource + Form + Table + Pages)
- `app/Filament/Resources/Settlements/` (Resource + Form + Table + Pages)
- `app/Filament/Resources/FormTemplates/` (Resource + Form + Table + Pages)
### Widgets mới
- `app/Filament/Widgets/ContractStatsOverview.php` - Dashboard tổng quan tài chính
- `app/Filament/Widgets/UpcomingPaymentsTable.php` - Danh sách đợt TT sắp đến hạn
### Models sửa đổi
- `app/Models/Contract.php` - Thêm `paymentTemplate()`, accessor `final_value`
- `app/Models/PaymentScheduleItem.php` - Thêm accessor `paid_amount`, `remaining_amount`
- `app/Models/User.php` - Thêm `FilamentUser` interface để user có quyền truy cập panel
### Forms/Tables sửa đổi
- `app/Filament/Resources/Contracts/ContractResource.php` - Fix action `EditAction` namespace (`Filament\Actions\EditAction`)
- `app/Filament/Resources/Contracts/Schemas/ContractForm.php` - Fix `payment_template_id`, thêm `final_value_display`
- `app/Filament/Resources/Contracts/Pages/CreateContract.php` - Refactor dùng `$contract->payment_template_id`
- `app/Filament/Resources/Payments/Schemas/PaymentForm.php` - Thêm validation amount + helper text công nợ
- `app/Filament/Resources/Payments/Tables/PaymentsTable.php` - Thêm cột Loại đợt, Đối soát, Còn thiếu
- `app/Filament/Resources/Payments/PaymentResource.php` - Thêm eager load `scheduleItem.payments`
### Config/Provider sửa đổi
- `app/Providers/Filament/AdminPanelProvider.php` - Đăng ký widgets mới
- `phpunit.xml` - Cấu hình PostgreSQL testing (DB_HOST, DB_DATABASE, etc.)
- `config/database.php` - Default `pgsql`
- `composer.json` - Xóa script tạo SQLite
---
## 9. FILE HỖ TRỢ CHUYỂN MÁY
- `NEXT_SESSION.md` - Checklist và hướng dẫn nhanh cho phiên làm việc tiếp theo
- `COMMIT_GUIDE.md` - Hướng dẫn commit toàn bộ thay đổi chưa commit
---
*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.*