Days sales outstanding, inventory turnover, and financial close duration — computed live from the general ledger and open receivables, and set against published retail and consumer-goods benchmarks.
One metric is competitive. One is a collections problem wearing an averages disguise. One is a control process that has never been performed.
The single most important nuance in this report: the headline DSO of 175 days and the aging profile behind it point to opposite conclusions. Customers who pay, pay essentially on receipt (median 0 days). The receivables balance is dominated by a small, stagnant tail. This is the difference between a pricing-and-terms problem (structural, slow to fix) and a collections-hygiene problem (fixable in one quarter).
The most important governance finding is not a ratio at all: every monthly accounting period in the account, going back through the full transaction history, remains open. Prior-period figures — including every number in this report — are permanently editable until a close discipline is instituted.
Live figures computed from NetSuite production data on 24 August 2026, trailing-twelve-month basis, against the closest published peer benchmarks.
| Metric | This Account | Benchmark | Peer Basis | Verdict |
|---|---|---|---|---|
| DSO — credit sales basis | 175.1 days | ~25 days | General retail (Allianz Trade, 2023) | 7.0× WORSE |
| DSO — incl. cash sales | 166.9 days | 59 days | Global all-industry average | 2.8× WORSE |
| Days to pay — collected invoices only | 1.3 days avg / 0 median | ≤ terms | — | EXCELLENT |
| Inventory turns — avg. inventory | 4.86× (DIO 75) | 4–6× | Apparel / home / electronics mix | IN RANGE |
| Inventory turns — ending inventory | 3.48× | 9.99× | Online retail, COS basis (CSIMarket, TTM Q2 2026) | BELOW E-COMM |
| Close duration — calendar days | Never performed | ~6.4 days median | Cross-industry (APQC, see source note) | NOT COMPARABLE |
DIO = days inventory outstanding (365 ÷ turns). TTM = trailing twelve months ending 24 Aug 2026.
Open receivables of $928,247 against $1.93M of trailing-twelve-month credit sales produce a DSO of 175 days — seven times the retail benchmark. The distribution behind the average tells a different, and more actionable, story.
Two facts must be held simultaneously. First, collected invoices clear almost instantly: across 369 invoices paid in the trailing twelve months, the average invoice-to-payment interval was 1.3 days and the median was zero — payment is typically recorded the same day the invoice is raised. Second, the open book is stagnant: 85% of open receivables by value are past 60 days, and 69% are past 90.
This combination rules out a payment-terms or customer-quality explanation. The operative problem is a tail of 17 aged invoices totaling $643,077 that are neither being collected nor being dispositioned (written off, credited, or disputed). Every month they remain open, they add roughly 121 days to the headline DSO.
A useful yardstick: at the 25-day retail benchmark, target open A/R would be approximately $132,504 ($1,934,564 ÷ 365 × 25). The current 0–30-day bucket holds $129,007 — almost exactly that figure. The current book is already benchmark-shaped; the aged tail is the entire gap.
4.86 turns on average inventory (75 days on hand) is respectable for an apparel, beauty, home & decor, and electronics mix. The caution flag is the denominator: inventory grew 2.3× in twelve months.
On the standard average-inventory basis the account performs within the 4–6× band typical for its category mix; the pure-play online-retail figure of ~10× represents the most aggressive peer set, not a like-for-like comparison for a business running two physical stores and two distribution centers.
The structural concern is trajectory. Inventory rose from $920,980 to $2,128,362 during a year in which COGS ran $7.41M. Measured on ending inventory, turns are only 3.48× — meaning the business is currently positioned below its own trailing performance. If the build is deliberate (new-location stocking, 3PL/FBA channel ramp — both location types exist in the account), the metric will normalize as those channels sell through. If it is not deliberate, on the order of $600K–$900K of the build is excess relative to the current sales rate and carries markdown risk, particularly in seasonal apparel.
A slow-mover analysis by item class and location would separate the two cases; it is recommended as an immediate follow-up (Section 06).
The benchmark question — how many days after period-end are the books closed? — cannot be answered, because no accounting period in the account has ever been closed.
| Evidence | Finding |
|---|---|
| Monthly periods inspected | 30 most recent (Mar 2024 → Aug 2026), plus full history |
| Periods with closed = T | Zero |
| Periods with a recorded close date | Zero — closedondate is null on every row |
| Benchmark — median monthly close | ~6.4 calendar days (APQC, cross-industry; see source note in Section 09) |
| Benchmark — top performers | ≤ 5 calendar days; best-practice organizations target 3 |
This is the report’s most significant governance finding, and the easiest to misread. There is no “slow close” to accelerate; the close process is structurally absent. Consequences follow directly:
Every historical figure is soft. With all periods open, any user with transaction-entry permissions can post to, edit, or delete activity in any prior month. Every metric in this report — and any statement previously issued from this ledger — is subject to silent restatement.
The gap is procedural, not technical. NetSuite’s period-close checklist (lock A/R, lock A/P, lock all, resolve, close) is available and unused. A month-end-close process definition already exists in this account’s Sonar process library; instituting a monthly cadence requires a decision, not a build.
Open periods compound the other two findings: the aged receivables tail cannot be reliably reserved against, and the inventory build cannot be reliably valued, while the underlying months remain editable. Closing the calendar-2024 and 2025 periods first would fence off the largest share of restatement risk at minimal operational cost.
Sequenced by risk reduction per unit of effort.
Rank by balance; for each, decide collect / credit / write off within 30 days. Because payment behavior on the active book is excellent, resolving the tail moves DSO from 175 to approximately 54 days in a single cycle — and a settled tail brings it to benchmark.
Close all periods through Dec 2025 in one supervised pass, then adopt a business-day-4 target for the current month forward. The account’s existing month-end-close process definition provides the checklist.
Classify the $1.2M inventory build as deliberate channel stocking vs. excess. Age on-hand quantities by last-sale date across the five product classes and the store / DC / 3PL / FBA locations; flag items with >180 days of supply for markdown or transfer.
A monthly DSO / DIO / close-status snapshot (saved search or scheduled query) turns this one-time review into drift detection. The A/R aging profile in particular should be watched at the 61–90 day bucket, where today’s $149,971 is next quarter’s tail.
All figures computed 24 August 2026 directly from production tables via SuiteQL (queries reproduced in Section 10). Trailing twelve months = 24 Aug 2025 → 24 Aug 2026.
Open A/R = sum of foreignamountunpaid on open customer invoices (type='CustInvc', status='A'). Credit sales = foreigntotal of all invoices dated within the TTM window. Cash sales excluded from the primary figure because they generate no receivable (countback and cash-inclusive variants shown for completeness). Days-to-pay computed as closedate − trandate on invoices fully paid within the window (n = 369).
COGS = posting GL activity on accounts of type COGS within the window. Inventory = cumulative posting balance of accounts 1210 Inventory in Stock, 1215 Inventory In Transit, and 1220 Inventory Returned Not Credited (internal ids 10, 227, 119), measured at both window endpoints. Two-point average; a monthly average was not used because the ledger’s open-period state (Section 05) makes intra-year balances equally provisional.
External benchmarks were fetched live on 24 August 2026 where possible. Provenance and reliability are flagged per source.
All queries executed as SuiteQL against production on 24 August 2026. Reproduced verbatim for auditability.
SELECT
ROUND(SUM(CASE WHEN t.type='CustInvc' AND t.status='A'
THEN t.foreignamountunpaid ELSE 0 END),2) AS open_ar,
ROUND(SUM(CASE WHEN t.type='CustInvc'
AND t.trandate >= ADD_MONTHS(TRUNC(SYSDATE),-12)
THEN t.foreigntotal ELSE 0 END),2) AS ttm_invoice_sales,
ROUND(SUM(CASE WHEN t.type='CashSale'
AND t.trandate >= ADD_MONTHS(TRUNC(SYSDATE),-12)
THEN t.foreigntotal ELSE 0 END),2) AS ttm_cash_sales
FROM transaction t
WHERE t.type IN ('CustInvc','CashSale')
SELECT COUNT(*) AS paid_invoices, ROUND(AVG(TRUNC(t.closedate) - TRUNC(t.trandate)),1) AS avg_days_to_pay, ROUND(MEDIAN(TRUNC(t.closedate) - TRUNC(t.trandate)),1) AS median_days_to_pay FROM transaction t WHERE t.type='CustInvc' AND t.status='B' AND t.trandate >= ADD_MONTHS(TRUNC(SYSDATE),-12) AND t.closedate IS NOT NULL
SELECT
CASE WHEN TRUNC(SYSDATE)-TRUNC(t.trandate) <= 30 THEN 'a. 0-30'
WHEN TRUNC(SYSDATE)-TRUNC(t.trandate) <= 60 THEN 'b. 31-60'
WHEN TRUNC(SYSDATE)-TRUNC(t.trandate) <= 90 THEN 'c. 61-90'
WHEN TRUNC(SYSDATE)-TRUNC(t.trandate) <= 180 THEN 'd. 91-180'
WHEN TRUNC(SYSDATE)-TRUNC(t.trandate) <= 365 THEN 'e. 181-365'
ELSE 'f. over 365' END AS age_bucket,
COUNT(*) AS invoices,
ROUND(SUM(t.foreignamountunpaid),2) AS open_amount
FROM transaction t
WHERE t.type='CustInvc' AND t.status='A' AND t.foreignamountunpaid > 0
GROUP BY CASE ... END ORDER BY 1
SELECT
ROUND(SUM(CASE WHEN a.accttype IN ('Income','OthIncome')
AND t.trandate >= ADD_MONTHS(TRUNC(SYSDATE),-12)
THEN -tal.amount ELSE 0 END),2) AS ttm_gl_revenue,
ROUND(SUM(CASE WHEN a.accttype = 'COGS'
AND t.trandate >= ADD_MONTHS(TRUNC(SYSDATE),-12)
THEN tal.amount ELSE 0 END),2) AS ttm_gl_cogs
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','OthIncome','COGS')
-- Decomposition: GROUP BY t.type on the Income filter revealed
-- Journal $10.41M / CustInvc $1.79M / CashSale $0.09M
SELECT a.id, a.acctnumber, a.fullname, ROUND(SUM(tal.amount),2) AS balance FROM account a JOIN transactionaccountingline tal ON tal.account = a.id JOIN transaction t ON tal.transaction = t.id WHERE t.posting='T' AND UPPER(a.fullname) LIKE '%INVENT%' GROUP BY a.id, a.acctnumber, a.fullname -- Prior-year endpoint: same join, accounts IN (10,119,227), -- filtered t.trandate < ADD_MONTHS(TRUNC(SYSDATE),-12) → 920,980.19
SELECT id, periodname, TO_CHAR(enddate,'YYYY-MM-DD') AS enddate,
closed, TO_CHAR(closedondate,'YYYY-MM-DD') AS closedondate,
CASE WHEN closedondate IS NOT NULL
THEN TRUNC(closedondate) - TRUNC(enddate) END AS days_to_close
FROM accountingperiod
WHERE isquarter='F' AND isyear='F' AND startdate <= SYSDATE
ORDER BY startdate DESC
FETCH FIRST 30 ROWS ONLY
-- Result: closed='F', closedondate NULL on every row returned;
-- full-history check confirmed zero closed periods account-wide.
-- account.acctname is NOT_EXPOSED to SuiteQL in this account; use a.fullname.
-- Inventory accounts carry accttype 'OthCurrAsset', not 'InvtAsset'.
-- transaction.status filters require single-letter codes ('A' open, 'B' paid).
-- foreignamountunpaid / foreigntotal used throughout (single-currency USD).