AstroBaaS

Orders & fulfilment

Order Invoice Documents

Free — GPL coresize Mplanned, not built

Generated from docs/plan/core/order-invoice-documents/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

Merchants have no formal invoice entity or sequential invoice numbers. The /receipt endpoint is marked as non-fiscal, so invoices cannot be used for tax filing or bookkeeping reconciliation. This feature introduces invoices as a first-class legal document.

The problem

I have no formal invoices with sequential numbers. Tax authorities require invoices for every sale, but I can only generate a ‘receipt’ that isn’t legally recognized. I can’t do bookkeeping reconciliation or tax filing without real invoices.

What it does

  • Add invoices collection: {id, order_id, invoice_number (sequential, unique per merchant), invoice_date, due_date, items: [{description, quantity, unit_price, total}], subtotal, tax_amount, total_amount, status (draft|issued|paid|cancelled), payment_method, payment_date}
  • Generate sequential invoice numbers (e.g., INV-001, INV-002, …) with configurable prefix and starting number
  • Support partial invoicing: one order can have multiple invoices (e.g., invoice for items shipped, second invoice for deposit)
  • PDF generation: professional invoice layout with merchant details, customer details, line items, totals, payment terms, invoice number and date
  • Mark invoice as paid when order payment is received
  • Store invoice as attachment (PDF stored in order record)
  • Email invoice to customer (optional, configurable)
  • Audit trail: invoice creation, modification, cancellation all logged

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Tax calculation or tax reporting (that is separate tax-compliance module) — core only stores tax amount, doesn’t calculate
  • Multi-currency invoicing — invoices use shop currency (frozen at order time)
  • Subscription or recurring invoicing — that is separate billing system
  • Electronic invoicing standards (e.g., UBL, XInvoice) — that is country-specific compliance, defer to plugin per jurisdiction

Data model

invoices collection: {id, order_id, invoice_number, invoice_date, due_date, items: [{description, quantity_integer, unit_price_minor, line_total_minor}], subtotal_minor, tax_amount_minor, total_amount_minor, status, paid_date, pdf_url, merchant_id}. orders.invoice_ids: [invoice_id]. Migration: new invoices collection and orders.invoice_ids field.

API

  • POST /api/admin/orders/:orderId/invoices — create invoice for order
  • GET /api/admin/orders/:orderId/invoices — list invoices for order
  • GET /api/admin/invoices/:invoiceId — fetch invoice details and PDF URL
  • PATCH /api/admin/invoices/:invoiceId/status — mark invoice as paid/cancelled
  • GET /api/admin/invoices?status=issued&start_date=2026-01-01 — query invoices for tax reporting

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Order detail includes ‘Invoices’ section. Button ‘Create Invoice’. List shows: invoice number, date, total amount, status badge (draft/issued/paid/cancelled). Clicking invoice shows: full details, customer details, line items, PDF preview, download/email buttons. Settings section: invoice prefix (e.g., ‘INV-’), starting number, due date terms (net 30, net 60).

The seam — why this is core

Core owns invoice entity, sequential numbering, PDF generation, and status tracking. No paid seam — invoicing is legal requirement and cannot be gated. This is foundational infrastructure like orders themselves.

Tax and accounting compliance seam. Every merchant is legally required to issue invoices with sequential numbers. This is a core seam that cannot be gated.

Dependencies

  • Existing orders, order_items collections
  • PDF generation library (e.g., jsPDF, PDFKit, weasyprint)
  • email layer (to send invoices to customers)
  • audit_log (to log invoice lifecycle changes)

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • Create invoice for order; confirm invoices collection stores invoice_number=‘INV-001’, invoice_date, total_amount_minor
  • Create second invoice for same order; confirm invoice_number increments to ‘INV-002’
  • Generate PDF and verify it contains invoice number, dates, customer details, line items, totals, payment terms
  • Mark invoice as paid; confirm status changes to ‘paid’ and paid_date is recorded
  • Query invoices by date range and confirm only invoices in range are returned
  • Verify invoice PDF URL is accessible and PDF is complete (no missing data)

Risks

Invoice numbering must be sequential and never skip (legal requirement). Implement database constraint to prevent duplicate invoice numbers. Cancelling an invoice doesn’t renumber; it leaves a gap (legal accounting practice). PDF generation with complex layouts can be slow; implement async generation and caching. Invoice PDFs must be immutable once issued; use archive storage for compliance.

Commercial context

Suggested priceFree
Rival anchorMagento ships invoice entities, numbering schemes, PDF generation, and partial invoicing workflows free.

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.