Sample output from the Terms vs. Behavior Audit prompt in the Sonar AI Prompt Library, run against a NetSuite test account. Every name and number here is test data. Back to the post · The library
Accounts Receivable Intelligence

Terms vs. Behavior Audit

Do customers actually pay the way their assigned terms say they will? A payment-application-level analysis of every customer payment in the account — with anomalies, trends, and negotiating leverage surfaced along the way.

August 16, 2026Report date
Dec 2023 – Aug 2026Payment activity window
1,472 payments · $3.65MApplications analyzed
100 customers51 met the ≥3-invoice threshold
Sonar AIPrepared via live SuiteQL

1Executive Summary

The receivables book is in excellent shape on paper — but the interesting findings are in the exceptions, the trend line, and the free float being left on the table.

10.2
Avg days to pay
Simple average, all 1,472 applications
18.7
$-weighted days
Big invoices settle slower than small ones
96%
Paid within terms
1,414 of 1,472 applications on time or early
Jun ’26
Trend break
Avg days-to-pay jumped ~3 → ~18 and stayed there

⚠ Finding A — Payment behavior deteriorated sharply in June 2026

From Dec 2024 through May 2026 the portfolio paid in a remarkably tight 3–5 day average. In June 2026 the average jumped to 17.6 days (weighted: 23.9) and has stayed elevated through August (weighted: 28.7 — right at the Net-30 boundary). Application volume also quadrupled (≈35/mo → 130–189/mo) with ~$790K–$960K/month in settled dollars. This is either a real behavioral shift in the book, a change in mix (new large customers on terms), or a change in how payments are being entered. It deserves investigation before it becomes a DSO problem.

⚠ Finding B — 6 payments are dated before their invoices — including future-dated invoices

Three Alpha Demand invoices (INV1660–1662) are dated Aug 31, 2026 — two weeks in the future — yet were "paid" Aug 1–3. Frutti Di Mare (INV1721, −17 days), Buzzie's Sandwiches (INV503, −4), and Smith Pacific Northwest (#171, −2) show the same inversion. These are data-entry / process artifacts (deposits or prepayments applied to later-dated invoices), but they distort DSO math and are exactly what an auditor's cutoff test would flag.

ℹ Finding C — Your single biggest payer has no terms assigned

Alpha Demand (customer id 1615) accounts for 1,022 of 1,472 paid invoices ($195K) and pays in 6.2 days on average — yet the customer record has no payment terms. Every aging bucket, dunning rule, and due-date calculation treats these invoices as due-on-receipt. Assigning real terms (their behavior fits Net 7–Net 15) makes reporting honest at zero cost.

✓ Finding D — Terms compliance is excellent; the leverage runs the other way

Only 5 of 49 Net-30 customers average past 30 days, and the worst is just +3.4 days. Meanwhile 21 customers pay 15+ days early, including Whole Markets ($302K @ 16.9d), Acme Produce ($221K @ 9.4d), and Dubois Candy ($199K @ 10.8d). That's prepaid float you're receiving without offering any early-pay discount — pure negotiating capital.

2Methodology

Days-to-pay is measured at the payment-application level, not the invoice level — each application of a customer payment to an invoice is one observation, weighted by the dollars applied. This handles partial payments correctly and avoids the "last payment defines the invoice" distortion.

transaction (CustInvc) nexttransactionlinelink (linktype='Payment') transaction (CustPymt) customer.terms → term
Metric definitions
Days to payTRUNC(payment date) − TRUNC(invoice date) per application. Measured from invoice date, not due date — this is what "Net 30" promises against.
Avg daysSimple mean across a customer's applications. Every invoice counts equally.
Weighted daysΣ(days × $applied) ÷ Σ($applied). When weighted ≫ simple, the customer's large invoices are the slow ones — the pattern that becomes a collections problem.
VarianceAvg days − assigned terms days. Positive = pays late; negative = pays early.
Assumptions & scope decisions read before quoting numbers
≥ 3 invoicesCustomer-level table requires at least 3 paid invoices — below that, an "average" is noise. 51 of 100 paying customers qualify; excluded customers still count in portfolio totals.
Paid invoices onlyThis measures behavior on invoices that got paid. Currently-open and never-paid invoices are out of scope (that's the A/R aging's job). Survivorship bias: true behavior is slightly worse than shown.
Payments onlylinktype='Payment', CustInvc→CustPymt, positive applied amounts. Credit memos (49 in the account) and journal applications are excluded — they represent adjustments, not payment behavior.
Link-table datesDates come from nexttransactionlinelink.previousdate / nextdate (invoice and payment tran dates). Negative values were kept and reported as anomalies (Finding B), not silently dropped.
Currencyforeignamount = transaction currency. Dollar totals assume a single-currency book; if multi-currency is active, cross-currency sums are approximate.
No-terms customersTreated as 0-day terms for variance math, and flagged separately (Finding C) rather than buried in averages.
"Within terms"Application counted as compliant when days-to-pay ≤ the customer's terms days. For no-terms customers this is a harsh ≤0 test — the true portfolio compliance rate is therefore understated.

