PRD: Invoice Issuance Experience
| Module | Tax & Invoice | PRD ID | PRD-ISS-001 |
| Status | Ready to dev | FEAT | ISS · BANA-1422 |
| Epic | BANA-1318 | Plane | BANA-1564 |
| Date | 2026-06-11 | Version | v1.0 |
| Packages | @nx/invoice | URD | ISS |
| Surface | Sale · POSClient · Owner/Mgr | ||
| Owner | Việt Võ · Phát Nguyễn | ||
TL;DR
- A cashier issues an e-invoice at the moment of payment at the POS - one action, or automatic per merchant configuration - without leaving the payment screen (🚧 not built; the issuance engine is ready behind the scenes, only the button/status on screen is missing).
- On the Client, a new invoice management screen shows the owner every invoice with its issuance status and tax-authority code - distinct from the "Invoice" tab that already exists at the POS, which is really an order list sharing the same name (🚧 not built).
- An owner adjusts an incorrectly issued invoice right from its detail screen (🔶 the processing engine is ready, the screen isn't); replacing an invoice isn't available at any layer yet, not even underneath the UI.
- A company buyer's VAT invoice is issued by picking a business-customer profile that already has a tax code - the invoice then carries that exact tax code and company name, gated on the Business Customers (
BIZ) feature shipping the same month (🔶 the system already accepts and stores an ad-hoc buyer tax code, there's just no saved profile to pick from yet).- A failed invoice shows up and can be retried from the management screen - no invoice silently vanishes because of a technical error (🚧 not built).
- Printing/sharing an issued invoice, and verifying the provider (VNPAY) connection from a config screen, are two smaller pieces left for later - neither has any surface today (🚧).
1. Context & Problem
The invoice lifecycle (queue → issue → status), the VNPAY provider integration (original/adjustment/cancellation operations), and tax identity/groups all shipped in Phase 1. The issuance engine already listens for successful-payment events and can queue an invoice the moment a sale is paid. Merchants own a well-working issuance machine running behind the scenes - there is just almost no way to see or drive it from a screen.
What's missing is the front-facing experience: the POS payment-success screen has no invoice-issuance action at all today (only sale-receipt and kitchen-ticket printing); the Client has no screen that shows an invoice's issuance status or tax-authority code. Worth flagging: the "Invoice" tab that already exists at the POS is easy to mistake for this - it shows order status (draft/processing/complete/cancelled), not e-invoice issuance status; two different concepts are sharing one name.
Invoice adjustment already has a ready processing engine (checks the original is issued, locks against double-processing, calls the provider) but no screen calls it yet; invoice replacement doesn't exist at any layer - it's only a named concept in the data model. Company invoices already accept and store a buyer's tax code via information attached to the order, but there is no business-customer profile to pick one from until the Business Customers (BIZ) feature ships, in the same July window.
2. Goals / Non-Goals
Goals
- A cashier issues an invoice at the POS at the moment of payment, in one action, or automatically per merchant configuration.
- The Client has an invoice management screen: a list filterable by issuance status and period, and a detail view with the tax-authority code and the full processing history.
- An owner issues an adjustment invoice for one that was issued incorrectly.
- A company invoice carries the tax code and company name of the business customer selected.
- A failed invoice shows up and can be retried from the management screen - no invoice silently disappears.
- An issued invoice can be printed/shared with the customer.
- The connection to the e-invoice provider can be verified from a config screen.
Non-Goals
- Invoice replacement - a named concept in the data model, with no processing flow or screen at any layer; out of scope for this increment (FR-003, §11).
- Tax declaration/filing (PRD-DCL-001).
- Providers other than VNPAY.
- Industry-specific issuance rules beyond what tax groups already define.
- Building the business-customer profile itself - owned by the Business Customers feature (
BIZ, PRD-BIZ-001); this PRD only consumes that profile when a company buyer is selected. - Rendering an invoice PDF - owned by the provider; the exact sharing mechanism is still an open question (§11).
- The full provider configuration/onboarding screen (
CFG) - this PRD only needs a connection-verification step, not the whole configuration flow rebuilt.
3. Success Metrics
| Metric | Target |
|---|---|
| POS issuance | A cashier issues an invoice at payment in one action, live merchant |
| No silent failures | Every failed invoice shows up on the management screen and can be retried from it |
| Correct company tax code | A company invoice carries the selected tax code exactly, no manual fix-up after issuance |
4. Personas & Use Cases
| Persona | Goal in this feature |
|---|---|
| Cashier | Issue an invoice at payment without needing to know anything about tax |
| Owner | Review invoices, fix mistakes with an adjustment, serve company buyers |
| Company buyer | Receive a valid VAT invoice carrying their company's exact tax code |
Core scenario: a cashier finishes a payment at the POS, and the invoice is issued automatically or with one tap. If a buyer later reports a wrong amount, the owner reopens that invoice on the Client and issues an adjustment invoice right from the detail screen - with no need to understand the tax process behind it, and no need to contact support.
5. User Stories
- As a cashier, I finish a payment and issue the invoice with one tap; the customer gets it immediately.
- As an owner, a buyer reports a wrong amount - I issue an adjustment invoice from the detail screen.
- As an owner, a company asks for a VAT invoice - I pick the business customer and the invoice carries their tax code.
- As an owner, an invoice fails to issue - I see the reason right on the management screen and retry it without contacting support.
- As an owner, a customer asks for their invoice again - I print or share the issued invoice from the detail screen.
6. Functional Requirements
| # | Requirement | Status | URD ref |
|---|---|---|---|
FR-001 | One-action issuance at the POS at payment, automatic or manual per merchant configuration | 🚧 | URD-ISS-001 |
FR-002 | Invoice management screen - list filterable by status/period + detail with tax-authority code and history | 🚧 | URD-ISS-002 |
FR-003 | Adjustment & replacement invoices for an issued invoice | 🔶 adjustment has an engine, replacement doesn't | URD-ISS-003 |
FR-004 | Company invoice carrying the tax code + name of the selected business customer | 🔶 gated on BIZ | URD-ISS-004 |
FR-005 | Failed issuance visible + retryable from the management screen | 🚧 | URD-ISS-005 |
FR-006 | Print/share an issued invoice with the customer | 🚧 | URD-ISS-006 |
FR-007 | Verify the provider connection (VNPAY) end-to-end from a config screen | 🚧 | URD-ISS-007 |
FR-001 - One-action issuance at the POS. Completing a payment at the POS triggers e-invoice issuance: per merchant configuration, this happens automatically (right when payment succeeds) or through a manual action by the cashier - an "Issue invoice" button next to the existing actions (print receipt, print kitchen ticket). The payment-success screen shows an issuance-status chip on the sale, with no need to leave the screen to know the outcome. The cashier needs no tax knowledge - just whether the invoice has been issued.
FR-002 - Invoice management screen. A new Client screen: an invoice list filterable by issuance status (Pending, Processing, Success, Failed, Cancelled) and by period; selecting a row opens a detail view showing the provider-assigned invoice number, the tax-authority code, and the full processing history (created, sent, signed, sent to the tax authority, accepted/rejected by the tax authority, adjusted, replaced, cancelled). This is a different screen from the "Invoice" tab that already exists at the POS - that tab actually shows order status (draft/processing/complete/cancelled), not e-invoice issuance status or the tax-authority code; the two concepts are easy to confuse from a quick look at the app (§11).
FR-003 - Adjustment & replacement invoices. From the detail screen of an invoice already issued successfully, an owner creates an adjustment invoice: entering a reason plus the list of corrected lines (ordinal, name, quantity, unit price, amount, tax); the new adjustment invoice references the original and goes through the same issuance lifecycle as any invoice. The adjustment processing engine (checking the original's status, locking against double-processing, calling the provider) is ready per PRD-INV-003 - only the screen is missing. That same backend increment also finished a cancellation flow with a mandatory reason, even though the ISS URD doesn't list cancellation as a requirement of its own (§11). Replacement - used when an invoice needs to be voided entirely and reissued rather than partially corrected - isn't available at any layer today: no processing flow, no API, no screen; it exists only as a named concept in the invoice data model.
FR-004 - Company invoice carrying the buyer's tax code. At checkout or at issuance, the owner/cashier picks a business customer that already has a profile (company name, tax code) - the issued invoice then carries that exact tax code and company name instead of a retail buyer's name. When no business customer is picked, the invoice uses the default name for a consumer not claiming a named invoice (per current regulation). The invoice system already accepts and stores a buyer's tax code via information attached to the order; what's missing is a business-customer profile to pick from - gated on the Business Customers (BIZ) feature, shipping the same July window.
FR-005 - Failed issuance visible + retryable. A failed invoice shows a Failed status with its reason on the invoice management screen, never disappearing from the owner's view. The system automatically retries on a schedule for failures identified as transient; the owner also needs to be able to retry from the detail screen (whether this is a separate manual action or just a display of the automatic retry in progress needs confirming, see §11). A retry - automatic or manual - never creates two invoices for the same sale.
FR-006 - Print/share an issued invoice. From the detail screen, the owner prints or shares a successfully issued invoice with the customer. This is distinct from the sale-receipt/kitchen-ticket printing already available at the POS. The exact sharing mechanism (a lookup link keyed on the tax-authority code, or something else) is still an open decision, since rendering the invoice PDF itself is out of scope for this PRD (owned by the provider).
FR-007 - Verify the provider connection. From a config screen, Operations/the merchant owner verifies that the connection to the e-invoice provider (VNPAY) is working - distinct from the existing VNPAY configuration for QR/Phone POS payments. This item depends on an invoice-provider config screen existing in the first place - no screen on the Client or Back Office reads or writes this configuration today, even though the backend (connection, retry policy) has shipped.
6.1 Acceptance criteria
- Complete a payment at the POS → the invoice is queued for issuance (automatically or via one action) → the issuance status shows immediately on the payment-success screen (FR-001).
- Open the invoice management screen on the Client, filter by Failed → see exactly the failed invoices with their reasons; open one → see its tax-authority code and full history (FR-002).
- From a Success invoice, create an adjustment with a reason + corrected lines → a new adjustment invoice appears, referencing the correct original (FR-003 adjustment).
- Try to create a replacement invoice → no action is available on the detail screen, matching current scope (FR-003 replacement, 🚧 out of scope).
- Pick a business customer with a tax code at checkout → the issued invoice carries that exact tax code and company name, with no manual fix-up (FR-004).
- Don't pick a business customer → the invoice uses the default retail-buyer name, with no tax code (FR-004).
- Simulate a failed issuance → the invoice shows a Failed status with its reason on the management screen; retry → issuance succeeds, no duplicate invoice created (FR-005).
- From a Success invoice, print it or get a share link → the customer receives a valid invoice (FR-006).
- From the provider config screen, verify the connection → see the real success or failure result from the provider (FR-007).
7. Non-Functional Requirements
| Area | Requirement |
|---|---|
| Doesn't block checkout | Invoice issuance runs in the background (async) - payment doesn't wait on the issuance result |
| Idempotent | A retry (automatic or manual) never creates two invoices for the same sale |
| State integrity | An invoice being processed can't be cancelled or edited until the provider returns a result |
| Real-time display | Invoice status on the management screen updates without a page reload |
8. UX & Flows
Issuing an invoice at the POS at payment:
Working an invoice from the management screen:
9. Data & Domain
| Entity | Role |
|---|---|
| Invoice issuance | A single-issuance record - status, tax-authority code, event history |
| Invoice request | Buyer information attached before issuance - name, tax code (if any), address |
| Business-customer profile | Owned by the Business Customers (BIZ) feature - the source of a tax code/company name to pick |
| Provider configuration | Connection + retry policy toward the e-invoice provider (VNPAY), per merchant |
Conceptual only - the full schema lives in the developer domain model.
10. Dependencies & Assumptions
Depends on
- Business Customers (
BIZ, PRD-BIZ-001) - the tax code + company name profile to pick from when issuing a company invoice (FR-004). - Provider configuration per merchant (
CFG, backend shipped) - the connection + retry policy for issuance (FR-001, FR-005, FR-007). - Retail correctness (PRD-RTL-001) - retail merchants issue with the right tax behaviour.
Assumptions
BIZships in the same July window asISS; if it slips, FR-004 keeps the existing ad-hoc path (no profile to pick from, tax code entered manually if the buyer provides one) untilBIZis ready.- The automatic retry policy (max attempts, delay) is already configured per merchant; this PRD doesn't redefine that policy, only surfaces its outcome.
11. Risks & Open Questions
| Risk / question | Mitigation / status |
|---|---|
| The "Invoice" tab that already exists at the POS shares its name with the new e-invoice screen, which can make readers assume the feature already exists | Rename or replace the existing tab once the invoice management screen (FR-002) ships - decision pending |
| Invoice replacement (FR-003) doesn't exist at any layer - further behind than the "modeled but not issued" note in the previous version of this PRD | Already scoped out (§2); revisit only if there's a real ask to pull it into this increment |
| Retrying a failed issuance (FR-005) only has an automatic, scheduled mechanism today; unclear whether a separate manual-retry action is needed | Confirm with the backend team before committing "retry from the screen" as a button, versus just showing the automatic retry in progress |
| The "share" mechanism for an invoice (FR-006) isn't decided at the data-contract level - it could be a lookup link keyed on the tax-authority code, or something else | Pin down the design before writing detailed acceptance criteria for FR-006 |
Verifying the provider connection (FR-007) depends on a CFG config screen that doesn't exist on any surface today | Confirm whether FR-007 includes building a minimal config screen, or should be split off as a dependency on CFG shipping separately |
| Two old "Issue invoice" entry points in the Client are currently disabled (a quick-action and a Finance-module item) | Decide whether to revive or delete them once FR-001/FR-002 ship, to avoid two conflicting entry points |
| Invoice cancellation already has a complete backend with a mandatory reason (PRD-INV-003), but URD-ISS-003 only names adjustment & replacement, never cancellation, as a requirement of the experience | Confirm whether cancellation belongs in the invoice management screen's scope (FR-002) for this increment, or is left to another PRD |
12. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P2 - July (WK27-31), alongside BIZ |
| Rollout | Direct launch to live merchants once criteria are met; the engine shipped in Phase 1, no separate feature flag needed for this increment |
| Migration | None - this only builds a new operating surface on top of existing infrastructure |
| Launch criteria | AC-ISS-01 (URD) passes on a live merchant - one invoice issued at the POS, one company invoice with a tax code, one recovered failure; all of §6.1 passes except invoice replacement (FR-003, out of scope) |
| Monitoring | Successful-issuance rate at payment; count of failed invoices still open on the management screen; average time from failure to a successful retry |
13. FAQ
Is this rebuilding the invoice engine? No - the lifecycle, VNPAY integration, and tax identity all shipped in Phase 1; this PRD only builds the user-facing operating surface.
Is the "Invoice" tab that already exists at the POS the invoice management screen from this PRD? No - that tab shows order status, not issuance status or the tax-authority code; it will be replaced or renamed once FR-002 ships (§11).
Is invoice replacement part of this increment? No - it's out of scope because there's no engine for it at any layer, unlike adjustment which already has a processing engine (§2, §11).
What if Business Customers (BIZ) doesn't ship in time? A company invoice can still be issued through the existing ad-hoc path - no profile to pick from, tax code entered manually if the buyer provides one - until BIZ is ready.
What does "sharing an invoice" mean? Not decided yet - most likely a lookup link keyed on the tax-authority code from the provider, not a self-rendered PDF (§11).
References
- URD: Tax & Invoicing -
ISS - Related: PRD-INV-001 - Invoice Lifecycle & Issuance · PRD-INV-002 - E-Invoice Provider Integration · PRD-INV-003 - Invoice Adjustment & Cancellation Flows · PRD-BIZ-001 - Business Customers · PRD-RTL-001 - Retail Business Type
- Module: Tax & Invoicing - URD · Roadmap: Phase 2 - By Month
- Developer: @nx/invoice