Wise Hustlers — Digital Product & App Development Studio Logo
Get Consultation
By Wise Hustler Admin•9/15/2026•12 min read

Document Series and Numbering: The Invisible Rule That Blocks Entire Modules

Document Series and Numbering: The Invisible Rule That Blocks Entire Modules

# Document Series and Numbering: The Invisible Rule That Blocks Entire Modules

TL;DR: If a document type has no correctly configured, active series, the module that issues it doesn't fail with an error — it simply shows nothing to create, because the query behind the form depends on a series that doesn't exist. Numbering design isn't an administrative detail; it's a structural precondition for the module to work at all, and in Angola it's tied to a concrete tax requirement — sequential, chronological numbering with no gaps.

The symptom: a blank screen, not an error message

There's a failure pattern that repeats itself in management systems whenever someone tries to activate a new module — a new branch, a new credit note type, a new invoicing establishment: the "Create" button is there, the form loads, but on submit nothing happens, or the document number field stays empty, or the list of available series is blank. No exception, no stack trace, no "series not found" message. From the user's point of view, the module simply doesn't work.

The root cause is almost never in the module's business logic. It's one layer down: the document type in question (invoice, credit note, delivery note, material requisition, purchase order) has no active document series associated with it, for that establishment, for that fiscal year. Without a series, there's nowhere to pull the next number from. Without a number, the record can't be created — because the document number is typically part of what makes the record valid, both to the system and, in Angola, to the Administração Geral Tributária (AGT).

This is made worse by the fact that document numbering almost never shows up in the functional requirements of a new module. Whoever designs the "New Material Requisition" screen thinks about fields, approvals, cost centers — not about the fact that, without a row in the series table, that screen will never manage to save anything. It's a structural requirement, not a functional one, which is exactly why it's easy to forget until the day someone tries to use the module in production.

What a document series actually is, technically

A document series is, in practice, a counter with rules attached. It's defined by a set of attributes: a document type, a unique prefix (or identifier), a scope (usually the calendar year, sometimes the issuing establishment or legal entity), and a sequential number that advances monotonically, without going backward, within that scope. In Angola the law requires "sequential and chronological numbering by document type and the respective economic year, and one or more duly identified series may be used" (Art. 10(1)(b) of Presidential Decree No. 71/25). In invoicing-software practice, one series is created per year with the year in its name — in a series "2025A", the first invoice is issued as "2025A/1" (WISEDAT).

In an ERP's data model, this typically materializes as a DocumentSeries table (or equivalent) with columns like documentType, prefix, fiscalYear, establishmentId, currentNumber, and isActive, referenced by foreign key from every document table (Invoice, CreditNote, PurchaseOrder, MaterialRequisition). The most common design mistake is treating that reference as optional — letting seriesId be nullable "for now," intending to fill it in later. That solves the short-term problem of getting the module's development started, but it moves the real problem into production: the day a business user tries to issue the first document of a new type, there's no series, no number, and the screen is empty.

In Angola, the issuance of invoices and equivalent documents is regulated by the Regime Jurídico das Facturas e Documentos Equivalentes (RJFDE), originally approved by Presidential Decree No. 292/18 of 3 December, in force since 2 April 2019. That decree was repealed by Presidential Decree No. 71/25 of 20 March 2025 (Art. 40), which approves the new Legal Regime for Invoices and entered into force six months after publication, on 20 September 2025 (Art. 42) (Angolex — Decree 71/25; Angolex — Decree 292/18). The numbering rule survived the change: it was Article 11 of the 2018 decree and is now Article 10(1)(b) of DP 71/25 — sequential and chronological numbering by document type and economic year (EY Angola).

In operational terms, this means three things for whoever is designing the system:

1. Certified invoicing software must guarantee sequential, chronological numbering and must prevent documents from being deleted after issuance (this is how Art. 3 of DP 71/25 defines "invoicing software") — there can be no code path, not even an administrative one, that removes an already-assigned number without leaving a trace.

2. The sequence restarts per economic year and per document type, which in practice means creating new series at the start of each year (with the year in the identifier, such as "2026A") — the system has to treat the year as part of the series' scope, not as a display detail.

3. Taxpayers must electronically communicate to AGT the identification of every series, used and unused (Art. 24(1)(c)). And the consequence of failing is heavy: invoices whose series were not communicated are deemed not issued (Art. 35(4)), which attracts the fines for failing to issue an invoice — 7% of the invoice value, 15% for repeated non-compliance (Art. 35(1)). A series isn't just an internal system artifact — it's an entity that has to be declared and must reconcile with what the tax authority has on record.

This link between numbering and tax obligation is exactly why a "blank screen" is, in a sense, the correct behavior of the system when no valid series exists — even though the error message really should be more explicit. A well-designed system should never let a user create a document number outside a declared series, because that would create precisely the kind of gap the law prohibits. The weak point isn't the rule; it's the absence of a clear message when the rule blocks the operation. This is also the backdrop that makes mandatory electronic invoicing in Angola so sensitive to how series are designed: if the series feeding the electronic invoice isn't correctly configured, the problem propagates straight into the communication with AGT.

The prefix has a limit — and the limit forces abbreviation

