Kimi chinh sua

This commit is contained in:
2026-04-24 08:58:53 +00:00
parent 91ff4a5e4d
commit 86216ef872
43 changed files with 2868 additions and 597 deletions

314
AGENTS.md Normal file
View File

@@ -0,0 +1,314 @@
# 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)
- `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``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.*