ইনভয়েস হলো গ্রাহককে পাঠানো ফরমাল বিলিং নথি। ফরম্যাট: জুরিসডিকশন-নির্দিষ্ট (বাংলাদেশের NBR, ভারতের GST)। ইনভয়েস নম্বরিং: কঠোর অনুক্রমিক প্রতি বছর। স্টেট: DRAFT → ISSUED → PARTIALLY_PAID → PAID।
Chapter 5.3 — Billing & Invoicing Lifecycle
chapter: 05-accounting/03-billing-invoicing
version: 1.0.0
status: stable
last_reviewed: 2026-05-26
owners: [accounting, product]
1. Purpose
This chapter covers customer invoicing end-to-end: how invoices are created from operational events, the document lifecycle, credit notes, dunning, and the relationship between an invoice and the underlying journal entries.
2. Why this matters in modern travel accounting
In a travel business, an invoice is not the source of the revenue record — the booking is. The invoice is the legal document presented to the customer. Confusing the two leads to common defects:
- Two invoices for the same booking (duplicate revenue in reports).
- An invoice issued, the customer pays, but the booking was never ticketed — the agency receivable is wrong.
- A credit note that does not link back to the original invoice — VAT filing breaks.
travoBooks treats invoices as derivable from operational events, with explicit linkage and a controlled lifecycle.
3. Industry relevance
For B2B agencies, the invoice is the primary commercial artefact: corporate customers will not pay without one matching their PO. For B2C, the invoice doubles as a tax receipt. For sub-agent settlements, the invoice is the monthly consolidation. Each use case has different requirements; travoBooks supports all three.
4. Compliance considerations
- Tax invoice rules vary by jurisdiction (VAT/GST regulations specify mandatory fields, numbering schemes, and time-of-issuance rules).
- Sequential numbering is mandatory in many countries (Bangladesh, India, UAE, EU, etc.). Gaps must be explainable.
- PDF immutability: once issued, the PDF of an invoice must be retrievable in its original form for the statutory retention period (5–10 years depending on jurisdiction).
- IFRS 15: the invoice does not by itself recognise revenue; revenue follows the performance obligation.
5. Business logic
5.1 Invoice lifecycle
States:
- Draft — editable; not visible to customer; no JE.
- Issued — locked; invoice_no assigned; customer-facing; AR created via JE link to booking.
- PartiallyPaid / Paid — receipts applied; tracked in invoice_allocations.
- Overdue — derived state; computed from due_date and balance.
- CreditNoted — fully neutralised by one or more credit notes.
- Cancelled — only from Draft.
- Closed — historical; locked further.
5.2 Invoice structure
Invoice
├── id, partner_id, customer_id
├── invoice_no (sequential, gap-free per partner+series)
├── series (e.g., "INV", "PI" proforma, "RCT" receipt)
├── issue_date, due_date
├── currency, fx_rate_to_functional
├── status
├── source_type (booking | manual | subscription | merge)
├── source_ids[] (one invoice can span multiple bookings)
├── billing_address, shipping_address
├── tax_summary
├── totals: subtotal, tax_total, discount_total, grand_total, paid, balance
├── notes, terms
├── pdf_url (signed, partner-scoped)
├── created_by, issued_by, approved_by
└── Lines[]
├── line_no
├── description
├── item_type (ticket | ancillary | service_fee | hotel | other)
├── source_ref (booking_id, ticket_id, etc.)
├── quantity
├── unit_price (transaction currency)
├── discount_amount
├── tax_code
├── tax_amount
├── line_total
├── account_code (revenue account this line maps to)
├── service_date (for revenue recognition)
└── passenger_name (for travel-related lines)
5.3 Numbering
Invoice numbers follow a partner-configured pattern, with mandatory gap-free sequencing per (partner_id, series, fiscal_year). Defaults:
| Series | Pattern | Example |
|---|---|---|
| INV (standard) | INV/{YYYY}/{NNNNNN} |
INV/2026/000123 |
| PI (proforma) | PI/{YYYY}/{NNNNNN} |
PI/2026/000045 |
| CN (credit note) | CN/{YYYY}/{NNNNNN} |
CN/2026/000007 |
| RCT (receipt) | RCT/{YYYY}/{NNNNNN} |
RCT/2026/000089 |
The sequence allocator is partner-scoped row-level locking on a sequences table to guarantee no gaps under concurrency.
5.4 Tax handling on the invoice
Each line has a tax_code that resolves to a tax rate plus tax-account mapping. The system computes per-line tax, sums to a tax summary (grouped by code), and writes the appropriate output-tax payable lines into the JE.
For pass-through items (airline ticket portion that is not taxable to the agency because the ticket is the airline's supply), the invoice line displays the gross amount as a "carriage" line with taxable = false; the agency's own service fee is the taxable component.
5.5 Discounts and surcharges
- Line-level discount: percentage or fixed; reduces taxable base.
- Invoice-level discount: applied proportionally to lines or to specific lines.
- Surcharge: payment-method fee (e.g., card surcharge); behaves like a line with its own tax code.
5.6 Multi-booking invoice (consolidation)
A common B2B pattern: one invoice consolidates a month's worth of bookings for a corporate client. The system supports merging draft invoices for the same customer prior to issuance.
5.7 Proforma invoices
A PI series invoice represents an expected charge; it does not affect AR. Used commonly for "send me a quote I can put on a PO". When the actual booking is finalised, the proforma is converted into a standard invoice (which then writes the AR).
5.8 Credit notes
A credit note reduces a previously-issued invoice. Use cases: refund, service failure compensation, error correction.
- Linked to a parent invoice (or several).
- Writes a reversing JE (full or partial of the parent).
- Reduces AR.
- If the customer has already paid the parent, credit note creates a customer credit balance (separate liability) usable on a future invoice, or refunded.
5.9 Dunning
A scheduled job evaluates Issued invoices against due_date. Reminders fire per the partner's dunning policy. Policies are sequences of (offset days, channel, template):
| Offset | Channel | Default template |
|---|---|---|
| −3 days | "Friendly upcoming-due reminder" | |
| 0 days | "Due today" | |
| +7 days | "First past-due" | |
| +14 days | Email + SMS | "Second past-due" |
| +21 days | Email + Phone task | "Account manager call required" |
| +30 days | Email + Statement | "Final notice + statement attached" |
Policies are customisable per customer (large clients often want different cadences). Automatic suspension of booking privileges at a configurable threshold is supported.
6. Inputs → processing → outputs
6.1 Auto-invoice on booking issuance
When a booking is ticketed and the customer is a credit customer (B2B), a draft invoice is auto-created. Whether it is auto-issued depends on customer.invoice_policy:
| Policy | Effect |
|---|---|
per_booking_auto_issue |
Draft is issued immediately. |
per_booking_manual_issue |
Stays in draft until a user issues. |
consolidated_weekly |
Accumulates into a weekly draft; issued by scheduler. |
consolidated_monthly |
Same, monthly. |
on_demand |
No draft until user creates one. |
6.2 Manual invoice (input)
invoice:
customer_id: "C-1023"
series: "INV"
issue_date: "2026-05-26"
due_date: "2026-06-09"
currency: "USD"
lines:
- description: "Hotel — Burj Al Arab, 26–28 May 2026"
item_type: "hotel"
source_ref: "BKG-P001-9001"
quantity: 2
unit_price: 1850.00
tax_code: "VAT-5"
account_code: "4023"
service_date: "2026-05-26"
passenger_name: "Mr. K. Roberts"
notes: "Per PO #44521"
6.3 Processing on issuance
- Validate customer, addresses, tax setup.
- Lock fields.
- Allocate
invoice_novia sequence service. - Compute tax per line.
- Write JE: 🅓 AR / 🅒 Revenue accounts per line + 🅒 Tax Payable.
- Generate PDF and store in object storage; assign signed URL.
- Emit
invoice.issuedevent → email to customer (ifauto_send_email). - Audit log.
6.4 Outputs
- The customer receives the invoice via email (with PDF attached) and a magic link to a customer portal page where they can view, download, and (where enabled) pay.
- AR balance updated.
- Searchable in invoice list.
7. Module dependencies
- Reads: customers, bookings/tickets, chart of accounts, tax profiles, FX rates, dunning policies, document templates.
- Writes:
invoices,invoice_lines,invoice_allocations,journal_entries,audit_logs, object storage, notification outbox. - Read by: payments, reports (AR ageing, sales by customer), dunning job, statements.
8. Security & permissions
| Permission | Allows |
|---|---|
invoice.read.partner |
View invoices |
invoice.create.own / .partner |
Create drafts |
invoice.edit.draft |
Edit drafts |
invoice.issue.partner |
Issue (allocate number, post JE) |
invoice.void.draft |
Cancel a draft |
invoice.credit_note.partner |
Issue credit notes |
invoice.email.partner |
Send to customer via email |
invoice.export.partner |
Bulk export |
invoice.read_payment_details.partner |
See full payment allocations |
Maker–checker on credit notes above threshold and on any backdated issue.
9. Validation rules
| Rule | Code |
|---|---|
| Customer is active | INVOICE_CUSTOMER_INACTIVE |
| Currency enabled for partner | INVOICE_CURRENCY_DISABLED |
| At least one line | INVOICE_NO_LINES |
Line unit_price > 0 (or explicit zero-rated allowed) |
INVOICE_LINE_PRICE_INVALID |
| Tax code valid for the customer's tax jurisdiction | INVOICE_TAX_INVALID |
due_date ≥ issue_date |
INVOICE_DATES_INVALID |
| FX rate available for the issue date | INVOICE_FX_MISSING |
issue_date is in an open period |
INVOICE_PERIOD_CLOSED |
| Credit note total ≤ original invoice's net of prior credit notes | CN_OVERCREDIT |
| Invoice cannot be edited once issued | INVOICE_LOCKED |
10. Error handling
- Sequence allocator collision: retry up to 3 times with row-level lock; on persistent failure, return 503 with retry hint. Will not allocate duplicates.
- PDF generation failure: the JE is not rolled back; the invoice is issued with
pdf_status = pendingand the PDF generator re-tries via the job queue. - Customer email bounce:
notification_outbox.status = bouncedand a task is created for the assigned account manager. - Credit-note overcrediting: rejected; UI must show remaining creditable balance.
11. Real-world example
Scenario. Corporate customer Beta Corp (C-1023). Consolidated monthly invoicing. In May 2026 they had:
- 2 May, Air, BKG-1010, sell USD 1,200, service fee USD 25, VAT 5% on service fee.
- 14 May, Hotel, BKG-1042, sell USD 3,700 (markup model — agency owns the sale), VAT 5% on full.
- 22 May, Air refund of BKG-0998 (issued April), refund fee USD 50 + VAT.
At end of May the consolidator job creates a draft INV/2026/000158. Lines:
| # | Description | Account | Tax | Amount |
|---|---|---|---|---|
| 1 | Air — DAC–LON 02-May (BKG-1010) | 4012 (carriage pass-through) | n/a | 1,200.00 |
| 2 | Service Fee — BKG-1010 | 4031 | VAT-5 | 25.00 |
| 3 | Hotel — XYZ 14–18 May (BKG-1042) | 4023 | VAT-5 | 3,700.00 |
| 4 | Cancellation Fee — BKG-0998 | 4041 | VAT-5 | 50.00 |
| Subtotal | 4,975.00 | |||
| Tax (VAT 5% on lines 2,3,4) | 188.75 | |||
| Total | 5,163.75 |
JE posted:
| Acct | 🅓 | 🅒 |
|---|---|---|
| 1022 AR – Beta Corp | 5,163.75 | |
| 4012 Air Pass-through | 1,200.00 | |
| 4031 Service Fee Revenue | 25.00 | |
| 4023 Hotel Revenue | 3,700.00 | |
| 4041 Cancellation Fee Revenue | 50.00 | |
| 2021 VAT Output Payable | 188.75 |
Note: the cost side (BSP payable for the air ticket; hotel net cost) was already journaled at booking issuance, not at invoicing. The invoice's job is to crystallise the customer's obligation, not to re-recognise the cost.
12. Step-by-step — issuing a draft invoice
13. Database tables touched
invoices,invoice_lines,invoice_allocationscredit_notes,credit_note_lines,credit_note_allocationssequencesjournal_entries,journal_entry_linesdocuments(PDF references)audit_logs,notification_outbox
14. Future scalability
| Need | Approach |
|---|---|
| Customer self-service portal | Magic-link page already; expand to full account view with statements and pay-now. |
| E-invoicing networks (Peppol, ZATCA, India IRP) | Per-country adapters that consume the issued invoice and submit to the network; store the network UUID on the invoice. |
| Embedded invoicing for partners' own customer apps | Render-as-component widget with HMAC-signed config; payments tunnel back to platform PSP. |
| Document templating per customer | Customer-level overrides for header/footer/language without forking the underlying engine. |
15. Common pitfalls
- ⚠️ Editing the customer address on a draft after pricing was computed — re-run tax computation explicitly; do not rely on auto-recompute.
- ⚠️ Issuing a credit note for an unpaid invoice without checking that the AR balance still matches. Always allocate the CN to the specific invoice.
- ⚠️ Using a manual JE to "correct" an invoice. Don't. Use a credit note + new invoice.
- ⚠️ Mixing currencies on a single invoice. Each invoice is one currency; if a booking spans currencies, split into multiple invoices.
- 🔒 Sequence-allocation outside the issuance flow (e.g., reserving a number "for later"). Forbidden — would create gaps.
Next: 04-payments-receipts.md — applying customer receipts and supplier disbursements.