14 KiB
14 KiB
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:freshtrê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
- LUÔN dùng
Schemasclass. KHÔNG định nghĩa inline trong Resource. GridvàSectionnằm trongFilament\Schemas\Components.- Khi render HTML động trong Form, dùng Inline Styles thay vì Tailwind class.
- Mọi trường JSONB trong Model phải khai báo trong
$casts = ['field' => 'array']. - 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,addresspayment_template_id(relationship với PaymentTemplate)
Product:
code,project_id,product_type(LAND | APARTMENT)area,price_per_unit,total_priceqsdd_value,foundation_temp_value,contract_temp_valueinfrastructure_status(JSONB)custom_data(JSONB): block, building_density, legal_status_rawstatus
Filament Resources:
ProjectResource→ProjectForm(Schemas)ProductResource
3.2. CRM (Khách hàng)
Model: Customer
Cấu trúc:
type: INDIVIDUAL | COMPANYfull_name,cmnd_cccd,tax_code,titlephone,secondary_phones(JSONB)email,dobpermanent_address,contact_address(lưu cứng, không JSON)id_issue_date,id_issue_placerepresentative_id(self-referencing, cho công ty)
Quan hệ:
representedCompanies(): Công ty mà khách hàng đại diệnrepresentative(): Ngườ đại diện của công tycontracts(): belongsToMany quacontract_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,statussigning_date,sale_date,hql_confirmation_dateland_value,foundation_value,total_value,total_value_with_foundationpaid_amount,remaining_amount,excess_amountdiscount_details(JSONB)brokerage_name,stored_contract_count,filing_notetransfer_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_pricekhi 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_defaultitems(): các đợt thanh toán mẫu
PaymentSchedule:
contract_id,template_iditems(): các đợt thanh toán thực tế
PaymentScheduleItem:
schedule_id(hoặctemplate_id- dùng chung bảng)installment_no,type(PaymentType enum),percentage,amount,due_datedays_after_signing,days_after_previous
Payment:
contract_id,schedule_item_id,amount,paid_datemethod,receipt_number,metadata(JSONB)
PaymentObserver (TỰ ĐỘNG):
- Khi tạo/sửa/xóa Payment:
- Tính lại
contract.paid_amount= SUM(payments) - Tính lại
remaining_amountvàexcess_amount - 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)
- Tính lại
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ánAppendixResource→ Quản lý phụ lục hợp đồngSettlementResource→ Quản lý quyết toán & sổ đỏ
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:
hopdong.xlsx: Dữ liệu tài chính (theo Số HĐMB)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ínhHd_kh.xlsx- Liên kết hợp đồng-khách hàngkhachhang.xlsx- Danh sách khách hàngsanpham.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
- Kiến trúc Schemas cho tất cả Resources
- Import Customers, Products, Contracts từ Excel
- Mở rộng bảng customers (type, representative, addresses...)
- Mở rộng bảng contracts (land_value, foundation_value, discount_details...)
- ContractScheduleService - Tạo lịch thanh toán từ template
- PaymentObserver - Tự động tính toán tài chính + khấu trừ dư
- PaymentResource (Form + Table)
- Test: ContractFinanceFlowTest (PASS)
- Cấu hình PHPUnit dùng PostgreSQL testing database
- Fix ContractForm:
payment_template_idđã lưu vào DB, tự động tạo lịch khi tạo HĐ mới - PaymentForm validation: Không cho phép thu quá công nợ đợt / HĐ
- PaymentsTable: Thêm cột Loại đợt, Trạng thái đối soát, Còn thiếu
- Command generate schedule hàng loạt:
php artisan contracts:generate-schedules - PaymentFine Resource: Form + Table đầy đủ
- Appendix Resource: Form + Table đầy đủ
- Settlement Resource: Form + Table đầy đủ
- Discount Engine: Tính toán tự động chiết khấu + hiển thị
final_valuetrong ContractForm
5.2. Đang dở / Cần tiếp tục
- 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Ý
- ContractTable đã thêm cột
paid_amount/remaining_amount, chuyển sang dùngContractsTableSchemas - Logic
syncWithoutDetachingtrong ImportContractsComplex đảm bảo nhiều KH cùng 1 HĐ không bị ghi đè - Fix N+1 query ở
PaymentScheduleItem::getPaidAmountAttribute()(dùngrelationLoaded) - Fix PaymentForm validation khi edit (
instanceof Paymentthay vì truthy check) - Fix ContractForm
final_value_displayhiển thị được cả khi create (dùng$getstate)
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)
- 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
- Hoàn thiện PaymentForm: Thêm validation số tiền không vượt quá công nợ đợt
- Cập nhật PaymentsTable: Thêm cột "Đợt TT", "Trạng thái đối soát", "Còn thiếu"
- Command generate schedule hàng loạt:
php artisan contracts:generate-schedulescho 139 hợp đồng đã import
Giai đoạn 2: Module Bổ sung (Ưu tiên TRUNG BÌNH)
- PaymentFine Resource: Quản lý tiền phạt chậm thanh toán
- Appendix Resource: Quản lý phụ lục hợp đồng
- Settlement Resource: Quản lý thanh lý hợp đồng
- Discount Engine: Tính toán tự động chiết khấu từ
discount_detailsvào giá trị hợp đồng
Giai đoạn 3: Báo cáo & Tối ưu (Ưu tiên THẤP)
- Dashboard Tài chính: Tổng doanh thu, dòng tiền dự kiến, công nợ phải thu
- Báo cáo theo Dự án: Thống kê bán hàng, thanh toán theo từng dự án
- Export Excel: Xuất báo cáo công nợ khách hàng
- Notification: Cảnh báo đợt thanh toán sắp đến hạn
7. CÂU LỆNH THƯỜNG DÙNG
# 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
Services mới
app/Services/DiscountEngine.php- Tính toán chiết khấuapp/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)
Widgets mới
app/Filament/Widgets/ContractStatsOverview.php- Dashboard tổng quan tài chínhapp/Filament/Widgets/UpcomingPaymentsTable.php- Danh sách đợt TT sắp đến hạn
Models sửa đổi
app/Models/Contract.php- ThêmpaymentTemplate(), accessorfinal_valueapp/Models/PaymentScheduleItem.php- Thêm accessorpaid_amount,remaining_amountapp/Models/User.php- ThêmFilamentUserinterface để user có quyền truy cập panel
Forms/Tables sửa đổi
app/Filament/Resources/Contracts/ContractResource.php- Fix actionEditActionnamespace (Filament\Actions\EditAction)app/Filament/Resources/Contracts/Schemas/ContractForm.php- Fixpayment_template_id, thêmfinal_value_displayapp/Filament/Resources/Contracts/Pages/CreateContract.php- Refactor dùng$contract->payment_template_idapp/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ếuapp/Filament/Resources/Payments/PaymentResource.php- Thêm eager loadscheduleItem.payments
Config/Provider sửa đổi
app/Providers/Filament/AdminPanelProvider.php- Đăng ký widgets mớiphpunit.xml- Cấu hình PostgreSQL testing (DB_HOST, DB_DATABASE, etc.)config/database.php- Defaultpgsqlcomposer.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 theoCOMMIT_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.