Skip to content

Instantly share code, notes, and snippets.

@amal-babu-git
Created April 29, 2026 04:05
Show Gist options
  • Select an option

  • Save amal-babu-git/4b22e9da16dcdf62a5f64f554fc9f590 to your computer and use it in GitHub Desktop.

Select an option

Save amal-babu-git/4b22e9da16dcdf62a5f64f554fc9f590 to your computer and use it in GitHub Desktop.

PS Construction — Accounting Module: Flow & Report Logic

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.


1. Overall System Flow

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

2. Chart of Accounts (CoA) Structure

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.

Account Natures (top-level classification)

Nature Statement Normal Side
Assets Balance Sheet Debit
Liabilities Balance Sheet Credit
Equity Balance Sheet Credit
Revenue P&L Credit
Expenses P&L Debit

Account Roles (functional tag driving report classification)

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

is_direct flag (Revenue & Expense ledgers only)

Value P&L placement
true Above gross-profit line (Direct Income / COGS / Direct Expenses)
false Below gross-profit line (Indirect Income / Indirect Expenses)

Standard Account Code Map (seed)

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
    …

3. Voucher Types & Numbering

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.


4. Double-Entry Rules Enforced

  1. Minimum 2 lines per voucher (one debit, one credit — or multiple lines summing to balance).
  2. XOR rule per line — a single line carries either a debit amount or a credit amount, never both.
  3. Balance rule on posting|Σ Debit − Σ Credit| < ₹0.01. Uses Decimal (not float) to avoid binary rounding errors.
  4. Active accounts only — accounts must be active at time of creation and re-validated at posting.
  5. Ledger accounts only — posting to a group (container) account is rejected.

5. Report Calculation Logic

Common rule for all reports: Only posted vouchers are included. draft and cancelled vouchers are always excluded.


5.1 Trial Balance

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.


5.2 Profit & Loss

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.


5.3 Balance Sheet

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).


5.4 General Ledger (Single Account)

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.


5.5 Cash Flow Statement (Direct Method)

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

5.6 Group Summary (Single Sub-tree Drill-down)

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:

  1. Fetch the selected group + all its descendants via recursive query.
  2. Aggregate posted movement up to as_of_date for all leaf ledgers in the sub-tree.
  3. Roll up debit / credit and signed balances bottom-up through the group hierarchy.

5.7 Ledger Summary (Full CoA Grouped View — Tally Style)

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)

6. Accountant Verification Checklist

# 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment