![Purchase Order Automation: 5 n8n lessons from a real client build [Workflow Included]](https://preview.redd.it/ruxuvutx7zah1.png?auto=webp&s=106db6cbcdd76a68e75a9bfd0e0ec9538f65a9ca)
Purchase Order Automation: 5 n8n lessons from a real client build [Workflow Included]
👋 Hey n8n community,
A few of you asked for more detail after my Purchase Order extractor post yesterday. The build looked simple on the surface, but a handful of things bit me along the way. Here are the five that cost me the most time, in case they save you some.
1. Only numbered rows are real articles. The POs had little note lines wedged between items ("2 Box", a location note under a lock, etc). My extraction kept swallowing those into the neighbouring product name, so one row would come out as two items mashed together. The fix wasn't in the workflow at all, it was in the document description I gave the extractor: spell out that only rows with a number in the No. column are real articles, and that unnumbered lines are notes belonging to the row above. That one paragraph cleaned up every merge. Lesson: when a document extraction misbehaves, describe the document better before you touch the nodes.
2. Keep numbers as text until you've checked for empties. Tempting to pull quantity and price straight as numbers. Don't, at least not yet. A missing field comes back as the string "null", and if the field is typed as a number that signal turns into a 0 or a real null and you lose the ability to spot the miss. I keep everything as text, run my checks, then cast to a number afterwards. Clean signal in, clean data out.
3. One helper to catch every flavour of empty. "Empty" is never just one thing. Across the docs I saw real null, the string "null", empty strings, and whitespace. I stopped writing one-off checks and made a single isMissing() helper that catches all of them, then used it everywhere. If a field is missing, the workflow flags it on the form's completion screen with the document name and which field failed, so my friend knows exactly which PO to eyeball instead of trusting the sheet blindly.
4. The Google Sheets checkbox that quietly broke everything. This one nearly broke me. New rows kept landing at the very bottom of the sheet instead of the top empty row. Turns out I'd added a checkbox column with Insert > Tick box, which silently writes a FALSE value into every one of the 1000 cells in the column. The Append node counts those as data, so it always appended below them. If you want checkboxes, add them through Data → Data validation instead, which draws the box without writing a value. Hours lost to a column that looked empty but wasn't.
5. Batch size 1 is not optional here. The extractor node bundles every input item into a single call, so if you hand it two PDFs at once you get one jumbled result. Wrapping it in a Loop Over Items with batch size 1 means each document gets its own clean pass. Small setting, big difference, and easy to miss until your two-file test comes back merged.
The whole thing runs on the easybits extractor node for the actual PDF reading, the rest is stock n8n. If you want to try the Purchase Order extractor yourself, feel free to grab it here:
https://github.com/felix-sattler-easybits/n8n-workflows/blob/c38749a68fd6ea4ae6ebff41789d35cceaacdef1/easybits-purchase-order-extractor-workflow/easybits_purchase_order_extractor_workflow.json
What's the dumbest time-sink you've hit on a build that looked easy? Always happy to hear how other builders tackle this stuff.
Best,
Felix