Skip to content

Vouchers

Receipt, Payment, and Contra voucher forms. The operator's day-to-day entry point into the ledger — every voucher posts a balanced double-entry journal under the hood via createJournalWithLines.


1. Types

Voucher Debit Credit Use case
Receipt Cash / Bank account Customer / Agent / Supplier-refund source Money coming in from a customer, agent, or as a supplier refund.
Payment Supplier / Expense / Agent-commission / Booking Cash / Bank account Money going out to a supplier, as an expense, commission, or booking-side payout.
Contra Cash/Bank target account Cash/Bank source account Transfer between two cash/bank accounts (e.g. bank → petty cash).

All three share one guarantee: debits = credits, enforced by createJournalWithLines (src/lib/api.ts:1929-1933).


2. Receipt vouchers — smarter forms

PRs #99 and the #120 lineage reshaped the receipt voucher forms so the UI blocks invalid combinations up-front instead of failing at post time.

Receipt sources

The form supports four receipt flavours (src/lib/api.ts:11125-11128):

Path Purpose
/finance/vouchers/customer-on-account-receipt Customer pays on account (not yet applied to a specific booking).
/finance/vouchers/agent-on-account-receipt Agent pays on account.
/finance/vouchers/agent-receipt-allocate Apply an existing on-account agent receipt to a booking / invoice.
/finance/vouchers/supplier-refund-receipt Supplier refunds us (money in on a purchase-side ledger).

Source account validation

The receipt source account (the account we credit on payment / debit on refund) now goes through strict validation:

  • Must be a leaf — group accounts rejected.
  • Must be the correct side — a supplier-refund receipt can't debit a revenue account, etc.
  • Must exist + be active at post time.

Source account column

supabase/migrations/20260418123000_payment_source_account.sql adds Payment.sourceAccountId TEXT so a receipt/payment can explicitly carry its cash/bank account rather than relying on lookup by side effect. This unlocks:

  • Cash drawer audit trails (cashier X, drawer Y).
  • Multi-bank setups where a payment could otherwise ambiguously hit any bank account.

3. Payment vouchers

Mirror of receipt — same shape, money flows the other way. Key paths:

  • Supplier payments — post as referenceType = 'supplier_payment'; the voucher prefix is PV (src/lib/api.ts:1954).
  • Booking-side payouts (airline refunds, group cost outflow) — pick the appropriate reference type so drill-downs work.
  • TDS toggle — planned on the supplier-payment form (see TDS); not yet wired.

4. Contra vouchers

Voucher prefix CT (src/lib/api.ts:1952). referenceType = 'contra_transfer'. Two lines only: debit target, credit source. The form ensures both accounts are cash/bank leaves.


5. Multi-currency — FX capture

When the source account or the voucher amount is in a non-INR currency, the posting captures both the header-level rate and per-line original amounts. See Journals → FX rate capture.

Voucher form UX:

  1. User enters amount + picks source currency.
  2. Form looks up today's rate from ExchangeRate (or uses a manually-set rate if isManual = true).
  3. On post, createJournalWithLines receives fxRateUsed, originalAmount, and per-line originalDebit/Credit/Currency/fxRate.
  4. The INR line amounts derive from the rate, and the original fields pin the audit trail.

Pure-INR postings

When both legs are INR, all four original-currency columns stay NULL. No conversion happened.


6. UI

Finance page → Vouchers tab (Finance.tsx:4660, value="vouchers"). Three sub-tabs for Receipt / Payment / Contra.

Each form:

  • Gates the "Post" button behind finance.create.
  • Runs client-side validation (balance, account side, required fields).
  • Submits to the per-voucher endpoint.
  • On success, shows the generated voucher number and routes the user to the voucher drill-down (VoucherDetailDialog.tsx).

7. Endpoints

Handled by handleFinanceVouchers at src/lib/api.ts:11124. The core receipt/payment paths call through to createJournalWithLines with the appropriate reference type + prefix.

Method Path Permission
POST /finance/vouchers/customer-on-account-receipt finance.create
POST /finance/vouchers/agent-on-account-receipt finance.create
POST /finance/vouchers/agent-receipt-allocate finance.payments.record
POST /finance/vouchers/supplier-refund-receipt finance.create
POST /finance/vouchers/debit-note finance.create
POST /finance/vouchers/credit-note finance.create
GET /finance/vouchers/customer-on-account-receipts/:customerId finance.view

All write endpoints route through the journal state machine — a freshly-posted voucher lands in pending status unless it's a system-reversal (see journals.md).


8. Permissions

Action Permission
Post receipt / payment / contra finance.create
Record a payment receipt against an invoice finance.payments.record
Refund (issue money out) finance.edit
Approve / reject the resulting journal approvals.approve (plus maker-checker)