3Portfolio View

How the 1,472 payment applications distribute, and how behavior has moved over 33 months.

Days-to-pay distribution count of payment applications per bucket
0–7 days 8–14 15–21 22–30 31–45 45+ 782 419 6 178 84 3
Note the bimodal shape: a fast cluster (0–14 days, 82%) and a "pay near the due date" cluster (22–30). The 15–21 day valley (only 6 payments) suggests two distinct payer populations, not one continuum.
Days-to-pay trend by payment month Dec 2023 – Aug 2026, capped at 30 for scale
0 10 20 30 TREND BREAK Dec ’23 Jun ’24 Dec ’24 Jun ’25 Dec ’25
Simple avg days $-weighted avg days Jun–Aug ’26: weighted avg hits 28.7 — brushing the Net-30 ceiling

4Customer-Level Results

All 51 customers with ≥3 paid invoices, ranked worst-to-best by variance from assigned terms. The bar shows how far behavior deviates from terms (red = late, green = early).

Terms vs. behavior — full ranking variance = avg days-to-pay − terms days
CustomerTermsInv$ AppliedAvg dWtd dWorstVarianceFlag
BCP Customer 2568212.612.624+12.6NO TERMS
Alpha Demand1,022195,1326.26.113+6.2NO TERMS
Baxter Elementary SchoolNet 30549,05433.433.434+3.4LATE
Bonita InnNet 3038,67733.033.033+3.0LATE
Sam's Stop N GoNet 30521,78132.432.334+2.4LATE
Snaptags ConsultingNet 30336,57030.030.0310.0AT TERMS
Photolist FoundationNet 30347,97030.030.0310.0AT TERMS
Realpoint Co.Net 30336,57030.030.0310.0AT TERMS
Skibox LLC.Net 30432029.529.531−0.5AT TERMS
Oozz IncorporatedNet 305134,15529.029.631−1.0AT TERMS
Riffpedia CompanyNet 30539,97528.828.831−1.2AT TERMS
Ntags AssociatesNet 30323,68928.730.431−1.3AT TERMS
Phasellus Vitae Mauris Inc.Net 30338,07028.727.531−1.3AT TERMS
Oyope IndustriesNet 30444,97128.527.331−1.5AT TERMS
Wapp Hardware SalesNet 30475,98028.328.331−1.8AT TERMS
Realcube IndustriesNet 3049,30828.328.331−1.8AT TERMS
Rhycero LPNet 30530,47528.028.031−2.0AT TERMS
Sem Corporation AssociatesNet 30520028.028.031−2.0AT TERMS
Keller PRNet 30699,27528.028.031−2.0AT TERMS
Meedoo IndustriesNet 30326,73927.727.828−2.3AT TERMS
Smith Pacific Northwest StoreNet 3027151,61327.020.166−3.0ERRATIC
Dab's DeliNet 3037,22427.030.340−3.0WTD>TERMS
Shuffle's GroceryNet 30762,39526.125.928−3.9
McEdwards & Whitwell SteakhouseNet 30413,18125.025.025−5.0
Wikizz IndustriesNet 30716,44824.126.431−5.9
Chatter's Candy CounterNet 3011104,00923.619.631−6.4
Red Oak Country ClubNet 30617,45522.722.724−7.3
Nightingale Senior CenterNet 3011183,26222.523.531−7.5
Vinder Commercial CleanersNet 30592,33020.09.425−10.0
Crescent Street GrilleNet 3078,19119.623.727−10.4
Camido CocinaNet 301044,84518.624.928−11.4
Frutti Di Mare RestaurantNet 3021130,06317.412.440−12.6ANOMALY
Whole MarketsNet 3021302,22716.919.534−13.1EARLY $
Abbott's RestaurantNet 301441,04414.818.635−15.2
DynaCare Health StopNet 30736,97813.913.915−16.1
Meetz inc.Net 302186,27913.926.331−16.1BIG=SLOW
Webster GrillNet 30625,49213.713.714−16.3
Buzzie's SandwichesNet 3046,00813.020.828−17.0ANOMALY
Cooper ConcessionsNet 301151,58212.720.627−17.3
Magna Janitorial ServicesNet 308136,48112.15.814−17.9EARLY $
Restaurant Wholesale IncNet 301194,57711.613.2114−18.4OUTLIER
BCP Customer 3Net 30101,36411.611.623−18.4
Telescope Knoll Country ClubNet 301121,89511.419.024−18.6
Viva CafeNet 301751,29411.418.831−18.6
Dubois Candy EmporiumNet 3012199,23510.87.118−19.3EARLY $
Volutpat IndustriesNet 30613,00110.310.311−19.7
Acme Produce MarketNet 3019220,8499.48.727−20.6EARLY $
BCP Customer 1Net 3056168.88.822−21.2
Underwood Produce MarketNet 30337,0898.35.922−21.7
Skipstorm SeafoodNet 30616,7925.05.48−25.0
Moore FoodsNet 30336,7734.311.712−25.7

