Skip to content

PRD: Invoice lifecycle & issuance

ModuleTax & Invoice (CORE-10)PRD IDPRD-INV-001
StatusShippedOwnerTax & Invoice squad
Date2026-04-13Versionv1.0
Packages@nx/invoice · @nx/taxation · @nx/iiapi · @nx/t-vanURDINV · REQ · MOD

TL;DR

Turns a completed payment into a legal Vietnamese electronic invoice - automatically queued and issued through an authorized provider, tracked through its lifecycle with retry, submitted to the tax authority, and recorded in an immutable audit trail. For owners and cashiers it means every paid order can become a numbered, compliant invoice; for buyers it means self-claiming their own invoice from a receipt QR. The outcome: a paid order is no longer legally incomplete - it ends in an issued invoice with full traceability.

1. Context & Problem

A completed payment is not legally complete in Vietnam until a numbered electronic invoice is issued through an authorized e-invoice provider and (when required) submitted to the tax authority. The module already records the seller tax identity, tax groups, and invoice configuration, but there is no path from a paid order to an issued invoice - no engine that consumes payment-success, drives issuance, tracks status, retries failures, or keeps an audit trail.

This increment builds the issuance engine on top of that configuration: an @nx/invoice package that turns payment-success into a queued issuance, issues through the provider, tracks the invoice through its lifecycle, and records every event immutably. The provider path runs through iiapi (VNPAY / VNIS) as the single issuance gateway, with buyer-info capture and a self-service claim flow so an invoice can be requested at the counter or claimed by the buyer.

2. Goals & Non-Goals

Goals

  • Queue an invoice for issuance automatically on a successful payment, issue it via the provider, and capture the invoice number and tax-authority code.
  • Track the invoice through pending → processing → success / failed / cancelled with a configured retry policy on failure.
  • Submit issued invoices to the tax authority (CQT via T-VAN) when enabled and track the submitted status.
  • Record an immutable audit-trail entry for every invoice event.
  • Support invoice adjustment, replacement, and cancellation (with reason) against an issued invoice.
  • Capture buyer info (name, tax code, address, email) and support a buyer self-service claim via receipt QR with a claim token and deadline.
  • Support the four issuance modes: real-time on payment, manual at the counter, scheduled batch, and buyer self-service.

Non-Goals

  • Multiple invoice providers beyond the current iiapi / T-VAN set.
  • PDF rendering of the invoice - produced provider-side, not in-repo.
  • Tax-rate calculation at sale time - owned by the pricing engine.
  • Tax declaration / filing automation.
  • Seller tax identity, tax groups, and invoice configuration - owned by Tax Identity & Groups and the invoice config feature.

3. Success Metrics

MetricTarget / signal
Issuance coverage100% of eligible paid orders queue an invoice on payment-success
Issuance success rateIssued / queued trends up; failures retried per policy before terminal failure
Tax-authority acceptanceSubmitted invoices accepted by CQT (where submission is enabled)
Audit completenessEvery state change has a matching immutable audit-trail entry; zero gaps
Claim conversionBuyer self-service claims completed before deadline vs. links issued

4. Personas & Use Cases

PersonaGoal in this feature
OwnerEnsure every sale produces a compliant invoice; adjust / replace / cancel when needed
CashierCollect buyer info and issue the invoice at the counter
BuyerSelf-claim their own invoice from the receipt QR
Accountant (downstream)Rely on issued invoices + audit trail for tax reporting

Core scenarios: a payment succeeds → an invoice is queued and issued via the provider → its number and tax-authority code are captured → it is submitted to CQT and tracked → every event is recorded; alternatively a cashier issues manually with buyer info, or the buyer self-claims via receipt QR before a deadline.

5. User Stories

  • As an owner, I want an invoice issued automatically when a payment succeeds, so every sale becomes legally compliant without manual work.
  • As an owner, I want failed issuances retried per a configured policy, so transient provider errors don't lose invoices.
  • As an owner, I want issued invoices submitted to the tax authority and tracked, so I meet CQT obligations.
  • As an owner, I want to adjust, replace, or cancel an issued invoice with a reason, so I can correct mistakes legally.
  • As a cashier, I want to capture buyer info and issue the invoice at the counter, so a buyer who asks gets their invoice on the spot.
  • As a buyer, I want to scan the receipt QR and submit my own info before a deadline, so I can claim my invoice myself.
  • As an owner, I want every invoice event in an immutable audit trail, so the invoice history is verifiable.

6. Functional Requirements

