Accidental duplicate invoices are impossible

The database itself refuses a second invoice for the same project, same amount, same day — and names the one it already has.

What it is

A unique database index, not a UI check. Same org, same project, same total, same issue date collides. Equal progress draws are still legal — three identical instalments on one job is a real billing pattern — because an accidental repeat always lands on the same day with the same figure, which is what the index actually outlaws.

Also called: invoiced twice · duplicated the invoice · double billed the customer · clicked save twice

See it, piece by piece
01

The second identical invoice is refused by the database, not warned about on screen

Same business, same project, same total, same day collides and the save is rejected. A check in the interface is bypassed by a second browser tab, a retry after a timeout, a background sync, and every code path written after it — and the failure here is a retry: the save looked like it had not worked, so it was done again. Only the database is present for every write.

New Invoice — Line Items
Line Items?+ Add Line
Project Estimate
Materials — Post-Frame Package
40×64×14 shop: posts, trusses, purlins, 29ga steel, trim package.
Quantity
1
ea
Unit
EachHoursqft…
Unit Price
$
41850.00
/ea
Total
$41,850.00
Change Order
CO-3 — Add two 12×12 overhead doors
Openings framed, headers upsized, jambs and track included.
Quantity
2
ea
Unit
EachHoursqft…
Unit Price
$
3240.00
/ea
Total
$6,480.00
Subtotal$48,330.00
Tax (6%)$2,899.80
Total$51,229.80
Saving the lines is what puts the total on the row, and that is where a repeat is refused. The real screen, drawn from the product’s own design system. Sample data — no customer information appears here.
02

Three equal instalments on one job are still legal — you say so on the record

Billing the same job in equal draws is ordinary, so the block offers a second, deliberately differently worded action: this is a separate charge, save it as well. That writes an acknowledgement against the row and the invoice is allowed through. Duplication stops being something that happens to you and becomes something a person states on purpose.

03

The refusal names the invoice you already have

Instead of a failed save you are told that INV-2026-0041, for this exact amount, was issued today — with two ways out: keep the one you have, or confirm this is a separate charge. The draft the blocked attempt created is removed, so a refused save does not leave half an invoice behind for you to find later.

04

The same cheque cannot be recorded twice against an invoice

A payment carrying the same reference and amount on the same invoice is refused, and the entry form stays open with an explanation saying it was not added a second time — because closing it would look like the entry went through, and “try again” is exactly how $10,205.06 got recorded twice. Cash and unreferenced payments are deliberately not constrained: the same customer paying the same round sum twice is ordinary.

How it works
  1. 1invoices_no_accidental_dup_idx is unique over (org_id, project_id, total, issued_date, coalesce(duplicate_ack,'')), excluding voided, deleted, project-less and zero-total rows.
  2. 2The total first lands on the row during the line-item save, so that is where the index fires and returns Postgres error 23505.
  3. 3The client surfaces the code intact rather than converting it to a generic failure, and looks up the colliding invoice by the same predicate so it can be named.
  4. 4The draft the blocked attempt just created is removed, so a refused save leaves no half-invoice behind.
Why we built it

A builder hit save on an invoice, the screen lagged, he closed out, came back and did it again — and the job ended up billed twice. A check in the screen would not have caught it: two browser tabs, a retry after a timeout and a background sync all step around one, and the failure is a retry by definition, because the save looked like it had not worked. The rule lives in the database instead, where every write has to pass it, so an identical invoice for the same amount on the same job on the same day cannot be created at all.

The problem
  • Retries after an apparent failure creating a second identical invoice.
  • Two tabs or a background sync racing to create the same bill.
  • Duplicates only discovered when the customer complains.
Sound familiar?
What you get
Duplication stops being something that can happen to you.
The blocked save names the existing invoice instead of leaving you hunting.
Legitimate equal instalments are still allowed.
What's inside

See it on your own jobs

Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.

or keep browsing features →