URD: Expenses
| Module | CORE-12 | Version | v0.4 |
|---|---|---|---|
| Status | In-progress | Date | 2026-05-30 |
1. Purpose
Define the user-facing requirements for Expenses — the merchant's books. The module must track money across accounts (cash, bank, QR, mobile-POS), record every movement as a balanced double-entry voucher, classify income and expense by category, and create most postings automatically in response to sales, purchases, and stock movements so owners do not record routine money flows by hand.
2. Scope
| Included | Excluded |
|---|---|
| Money accounts / wallets (Cash, Bank, QR, Mobile-POS) | Payment-gateway processing (Payment module) |
| Internal control accounts (Inventory, Cost of Goods Sold) | Tax invoice issuance (Invoice module) |
| Vouchers: receipt, payment, transfer, adjustment | Stock quantity & costing math (Inventory module) |
| Ledger lines (debit / credit) per voucher | Budget tracking, P&L, cash-flow forecast (future) |
| Income / expense categories (seeded + custom) | Recurring / scheduled expenses (future) |
| Auto posting from sale payment, PO receipt, stock movement | Receipt-image capture / OCR (future) |
| Voucher void by balanced reversal | Multi-currency conversion (single currency per voucher) |
3. Definitions
| Term | Definition |
|---|---|
| Account (wallet) | A place money lives — a cash drawer, bank account, QR acceptance account, or mobile-POS terminal. Holds a running balance. |
| Internal control account | A non-cash bookkeeping account (Inventory, Cost of Goods Sold) the system maintains automatically; not user money. |
| Voucher | One bookkeeping document recording a money event: a receipt (money in), payment (money out), transfer (between accounts), or adjustment. |
| Ledger line | One debit or credit row inside a voucher. A voucher always balances: total debits equal total credits where both sides apply. |
| Category | The income/expense classification on a movement (e.g. Sale, Purchase, Rent). |
| Default account | The account a given type of automatic posting routes to by default — one per type per merchant. |
| Void | Cancelling an issued voucher by posting an equal-and-opposite reversal, preserving the original for audit. |
4. Conceptual Model
Conceptual only — the full schema, enums, and invariants live in the finance developer domain model.
5. Functional Requirements
One table per functional area. Priority = MoSCoW (Must / Should / Could / Won't). Area codes line up with the test-case IDs.
5.1 Accounts (WAL)
| ID | P | Requirement |
|---|---|---|
| URD-WAL-001 | M | Hold accounts of types Cash, Bank, QR, and Mobile-POS, each owned by one merchant |
| URD-WAL-002 | M | Maintain a default account per type per merchant for routing automatic postings |
| URD-WAL-003 | M | Auto-create each merchant's default and internal control accounts when the merchant is created |
| URD-WAL-004 | M | Track each account's running current balance as vouchers post |
| URD-WAL-005 | S | Allow account currency (default VND) |
| URD-WAL-006 | S | Restrict account visibility to merchants the user is granted (admins see all) |
5.2 Vouchers & posting (VCH)
| ID | P | Requirement |
|---|---|---|
| URD-VCH-001 | M | Record money events as vouchers of type receipt, payment, transfer, or adjustment |
| URD-VCH-002 | M | Every voucher is balanced — debits equal credits where both sides apply |
| URD-VCH-003 | M | Auto-issue a receipt voucher when a sale payment succeeds, classified as Sale |
| URD-VCH-004 | M | Auto-issue a payment voucher to the vendor when a purchase order is received |
| URD-VCH-005 | M | Auto-post cost of goods sold and stock adjustments to internal control accounts on stock movement |
| URD-VCH-006 | M | Automatic postings are idempotent — a repeated event never double-posts |
| URD-VCH-007 | M | Link each voucher to its source document (sale order, purchase order, stock movement, manual) |
| URD-VCH-008 | S | Number each issued voucher per merchant, per type, per month |
| URD-VCH-009 | S | Support a manual lifecycle: draft → issue, and delete a draft before issue |
| URD-VCH-010 | S | Transfer money between two accounts as a single balanced transfer voucher |
| URD-VCH-011 | S | Void an issued voucher via a balanced reversal; the original is preserved |
| URD-VCH-012 | C | Attribute a voucher to a POS shift session for shift cash movements |
5.3 Ledger lines (TXN)
| ID | P | Requirement |
|---|---|---|
| URD-TXN-001 | M | Each voucher posts debit/credit ledger lines against accounts |
| URD-TXN-002 | M | A line carries the account it affects, an optional category, an amount, and balance-before/after snapshot |
| URD-TXN-003 | M | Lines share the voucher's currency |
| URD-TXN-004 | S | A line may reference its source document for traceability |
5.4 Categories (CAT)
| ID | P | Requirement |
|---|---|---|
| URD-CAT-001 | M | Provide 14 seeded system categories spanning income and expense |
| URD-CAT-002 | M | Categories are typed income or expense |
| URD-CAT-003 | M | Apply a system category automatically to auto-generated vouchers (e.g. Sale, Purchase) |
| URD-CAT-004 | S | Merchants may add custom categories, nested under a parent |
6. Acceptance Criteria
AC-VCH-01: Auto receipt on paid sale
| Given | When | Then |
|---|---|---|
| A sale order is paid | The payment-succeeded event arrives | A receipt voucher is issued, classified as Sale, linked to the sale order |
| The receiving account's balance goes up by the amount | ||
| The same event arrives again | Processed a second time | No second voucher is created (idempotent) |
AC-VCH-02: Auto payment on purchase-order receipt
| Given | When | Then |
|---|---|---|
| A purchase order is received | The PO-received event arrives | A payment voucher is issued to the vendor, linked to the purchase order |
| Inventory value is positive | The voucher balances a stock asset leg against the cash leg(s) |
AC-WAL-01: Default & control accounts on new merchant
| Given | When | Then |
|---|---|---|
| A merchant is created | The merchant event is reconciled | The merchant's default accounts are seeded |
| Internal Inventory and Cost-of-Goods-Sold control accounts exist |
AC-VCH-03: Transfer between accounts
| Given | When | Then |
|---|---|---|
| Two accounts of the merchant | Owner transfers an amount A → B | One transfer voucher posts a debit and a credit of equal value |
| Account A goes down and Account B goes up by the same amount |
AC-VCH-04: Void by reversal
| Given | When | Then |
|---|---|---|
| An issued voucher | Owner voids it | A balanced reversal voucher is posted; the original is preserved |
| Affected account balances return to their pre-voucher state |
7. Constraints & Non-Goals
Constraints
| ID | Constraint |
|---|---|
| C-01 | Every voucher must balance (debits equal credits where both sides apply) |
| C-02 | Exactly one default account per type per merchant |
| C-03 | Automatic postings must be idempotent under repeated events |
| C-04 | All ledger lines in a voucher share the voucher's currency (single-currency; default VND) |
| C-05 | The 14 seeded system categories are not merchant-owned |
| C-06 | Records use soft-delete; issued vouchers are never hard-deleted — they are voided |
| C-07 | Internal control accounts must exist before cost-of-goods postings |
Non-Goals
- Budget tracking and variance
- Recurring / scheduled expense automation
- Profit & loss statement and cash-flow forecasting
- Receipt-image capture / OCR
- Multi-currency conversion within a single voucher
8. Version History
| Date | Author | Description | Ver |
|---|---|---|---|
| 2026-02-26 | P. Do — Product Owner | Initial user stories | v0.1 |
| 2026-04-16 | P. Do — Product Owner | Wallets, transactions, categories scope | v0.3 |
| 2026-05-30 | Docs migration | Restructured to verified double-entry voucher model (accounts / vouchers / ledger lines / categories); corrected account types and transaction model | v0.4 |