Skip to main content

Document Numbering

FlowPOS assigns every document two numbers:

FieldScopeUsed for
documentNumber(businessId, documentType)Business-wide reference, FEL/SAT, AR/AP cross-location
locationDocumentNumber(businessId, locationId, documentType)Display-only — receipts, POS UI, store-local search

Both numbers are assigned atomically at creation time inside the same DB transaction. No backfill is performed on historical records.


Dual-numbering model

documentNumber

The existing business-scoped sequence. Incremented from the document_counter table keyed on (business_id, document_type). Formatted as {prefix}{000000} (6-digit zero-padded; prefix defaults to "" for most types).

This is the authoritative reference for:

  • FEL/SAT electronic invoice payloads (felNumber, felAuthorization)
  • Accounts Receivable / Accounts Payable cross-location lookups
  • Any external integration (certifiers, integrations)

locationDocumentNumber

A new location-scoped sequence. Incremented from document_location_counter keyed on (business_id, location_id, document_type). Formatted as a bare 6-digit zero-padded number (no prefix).

This is:

  • Display-only — shown on receipts, POS UI, and list views for store staff
  • Separate per location — location A and location B each have their own 000001 counter
  • Nullable — when a document has no locationId, locationDocumentNumber is null (graceful skip)
  • Never sent to FEL certifiers, SAT, or any financial integration

FEL/SAT boundary

Documents going through FEL certification always use documentNumber only. Code integration points are annotated with:

// FEL: business-scoped documentNumber only — locationDocumentNumber is display-only and not sent to SAT/certifier

Graceful skip (no location)

Some documents allow creation without a locationId (e.g. purchases, credit/debit notes). When locationId is absent or null, only documentNumber is assigned and locationDocumentNumber remains null. No error is thrown. This makes the feature strictly additive — existing API clients are unaffected.


Transfer documents

For the transfer family (inventory_transfer, transfer_request, transfer_dispatch_note, transfer_goods_receipt), the location counter uses originLocationId as the scope. The destination location is not used for counter keying.


Service API

All create flows use the generateDocumentNumbers facade in apps/backend/src/common/services/document-number.service.ts:

const { documentNumber, locationDocumentNumber } = await generateDocumentNumbers({
trx,
businessId,
documentType: DocumentType.SALE,
locationId: sale.locationId ?? undefined, // graceful skip when null
});

The legacy generateDocumentNumber function remains unchanged for excluded flows (AR/AP/service-bookings which have no locationId column).


Counter tables

document_counter (existing)

ColumnNotes
business_idFK → business.id
document_typevarchar
last_numberinteger
prefixvarchar (optional; rarely used)
reset_frequencyvarchar (column exists but reset logic is deferred — no admin UI yet)

Unique: (business_id, document_type).

document_location_counter (new)

ColumnNotes
business_idFK → business.id
location_idFK → location.id
document_typevarchar
last_numberinteger

Unique: (business_id, location_id, document_type).
No prefix or reset_frequency columns (reset logic deferred).


Counter configuration

Counters are created automatically on first use via an upsert-style SELECT … FOR UPDATE → INSERT. There is no admin UI for manually configuring starting numbers or prefixes. Direct DB seed is the current approach when needed.

Per-period reset (deferred)

The document_counter.reset_frequency column exists (values: never | daily | monthly | yearly) but the reset logic has not been implemented — there is no admin UI to configure it. This is intentionally deferred until a configuration screen is available.


Excluded document types

The following document types remain business-scoped only (no location counter) because their tables have no location_id column:

  • accounts_receivable_invoice
  • accounts_receivable_receipt
  • accounts_payable_bill
  • accounts_payable_payment
  • service_booking

Where locationDocumentNumber is shown

Backend API

Returned on all list/detail endpoints for in-scope document types. Searchable via locationDocumentNumber query parameter on repositories that already support documentNumber search (quotes, GRN, purchase orders, transfers, production runs, etc.).

Thermal receipts

Rendered as a "Tienda: {number}" line below the business documentNumber line (when present). Label is overridable via ReceiptLayoutOptions.labels.store.

PDFs

Exposed as locationDocumentNumber in PDF data transformers (SalePdfData, OrderPdfData, QuotePdfData, purchase/inventory/transfer types, etc.). Handlebars templates render it as Tienda: when the value is present.

Covered template families (apps + packages/backend/database/src/templates/ mirror):

  • Receipts / thermal: sale-receipt, sale-receipt-thermal, order-bill-receipt, order-bill-receipt-thermal, order-receipt-thermal, cash-register-session, cash-register-session-thermal
  • Full PDFs: sale, order, order-bill, quote, purchase, purchase-order, goods-received-note, inventory-adjustment, inventory-transfer, transfer-request, transfer-dispatch-note, transfer-goods-receipt, contractor-assignment, material-consumption, production-run

Out of scope for templates: AR/AP, service bookings, Z-report session rows, static FEL credit/debit note templates, stock-count PDFs.

Print-bridge: Thermal rendering uses @flowpos-workspace/receipt-layout buildDocumentReceiptLines, which includes the same Tienda: line for sale, order, order-bill, and cash-register-closing payloads.

DB-custom templates: Merchants who override templates in the database must add the {{#if locationDocumentNumber}} block manually; seeded defaults include it after migration.

PWA

Store locationDocumentNumber is the primary identifier in POS headers, toolbars, and search/list tables. Business documentNumber appears as a muted secondary line when both numbers exist.

Sale text search matches both documentNumber and locationDocumentNumber (same as quotes).