There's a concrete technical constraint that rarely gets discussed before it becomes a problem: the composite identifier that combines document type, internal code, and series has a maximum length. The technical specification for SAF-T (AO) — the standardized tax audit file companies in Angola submit to AGT — defines the InvoiceNo and DocumentNumber fields with a 60-character limit and a mandatory pattern in the form [Document Type] [Internal Code]/[Sequential Number] (SAF-T AO XSD, `SAFTAO1.01_01.xsd`, published by ASSOFT on GitHub). The schema's own examples are short: FT S001/1, NC S001/1.

Sixty characters looks generous — until you break down what has to fit inside it: the document type (for example "FT" for invoice, "NC" for credit note), a mandatory space, the internal code the application assigns to that document type, the series identifier, a slash, and finally the sequential number, which on a high-volume operation can run to six or seven digits after a few years. If the logical name of a series is something like "MATERIAL-REQUISITION-WAREHOUSE-LUANDA-2026," it simply doesn't fit. The practical result is that whoever designs the series is forced to abbreviate — "RM-LDA-2026" instead of the descriptive name — and that abbreviation has to be decided once, consistently, before the series goes into use, because changing an active series' prefix mid-year breaks the continuity the law requires.

This has a direct implication for the DocumentSeries table design: the prefix field should not be an unconstrained varchar — it needs an explicit limit (typically 4 to 12 characters, leaving room for the rest of the composite identifier) validated at series-creation time, not discovered later when the SAF-T export fails schema validation. Catching this in production, on the day of the monthly file submission, is far more expensive than validating the length in the series-creation form.

Designing document series so they don't block modules

A robust design separates three concerns that are tempting to conflate: defining the series, atomically assigning the next number, and validating that a series exists before the screen is even rendered.

ConcernWhat to guarantee
Series definitionOne series per document type, per issuing entity, per fiscal year; prefix validated for length; explicit isActive flag
Number assignmentAtomic increment (a transaction using SELECT ... FOR UPDATE, or a dedicated database sequence) — never compute "max + 1" in application memory, which collides under concurrency
User-facing availabilityThe document-creation screen checks for an active series before rendering the form, and shows an explicit message — "No active series for Credit Note in 2026" — instead of an empty form

Atomic assignment deserves particular attention in environments with multiple users issuing documents concurrently — typical of a warehouse or an offshore operations base with several shifts logging requisitions at the same time. Reading the highest existing number and adding one, without locking, is the most common way to produce two documents with the same number — exactly the gap that sequential numbering exists to prevent. The correct alternative is a database-managed sequence, or a transaction that locks the series row until commit.

It's also worth considering that in a group with several companies sharing the same system instance, each legal entity needs its own numbering — a series cannot be shared between two distinct legal persons, because the no-gaps sequencing obligation applies per taxpayer. This is one of the places where series design intersects directly with how you model multiple entities in a shared PostgreSQL database: the series has to be isolated by companyId with the same discipline used to isolate any other data that shouldn't leak between entities.

Auditability: proving there are no gaps

A well-designed series isn't just a source of numbers — it's a structure that lets you answer, at any moment and without manual reconciliation, the question "is there a missing number in this series?" That reduces to a straightforward query over the sequence of issued numbers per series: compare the count of existing documents against the difference between the first and last number, grouped by series and year. A mismatch signals a gap — a document voided without a valid successor, an import error, or worse, a concurrency failure in number assignment.

This is precisely the logic underpinning the extraction of the SAF-T (AO) accounting file without manual reconciliation: if numbering integrity is guaranteed at the source, at the level of the transaction that creates the document, exporting to SAF-T becomes a direct projection of the data — not a detective exercise in the middle of the monthly submission.

FAQ

What happens if I delete an invoice that already has a number assigned?

Under the RJFDE, certified invoicing software must prevent documents from being deleted after issuance. The correct practice, when a document is wrong, is to issue a credit note or a cancellation document that references the original number — never delete the row, because that would create a gap in the sequence.

Can I reuse the same series from one year to the next?

It isn't the safe path. Numbering is sequential and chronological by document type and economic year (Art. 10 of DP 71/25), and standard practice in certified software is to create a new series each year, with the year in the identifier (for example "2026A"). At the start of each fiscal year, the new series for the document types in use have to be created and communicated to AGT.

Why won't my material requisition module let me create anything, even without an error message?

That's the symptom this article describes: there's likely no active series configured for that document type in the current establishment and year. It's worth checking the series table directly before assuming a defect in the module's business logic.

Does this only apply to invoices, or also to internal documents like requisitions and purchase orders?

The legal obligation for sequential, gap-free numbering, as described in the RJFDE, applies to invoices and fiscally equivalent documents. But the design pattern — an active series as a precondition for the module to work — is useful for any document that needs a unique, auditable identifier, even where there's no direct tax requirement behind it.

A note on who's writing this

Wise Hustlers is developing Enerxia, its ERP for Angola's oil and gas sector, with modules covering upstream, wells, production, projects and contracts, procurement, suppliers, inventory, MRO, maintenance, fleet, logistics, HSE, quality, HR, training, finance, tax and compliance — including the document series and numbering module that underpins the invoicing and internal documents described above. When a team needs custom software where this kind of structural rule is handled from the data model outward, rather than patched in after the module is already in production, that's the kind of work we do in custom software development.

Sources

Related articles