Supplier invoices read on your own PC
Invoices dropped in a folder are read by an AI model running on a PC in the office. Plain code checks every line and total, a person approves or fixes each one, and the approved ones export to a CSV for Xero's bill import. Nothing is sent to the cloud.
Every supplier, invoice and figure here is made up, and each invoice says so in its footer. The model runs, the checks and both recordings are real.
How it works
- Read. A local model (qwen2.5-coder:7b, through Ollama) copies the supplier, VAT number, invoice number, dates, currency, each line and the printed totals. It only copies. It never adds anything up.
- Check. Code checks quantity times price on each line, the lines against the net total, the VAT per rate, net plus VAT against the total, real dates, and the fields that must be there. One failed check and the invoice goes to "check".
- Review. A page shows the invoice next to what was read. A person approves, fixes a field (the checks run again) or holds it to ask the supplier. Approve only works when every check passes.
- Export. Approved invoices go to a CSV in the shape of Xero's bill import, one row per line.
The results
All 10 invoices read for real and every field compared with what the invoice says, in code. On one PC with an RTX 3080.
| Model | Right first time | Wrong fields | Seconds each |
|---|---|---|---|
| qwen2.5-coder:7b (the default) | 10 of 10 | 0 | 4.2 (2.5 to 6.5); the first took 62 s, loading the model |
| gemma3:4b (smaller, on purpose) | 4 of 10 | 17 | 5.1; the first took 36 s |
| Invoice | Supplier and what it tests | Default model | Status | Smaller model |
|---|---|---|---|---|
| 01 | Kade Office Supply B.V. One VAT rate | all right | ready | 2 wrong, check |
| 02 | Oostkade Catering Two VAT rates, 9% and 21% | all right | ready | 3 wrong, check |
| 03 | Wendrich Druck GmbH German layout, 19% and 7% | all right | ready | 0 wrong, ready |
| 04 | Lumen Cloud Services Ltd EU reverse charge, 0% VAT | all right | ready | 0 wrong, ready |
| 05 | Atelier Moreau SARL French layout, totals above the lines | all right | ready | 1 wrong, check |
| 06 | Kade Office Supply B.V. Eight lines | all right | ready | 7 wrong, check |
| 07 | Noordwind Transport B.V. A discount line | all right | ready | 2 wrong, check |
| 08 | Wendrich Druck GmbH A credit note | all right | ready | 0 wrong, ready |
| 09 | Oostkade Catering The supplier's total is 10.00 too high | all right | check | 2 wrong, check |
| 10 | Baltic Pine Furniture UAB Large amounts | all right | ready | 0 wrong, ready |
Invoice 09 is the supplier's own mistake. Both models flagged it: "net + VAT is 242.80, total says 252.80".
When the model gets it wrong
The smaller model misread 6 invoices, mostly copying a line's unit price as its amount. Every one failed a check, so none could be approved until a person fixed it.
| Invoice | What it misread | The check that caught it |
|---|---|---|
| 01 | line 1 amount: read 24.5, invoice has 98.0 (and 1 more) | a line's amount is not quantity times unit price (2 lines) |
| 02 | line 1 amount: read 16.5, invoice has 297.0 (and 2 more) | a line's amount is not quantity times unit price (3 lines) |
| 05 | net total: read 3444.0, invoice has 2870.0 | lines add up to 2870.00, net total says 3444.00 |
| 06 | line 1 amount: read 18.95, invoice has 37.9 (and 6 more) | a line's amount is not quantity times unit price (7 lines) |
| 07 | line 1 amount: read 145.0, invoice has 435.0 (and 1 more) | a line's amount is not quantity times unit price (2 lines) |
| 09 | line 1 amount: read 12.75, invoice has 153.0 (and 1 more) | a line's amount is not quantity times unit price (2 lines) |
Fair warning
- 10 invoices is a small test, on layouts we made. Your own invoices are the real test.
- It reads PDFs that have text in them. Scanned paper needs OCR or a model that reads images first.
- Account codes and tax type names belong to each Xero organisation, so they are settings, checked against your own import template.
What a real setup can add
- Watching a mailbox or a shared folder instead of a local one.
- Remembering each supplier's VAT number and usual account code.
- Catching the same invoice sent twice.
- Sending approved bills straight to the accounting software instead of a CSV.