Working with sources
The invoice lines an importer quietly drops
A comma in a price is the most expensive punctuation in a supplier export. Why the rows it dropped were never a random sample of your invoice.
- Published
- Figures measured
- Read
- 3 min
- By
- Novus Stream Solutions
An importer that rejects a row tells you it rejected a row. What it cannot tell you is whether the rows it dropped were a fair sample of your invoice, and that turns out to be the question that matters.
This site's purchase importer had a defect in the code that reads a price out of a cell. It stripped everything that could not be part of a number, and through a quirk of how that rule was written, the comma survived the strip. A price written with a thousands separator therefore arrived at the number parser still carrying it, failed to parse, and left the row with no total. A row with no total is not stored.
A comma thousands separator is what a spreadsheet writes by default across most English-speaking locales, so this was not an exotic input. It was the ordinary one.
What each format does now
| Cell | Read as | Why |
|---|---|---|
| 1234.56 | 1234.56 | Unambiguous |
| 1,234.56 | 1234.56 | Both separators present, so the rightmost is the decimal point |
| $1,234.56 | 1234.56 | Currency symbols and spaces are ignored |
| 1.234,56 | 1234.56 | Both separators again, read the same way |
| 1,234,567 | 1234567 | A decimal separator cannot repeat, so these group |
| (123.45) | -123.45 | Accounting notation for a negative |
| 1,234 | Refused | 1234 in London, 1.234 in Berlin, and nothing in the cell decides which |
Measured Sep 12, 2026 from the numeric reader in src/lib/imports/normalizer.ts, run case by case. This data is re-ingested daily, so treat these as a snapshot rather than a live count.
The last row is the interesting one
A single comma with no decimal point is genuinely ambiguous. The same characters mean a thousands separator in one country and a decimal comma in another, and the cell carries nothing that settles it. The parser could pick the more common reading and be right most of the time.
It does not, and the reason is the size of the error rather than its frequency. Guessing wrong is not a rounding difference; it is a cost wrong by a factor of a thousand, and it would be invisible afterwards because every figure downstream would still look like a plausible number. So the row is refused and counted, and the rejection says which shape caused it, so the fix is one export setting away.
What to do with your own file
- Choose the file on the imports screen. It is read in your browser first, and nothing is transmitted until you have seen what would be stored.
- Read the refused count before the accepted one. A number there is a question, not a failure.
- If the reason names an ambiguous number, change the export to use a decimal point, or add decimal places so the shape resolves itself.
- Check one expensive line against the paper invoice. If the unit, pack size and total match, the rest of the file follows the same rules.
The wider lesson is not about commas. An import that silently discards a biased slice of your data is worse than one that fails outright, because the totals it produces still look reasonable. The count of what was refused is worth as much attention as the figures that survived.
Reproducing these figures
Every number above was read on September 12, 2026. Re-running these gives a different result on a later day, which is the point: the figures are dated so they can be checked rather than trusted.
- The formats table: call normalizePurchaseRow with a supplier, an item, a date, and each total shown, then read totalPrice from the result.
- The same cases run as assertions in tests/unit/import-number-formats.test.ts, so npm test reproduces the whole table.
- The rule the parser follows is published at /docs/import-contract, and tests/unit/import-contract.test.ts re-runs every worked example on that page through the real parser.
- To see it on your own file, choose a CSV on the imports screen: the preflight reads it in your browser and reports what would be stored before anything is sent.
Sources
Read next
Reading the data
The totals this site will not calculate
Currencies, units, price levels and review sources are kept apart here. The reasoning, and two places that rule had quietly slipped.
- Published
- Figures measured
- Read
- 3 min
Working with sources
One item, many pack sizes
On 2026-09-07 Canada's wholesale feed listed tomatoes under 29 pack descriptions. Why the site keeps every one apart, and how to pick the series you buy.
- Published
- Figures measured
- Read
- 4 min