Extraction was previously manual: an agent read each PDF, mapped the columns by hand and wrote data/source/invoice-*.json. That was the only way anything got in, and the upload button just filed the document without reading it. That supplier's report is one fixed template — the columns sit at identical x-positions on every invoice, and only the line count and page count vary — so the figures are now read by coordinate instead. Deliberately not an AI extractor: this input does not need one, and a deterministic parse that fails loudly is worth more here than a flexible one that can hallucinate a total. lib/invoice-parser.ts reads the header, the machine lines across all pages, the "Plant Hire Total" row and the SUB TOTAL / Escalation / PLUS VAT / INVOICE TOTAL block, then applies the same arithmetic gates the seed does: lines must sum to the subtotal, each line must satisfy qty x rate = amount and amount + VAT = total, and VAT must match the stated rate. Anything that does not reconcile is refused with the reason — never partially imported. Validated by parsing all five existing invoices and comparing every field against the hand-extracted JSON: identical, including the R24,205.13-VAT column that a plain text read gets wrong. PHI 169 was then deleted and re-ingested through the HTTP endpoint alone and came back field-for-field identical, with no agent involved. - "Add Invoice" drops a PDF in and imports it; lines are matched to plant items by the code the invoice prints, and an unmatched line (the container codes MPLANT04/MPLANT05) is left unassigned rather than guessed. - A "Problem invoices" inbox lists every PDF that failed, with the reason, and Retry re-reads the stored document and re-runs the parse. Retry re-reports rather than claiming success, and only files imported data. - invoice_intake collection records each attempt. pdfjs-dist is in serverExternalPackages: bundled, it rewrites its own lazy worker import to a .next path absent from the standalone image and every parse dies with "Setting up fake worker failed". The parser also copies the buffer before handing it over, since pdfjs transfers and detaches it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
44 lines
1.2 KiB
JSON
44 lines
1.2 KiB
JSON
{
|
|
"name": "mega-plant",
|
|
"version": "0.1.0",
|
|
"private": true,
|
|
"scripts": {
|
|
"dev": "next dev --webpack -H 0.0.0.0 -p 6007",
|
|
"build": "next build --webpack",
|
|
"start": "next start -H 0.0.0.0 -p 6007",
|
|
"lint": "next lint",
|
|
"typecheck": "tsc --noEmit",
|
|
"seed": "node scripts/seed.mjs"
|
|
},
|
|
"dependencies": {
|
|
"@ducanh2912/next-pwa": "^10.2.9",
|
|
"@radix-ui/react-dialog": "^1.1.4",
|
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
|
"@radix-ui/react-label": "^2.1.1",
|
|
"@radix-ui/react-select": "^2.1.4",
|
|
"@radix-ui/react-slot": "^1.1.1",
|
|
"@radix-ui/react-tabs": "^1.1.2",
|
|
"@radix-ui/react-tooltip": "^1.1.6",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"lucide-react": "^0.469.0",
|
|
"next": "^16",
|
|
"pdfjs-dist": "^4.10.38",
|
|
"pocketbase": "^0.27.3",
|
|
"react": "^19.0.0",
|
|
"react-dom": "^19.0.0",
|
|
"recharts": "^2.15.0",
|
|
"tailwind-merge": "^2.6.0",
|
|
"xlsx": "^0.18.5"
|
|
},
|
|
"devDependencies": {
|
|
"@tailwindcss/postcss": "^4.0.0",
|
|
"@types/node": "^22.10.0",
|
|
"@types/react": "^19.0.0",
|
|
"@types/react-dom": "^19.0.0",
|
|
"postcss": "^8.4.49",
|
|
"tailwindcss": "^4.0.0",
|
|
"tsx": "^4.19.2",
|
|
"typescript": "^5.7.2"
|
|
}
|
|
}
|