A measured assessment of this company's NetSuite instance: revenue trajectory and composition, receivables discipline, concentration, dimensional integrity, and data governance — with every query, assumption, and derivation disclosed.
This is a single-currency, US-only consumer-products business running a four-entity OneWorld structure, operating a two-speed model: high-volume retail through two stores and low-volume, high-value wholesale through two distribution centers. Transactionally, the company has pivoted hard to wholesale — 2026 year-to-date revenue of $1.35M has already passed full-year 2025, and 95.4% of it is invoice-based.Measured
Three problems dominate everything else:
First, the revenue record is split in two. The GL reports $8.39M of 2026 income, but invoices and cash sales explain only $1.35M of it. The remaining $7.04M — 83.9% — arrives via 48 recurring monthly journal entries posted directly to two income accounts, with no customer, item, or document trail behind them (F-06). Whatever those journals represent — a summarized side-channel, imported history, or seeded data — the company's P&L is currently dominated by revenue that cannot be traced to a transaction.Measured
Second, receivables discipline broke under wholesale growth. 86.1% of open A/R is past due; half the balance is aged beyond 90 days; the oldest invoice is 510 days overdue (F-01). Concentration compounds it: ten customers hold 65.9% of lifetime wholesale revenue, and five of them individually owe $80K+ overdue (F-02).Measured
Third, governance is thinner than the structure suggests. Plaintext credentials sit on four vendor records (F-03); the GL-impacting Cost Center segment is at 0% adoption across 64,466 lines; a quarter of revenue carries no category or location tag (F-04); and no self-balancing capability exists below the subsidiary line (F-05).Measured
Before this company can trust a single report it produces, it must answer one question — what are the 48 journals that carry 84% of its revenue? — and then collect the $799K its real customers already owe it.
Legal structure — four subsidiaries, all US, single currency (USD): Parent Company (1), Subsidiary 1 (2), Subsidiary 2 (3), and xElim (4, elimination). OneWorld enabled; Multiple Currencies off — no FX revaluation entry path exists, which removes one classic source of untagged system-generated postings.Measured
Operating profile — 273 customers, 94 vendors, 374 items (263 inventory, matrix apparel in use), ~7.9K transactions across full order-to-cash and procure-to-pay cycles, with light manufacturing (work orders / builds). Product mix: Home & Decor ($1.12M lifetime), Apparel ($694K), Beauty ($273K).Measured
The wholesale/retail asymmetry is stark: the two stores produced 1,551 transactions and 9.0% of tagged lifetime revenue; the two distribution points produced 278 transactions and 64.5%. The DCs are the business; the stores are the storefront.Measured
| Year | GL Income | GL COGS | Gross Margin | GM % |
|---|---|---|---|---|
| 2024 | $3,432,291 | $2,190,541 | $1,241,750 | 36.2% |
| 2025 | $10,898,026 | $6,735,502 | $4,162,524 | 38.2% |
| 2026 YTD | $8,388,817 | $5,101,962 | $3,286,855 | 39.2% |
Q8/Q9. Margin is improving ~1 point per year — but read §4 before trusting these numbers: both sides of this margin are dominated by journal-posted amounts, so the GM% is only as reliable as the journals feeding it.
This is the discovery that reframes the report. Decomposing GL income by transaction type (Q9) shows that documents — invoices and cash sales — explain only a small fraction of what the P&L reports:
| Year | GL Income | From invoices + cash sales | From journal entries | Journal share |
|---|---|---|---|---|
| 2024 | $3,432,291 | $289,375 | $3,142,917 | 91.6% |
| 2025 | $10,898,026 | $1,249,984 | $9,648,042 | 88.5% |
| 2026 YTD | $8,388,817 | $1,353,245 | $7,036,333 | 83.9% |
| Lifetime | $22,719,134 | $2,892,603 | $19,827,292 | 87.3% |
The journal population is uniform and deliberate: 48 journal entries, one per month from September 2024 through August 2026, posting to exactly two accounts — 4210 Sales : Revenue - Products ($18.24M) and 4310 Sales : Revenue - Services ($1.59M). COGS shows the same pattern: $12.84M of lifetime COGS is journal-posted versus ~$1.20M from shipments and cash sales (Q10–Q12).Measured
The monthly cadence and two-account concentration suggest a summarized feed — an imported history, a side-channel business posting in summary, or environment seed data. The instance itself cannot tell you which; only the person who books them can. What the instance can tell you is the consequence, and it is the same in every scenario: 87% of reported revenue has no customer, no item, no source document, and no dimension enforcement behind it. Every category chart, location P&L, and channel report in this account silently describes only the 13% minority.
An auditor tracing revenue to source documents stops at journal 1 of 48. If these journals summarize a real system, the sub-ledger behind them must be identified, reconciled monthly, and referenced on each entry. If they are seed data, every revenue statement produced from this GL overstates the operating business by ~7×. Neither state is acceptable to leave undocumented — and today, nothing on the entries says which it is.
Severity: Critical = invisible until an auditor finds it · High = quantified exposure · Medium = control or process gap. Every finding carries its measured number and query reference.
cseg_atlas_cost_ctr) is populated on 0 of 64,466 lines — provisioned, never used; (2) $786,944 (27.2%) of transactional revenue has no product class; (3) ~$764,728 (26.4%) has no location (inferred). Bright spot: Sales Channel tagging on revenue lines is 98.9% (cash sale) / 98.0% (invoice) — the earlier-observed 44% line-level gap lives on non-revenue lines. No mandatory-field enforcement exists on any dimension, on any entry path.| Customer | Open | Overdue | Max days late | Also top-10 revenue? |
|---|---|---|---|---|
| Global Information | $110,579 | $110,579 | 266 | Yes — #9 |
| Red Rivers Consulting | $102,906 | $102,906 | 159 | Yes — #10 |
| Magna Tech Limited | $97,942 | $97,942 | 36 | — |
| Falcon Systems | $86,007 | $86,007 | 86 | — |
| Mercury Co. | $80,079 | $80,079 | 464 | — |
| Gotter inc. | $68,119 | $68,119 | 260 | — |
| Blockster Inc. | $53,424 | $53,424 | 84 | — |
| Haskell Associates | $43,941 | $43,941 | 331 | — |
| Macgruber Incorporated | $35,372 | $0 | current | — |
| John G. Roche Opticians | $31,810 | $31,810 | 133 | — |
Eight of the ten largest open balances are 100% overdue, each a single large invoice — consistent with wholesale shipments made without credit-limit enforcement or follow-up cadence.
DSO ≈ open A/R ÷ (YTD invoice revenue ÷ days elapsed) = $928,246.62 ÷ ($1,290,377.75 ÷ 238 days) = 171.2 days. This is a point-in-time approximation using invoice revenue only; a proper rolling-13-week DSO would require monthly A/R snapshots that the instance does not retain. Direction is unambiguous: best-practice wholesale DSO is 30–60 days on net-30/net-60 terms.
| # | Action | Addresses | Effort |
|---|---|---|---|
| 1 | Identify the 48 journals. Interview whoever books them; if they summarize a real sub-ledger, name it, add source references to each entry, and institute a monthly reconciliation; if seed data, document that and segregate reporting so operating statements exclude them | F-06 | Days |
| 2 | Collectability review of the 13 invoices aged 90+ days ($472.9K); reserve or write off the uncollectible tranche — drafted schedules for controller approval, nothing auto-posted | F-01 | Days |
| 3 | Credit policy for the top ten: formal limits and terms tied to each account's own aging; hold new shipments to accounts with 90+ day balances until cleared or re-termed | F-01 · F-02 | Days |
| 4 | Credential remediation: migrate the 4 vendor values to NetSuite API Secrets (or external store); clear and retire custentity_ps_password | F-03 | Hours |
| 5 | Dimension decision: activate the dormant Cost Center segment with enforcement, or retire it; make class and location mandatory on revenue-bearing lines — enforcement per entry path (UI form + CSV template + any integration), not UI-only | F-04 | Weeks |
| 6 | Historical backfill of class/location only if period-over-period category reporting is required; otherwise draw a line and enforce forward | F-04 | Optional |
Ordering rationale: item 1 precedes everything because every other number in the company's reporting inherits its answer. Items 2–4 are containment. Items 5–6 are hygiene, sequenced last because tagging a ledger whose majority revenue is journal-posted (F-06) delivers less than fixing the journals first. No remediation entry posts without human approval — items 2 and 3 produce drafted schedules and policy documents, not automated postings.
The engagement followed a fixed order: classify → measure → find → design → deliver. No finding or design sentence was written ahead of its evidence. Three verbs are used precisely throughout: measured (a query ran, reproduced in Appendix A), inferred (derived from measurements, derivation shown inline), assumed (flagged in §9 with what would confirm it). The measurement sequence, in execution order:
The GL decomposition (rows 10–11) was triggered by a discrepancy check — GL income of $10.9M against transactional revenue of $1.25M for 2025 failed a reasonableness test, and the investigation of that gap produced F-06. Discrepancies between two measurements are treated as findings-in-waiting, never averaged away.
· A1. "Transactional revenue" is defined as invoice + cash-sale net line amounts (mainline and tax lines excluded), posted, elimination subsidiary excluded. Credit memos and refunds (−$911 lifetime) are immaterial and not netted. Confirm: controller sign-off on the revenue definition.
· A2. 2024 is treated as a partial first year — earliest journal activity is Sep 2024. Confirm: business history from management.
· A3. The 48 monthly journals are assumed to be a summarized feed or seeded history, not fraud — based on their uniform cadence and two-account concentration. Confirm: interview the preparer; inspect journal memos and creator via system notes.
· A4. The no-location revenue figure ($764,728) is inferred as total revenue minus location-tagged revenue, not directly queried. Confirm: direct NULL-location query (one additional measurement).
· A5. DSO (~171 days) is a point-in-time approximation; see §6 for the derivation and its limits.
· A6. Individual invoice collectability was not assessed — F-01's reserve recommendation requires human review of each 90+ day invoice. This report identifies the population; it does not judge the invoices.
· Read-only diagnostic: no records were created, modified, or deleted; no remediation entries were drafted into the system.
· Expense-side analysis (vendor spend, payroll, opex trend) was not in scope and is unmeasured.
· Journal creator/approver attribution (system notes) was not queried; it is the natural first step of Recommendation 1.
· Entity names appear as recorded in the instance. This account exhibits demonstration-data characteristics (see A3); if used as a template against a production instance, all queries in Appendix A rerun as-is.
Every figure in this report traces to one of the following SuiteQL queries, executed Aug 26, 2026 against account TD3016323 under an administrator session. Queries are reproduced verbatim and rerun as-is for reproduction or audit.
SELECT TO_CHAR(t.trandate,'YYYY') AS yr, t.type, COUNT(DISTINCT t.id) AS tx_count,
ROUND(SUM(ABS(tl.netamount)),2) AS revenue
FROM transaction t
JOIN transactionline tl ON tl.transaction = t.id AND tl.mainline='F' AND tl.taxline='F'
WHERE t.type IN ('CustInvc','CashSale') AND t.posting='T' AND tl.subsidiary <> 4
GROUP BY TO_CHAR(t.trandate,'YYYY'), t.type
ORDER BY TO_CHAR(t.trandate,'YYYY')SELECT * FROM customsegment FETCH FIRST 10 ROWS ONLY
SELECT 'cost_ctr' AS seg, COUNT(*) AS total_lines,
SUM(CASE WHEN cseg_atlas_cost_ctr IS NOT NULL THEN 1 ELSE 0 END) AS tagged
FROM transactionline
UNION ALL
SELECT 'sls_chan', COUNT(*),
SUM(CASE WHEN cseg_atlas_sls_chan IS NOT NULL THEN 1 ELSE 0 END)
FROM transactionlineSELECT TO_CHAR(t.trandate,'YYYY-MM') AS mo, ROUND(SUM(ABS(tl.netamount)),2) AS revenue
FROM transaction t
JOIN transactionline tl ON tl.transaction = t.id AND tl.mainline='F' AND tl.taxline='F'
WHERE t.type IN ('CustInvc','CashSale') AND t.posting='T' AND tl.subsidiary <> 4
AND t.trandate >= TO_DATE('2025-01-01','YYYY-MM-DD')
GROUP BY TO_CHAR(t.trandate,'YYYY-MM')
ORDER BY TO_CHAR(t.trandate,'YYYY-MM')SELECT c.entityid, ROUND(SUM(ABS(tl.netamount)),2) AS revenue FROM transaction t JOIN customer c ON t.entity = c.id JOIN transactionline tl ON tl.transaction = t.id AND tl.mainline='F' AND tl.taxline='F' WHERE t.type='CustInvc' AND t.posting='T' AND tl.subsidiary <> 4 GROUP BY c.id, c.entityid ORDER BY SUM(ABS(tl.netamount)) DESC FETCH FIRST 10 ROWS ONLY
SELECT COUNT(*) AS open_invoices, ROUND(SUM(t.foreignamountunpaid),2) AS open_ar,
SUM(CASE WHEN t.duedate < TRUNC(SYSDATE) THEN 1 ELSE 0 END) AS overdue_count,
ROUND(SUM(CASE WHEN t.duedate < TRUNC(SYSDATE) THEN t.foreignamountunpaid ELSE 0 END),2) AS overdue_amt,
MAX(CASE WHEN t.duedate < TRUNC(SYSDATE) THEN TRUNC(SYSDATE) - TRUNC(t.duedate) END) AS max_days_overdue
FROM transaction t
WHERE t.type='CustInvc' AND t.status='A' AND t.foreignamountunpaid > 0SELECT CASE WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 0 THEN '0_current'
WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 30 THEN '1_1-30'
WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 90 THEN '2_31-90'
WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 180 THEN '3_91-180'
ELSE '4_180+' END AS bucket,
COUNT(*) AS invoices, ROUND(SUM(t.foreignamountunpaid),2) AS amt
FROM transaction t
WHERE t.type='CustInvc' AND t.status='A' AND t.foreignamountunpaid > 0
GROUP BY CASE WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 0 THEN '0_current'
WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 30 THEN '1_1-30'
WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 90 THEN '2_31-90'
WHEN TRUNC(SYSDATE)-TRUNC(t.duedate) <= 180 THEN '3_91-180'
ELSE '4_180+' END
ORDER BY 1SELECT TO_CHAR(t.trandate,'YYYY') AS yr, a.accttype, ROUND(SUM(-tal.amount),2) AS amt
FROM transactionaccountingline tal
JOIN transaction t ON tal.transaction = t.id
JOIN account a ON tal.account = a.id
WHERE t.posting='T' AND a.accttype IN ('Income','COGS')
AND t.trandate >= TO_DATE('2024-01-01','YYYY-MM-DD')
GROUP BY TO_CHAR(t.trandate,'YYYY'), a.accttype
ORDER BY 1, 2SELECT TO_CHAR(t.trandate,'YYYY') AS yr, t.type, ROUND(SUM(-tal.amount),2) AS income_amt
FROM transactionaccountingline tal
JOIN transaction t ON tal.transaction = t.id
JOIN account a ON tal.account = a.id
WHERE t.posting='T' AND a.accttype = 'Income'
AND t.trandate >= TO_DATE('2024-01-01','YYYY-MM-DD')
GROUP BY TO_CHAR(t.trandate,'YYYY'), t.type
ORDER BY 1, 3 DESCSELECT COUNT(DISTINCT t.id) AS journals, MIN(t.trandate) AS first_dt, MAX(t.trandate) AS last_dt,
COUNT(DISTINCT tal.account) AS accts, ROUND(SUM(-tal.amount),2) AS income_amt
FROM transactionaccountingline tal
JOIN transaction t ON tal.transaction = t.id
JOIN account a ON tal.account = a.id
WHERE t.posting='T' AND t.type='Journal' AND a.accttype='Income'SELECT a.acctnumber, a.fullname, COUNT(DISTINCT t.id) AS journals,
ROUND(SUM(-tal.amount),2) AS amt, MIN(t.trandate) AS first_dt, MAX(t.trandate) AS last_dt
FROM transactionaccountingline tal
JOIN transaction t ON tal.transaction = t.id
JOIN account a ON tal.account = a.id
WHERE t.posting='T' AND t.type='Journal' AND a.accttype='Income'
GROUP BY a.acctnumber, a.fullname
ORDER BY 4 DESCSELECT TO_CHAR(t.trandate,'YYYY') AS yr, t.type, ROUND(SUM(tal.amount),2) AS cogs_amt
FROM transactionaccountingline tal
JOIN transaction t ON tal.transaction = t.id
JOIN account a ON tal.account = a.id
WHERE t.posting='T' AND a.accttype='COGS'
AND t.trandate >= TO_DATE('2024-01-01','YYYY-MM-DD')
GROUP BY TO_CHAR(t.trandate,'YYYY'), t.type
ORDER BY 1, 3 DESCSELECT c.entityid, COUNT(*) AS open_inv, ROUND(SUM(t.foreignamountunpaid),2) AS open_amt,
ROUND(SUM(CASE WHEN t.duedate < TRUNC(SYSDATE) THEN t.foreignamountunpaid ELSE 0 END),2) AS overdue_amt,
MAX(CASE WHEN t.duedate < TRUNC(SYSDATE) THEN TRUNC(SYSDATE)-TRUNC(t.duedate) END) AS max_days
FROM transaction t
JOIN customer c ON t.entity = c.id
WHERE t.type='CustInvc' AND t.status='A' AND t.foreignamountunpaid > 0
GROUP BY c.id, c.entityid
ORDER BY SUM(t.foreignamountunpaid) DESC
FETCH FIRST 12 ROWS ONLYSELECT COUNT(*) AS vendors_with_value FROM vendor WHERE custentity_ps_password IS NOT NULL
SELECT t.type, COUNT(*) AS lines,
SUM(CASE WHEN tl.cseg_atlas_sls_chan IS NULL THEN 1 ELSE 0 END) AS untagged
FROM transactionline tl
JOIN transaction t ON tl.transaction = t.id
WHERE t.type IN ('CustInvc','CashSale') AND tl.mainline='F' AND tl.taxline='F'
GROUP BY t.typeSupplementary calls not shown as SQL: account feature flags (accountFeaturesGet), subsidiary list (subsidiaryList), and lifetime revenue by location / class (same join pattern as Q1 grouped by location / classification). Entity/transaction volume counts in §2 derive from prior verified session measurements of this account (Aug 3, 2026) and were not re-run; all risk-bearing figures were measured fresh this session.