5Deep Dives

Restaurant Wholesale Inc — the 114-day outlier customer id 483 · all 11 payment applications
InvoiceInv DateDue DateInv TotalPaymentPay DateAppliedDays
INV6222026-05-022026-06-0210,428.20PYMT3772026-08-2410,000.00114
INV17662025-11-112025-12-106,162.76PYMT14522025-11-136,162.762
INV17672025-12-022026-01-026,279.88PYMT14532025-12-046,279.882
INV17692026-05-182026-06-184,111.84PYMT14552026-05-204,111.842
INV17682026-01-062026-02-053,115.06PYMT14542026-01-083,115.062
INV18252025-05-022025-06-0210,264.60PYMT15112025-05-0310,264.601
INV17792025-04-222025-05-2110,428.20PYMT14652025-04-2310,428.201
INV17802025-10-172025-11-1710,428.20PYMT14662025-10-1810,428.201
INV17812026-01-152026-02-1413,093.54PYMT14672026-01-1613,093.541
INV18242025-02-282025-04-0110,264.60PYMT15102025-03-0110,264.601
INV17782024-11-162024-12-1510,428.20PYMT14642024-11-1710,428.201

Verdict: dispute, not distress

This customer pays in 1–2 days, every single time — except INV622, which sat 114 days and was then settled with a round $10,000 against a $10,428.20 invoice, leaving $428.20 apparently short-paid. A near-perfect payer suddenly short-paying one specific invoice is the signature of a disputed line item or pricing disagreement, not credit deterioration. Also note PYMT377 is dated 2026-08-24 — 8 days in the future relative to this report, another cutoff artifact. Action: confirm the $428.20 residual on INV622 and whether a credit memo is pending.
Payments dated before their invoices 6 applications — Finding B detail
CustomerInvoiceInv DatePaymentPay DateAppliedDays
Alpha DemandINV16602026-08-31 ⚠ futurePYMT13812026-08-01321.30−30
Alpha DemandINV16612026-08-31 ⚠ futurePYMT13822026-08-02236.40−29
Alpha DemandINV16622026-08-31 ⚠ futurePYMT13832026-08-0394.90−28
Frutti Di Mare RestaurantINV17212026-08-27PYMT14232026-08-101,170.00−17
Buzzie's SandwichesINV5032026-08-18PYMT2392026-08-141,326.71−4
Smith Pacific Northwest Store1712026-08-15PYMT2112026-08-134,050.00−2

6Recommended Actions

