ADR-0001. Mô hình phiếu ghi sổ kép + sổ cái
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-04-22 |
| Deciders | Phat Nguyen |
| Supersedes | - |
Bối cảnh
- Mô hình trước ghi nhận biến động tiền dưới dạng các dòng
FinanceTransactionphẳng, kèm một loạiINCOME/EXPENSE/TRANSFERvà một tài khoản duy nhất - không có nhóm chứng từ, không có vế đối ứng, và không có phiếu sẵn sàng cho kiểm toán. - Sổ sách kế toán POS Việt Nam đòi hỏi các chứng từ nhận diện được: Phiếu thu, Phiếu chi, Phiếu chuyển khoản, Phiếu kế toán (điều chỉnh), mỗi loại có số chạy riêng theo từng merchant.
- Biến động giá vốn (COGS) và tài sản tồn kho cần một vế đối ứng cân bằng (ghi Nợ một tài khoản, ghi Có tài khoản khác) - điều không thể làm với giao dịch một vế.
- 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ẽ mô hình hóa finance theo ghi sổ kép: một header FinanceVoucher (loại RECEIPT / PAYMENT / TRANSFER / ADJUSTMENT) sở hữu N dòng FinanceTransaction, mỗi dòng là một bút toán DEBIT (100_DEBIT, làm số dư tăng) hoặc CREDIT (200_CREDIT, làm số dư giảm) trên một FinanceAccount.
Hướng của dòng được suy ra đối với RECEIPT (toàn bộ là DEBIT) và PAYMENT (toàn bộ là CREDIT), và phải tường minh + cân bằng đối với TRANSFER (Σdebit == Σcredit) và ADJUSTMENT. Số chứng từ được cấp theo (merchantId, type, yearMonth) qua FinanceVoucherSequence với tiền tố PT/PC/PCK/PKT. Mỗi dòng đã ghi sổ lưu snapshot balanceBefore/balanceAfter và một postingSequence tăng đơn điệu; dòng tài khoản được khóa FOR UPDATE trong suốt quá trình ghi sổ.
Hệ quả
| Ưu | Nhược |
|---|---|
| Chứng từ sẵn sàng cho kiểm toán với số ổn định theo từng merchant | Nhiều bảng hơn + một công cụ ghi sổ cần duy trì |
| Vế đối ứng cân bằng cho phép hạch toán giá vốn / tài sản tồn kho | Bên gọi TRANSFER/ADJUSTMENT phải cung cấp các dòng cân bằng |
| Snapshot số dư theo từng dòng + posting sequence khiến sổ cái chống giả mạo | Ghi sổ một phiếu là một transaction nhiều dòng (tranh chấp khóa khi tải cao) |
| Việc hủy trở thành bút toán đảo cân bằng, không bao giờ là chỉnh sửa phá hủy | Mỗi phiếu chỉ dùng một loại tiền tệ (đ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 vế phẳng (mô hình trước) | Đơn giản nhất | Không chứng từ, không vế đối ứng, không hỗ trợ giá vốn | Không thể biểu diễn bút toán cân bằng |
| Sổ cái tổng đầy đủ với hệ thống tài khoản kế toán | Hoàn chỉnh về kế toán | Quá mức cho POS quy mô nhỏ; trải nghiệm vận hành phức tạp | Quá nặng so với phạm vi hiện tại |
| Sổ cái dạng event-sourced (ghi nối tiếp sự kiện, dựng lại số dư) | Khả năng kiểm toán mạnh | Hạ tầng mới; độ trễ khi dựng lại số dư | postingSequence + snapshot đã đáp ứng kiểm toán mà không tốn chi phí dựng lại |
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