In this volume · VOLUME 05
Accounting
Chart of Accounts Journals & Ledger Billing & Invoicing Payments & Receipts Payment Reconciliation Multi-Currency Deferred Revenue Commission Accounting Tax (VAT/GST) Period Close

Chapter 5.4 — Payments & Receipts

1. Purpose

This chapter defines the money-in and money-out modules: how customer payments are captured (cash, card, bank transfer, gateway, wallet credit), how supplier payouts are made, and how each event posts to the ledger. Reconciliation against bank statements is covered in Chapter 5.5; this chapter focuses on the in-platform event itself.

2. Why it matters

Payments are the only path by which AR/AP balances clear. Modelling them sloppily leads to: - Unapplied cash (received but not matched to invoice) - Double-applied receipts - FX gain/loss landing in the wrong account - Cash-drawer drift at retail branches - Failed payout reversals leaving phantom AP

3. Industry relevance

travoBooks handles the full payment-stack travel agencies need: walk-in cash, branch terminals, online gateway, corporate wire transfers, BSP wires (out), supplier-direct payouts (out), and customer wallet (internal credit).

4. Compliance considerations

  • PCI DSS — gateway tokens only; no PAN storage; SAQ-A scope.
  • AML / KYC — large cash receipts trigger threshold reporting.
  • IFRS 9 — FX revaluation rules apply at receipt.
  • Local cash-handling regulations — daily reconciliation, dual-control for large cash.

5. Business logic

5.1 Payment record (money-in)

Field Notes
payment_id PK
partner_id Tenant
customer_id Payer
payment_type cash, card, bank_transfer, gateway, wallet_credit, cheque
gateway_provider stripe, sslcommerz, razorpay, manual, etc.
gateway_transaction_id Provider reference
transaction_currency
transaction_amount Gross amount received
fx_rate If non-functional
functional_amount Translated
received_at Effective receipt date
cash_drawer_id If cash
bank_account_id If wire/gateway
received_by_user_id Cashier/agent
state pending, cleared, failed, reversed, partial_refunded, refunded
applied_amount Sum applied to invoices
unapplied_amount Sitting as customer credit
notes

5.2 Receipt application

A payment can be applied to one or many invoices. The application table payment_invoice_applications links payment → invoice with applied_amount. Invoice's paid_amount and state flag (Paid / PartiallyPaid) recompute on each application.

Application order: - Oldest invoice first (default policy) - Explicit selection by accountant - Customer-instructed allocation (per remittance advice)

Unapplied amount becomes customer credit balance — usable on future invoices.

5.3 Receipt JE

For a BDT 100,000 cash receipt against Beta Corp:

Debit  1001 Cash on Hand                 100,000  cash_drawer = DHK-01
Credit 1101 AR — Beta Corp               100,000  customer = beta_id

For a USD 5,000 wire receipt where functional currency is BDT (rate at receipt: 1 USD = 113):

