PRD: Chứng từ & hạch toán
| Module | Tài chính | PRD ID | PRD-VCH-001 |
| Trạng thái | Sẵn sàng dev | FEAT | VCH |
| Epic | — | Plane | BANA-1497 |
| Ngày | 2026-05-22 | Phiên bản | v0.1 |
| Gói | @nx/finance | URD | VCH |
| Surface | Backend | ||
| Phụ trách | Phát Nguyễn | ||
TL;DR
Mỗi dòng tiền trở thành một chứng từ ghi sổ kép cân đối, thay cho con số tổng chạy theo từng ví. Hệ thống seed sẵn các tài khoản có kiểu (tiền mặt, ngân hàng, QR, mobile-POS) và tài khoản kiểm soát nội bộ cho mỗi merchant; ma trận payment integration đẩy mỗi payment đã thanh toán về đúng tài khoản và tự phát hành đúng chứng từ - nhờ vậy bán hàng, mua hàng và biến động kho lên sổ tự động, idempotent, và truy vết được về chứng từ nguồn.
1. Bối cảnh & Vấn đề
Sổ sách phải ghi mọi dòng tiền thành một chứng từ kế toán cân đối, không phải một con số tổng chạy theo từng ví. Mô hình cũ chỉ giữ được một con số cho mỗi ví: không phân biệt được phiếu thu với phiếu chi, không cân được bên nợ với bên có, và thiếu hẳn tài khoản kiểm soát nội bộ cho giá trị kho hay giá vốn hàng bán. Hệ quả là sổ sách không kiểm toán được và không thể lên báo cáo thu/chi đáng tin - đúng thứ kế toán HKD/SME mà BANA nhắm tới lại không làm nổi.
Vì sao lúc này: đợt refactor payment cần một chỗ để payment bán hàng đổ vào sổ. Mô hình tài khoản có kiểu cùng lớp điều hướng payment integration biến mỗi payment đã thanh toán thành một chứng từ cân đối, định tuyến chính xác - nền tảng cho mô hình ghi sổ kép của module Tài chính.
2. Mục tiêu & Phi mục tiêu
Mục tiêu
- Thay mô hình ví cũ bằng các tài khoản có kiểu (tiền mặt, ngân hàng, QR, mobile-POS) cùng tài khoản kiểm soát nội bộ, seed theo từng merchant.
- Ghi mỗi dòng tiền thành một chứng từ cân đối với các dòng nợ/có.
- Điều hướng hạch toán từ payment integration: payment đã thanh toán tự phát hành đúng chứng từ vào tài khoản và danh mục được định tuyến.
- Liên kết mỗi chứng từ với nguồn của nó, và giữ hạch toán tự động idempotent qua các event lặp lại.
Phi mục tiêu
- Theo dõi ngân sách, P&L, và dự báo dòng tiền (Non-Goals của URD).
- Tự động hóa chi phí định kỳ / theo lịch.
- Chụp ảnh hóa đơn / OCR.
- Quy đổi đa tiền tệ trong cùng một chứng từ - một tiền tệ duy nhất, mặc định VND.
3. Chỉ số thành công
| Chỉ số | Mục tiêu / tín hiệu |
|---|---|
| Độ phủ hạch toán tự động | 100% payment bán hàng thành công tạo ra một chứng từ thu tương ứng |
| Tính toàn vẹn cân đối | Mọi chứng từ đã phát hành đều cân đối (bên nợ bằng bên có ở những nơi cả hai bên áp dụng); không có hạch toán mất cân đối |
| Idempotency | Một payment event phát lại không bao giờ tạo ra chứng từ thứ hai |
| Khả năng truy vết | Mọi chứng từ tự phát hành đều liên kết ngược về chứng từ nguồn (đơn bán, PO, biến động kho) |
| Seed tài khoản | Mọi merchant mới đều được tạo các tài khoản mặc định và kiểm soát nội bộ |
4. Persona & Tình huống
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Owner | Thấy các dòng tiền được hạch toán thành các chứng từ cân đối đối với đúng tài khoản, có áp danh mục |
| Kế toán / Quản lý | Tin tưởng sổ sách phản ánh bán hàng và mua hàng mà không cần nhập liệu tay |
| Hệ thống (payment integration) | Điều hướng một payment đã thanh toán tới đúng tài khoản/danh mục và phát hành chứng từ tự động |
Tình huống cốt lõi: merchant mới được seed các tài khoản mặc định và kiểm soát có kiểu → một payment bán hàng thành công → payment integration điều hướng nó tới đúng tài khoản và danh mục → một chứng từ thu cân đối tự phát hành, liên kết với đơn nguồn → event phát lại bị bỏ qua (idempotent).
5. User Story
- Là owner, tôi muốn mỗi merchant mới khởi đầu với các tài khoản mặc định và kiểm soát nội bộ, để sổ sách sẵn sàng trước lần bán hàng đầu tiên.
- Là kế toán, tôi muốn mọi dòng tiền được ghi nhận dưới dạng một chứng từ cân đối với các dòng nợ/có, để sổ sách là ghi sổ kép có thể kiểm toán, chứ không phải một con số tổng chạy.
- Là owner, tôi muốn một đơn bán đã thanh toán tự phát hành một chứng từ thu đối với tài khoản được điều hướng, để tôi không phải ghi nhận doanh thu thường lệ bằng tay.
- Là hệ thống, tôi muốn một ma trận payment integration ánh xạ một payment tới đúng tài khoản và danh mục, để việc hạch toán được điều hướng một cách xác định.
- Là kế toán, tôi muốn mỗi chứng từ liên kết với chứng từ nguồn của nó, để tôi có thể truy vết một hạch toán ngược về đơn hoặc biến động của nó.
- Là hệ thống, tôi muốn việc hạch toán tự động là idempotent, để một payment event lặp lại không bao giờ hạch toán trùng.
6. Yêu cầu chức năng
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Giữ các tài khoản tiền có kiểu (tiền mặt, ngân hàng, QR, mobile-POS) cùng các tài khoản kiểm soát nội bộ, sở hữu theo từng merchant | URD-WAL-001 |
| FR-2 | Seed các tài khoản mặc định và kiểm soát nội bộ của mỗi merchant khi merchant được tạo | URD-WAL-003 |
| FR-3 | Duy trì một tài khoản mặc định mỗi kiểu mỗi merchant để điều hướng hạch toán tự động | URD-WAL-002 |
| FR-4 | Ghi nhận các dòng tiền dưới dạng chứng từ kiểu thu, chi, chuyển khoản, hoặc điều chỉnh | URD-VCH-001 |
| FR-5 | Mọi chứng từ đều cân đối - bên nợ bằng bên có ở những nơi cả hai bên áp dụng | URD-VCH-002 |
| FR-6 | Tự phát hành một chứng từ thu khi một payment bán hàng thành công, phân loại là Sale | URD-VCH-003 |
| FR-7 | Tự phát hành một chứng từ chi cho vendor khi một purchase order được nhận | URD-VCH-004 |
| FR-8 | Tự hạch toán giá vốn hàng bán và điều chỉnh kho vào các tài khoản kiểm soát nội bộ khi kho biến động | URD-VCH-005 |
| FR-9 | Hạch toán tự động là idempotent - một event lặp lại không bao giờ hạch toán trùng | URD-VCH-006 |
| FR-10 | Liên kết mỗi chứng từ với chứng từ nguồn của nó (đơn bán, PO, biến động kho, thủ công) | URD-VCH-007 |
| FR-11 | Đánh số mỗi chứng từ đã phát hành theo từng merchant, từng kiểu, từng tháng | URD-VCH-008 |
| FR-12 | Hỗ trợ vòng đời thủ công (draft → phát hành, xóa một draft), chuyển khoản giữa tài khoản, và void bằng đảo ngược | URD-VCH-009..011 |
Toàn bộ nội dung yêu cầu và tiêu chí chấp nhận nằm trong Finance URD. PRD này tham chiếu chúng thay vì lặp lại.
7. Yêu cầu phi chức năng
| Khu vực | Yêu cầu |
|---|---|
| Data integrity | Một chứng từ và các dòng ledger line của nó được ghi cùng nhau; mọi chứng từ đều cân đối (bên nợ bằng bên có ở những nơi cả hai bên áp dụng) |
| Idempotency | Hạch toán tự động được khóa theo event nguồn nên một event phát lại không bao giờ hạch toán trùng |
| Immutability | Chứng từ đã phát hành không bao giờ bị xóa cứng; việc sửa được thực hiện bằng đảo ngược cân đối (void), giữ nguyên bản gốc |
| Tenancy & authz | Tài khoản và chứng từ chỉ giới hạn trong merchant của chính người dùng; người dùng không phải admin chỉ thấy các merchant được cấp quyền |
| Precision | Phép tính tiền tệ dùng độ chính xác 4 chữ số thập phân; một tiền tệ duy nhất mỗi chứng từ, mặc định VND |
| i18n | Nhãn/kiểu/danh mục hiển thị cho người dùng là song ngữ (tiếng Anh và tiếng Việt) |
8. UX & Luồng
Hạch toán do event điều khiển, không phải màn hình: merchant nhận payment trong app merchant, chứng từ thu tự động được phát hành bởi tiến trình hạch toán tài chính. App merchant cũng có các màn hình thủ công cho tài khoản, chứng từ (draft → phát hành, void) và chuyển khoản.
9. Dữ liệu & Miền
| Khái niệm | Vai trò |
|---|---|
| Tài khoản tài chính | Một tài khoản tiền có kiểu (tiền mặt, ngân hàng, QR, mobile-POS) hoặc tài khoản kiểm soát nội bộ; giữ một số dư chạy |
| Chứng từ | Một chứng từ kế toán cân đối cho một dòng tiền (thu, chi, chuyển khoản, điều chỉnh), liên kết với nguồn của nó |
| Dòng sổ cái | Một dòng nợ hoặc có bên trong một chứng từ, mang theo tài khoản, danh mục tùy chọn, số tiền, và snapshot số dư trước/sau |
| Payment integration | Ma trận điều hướng ánh xạ một payment đã thanh toán tới đúng tài khoản và danh mục |
| Danh mục | Phân loại thu/chi áp lên một chứng từ |
Chỉ mang tính khái niệm - schema, tập giá trị, và bất biến đầy đủ nằm trong finance domain model.
10. Phụ thuộc & Giả định
Phụ thuộc
- Payment - một payment bán hàng thành công là trigger điều hướng và hạch toán chứng từ thu.
- Commerce / Merchant - một merchant mới được reconcile các tài khoản mặc định và kiểm soát nội bộ tự động.
- Inventory - việc nhận purchase order và biến động kho điều khiển các chứng từ chi/giá vốn.
- Categories (URD-CAT) - các danh mục hệ thống phân loại các chứng từ tự sinh.
Giả định
- Các tài khoản kiểm soát nội bộ của merchant tồn tại trước khi việc hạch toán giá vốn được thực hiện.
- Tồn tại đúng một tài khoản mặc định mỗi kiểu mỗi merchant để điều hướng xác định.
- Payment event mang đủ ngữ cảnh (số tiền, phương thức, chứng từ nguồn) để điều hướng và liên kết chứng từ.
11. Rủi ro & Câu hỏi mở
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Một payment event phát lại có thể hạch toán trùng | Hạch toán tự động là idempotent - khóa theo event nguồn |
| Hạch toán giá vốn trước khi tài khoản kiểm soát tồn tại | Tài khoản kiểm soát được seed khi tạo merchant; việc hạch toán yêu cầu chúng phải có sẵn |
| Đảo ngược/void một chứng từ gắn với một payment đã tất toán | Void bằng đảo ngược cân đối giữ nguyên bản gốc; đường bù trừ được theo dõi khi tính năng trưởng thành |
| Chỉ một tiền tệ | Ngoài phạm vi; được ghi nhận như một ràng buộc (mặc định VND) |
| Hạch toán tự động cho nhận PO, biến động kho, chuyển khoản, và void | Đã triển khai - nhận PO hạch toán phiếu chi NCC, biến động kho hạch toán phiếu giá vốn/điều chỉnh tồn kho, và chuyển khoản cùng void bằng đảo ngược được bộ máy phiếu và màn hình hỗ trợ |
12. Kế hoạch phát hành & Tiêu chí ra mắt
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P1 (nền tảng) - xem feature catalog của URD |
| Rollout | Tất cả merchant; không feature flag |
| Migration | Redesign mô hình account (số dư chạy theo-từng-ví cũ → tài khoản tài chính có kiểu); seed tài khoản mặc định và kiểm soát nội bộ theo từng merchant |
| Launch criteria | Đơn bán đã thanh toán tự phát hành một chứng từ thu cân đối, có liên kết; event phát lại không hạch toán trùng; merchant mới được tạo các tài khoản đã seed |
| Monitoring | Khối lượng và tỷ lệ lỗi hạch toán tự động, kiểm tra chứng từ mất cân đối, số lượt bỏ qua do idempotency |
13. FAQ
Cái gì thay thế mô hình ví cũ? Một mô hình tài khoản tài chính có kiểu với các kiểu tài khoản cùng các tài khoản kiểm soát nội bộ (kho, giá vốn hàng bán), được seed theo từng merchant.
Merchant có ghi nhận doanh thu bán hàng bằng tay không? Không - một payment bán hàng thành công tự phát hành một chứng từ thu, phân loại là Sale, đối với tài khoản được điều hướng.
Làm sao một payment biết hạch toán vào tài khoản nào? Một ma trận payment integration điều hướng một payment đã thanh toán tới đúng tài khoản và danh mục; sau đó tiến trình hạch toán tài chính phát hành chứng từ.
Cái gì ngăn một event phát lại hạch toán trùng? Hạch toán tự động là idempotent - một event lặp lại không bao giờ tạo ra chứng từ thứ hai.
Một chứng từ đã phát hành có thể bị xóa không? Không - chứng từ đã phát hành được void bằng một đảo ngược cân đối, giữ nguyên bản gốc để kiểm toán.
Tham chiếu
- URD: Finance - Vouchers & Posting · Accounts
- Builds on: Categories · Ledger Lines
- Module: Tài chính - URD
- Developer: @nx/finance · domain model