Ordered by impact-per-effort. Items 1–3 can be executed directly from this session.

  1. 5 MINAssign terms to Alpha Demand (id 1615) and BCP Customer 2 (id 1178)1,027 invoices currently age as due-on-receipt. Alpha Demand's 6.2-day behavior fits Net 7–Net 15; pick the term and it's a one-field update. This alone fixes the biggest distortion in your aging report.
  2. 15 MINInvestigate the June 2026 trend breakSlice the Jun–Aug 2026 payment population by customer to see whether the 3→18 day jump is a mix shift (new slow-paying customers), a process change (batch payment entry), or genuine deterioration. Weighted days hit 28.7 in August — one more push and money starts arriving late.
  3. 10 MINResolve the INV622 short-pay ($428.20) with Restaurant Wholesale IncModel 1–2-day payer, one 114-day invoice settled at a round $10,000. Confirm the dispute and clear the residual before it fossilizes in aging.
  4. 30 MINCorrect the 6 date-inverted applicationsFuture-dated invoices (INV1660–1662 dated Aug 31) applied against earlier payments distort DSO and would be flagged in any audit cutoff test. Likely deposits/prepayments applied to later-dated invoices — reclassify or correct the invoice dates.
  5. STRATEGICMonetize the early-payer cohort21 customers pay 15+ days early on ~$1.4M of volume with no discount incentive. Options: leave it (free float), formalize 2/10 Net 30 selectively where it buys loyalty, or use it as goodwill capital in the next price negotiation. Their credit limits can also safely rise.
  6. WATCHPut Meetz inc. on a quiet watchlistSimple average 13.9 days but dollar-weighted 26.3 — their large invoices are the slow ones. That divergence is the earliest observable signal of a future collections problem.

7Appendix — Source Queries

Every number in this report traces to one of these SuiteQL queries, run live against the account on Aug 16, 2026. Rerun any of them to reproduce or refresh the analysis.

Q1 · Customer-level terms vs. behavior (primary dataset — Section 4)
SELECT
  c.id AS customer_id,
  COALESCE(c.companyname, c.entityid) AS customer,
  COALESCE(tm.name, '(no terms)') AS assigned_terms,
  COALESCE(tm.daysuntilnetdue, 0) AS terms_days,
  COUNT(DISTINCT l.previousdoc) AS invoices_paid,
  ROUND(SUM(l.foreignamount), 2) AS total_applied,
  ROUND(AVG(TRUNC(l.nextdate) - TRUNC(l.previousdate)), 1) AS avg_days_to_pay,
  ROUND(SUM((TRUNC(l.nextdate) - TRUNC(l.previousdate)) * l.foreignamount)
        / NULLIF(SUM(l.foreignamount), 0), 1) AS wtd_days_to_pay,
  MAX(TRUNC(l.nextdate) - TRUNC(l.previousdate)) AS worst_days,
  ROUND(AVG(TRUNC(l.nextdate) - TRUNC(l.previousdate))
        - COALESCE(tm.daysuntilnetdue, 0), 1) AS variance_days
FROM nexttransactionlinelink l
JOIN transaction inv ON l.previousdoc = inv.id
JOIN customer c ON inv.entity = c.id
LEFT JOIN term tm ON c.terms = tm.id
WHERE l.linktype = 'Payment'
  AND l.previoustype = 'CustInvc'
  AND l.nexttype = 'CustPymt'
  AND l.foreignamount > 0
GROUP BY c.id, COALESCE(c.companyname, c.entityid),
  COALESCE(tm.name, '(no terms)'), COALESCE(tm.daysuntilnetdue, 0)
HAVING COUNT(DISTINCT l.previousdoc) >= 3
ORDER BY ROUND(AVG(TRUNC(l.nextdate) - TRUNC(l.previousdate))
  - COALESCE(tm.daysuntilnetdue, 0), 1) DESC
Q2 · Portfolio summary + distribution buckets (Sections 1, 3)
SELECT
  COUNT(*) AS applications,
  COUNT(DISTINCT l.previousdoc) AS invoices,
  COUNT(DISTINCT inv.entity) AS customers,
  ROUND(SUM(l.foreignamount), 2) AS total_dollars,
  ROUND(AVG(TRUNC(l.nextdate) - TRUNC(l.previousdate)), 1) AS avg_days,
  ROUND(SUM((TRUNC(l.nextdate) - TRUNC(l.previousdate)) * l.foreignamount)
        / NULLIF(SUM(l.foreignamount),0), 1) AS wtd_days,
  SUM(CASE WHEN TRUNC(l.nextdate) - TRUNC(l.previousdate)
        <= COALESCE(tm.daysuntilnetdue, 0) THEN 1 ELSE 0 END) AS within_terms,
  -- bucket columns: 0-7, 8-14, 15-21, 22-30, 31-45, 45+ via CASE WHEN ... BETWEEN
  SUM(CASE WHEN TRUNC(l.nextdate) - TRUNC(l.previousdate) <= 7 THEN 1 ELSE 0 END) AS b_0_7
  /* ... remaining buckets elided for brevity — same pattern ... */