Debit  1011 Bank — USD Account           5,000 USD  fx_rate = 113.00; functional = 565,000 BDT
Credit 1101 AR — Beta Corp               5,000 USD  functional = ? (depends on invoice's original FX rate)

If the invoice was raised at FX 110, the AR was 550,000 BDT functional. Receipt of 565,000 BDT functional creates a realised FX gain of 15,000 BDT posted to 4091 — Realised FX Gain.

5.4 Payout record (money-out)

Field Notes
payout_id PK
partner_id Tenant
supplier_id Beneficiary
payout_type bank_wire, bsp_wire, manual_card, cheque, gateway_payout
currency
amount
state draft, pending_approval, approved, sent, cleared, failed, reversed
bank_account_id Source
supplier_bank_details_id Destination
requested_by_user_id Maker
approved_by_user_id Checker
sent_at / cleared_at
payment_file_id If batch file generated
applied_invoices M-to-M with supplier invoices
je_id

5.5 Payout JE

Wire to Hotelbeds EUR 10,000 (functional BDT, rate 132 at payout):

Debit  2003 AP — Hotelbeds               10,000 EUR (1,320,000 BDT functional)
Credit 1012 Bank — EUR Account           10,000 EUR (1,320,000 BDT functional)

(Plus FX gain/loss if invoice was booked at different rate.)

5.6 Wallet / customer credit

Some refunds, overpayments, or promotional credits accumulate as customer credit balance. This is a liability (2105 — Customer Credit Liability) until used or expired.

Application: at invoice time, credit balance may be auto-applied per partner config.

5.7 BSP weekly wire

The BSP-payable account (2011) is settled by a single weekly/semi-monthly wire to the BSP clearing bank account. The wire posts:

Debit  2011 BSP Payable                  X
Credit 1013 Bank — BSP Settlement A/c    X

Wire amount is determined by the BSP billing statement (imported per Ch 11.3). Discrepancies between our ledger and BSP statement trigger a reconciliation workflow.

5.8 Failed / reversed payments

Gateway chargebacks, NSF cheques, bank reversals are first-class events. They post:

Debit  1101 AR — Customer                X  (restoring AR)
Credit 1001/1011/etc                     X  (reversing cash)
+ chargeback fee handling

The original payment record is not deleted — it's marked state = reversed with a reversed_by_payment_id link.

6. Inputs → processing → outputs

Capture cash receipt

Input: {customer_id, amount, currency, cash_drawer_id, apply_to_invoices[]}

Processing: 1. Permission check (payments.create.partner). 2. Validate cash drawer is open + assigned to user. 3. Insert payment row (state = cleared for cash). 4. Apply to invoices in order or as specified. 5. Update invoice paid/state. 6. Post JE. 7. Update customer balance. 8. Update cash drawer running total. 9. Issue receipt PDF.

Output: payment_id, receipt PDF URL.

Initiate supplier payout

Input: {supplier_id, currency, amount, invoices_to_apply[], bank_account_id}

Processing: 1. Permission check (suppliers.payout.create.partner). 2. Validate supplier active, bank details on file, amount ≤ open AP. 3. Insert payout row (state = pending_approval if above threshold, else approved). 4. Optionally generate bank-format payment file (SWIFT MT103, ACH NACHA, local format). 5. On approval, mark sent. 6. Post JE (cleared once bank confirms; for now AP is reduced and an "in-transit" account is debited). 7. Reconciliation matches bank statement to clear in-transit.

Output: payout_id, file download (if batch), audit trail.

7. Module dependencies

Direction Module
Depends on Customer / Supplier, Invoicing, JE Engine, FX, Bank Accounts, Cash Drawer module
Depended on by Reconciliation, Reporting, Dunning

8. Security & permissions

Permission Allows
payments.create.partner / .branch:{id} Capture receipt
payments.apply.partner Apply unapplied cash
payments.reverse.partner Reverse payment (maker-checker)
payouts.create.partner Initiate payout
payouts.approve.partner Approve payout
payouts.cancel.partner Cancel before send
cash_drawer.open.branch:{id} Open drawer
cash_drawer.close.branch:{id} Close drawer
cash_drawer.reconcile.branch:{id} Daily recon

9. Validation rules

Code Condition
PAYMENT_AMOUNT_INVALID ≤ 0
PAYMENT_CURRENCY_UNSUPPORTED Not in partner currencies
PAYMENT_DRAWER_CLOSED Cash drawer not open
PAYMENT_DRAWER_WRONG_USER Drawer not assigned to caller
PAYMENT_APPLY_EXCEEDS Apply amount > unapplied + invoice open balance
PAYMENT_GATEWAY_REJECTED
PAYMENT_DUPLICATE Same gateway_transaction_id
PAYMENT_FX_RATE_MISSING No rate for transaction date
PAYMENT_PERIOD_CLOSED Receipt date in closed period
PAYOUT_BANK_DETAILS_INVALID
PAYOUT_INSUFFICIENT_AP
PAYOUT_REQUIRES_APPROVAL
PAYOUT_DUAL_CONTROL_VIOLATION Maker = Checker

10. Error handling

  • Gateway timeouts → poll provider for status before declaring failure (avoids customer dispute).
  • Cash overage at drawer close → write to 2106 — Cash Overage Liability for accountant resolution.
  • Cash shortage at drawer close → write to 5081 — Cash Shortage Expense with audit & approval.

11. Real-world examples

A — Apply against multiple invoices

Beta Corp wires BDT 250,000. Three open invoices: INV-501 (90,000), INV-502 (110,000), INV-503 (75,000). Total open: 275,000. - Auto-apply oldest first: INV-501 fully (90k), INV-502 fully (110k), INV-503 partially (50k). - INV-503 remaining: 25,000. - One JE; three application rows.

B — Multi-currency receipt with FX gain

Beta wires USD 5,000 against invoice raised at FX 110 (550k BDT functional). Receipt FX 113 → 565k BDT received. Realised FX gain 15k.

C — Cash drawer end-of-day

Cashier closes drawer; system-computed cash = 145,000; physical count = 144,800. Shortage 200. - 200 posted to 5081 Cash Shortage Expense. - Cashier signs off; manager approves.

12. Step-by-step workflow

sequenceDiagram autonumber actor C as Cashier participant T as travoBooks participant DB as MySQL participant CD as Cash Drawer State C->>T: Receive BDT 100,000 cash (Customer Beta) T->>CD: Verify drawer open + assigned T->>DB: BEGIN T->>DB: INSERT payments T->>DB: INSERT payment_invoice_applications (oldest first) T->>DB: UPDATE invoices.paid_amount + state T->>DB: INSERT journal_entries + lines T->>DB: UPDATE customer_balances T->>DB: UPDATE cash_drawer running_total T->>DB: COMMIT T-->>C: Receipt PDF + transaction ID

13. Database tables touched

Table Role
payments Money-in records
payment_invoice_applications Application matrix
payouts Money-out records
payout_supplier_invoice_applications
cash_drawers State + running totals
cash_drawer_sessions Open/close events
bank_accounts Sources/destinations
customer_credit_balance Unapplied money
journal_entries / _lines
audit_logs

14. Future scalability

  • Tokenised card-on-file for repeat corporate clients.
  • Real-time bank API receipt-matching (Open Banking / PSD2).
  • Multi-currency wallet with FX hedging hooks.
  • Auto-payout scheduling for trusted suppliers (avoid manual approval loop on routine payouts under limit).

15. Common pitfalls

  • ⚠️ Applying gross amount when fees were deducted. Gateway fees should be a separate expense line, not silently reduce invoice apply.
  • ⚠️ Using receipt-date FX rate on a settled invoice. The AR side should reverse at the invoice's original rate; the difference is realised FX.
  • ⚠️ Allowing same user to capture + reverse without dual control. Dual control essential for reversal.
  • 🔒 Storing PANs. Never. Tokens only.
  • ⚠️ Forgetting BSP wire timing. BSP wires are deadline-driven; miss = penalty.