TECHNICAL GUIDE: MODULE QUẢN LÝ ĐỐI SOÁT (RECONCILIATION)1. Tổng quan nghiệp vụ & Phân quyềnModule này quản lý dòng tiền giữa Công ty vận chuyển và Khách hàng (Shop). Hệ thống cần tự động phân loại luồng tiền dựa trên công thức:$$Thuc\_Nhan = \sum COD - \sum Phi\_Van\_Chuyen$$1.1. Phân định vai trò (Role Based Access Control)Nhân viên Sale (NVKD):Là người Khởi tạo.Chỉ nhìn thấy danh sách khách hàng do mình quản lý.Nhiệm vụ: Theo dõi công nợ khách mình phụ trách và Tạo phiếu đối soát (Thu/Chi).Kế toán (Accountant):Là người Kiểm soát & Thực thi.Nhìn thấy danh sách phiếu đối soát do tất cả Sale gửi lên.Nhiệm vụ: Kiểm tra số liệu, Duyệt/Từ chối và Xác nhận dòng tiền (Đã thu/Đã chi).2. Thiết kế Cơ sở dữ liệu (Database Schema Suggestion)2.1. Bảng reconciliation_slips (Phiếu đối soát)Lưu trữ thông tin header của phiếu. Cần bổ sung trường để tracking ai tạo, ai duyệt.Field NameTypeDescriptionidUUID/BigIntPrimary KeycodeVarchar(20)Mã phiếu (VD: #PC-2025001, #PT-2025002)customer_idBigIntFK tới bảng Customerscreated_byBigIntFK tới bảng Users (Sale ID) - Người tạo phiếuapproved_byBigIntFK tới bảng Users (Accountant ID) - Người duyệt (Nullable)typeEnumPAYABLE (Phiếu Chi), RECEIVABLE (Phiếu Thu)statusEnumDRAFT (Nháp), PENDING_APPROVAL (Chờ duyệt), APPROVED (Đã duyệt), COMPLETED (Hoàn thành), REJECTED (Từ chối)total_codDecimalTổng tiền thu hộtotal_feeDecimalTổng phí dịch vụfinal_amountDecimalGiá trị tuyệt đối của (COD - Fee)payment_methodVarcharTên ngân hàng/Ví (với Phiếu Chi) hoặc Hình thức nộp (với Phiếu Thu)proof_image_urlVarcharLink ảnh UNC hoặc Bill chuyển khoản (Nullable)transaction_codeVarcharMã giao dịch ngân hàng (Nullable)internal_noteTextGhi chú nội bộ (Sale note cho Kế toán hoặc Kế toán note lý do từ chối)created_atDateTimeapproved_atDateTimeThời điểm duyệtcompleted_atDateTimeThời điểm xác nhận thanh toán2.2. Bảng reconciliation_details (Chi tiết phiếu)Lưu trữ danh sách đơn hàng thuộc phiếu.Field NameTypeDescriptionidUUID/BigIntPrimary Keyslip_idUUID/BigIntFK tới bảng reconciliation_slipsorder_idBigIntFK tới bảng Orders (Mã vận đơn)applied_codDecimalGiá trị COD tại thời điểm đối soát (Snapshot)applied_feeDecimalGiá trị Phí tại thời điểm đối soát (Snapshot)Lưu ý quan trọng: Cần có cơ chế Locking. Khi order_id đã nằm trong bảng reconciliation_details (mà trạng thái phiếu khác REJECTED/CANCELLED), đơn hàng đó không được phép xuất hiện trong danh sách "Chờ đối soát" nữa.2.3. Bảng reconciliation_logs (Lịch sử thao tác - MỚI)Dùng để lưu vết mọi hành động (Audit Log).Field NameTypeDescriptionidBigIntPrimary Keyslip_idUUID/BigIntFK tới bảng reconciliation_slipsactor_idBigIntFK tới bảng Users (Người thực hiện hành động)action_typeEnumCREATE, UPDATE, SUBMIT, APPROVE, REJECT, CONFIRM_PAYMENTold_statusVarcharTrạng thái trước khi thay đổi (Nullable)new_statusVarcharTrạng thái sau khi thay đổi (Nullable)noteTextGhi chú kèm theo hành động (VD: Lý do từ chối, Note của Sale lúc tạo)metadataJSONLưu thêm data nếu cần (VD: IP Address, User Agent)created_atDateTimeThời điểm thao tác3. Quy trình & Logic Xử lý (Backend Logic)3.1. API: Lấy danh sách khách hàng & Công nợ (Màn hình 1 - Dành cho Sale)Endpoint: GET /api/reconciliation/overviewPermission: ROLE_SALELogic:Filter Context: Chỉ lấy các khách hàng được gán cho User đang đăng nhập (WHERE customer.sale_id = current_user.id).Query tất cả đơn hàng có status = 'DELIVERED/RETURNED' VÀ is_reconciled = false của các khách hàng đó.Group by customer_id.Sum cod và Sum fee.Mục đích: Để Sale biết khách nào đang nợ nhiều/cần trả nhiều để tiến hành tạo phiếu.3.2. API: Tạo phiếu đối soát (Màn hình 2 - Dành cho Sale)Endpoint: POST /api/reconciliationPermission: ROLE_SALELogic:Tạo record trong bảng reconciliation_slips với created_by = current_user.id.Lưu chi tiết vào bảng reconciliation_details.Ghi Log: Insert vào reconciliation_logs với action_type = 'CREATE', note = note của Sale.Lock các đơn hàng liên quan.3.3. API: Danh sách phiếu đối soát (Màn hình 3 - Dành cho Kế toán)Endpoint: GET /api/reconciliation/slipsPermission: ROLE_ACCOUNTANT (Xem tất cả) hoặc ROLE_SALE (Chỉ xem phiếu mình tạo)Logic hiển thị:Kế toán vào sẽ thấy danh sách toàn bộ phiếu PENDING_APPROVAL từ các Sale gửi lên.Có thể filter theo created_by (Sale nào tạo).3.4. API: Xử lý trạng thái (Action - Dành cho Kế toán)Endpoint: PUT /api/reconciliation/{id}/statusPermission: ROLE_ACCOUNTANTLogic Log: Mọi hành động dưới đây đều phải insert 1 dòng vào bảng reconciliation_logs.APPROVE (Duyệt):Cập nhật approved_by.Chuyển trạng thái sang APPROVED.Log: action_type = 'APPROVE'.REJECT (Từ chối):Chuyển trạng thái sang REJECTED.Release (Mở khóa) đơn hàng.Log: action_type = 'REJECT', note = Lý do từ chối.COMPLETE (Hoàn thành):Cập nhật thông tin thanh toán.Chuyển trạng thái sang COMPLETED.Log: action_type = 'CONFIRM_PAYMENT', note = "Xác nhận đã thu/chi tiền".3.5. API: Lấy lịch sử thao tác (MỚI)Endpoint: GET /api/reconciliation/{id}/logsPermission: ROLE_SALE (chỉ xem phiếu mình), ROLE_ACCOUNTANT.Response: Trả về danh sách logs sắp xếp theo created_at giảm dần.[
  {
    "time": "30/11/2025 10:05",
    "actor": "Kế toán trưởng A",
    "action": "Từ chối",
    "note": "Sai cước phí đơn #DH001"
  },
  {
    "time": "30/11/2025 09:00",
    "actor": "Sale B",
    "action": "Tạo phiếu",
    "note": "Chị duyệt gấp giúp em"
  }
]
4. Hướng dẫn Frontend (UI/UX Implementation)4.1. Phân quyền UI (Sale vs Kế toán)Với tài khoản SALE:Màn hình 1: Thấy khách của mình.Màn hình 2: Nút "Tạo phiếu".Màn hình 3: Chỉ xem chi tiết phiếu mình tạo. KHÔNG có nút Duyệt/Từ chối.Với tài khoản KẾ TOÁN:Màn hình 3: Thấy tất cả phiếu chờ duyệt. Có đủ nút Duyệt, Từ chối, Xác nhận CK, Xác nhận Thu.4.2. Hiển thị Lịch sử (Mới)Trong Modal Chi tiết phiếu hoặc màn hình Chi tiết phiếu, cần bổ sung thêm một Tab hoặc một Section ở cuối trang: "Lịch sử hoạt động".Hiển thị dạng Timeline dọc:Dòng 1 (Mới nhất): [30/11 10:00] Kế toán A đã Từ chối - Lý do: Sai phí.Dòng 2: [30/11 09:00] Sale B đã Tạo phiếu.5. Checklist kiểm thử (QA Checklist)[ ] Phân quyền dữ liệu: Login user Sale A, không được nhìn thấy khách hàng của Sale B.[ ] Quyền tạo/duyệt: Kiểm tra chặt chẽ quyền ROLE_SALE và ROLE_ACCOUNTANT.[ ] Luồng Log:Sale tạo phiếu -> Check DB bảng Logs có dòng CREATE chưa.Kế toán từ chối -> Check DB bảng Logs có dòng REJECT và ghi chú lý do chưa.Xem lại chi tiết phiếu -> Đảm bảo lịch sử hiện đúng thứ tự thời gian.[ ] Luồng phối hợp: Sale tạo -> Kế toán Duyệt -> Kế toán Hoàn thành.[ ] Luồng từ chối & Nhả đơn: Kế toán từ chối -> Đơn hàng trong phiếu đó được nhả ra ở Màn hình 1 của Sale.