FROM nexttransactionlinelink l
JOIN transaction inv ON l.previousdoc = inv.id
JOIN customer c ON inv.entity = c.id
LEFT JOIN term tm ON c.terms = tm.id
WHERE l.linktype = 'Payment' AND l.previoustype = 'CustInvc'
  AND l.nexttype = 'CustPymt' AND l.foreignamount > 0
Q3 · Monthly days-to-pay trend (Section 3 chart)
SELECT
  TO_CHAR(l.nextdate, 'YYYY-MM') AS pay_month,
  COUNT(*) AS applications,
  ROUND(SUM(l.foreignamount), 2) AS dollars,
  ROUND(AVG(TRUNC(l.nextdate) - TRUNC(l.previousdate)), 1) AS avg_days,
  ROUND(SUM((TRUNC(l.nextdate) - TRUNC(l.previousdate)) * l.foreignamount)
        / NULLIF(SUM(l.foreignamount),0), 1) AS wtd_days
FROM nexttransactionlinelink l
JOIN transaction inv ON l.previousdoc = inv.id
WHERE l.linktype = 'Payment' AND l.previoustype = 'CustInvc'
  AND l.nexttype = 'CustPymt' AND l.foreignamount > 0
GROUP BY TO_CHAR(l.nextdate, 'YYYY-MM')
ORDER BY TO_CHAR(l.nextdate, 'YYYY-MM')
Q4 · Restaurant Wholesale Inc drill-down (Section 5)
SELECT
  inv.tranid, TO_CHAR(inv.trandate,'YYYY-MM-DD') AS invoice_date,
  TO_CHAR(inv.duedate,'YYYY-MM-DD') AS due_date, inv.foreigntotal,
  pay.tranid AS payment_num, TO_CHAR(pay.trandate,'YYYY-MM-DD') AS payment_date,
  l.foreignamount AS applied,
  TRUNC(l.nextdate) - TRUNC(l.previousdate) AS days_to_pay
FROM nexttransactionlinelink l
JOIN transaction inv ON l.previousdoc = inv.id
JOIN transaction pay ON l.nextdoc = pay.id
WHERE l.linktype = 'Payment' AND l.previoustype = 'CustInvc'
  AND l.nexttype = 'CustPymt' AND inv.entity = 483
ORDER BY days_to_pay DESC
Q5 · Date-inversion anomaly sweep (Finding B)
SELECT
  COALESCE(c.companyname, c.entityid) AS customer,
  inv.tranid, TO_CHAR(inv.trandate,'YYYY-MM-DD') AS invoice_date,
  pay.tranid AS payment_num, TO_CHAR(pay.trandate,'YYYY-MM-DD') AS payment_date,
  l.foreignamount, TRUNC(l.nextdate) - TRUNC(l.previousdate) AS days
FROM nexttransactionlinelink l
JOIN transaction inv ON l.previousdoc = inv.id
JOIN transaction pay ON l.nextdoc = pay.id
JOIN customer c ON inv.entity = c.id
WHERE l.linktype = 'Payment' AND l.previoustype = 'CustInvc'
  AND l.nexttype = 'CustPymt'
  AND TRUNC(l.nextdate) < TRUNC(l.previousdate)
ORDER BY days

Schema notes for reproducibility

Payment-to-invoice applications in this account live in nexttransactionlinelink with linktype='Payment' (verified: nexttransactionlink and previoustransactionlink carry no CustInvc→CustPymt rows here). Terms come from the term table (daysuntilnetdue); all terms in use are simple day-driven (no datedriven='T' terms encountered, so no end-of-month due-date math was needed). Amounts use foreignamount per the account's SuiteQL exposure. Account contains 1,865 CustInvc, 1,472 CustPymt, 49 CustCred.