Tips, fixes & use cases
Real problems from real back offices — what the logs showed, the theory that turned out to be wrong, and what actually fixed it. Use cases are written for owners and controllers; technical fixes for whoever is in the code.
-
Your AI bill is mostly the same instructions, repeated
Business AI tools resend the same instructions, and often the same document, on every call — at full price. Prompt caching reuses the repeated part for a fraction of the cost. On a PO booking workflow it cut PDF input cost by 58–70%.
-
Why prompt caching often saves nothing
Caching can be on and still save nothing. Parallel calls can’t share a cache none has written, a marker on changing content writes every time, small prompts are silently skipped, and the duration has to fit how often you call.
-
Five rules for matching remittances to the bank
Post on the bank date, don’t trust the “check” label, hold checks until they clear, never post the same cash twice, and give every deduction a reason. Five rules for automated cash application, and where each came from.
-
Cash application without the spreadsheet
Remittances arrive as emails, PDFs, portal exports and retailer files; the cash arrives separately at the bank. One console reads them all, matches each to invoices and the real deposit, handles deductions, and posts with the remittance attached.
-
The new hire got a text from “the owner”
Days into the job, a new AP employee got a text impersonating the owner. Was her number leaked from company systems? How we checked identity, sign-ins and mail rules without guessing, and what finance onboarding should cover.
-
We ordered 25 dozen and received 300
A PO for 25 dozen was received as 300 dozen; the bill was right and the PO showed fully billed. The variance was sitting in received-not-invoiced, caused by a screen that read in eaches and wrote in dozens.
-
Booking customer POs with the checks a senior CSR would make
Customer POs arrive as PDFs in a hundred layouts. A console reads each one, finds the customer, checks price against contract and history, flags duplicates, bad addresses, credit holds and card terms, then books and verifies the order.
-
Negative prices on a quote nobody typed wrong
A quote printed large negative prices. The data was fine: it had been created through the API, a script that sets a flag only ran in the UI, and the PDF template branched on that flag into legacy logic.
-
Finding the scripts that slow every save
Three SuiteQL queries explain most slow records: what’s deployed on them, what writes the most log rows, and what fails most often. And why the noisiest failing script may still be doing work you can’t lose.
-
Your ERP isn’t slow. It’s carrying years of customizations.
When order and customer entry crawl, the cause is rarely the ERP. It’s years of scripts, integrations and debug logging on the busiest records. What a performance review finds, and what slow saves cost a team every week.
-
The expenses that weren’t missing
An analysis concluded a big monthly expense category never hit the P&L. It had — the role running the SuiteQL couldn’t see credit card charges, so they were silently left out. Reconcile to the P&L before believing a gap.
-
The costs nobody looks at until renewal
Insurance, utilities, freight, software and services drift quietly between renewals. What to review quarterly, every six months and annually, how to net carrier bills against label cost, and the thresholds that make a line worth a phone call.
-
OCR promised this for a decade. AI finally does it.
Document capture has been promised for a decade and OCR never got past templates. One PDF with a hundred packing lists in it — split, read, matched to each PO, pre-filled for receiving, filed to the receipt, and flagged where something’s off.
-
Three ways our status guard let a shipped order slip
Blocking shipped→packed sounds like ten lines. The Mark Packed button submits as PACK, not EDIT. Integrations need a different path from people. And oldRecord is only as fresh as the page the user loaded.
-
The order shipped. The invoice never came.
When a shipped fulfillment slides back to packed, nothing errors — the goods are gone and the invoice never exists. Why it happens in nearly every ERP, what it does to revenue and cash, and why training a person only gets you so far.
-
Getting shipping data onto the 856 without anyone touching it
The 856 needs cartons and tracking from the shipping system. A one-time copy missed LTL PRO numbers that arrived later, a kit and an assembly sharing a SKU broke matching, ASNs went out before the data landed, and failed 850s named no document.
-
Five ways a NetSuite cash forecast goes quietly wrong
Status codes that change between contexts, amounts that come back null inside scripts, long text truncated without warning, a bank feed that copied one account into three, and double counting between run-rate and loan entries. None of them throws an error.
-
The 13-week cash forecast lenders now expect
AR is this, AP is that, the delta is cash. Lenders now want that every week, thirteen weeks out, and accurate. Why the spreadsheet that used to work no longer does, and what a forecast built from the ERP gets right.
-
What four marketplaces taught us about syncing from NetSuite
Sending a price is a few lines. Getting the app authorized on an account nobody can sign in to, learning that zero isn’t a quantity everywhere, surviving rate limits overnight, and building a console where a preview never looks like a send — that’s the job.
-
EDI didn’t go away when everything went API
New systems speak API; big customers still send an 850 and expect an 856 that matches the cartons. What each document does, what a bad ASN costs in chargebacks, and what onboarding a trading partner well looks like.
-
Selling it at the price you meant, only when you have it
A listing is two promises: this is the price, and we have it. Oversell and you eat cancellations and penalties; undersell and you hide stock you own. Why the ERP should drive every channel, and what a sync worth trusting looks like.
-
Stopping the same order from being picked twice
Between submitting orders to a background job and the job reaching them, they still look open — and a second user picks them again. An in-flight flag closes the window, a stale fallback stops crashed batches stranding orders, and a leading-wildcard LIKE is the wrong check.
-
An empty list is not an error message
One user saw no orders; everyone else saw hundreds. The query had failed and the catch returned an empty array, so failure looked like no work. Surface the error, bind your parameters, and don’t stop at the permissions theory.
-
SuiteScript 2.1 before the deadline: sixty-plus scripts in under a day
NetSuite is retiring SuiteScript 1.0 and 2.0. Most companies will budget it as a quarter-long, script-by-script project. We inventoried 1,600+ scripts, sorted what was the client’s problem from what wasn’t, and converted 60+ in under a day.
-
Four SDF deploy errors and what they actually mean
LONGTEXT is spelled CLOBTEXT, a feature you rely on has to be declared, <setting> isn’t valid on a script parameter, and a mandatory parameter needs a value on every deployment. Four SDF errors, four one-line fixes.
-
One order, six authorizations: tracking down a payment fan-out
Shipped orders sat on payment hold and never invoiced. The bundle was fine — one joined column in the search feeding it reauthorized each order once per row, until the gateway’s duplicate check started rejecting the last attempt.
-
The header location SuiteQL says is empty
The UI shows a header location, the script reads it, and SuiteQL says null. In SuiteQL the header location lives on the transaction line flagged as main line — and the mismatch can make a working script look broken.
-
SuiteQL doesn't accept INTERVAL '30' MINUTE
A syntax error near ‘30’ on a query that looks like perfectly good SQL. SuiteQL rejects ANSI interval literals; NetSuite timestamps are day-based numbers, so thirty minutes is 30/1440.
-
Pricing as a process, not an event
Costs now reprice monthly whether you do or not. A bigger annual increase fails in both directions — what works is a loop: a margin sensor at order entry, a queue that persists, a console with authority, and a memory that defends each change.
-
Repricing the orders that never should have booked
The report that flags thin orders is the easy half. The console that fixes prices held four traps — a swallowed save that hid a whole division, a display function returning account numbers, the discount gross-up, and the override you must refuse to reprice.
-
When the NetSuite form submits itself
“Unexpected token _ in JSON at position 0.” The JSON is fine — a button inside a serverWidget form defaulted to type=submit, and the request you are debugging never left the page.
-
Why that column prints blank on your PDF
It shows in the UI and prints empty. A rendered PDF sees stored data, not derived data — and the key you inject has to match what the template is actually looking up.
-
MAP_REDUCE_ALREADY_RUNNING is not an error
Show it to a user as a failure and they resubmit — duplicating work that was already queued. Some exceptions describe the environment, not the outcome of the request.
-
Blanket purchase orders: which release does this invoice belong to?
Six lines, same item, same rate, same quantity. Only the expected date differs. Match on item code and every invoice for the next twelve months posts against release one.
-
Filing inbound documents with AI
One document in three never made it onto the record, because attaching it was slower than skipping it. The AI reading the paper is the easy half — resolving a handwritten reference and writing it without duplicates is the work.
-
The freight you quoted versus the freight you paid
Across a large catalog item dimensions are never perfect, and the gap becomes shipping margin you lose one order at a time. Detecting it is the easy half; feeding the dimension errors back is what actually fixes it.
-
An ISO 20022 pain.001 file the bank accepts first time
Double-escaped entities, SWIFT character stripping, 35/140 truncation, BIC fallback — and the currency trap that overpays vendors by the FX rate without ever throwing an error.
-
ACH addenda: telling the vendor what you just paid them for
Adding a 705 addenda record is one line. Keeping the file from being rejected afterwards is the work — and the bigger prize is that paying and recording stop being two separate steps.
-
Stopping the work order cascade
A special-order item generated work orders all the way down the BOM — for subassemblies already on the shelf. The fix is one field. The three traps in getting it to stick are the interesting part.
-
MISSING_PDF_PARAMETERS when the template was never set
The error names your parameters. The parameters are fine — setTemplateByScriptId failed silently on a case mismatch four lines earlier, and a fallback path hid it for weeks.
-
Is the error you’re chasing the cause, or just a symptom?
An integration failure that looked like a payment script bug. Undeploying the script changed nothing — and that five-minute test reframed the whole investigation.
-
Reading a NetSuite stack trace
UNEXPECTED_ERROR is NetSuite saying it doesn’t know either. How to work backwards to the line that actually broke — and why the page came back full of zeroes instead of failing.
-
Fixing “(intermediate value).warn is not a function” in SuiteScript
It looks like a logging problem. It’s a mismatch between your define() array and your callback parameters — and the reason it appeared out of nowhere is worth knowing.
Nothing matches. Try fewer words, or ask us — it may be the next one we write.