#RequirementURD ref
FR-1Queue an invoice for issuance automatically on a successful paymentURD-INV-001
FR-2Issue the invoice via the provider and capture its number + tax-authority codeURD-INV-002
FR-3Track invoice status pending → processing → success / failed / cancelledURD-INV-003
FR-4Retry a failed issuance per the configured retry policyURD-INV-004
FR-5Submit the issued invoice to the tax authority (CQT via T-VAN) when enabled, and track its statusURD-INV-005
FR-6Record an immutable audit-trail entry for every invoice eventURD-INV-006
FR-7Adjust an issued invoice (correction linked to the original); replace or cancel with a reasonURD-INV-007..008
FR-8Process inbound provider webhooks with signature validation to update statusURD-INV-009
FR-9Capture buyer info (name, tax code, address, email); cashier-direct issuance at the counterURD-REQ-001..002
FR-10Buyer self-service claim via receipt QR with a claim token + deadline; claim lifecycle pending → claimed / expiredURD-REQ-003..004
FR-11Deliver the invoice / claim link by receipt QR, email, or SMSURD-REQ-005
FR-12Support four issuance modes: real-time, manual, scheduled batch, buyer self-serviceURD-MOD-001..004

Full requirement text and acceptance criteria live in the Tax & Invoice URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
Data integrityInvoice number + tax-authority code are recorded only on confirmed issuance; status transitions are coherent with the audit trail
ImmutabilityThe audit trail is append-only; corrections happen via adjustment/replacement entries, never edits
Tenancy & authzAll operations scoped per merchant (x-merchant-id); issuance/config gated by invoice permissions; provider credentials owner-gated
ReliabilityIssuance runs through a queue (Kafka + BullMQ) with idempotent processing and retry; webhooks validate signatures
SecurityProvider credentials stored encrypted; claim tokens unique and bound to a single invoice request
i18nUser-facing labels/statuses are bilingual ({ en, vi })

8. UX & Flows

Key screens: invoice configuration / onboarding wizard, invoice list and detail, manual / batch issuance, and the buyer self-service claim page reached from the receipt QR (backed by @nx/invoice; provider webhooks update status asynchronously).

9. Data & Domain

EntityRole
InvoiceThe issued invoice - status, number, tax-authority code, links to order and buyer info
InvoiceRequestBuyer-info capture + claim token/deadline that produces an invoice
InvoiceAuditTracingImmutable per-event trail of every invoice state change
MerchantInvoiceProfile / InvoiceProvider / InvoiceProviderConfigMerchant invoicing setup, provider credentials, serial + retry policy
InvoiceConfigMappingRoutes a sale channel to the provider config that issues its invoices

Conceptual only - full schema and invariants in the invoice domain model and taxation domain model.

10. Dependencies & Assumptions

Depends on

  • Invoice configuration (URD-CFG) - an invoice profile, connected provider, serial, and routing must exist.
  • Seller tax identity (URD-TAX) - the seller (MST, name, address) printed on every invoice.
  • Payment (payment.success) - a successful payment is what triggers automatic issuance.
  • Orders - the sale order supplies the line items and totals that fill the invoice.
  • Provider gateways (@nx/iiapi, @nx/t-van) - issuance and tax-authority connectivity.

Assumptions

  • The merchant has an active invoice profile with a connected provider and a routed channel.
  • A retry policy and (where required) tax-authority submission are configured.
  • Buyer tax info is available at issuance (collected at the counter or via claim) when a VAT invoice is requested.

11. Risks & Open Questions

Risk / questionMitigation / status
Provider outage / transient errorsQueued issuance with configured retry; terminal failure recorded in the audit trail
Duplicate issuance on event replayIdempotent queue processing keyed per order/request
Webhook spoofingInbound provider webhooks validated by signature before status update
Reversing an issued invoiceAdjustment / replacement / cancellation carry a reason and link to the original; nothing is hard-deleted
Single provider set (iiapi / T-VAN)Accepted for this increment; additional providers are a later phase

12. Release Plan & Launch Criteria

AspectPlan
PhaseP1 (foundation) - see URD feature catalog
RolloutAll merchants with an active invoice profile; gated by invoice configuration
MigrationNone (new entities; invoice config and provider credentials set up via onboarding)
Launch criteriapayment-success → queue → issue → number + tax-authority code captured verified end-to-end; retry on failure verified; CQT submission tracked; audit-trail entry per event; buyer self-service claim verified
MonitoringIssuance success/failure rate, retry counts, CQT acceptance rate, queue lag, webhook errors, claim conversion

13. FAQ

When does an invoice get issued? By default in real time on payment.success. It can also be issued manually by a cashier, in a scheduled batch, or by the buyer self-claiming via QR.

What happens if the provider rejects issuance? The invoice is retried per the configured policy; once retries are exhausted the status is failed and the failure is recorded in the audit trail.

Can an issued invoice be changed? Not in place - it can be adjusted (a correction linked to the original), replaced, or cancelled with a reason. The audit trail stays immutable.

Who renders the PDF? The provider, not the app. Rendering is provider-side.

How does a buyer claim their own invoice? They scan the receipt QR, open the claim link before the deadline, and submit their buyer info; the invoice is then issued with those details. After the deadline the claim is expired.

Does this calculate tax rates? No - tax-rate calculation at sale time is owned by the pricing engine; this increment issues the invoice from the order data it receives.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.