← All posts
Invoicing

The unbroken number series, and the four ways software breaks it

Bokföringslagen asks for a series with no holes and a document reproducible for seven years. Four ordinary implementation choices quietly break both. Here they are, and what to do instead.

The Closepact team9 min read

TL;DR

Two rules sit underneath Swedish invoice numbering. A number is never issued twice, and for an invoice series it is never skipped either. A sent invoice cannot be edited; the correction is a second document with the sign turned round. Both are easy to state and easy to break, and the four ways software breaks them are all reasonable-looking decisions made for other reasons.

What the law is actually asking for

Bokföringslagen wants three things of a customer invoice. The series has no gaps, so the absence of number 1043 is a question somebody can answer. The document is reproducible exactly as it was sent, for seven years. And a mistake is corrected by a new document rather than by changing the old one, because the old one has already been read by somebody outside the company.

Everything below follows from those three sentences.

Break 1: numbering the draft

The tempting design is to create an invoice row, give it a number, and let the office fill it in. It reads well in a database schema and it fails the first time somebody starts an invoice and abandons it.

A draft is not an invoice. It has no number, it may never be sent, and it can be thrown away for nothing. The moment a draft carries a number, deleting one leaves a hole in the series, and a year later nobody can say whether 1043 was cancelled, lost, or sent to a customer and hidden.

So the number is taken when the invoice is issued and at no other moment. A draft cancelled the same afternoon leaves no trace in the series, because it never took anything out of it.

Break 2: a database sequence

The second design is to let the database hand out numbers: a sequence, or an auto-incrementing column. This is the right tool for a primary key and the wrong one for an invoice number, for one specific reason.

A sequence survives a rollback. That is a feature — it is what lets a sequence be fast, because it never has to wait for anybody's transaction to finish. It is also exactly what you cannot have here. Take a number from a sequence, fail three lines later, roll the transaction back, and the number is gone permanently. Nothing carries it. The next invoice is 1044 and 1043 never existed.

The counter is therefore a row in a table, locked while it is read and written. Concurrent callers queue behind the lock rather than racing; the loser waits a few milliseconds and gets the next number instead of an error. And because it is a row rather than a sequence, a rollback returns the number and the next caller gets it. Nothing is skipped and nothing is issued twice.

Break 3: allocating outside the transaction

The third design allocates the number, then does the slow work — render the PDF, store it, write the row — and commits at the end.

If the render throws, the counter has already moved. Nothing carries the number it moved past. Bokföringslagen asks for an explanation of the gap and nobody can give one a year later.

So the number is allocated inside the transaction that uses it, alongside the render and the store. The price is real and worth naming: the series row stays locked while the PDF renders, so two people sending different invoices in the same second queue behind each other for a few hundred milliseconds. That is the right way round. Sending is not a hot path, and an unbroken series is a legal requirement while throughput here is a preference.

Break 4: the second click

Somebody presses Send, the browser times out, they press it again. Or a retry fires on a request whose response was never seen. Two requests, one invoice, and if both pass the "is this a draft?" check they take a number each — one document, two numbers, and the second sitting in the series with nothing to explain it.

The fix is to read the invoice again under a row lock rather than trusting what the route resolved, and to re-check inside that lock. The loser waits, reads its own work, and gets back a plain conflict naming the number that was already issued: this invoice was already issued as A-1043 and cannot be sent again; correct it with a credit note. That is a truthful answer rather than a 500, and it is truthful precisely because the check happened under the lock.

What "sent is sent" means in practice

The states an invoice can be in are written out rather than implied. A draft can become sent or cancelled. A sent invoice can become partially paid, paid, overdue, credited or written off. There is no path from sent back to draft, and there never will be.

Overdue is deliberately not a state anybody sets. It is what sent becomes when a date passes, and a scheduled job writes it down. Treating it as a decision would mean an invoice could be made overdue by hand, which is not a thing that happens.

The credit note takes its own series

A credit note is a document in its own right with its own number, and the number comes from its own counter. That is not cosmetic. Both counters start at 1, and invoices are unique on the combination of organisation, series and number — so leaving credit notes in the invoice series makes credit note 1 collide with invoice 1, and the office's first correction fails on a database constraint. The constraint is right, and what it is telling you is that these are two series rather than one. Ours derives the credit series from the original's, so a company keeping a separate run per office still has one.

A credit note also carries no OCR reference, on purpose. The two series count independently, so credit note 1 and invoice 1 reduce to the same digits and therefore the same payment reference — and the matcher would then find two documents for one incoming payment with no way to choose. OCR references and bankgiro numbers goes into that.

The date is Swedish, not UTC

The application runs in UTC. An invoice dated from UTC is dated yesterday for the two hours after midnight every summer. On the first of a month that puts the document in the previous VAT period — declared in the wrong quarter, and discovered by whoever reconciles the return rather than by anybody in the office.

So the issue date is taken in Europe/Stockholm and the due date is counted from it. The payment terms come off the invoice rather than being read from the customer again, because the terms were copied onto the draft when it was made and re-reading the customer would silently move the due date of a document whose terms were agreed weeks ago.

The PDF is rendered once

An invoice has to be reproducible exactly as it was sent for seven years. A template edited next spring would otherwise rewrite last autumn's documents, with no version of them left anywhere to compare against.

So the PDF is rendered once, at issue, stored with a checksum, and served from then on. Drafts may be rendered as often as anybody likes, because a draft is a preview and is watermarked as one — without the watermark, a draft printed off and handed to a customer is indistinguishable from an invoice, and it carries no number, so the customer pays against a reference that matches nothing.

Further reading

Keep reading

Want to see this with your own jobs?

Book a 20-minute demo. We set up one of your own jobs before the call: a quote, a week on the schedule or an invoice.

Book a demo