ADR-0001. Model phiếu ghi sổ kép + ledger
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-04-22 |
| Deciders | finance-team |
| Supersedes | — |
Bối cảnh
- Model trước ghi nhận biến động tiền dưới dạng các dòng
FinanceTransactionphẳng với typeINCOME/EXPENSE/TRANSFERvà một tài khoản duy nhất — không có nhóm chứng từ, không có counter-leg, và không có phiếu sẵn-sàng-audit. - Ghi sổ kế toán POS Việt Nam kỳ vọng các chứng từ nhận diện được: Phiếu thu (receipt), Phiếu chi (payment), Phiếu chuyển khoản (transfer), Phiếu kế toán (adjustment), mỗi loại có số chạy theo từng merchant.
- Biến động COGS và tài sản tồn kho cần một counter-leg cân bằng (DEBIT một tài khoản, CREDIT tài khoản khác) — không thể với giao dịch một-phía.
- Số dư tài khoản phải tái dựng được và chống giả mạo.
Quyết định
Chúng tôi sẽ model finance theo ghi sổ kép: một header FinanceVoucher (type RECEIPT / PAYMENT / TRANSFER / ADJUSTMENT) sở hữu N dòng FinanceTransaction, mỗi dòng là DEBIT (100_DEBIT, balance lên) hoặc CREDIT (200_CREDIT, balance xuống) trên một FinanceAccount.
Hướng dòng được suy ra cho RECEIPT (toàn DEBIT) và PAYMENT (toàn CREDIT), và explicit + cân bằng cho TRANSFER (Σdebit == Σcredit) và ADJUSTMENT. Số được tạo theo (merchantId, type, yearMonth) qua FinanceVoucherSequence với tiền tố PT/PC/PCK/PKT. Mỗi dòng đã post snapshot balanceBefore/balanceAfter và một postingSequence đơn điệu; dòng tài khoản được khóa FOR UPDATE cho toàn bộ quá trình post.
Hệ quả
| Ưu | Nhược |
|---|---|
| Chứng từ sẵn-sàng-audit với số ổn định theo từng merchant | Nhiều bảng hơn + một động cơ hạch toán phải duy trì |
| Counter-leg cân bằng cho phép kế toán COGS / tài sản tồn kho | Caller của TRANSFER/ADJUSTMENT phải cung cấp dòng cân bằng |
| Snapshot balance theo từng dòng + posting sequence làm ledger chống giả mạo | Post phiếu là một transaction nhiều dòng (tranh chấp lock dưới tải) |
| Void trở thành bút toán đảo cân bằng, không bao giờ chỉnh sửa phá hủy | Một tiền tệ thực thi theo từng phiếu (đa tiền tệ hoãn lại) |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do loại bỏ |
|---|---|---|---|
| Giao dịch một-phía phẳng (model trước) | Đơn giản nhất | Không chứng từ, không counter-leg, không hỗ trợ COGS | Không thể biểu diễn hạch toán cân bằng |
| Sổ cái tổng đầy đủ với chart-of-accounts | Hoàn chỉnh về kế toán | Quá mức cho POS SMB; UX vận hành dốc | Quá nặng cho phạm vi hiện tại |
| Ledger event-sourced (append event, project balance) | Audit mạnh | Hạ tầng mới; độ trễ project balance | postingSequence + snapshot đã cho audit mà không tốn chi phí rebuild |
Tham chiếu
packages/core/src/services/finance/finance-voucher.service.ts(_performIssue,postLines,resolveLineDirection,computeHeaderAmount)packages/core/src/models/schemas/finance/finance-voucher/,finance-transaction/,finance-voucher-sequence/- Domain Model