Purpose of this document A short, clear reference for an accounting professional to verify that the system's double-entry logic and report calculations are correct. Every formula shown here is implemented exactly as written in the production codebase.
Chart of Accounts (CoA)
│
▼
Create Voucher (DRAFT)
• 2+ lines required
• Accounts must be active
│
▼
Post Voucher
• Σ Debits = Σ Credits
(tolerance: diff < ₹0.01)
• Re-validates accounts
• Status becomes POSTED
│
▼
Financial Reports
(read POSTED vouchers only)
Voucher states:
| State | Financial Effect |
|---|---|
| Draft | No effect — does not appear in any report |
| Posted | Permanent — flows into all reports |
| Cancelled | Removed from report totals; audit trail retained |
The CoA is a single hierarchical tree (similar to ERPNext / Tally).
- Group accounts — containers only; no direct postings.
- Ledger accounts — leaf nodes; all voucher lines post here.
| Nature | Statement | Normal Side |
|---|---|---|
| Assets | Balance Sheet | Debit |
| Liabilities | Balance Sheet | Credit |
| Equity | Balance Sheet | Credit |
| Revenue | P&L | Credit |
| Expenses | P&L | Debit |
| Role | Used for |
|---|---|
cash / bank |
Cash flow detection |
receivable |
Accounts receivable, retention |
payable |
Accounts payable, sub-contractors, labour |
fixed_asset |
Balance sheet — Fixed Assets section |
accumulated_depreciation |
Contra to Fixed Assets |
capital_work_in_progress |
CWIP under Fixed Assets |
stock |
Inventory / material |
tax |
GST (CGST/SGST/IGST) and TDS accounts |
none |
No special treatment |
| Value | P&L placement |
|---|---|
true |
Above gross-profit line (Direct Income / COGS / Direct Expenses) |
false |
Below gross-profit line (Indirect Income / Indirect Expenses) |
1000 Assets
1100 Fixed Assets (role: fixed_asset)
1110 Accumulated Depreciation
1120 Capital Work in Progress
1200 Current Assets
1210 Bank Accounts (role: bank)
1220 Cash In Hand (role: cash)
1221 Cash
1230 Accounts Receivable (role: receivable)
1231 Debtors
1235 Retention Receivable
1240 Stock Assets (role: stock)
1241 Material Inventory
1250 Tax Assets (role: tax)
1251–1253 CGST/SGST/IGST Input
1254 TDS Receivable
1260 Loans and Advances (Assets)
1270 Work in Progress (construction)
2000 Liabilities
2100 Loans
2110 Secured Loans
2120 Unsecured Loans
2130 Bank Overdraft (role: bank)
2200 Current Liabilities
2210 Accounts Payable (role: payable)
2211 Creditors
2212 Sub-Contractor Payables
2213 Labour Payable
… GST Output, TDS Payable, Customer Advances, Retention Payable
3000 Equity
3100 Capital
3200 Retained Earnings
4000 Revenue (Income)
4100 Direct Income (is_direct=true)
4110 Contract Revenue, Retention Income, …
4200 Indirect Income (is_direct=false)
5000 Expenses
5100 Direct Expenses (is_direct=true)
5101 Sub-Contractor Charges
5102 Material Consumed
5103 Labour Charges (Direct)
…
5200 Indirect Expenses (is_direct=false)
5201 Salaries (Staff)
5210 Rent, Electricity, …
5250 Depreciation
…
| Type | Prefix | Purpose |
|---|---|---|
| Payment | PV |
Cash / bank payments (suppliers, salaries, …) |
| Receipt | RV |
Cash / bank receipts (clients, advances, …) |
| Contra | CV |
Bank-to-cash or inter-bank transfers |
| Journal | JV |
Adjustments, accruals, depreciation, write-offs |
| Purchase | PURV |
Purchase invoices → Accounts Payable |
| Sales | SLV |
Sales invoices → Accounts Receivable |
Format: PREFIX-YEAR-SEQUENCE e.g. PV-2026-0001
Sequence numbers are allocated atomically in the database (row-level lock, INSERT … ON CONFLICT DO UPDATE). Gaps are allowed (e.g. deleted drafts); reuse of a number is impossible.
- Minimum 2 lines per voucher (one debit, one credit — or multiple lines summing to balance).
- XOR rule per line — a single line carries either a debit amount or a credit amount, never both.
- Balance rule on posting —
|Σ Debit − Σ Credit| < ₹0.01. UsesDecimal(not float) to avoid binary rounding errors. - Active accounts only — accounts must be active at time of creation and re-validated at posting.
- Ledger accounts only — posting to a group (container) account is rejected.
Common rule for all reports: Only
postedvouchers are included.draftandcancelledvouchers are always excluded.
Input: As-of date.
Query: Aggregate per-ledger debit and credit totals of all posted vouchers with voucher_date ≤ as_of_date.
Per-ledger balance:
Debit-normal accounts (assets, expenses): balance = Σ debit − Σ credit
Credit-normal accounts (liabilities, equity, revenue): balance = Σ credit − Σ debit
Balance check:
grand_total_debit = Σ all ledger debits
grand_total_credit = Σ all ledger credits
is_balanced = |grand_total_debit − grand_total_credit| < 0.01
Output: Flat list of all active ledgers with movement + a hierarchical tree grouped by CoA structure.
Input: Date range (date_from to date_to).
Query: Per-ledger totals of revenue and expense ledgers for posted vouchers within the period (date_from ≤ voucher_date ≤ date_to).
Per-line amount:
Revenue ledger: amount = Σ credit − Σ debit (credit-normal)
Expense ledger: amount = Σ debit − Σ credit (debit-normal)
Sections and formulas:
Direct Revenue Total = Σ revenue amounts where is_direct = true
Direct Costs Total = Σ expense amounts where is_direct = true
Gross Profit = Direct Revenue Total − Direct Costs Total
Indirect Revenue Total = Σ revenue amounts where is_direct = false
Indirect Costs Total = Σ expense amounts where is_direct = false
Net Profit = Gross Profit + Indirect Revenue Total − Indirect Costs Total
Output sections in response:
| Section | Contents |
|---|---|
revenue |
All revenue ledgers (direct + indirect combined) |
direct_costs |
Expense ledgers with is_direct = true |
indirect_costs |
Expense ledgers with is_direct = false |
gross_profit |
Computed as above |
net_profit |
Computed as above |
Note for accountant: The is_direct flag on each ledger controls above/below-gross-profit placement. Verify that all COGS, sub-contractor charges, direct labour, and direct material accounts have is_direct = true.
Input: As-of date.
Query: Per-ledger debit/credit totals for all posted vouchers with voucher_date ≤ as_of_date (all five natures — assets, liabilities, equity, revenue, expenses).
Balance per ledger:
Asset ledger: balance = Σ debit − Σ credit
Liability / Equity ledger: balance = Σ credit − Σ debit
Asset bucketing by account_role:
| Role | Section |
|---|---|
fixed_asset |
Fixed Assets |
accumulated_depreciation |
Accumulated Depreciation (contra, reduces Fixed Assets) |
| anything else | Current Assets |
Net Fixed Assets = Fixed Assets Total + Accumulated Depreciation Total
(Acc. Depreciation is credit-normal → its balance is negative → reduces Fixed Assets)
Total Assets = Net Fixed Assets + Current Assets Total
Liabilities: All liability ledger balances combined into one section.
Equity: All equity ledger balances combined into one section.
Net Profit carried into Balance Sheet:
Net Profit (BS) = Σ (revenue: credit−debit) − Σ (expense: debit−credit)
(Same computation as P&L but cumulative all time up to as_of_date)
Balance equation check:
Total Liabilities & Equity = Total Liabilities + Total Equity + Net Profit
is_balanced = |Total Assets − Total Liabilities & Equity| < 0.01
Output: Flat sections + three hierarchical trees (assets tree, liabilities tree, equity tree).
Input: Account ID, optional date range.
Opening balance (if date_from supplied):
All posted entries with voucher_date < date_from for this account.
Debit-normal: opening = Σ debit − Σ credit
Credit-normal: opening = Σ credit − Σ debit
Running balance — updated line by line through the period:
Debit-normal: running = running + debit_amount − credit_amount
Credit-normal: running = running + credit_amount − debit_amount
Output: Full voucher trace — voucher number, date, type, header narration, line narration, debit, credit, running balance, closing balance.
Input: Date range.
Cash accounts: All ledgers with account_role = cash or account_role = bank.
Per-voucher net cash movement:
net = Σ cash_debit − Σ cash_credit
Positive = cash inflow; Negative = cash outflow
Activity classification — determined by looking at the non-cash (contra) lines of the same voucher:
| Contra line characteristic | Classified as |
|---|---|
account_role = fixed_asset / accumulated_depreciation / capital_work_in_progress |
Investing |
account_nature = equity, or liability code starts with 21 (Loans group) |
Financing |
| Both investing & financing contra lines present | Larger absolute contra amount wins |
| None of the above | Operating |
Totals:
opening_balance = Σ cash_debit − Σ cash_credit (all posted entries before date_from)
net_change = operating_total + investing_total + financing_total
closing_balance = opening_balance + net_change
Input: Group account ID, as-of date.
Purpose: Dashboard tiles or drill-downs for one specific branch (e.g. "Total Bank Balance", "Total Receivables") without running a full report.
Logic:
- Fetch the selected group + all its descendants via recursive query.
- Aggregate posted movement up to
as_of_datefor all leaf ledgers in the sub-tree. - Roll up debit / credit and signed balances bottom-up through the group hierarchy.
Input: Optional date_from, required date_to.
Purpose: A Tally / ERPNext-style view of the entire chart of accounts showing opening, period, and closing balances for every group and ledger.
Per-ledger split (single DB query using CASE WHEN):
Opening Dr/Cr = posted entries where voucher_date < date_from
Period Dr/Cr = posted entries where date_from ≤ voucher_date ≤ date_to
Closing Dr/Cr = Opening + Period
Group rows are rolled up bottom-up from all descendant ledgers.
Balance check:
is_period_balanced = (total_period_debit = total_period_credit)
| # | What to check | How |
|---|---|---|
| 1 | Trial Balance balances (Dr = Cr) | Run trial balance for any date; confirm is_balanced = true |
| 2 | Balance Sheet equation | Confirm Total Assets = Total Liabilities + Total Equity + Net Profit |
| 3 | P&L net profit ties to Balance Sheet net profit | Both use same posted entries; figures must match for same period |
| 4 | Cash book opening + movements = closing | Use General Ledger for each cash/bank account |
| 5 | Cash flow closing balance = sum of cash/bank ledger balances | Cross-check with Trial Balance |
| 6 | is_direct flags |
Confirm COGS, direct labour, direct material are is_direct = true |
| 7 | Account role tags | Confirm cash/bank/receivable/payable/tax accounts carry correct role |
| 8 | Accumulated depreciation sign | Should appear as a negative (contra) in Fixed Assets, reducing net fixed assets |
| 9 | GST / TDS netting | Input tax (1251–1254) vs Output tax — confirm both sides appear in trial balance |
| 10 | Voucher number continuity | No duplicates; gaps from deleted drafts are acceptable |