/* ============================================================= CoreIQ Office — Analytics (LIVE · legacy archive) Business intelligence over the 17-year retention archive: sales reporting, inventory intelligence, and debtor/supplier analytics. Every figure is a real aggregate from Aurora (/analytics/*) — nothing fabricated. ============================================================= */ const { useState: anUseState, useEffect: anUseEffect } = React; const anM = (c) => "$" + (Number(c || 0) / 100).toLocaleString("en-AU", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const anMk = (c) => { const d = Number(c || 0) / 100; return d >= 1000 ? "$" + (d / 1000).toFixed(d >= 100000 ? 0 : 1) + "k" : "$" + d.toFixed(0); }; const anN = (n) => Number(n || 0).toLocaleString("en-AU"); const anErr = (e) =>
{e}
; const anLoad = (t) =>
loading…

{t}

; // Vertical bar chart (months / hours / day-of-week) function VBars({ items, valueKey, labelKey, height = 120, color = "var(--brand)" }) { const mx = Math.max(1, ...items.map((d) => Number(d[valueKey]) || 0)); return (
24 ? 2 : 4, height}}> {items.map((d, i) => (
{d[labelKey]}
))}
); } // Horizontal bars (tender mix / shrinkage) function HBars({ items, valueKey, labelKey, fmt }) { const mx = Math.max(1, ...items.map((d) => Math.abs(Number(d[valueKey]) || 0))); return (
{items.map((d, i) => (
{d[labelKey]}
{fmt(d[valueKey])}
))}
); } // Interactive revenue mix — a stacked bar of Retail + Script co-pay + Govt PBS // subsidy; tick any series on/off and the bar recomputes so you can play with it. function RevenueMix({ split }) { const SERIES = [ { key: "retail", label: "Retail (front of shop)", value: split.privateCents, color: "var(--brand)" }, { key: "copay", label: "Script patient co-pay", value: split.pbsCents, color: "var(--hold)" }, { key: "subsidy", label: "Government PBS subsidy", value: split.govtSubsidyCents, color: "var(--navy-600)" }, ]; const [on, setOn] = anUseState({ retail: true, copay: true, subsidy: true }); const active = SERIES.filter((s) => on[s.key]); const total = active.reduce((a, s) => a + s.value, 0); const denom = Math.max(1, total); return (

Revenue mix

{anM(total)} · tick to add/remove
{active.map((s) => (
))}
{SERIES.map((s) => ( ))}
{active.length === 3 ? "Total income" : active.length === 0 ? "Nothing selected" : "Selected total"} {anM(total)}
); } // ----------------------------------------------------------------- // 1) SALES ANALYTICS // ----------------------------------------------------------------- function SalesAnalytics() { const [years, setYears] = anUseState([]); const [year, setYear] = anUseState(null); const [data, setData] = anUseState(null); const [loading, setLoading] = anUseState(true); const [err, setErr] = anUseState(null); anUseEffect(() => { window.OfficeAPI.analyticsMeta().then((m) => { setYears(m.years || []); setYear(m.latest); }).catch((e) => setErr(String(e.message || e))); }, []); anUseEffect(() => { if (!year) return; let alive = true; setLoading(true); setErr(null); window.OfficeAPI.analyticsSales(year) .then((s) => { if (alive) { setData(s); setLoading(false); } }) .catch((e) => { if (alive) { setErr(String(e.message || e)); setLoading(false); } }); return () => { alive = false; }; }, [year]); const DOW = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const dowFull = data ? DOW.map((d, i) => data.byDayOfWeek.find((x) => x.dow === i) || { day: d, dow: i, revenueCents: 0 }) : []; const hoursFull = data ? Array.from({ length: 24 }, (_, h) => data.byHour.find((x) => x.hour === h) || { hour: h, revenueCents: 0 }).filter((x) => x.hour >= 6 && x.hour <= 21) : []; const split = data?.revenueSplit; const splitTotal = split ? Math.max(1, split.privateCents + split.pbsCents) : 1; return (
live from Aurora

Sales analytics

{err && anErr("Couldn't load analytics: " + err)} {loading && !data &&
Crunching {year}…
} {data && ( <>

Revenue by month · {year}

{data.byMonth.length === 0 ?
No sales.
: ({ label: m.month.slice(5), revenueCents: m.revenueCents }))} valueKey="revenueCents" labelKey="label" height={150}/>}

By day of week

({ label: d.day, revenueCents: d.revenueCents }))} valueKey="revenueCents" labelKey="label" height={120} color="var(--teal-600,var(--brand))"/>

By hour of day

({ label: d.hour, revenueCents: d.revenueCents }))} valueKey="revenueCents" labelKey="label" height={120} color="var(--navy-600,var(--brand))"/>

Tender mix

Top sellers · {year}

by revenue
#
Product
SKU
Units
Revenue
{data.topProducts.map((p, i) => (
{i + 1}
{p.name}
{p.sku || "—"}
{anN(p.units)}
{anM(p.revenueCents)}
))}

By operator

Staff
Sales
Revenue
{data.byOperator.map((o) => (
{o.name}
{anN(o.sales)}
{anM(o.revenueCents)}
))}
)}
); } // ----------------------------------------------------------------- // 2) INVENTORY INTELLIGENCE // ----------------------------------------------------------------- function InventoryAnalytics() { const { setScreenState, setScreen } = window.useOffice(); const [data, setData] = anUseState(null); const [err, setErr] = anUseState(null); anUseEffect(() => { window.OfficeAPI.analyticsInventory().then(setData).catch((e) => setErr(String(e.message || e))); }, []); const open = (pid) => { if (pid) { setScreenState({ activeProductId: pid, productFrom: "inventoryAnalytics" }); setScreen("productDetail"); } }; if (err) return
{anErr("Couldn't load: " + err)}
; if (!data) return anLoad("Inventory intelligence"); return (
stale cutoff {data.cutoff}

Inventory intelligence

Dead & slow stock

on-hand > 0, no outward movement since {data.cutoff} · highest value first
{data.deadStock.length === 0 ?
No dead stock — everything's moving.
:
Product
SKU
On hand
Value
Last out
{data.deadStock.map((d) => (
open(d.productId)}>
{d.name}
{d.sku || "—"}
{anN(d.onHand)}
{anM(d.valueCents)}
{d.lastOut || "never"}
))}
}

Shrinkage by reason

anN(v) + " u"}/>

Fastest movers

units out, last 12 months
Product
Units out
{data.topMovers.slice(0, 12).map((m) => (
open(m.productId)}>
{m.name}
{anN(m.unitsOut)}
))}
); } // ----------------------------------------------------------------- // 3) FINANCIAL ANALYTICS — aged debtors + supplier spend // ----------------------------------------------------------------- function FinancialAnalytics() { const [tab, setTab] = anUseState("debtors"); const [deb, setDeb] = anUseState(null); const [sup, setSup] = anUseState(null); const [err, setErr] = anUseState(null); anUseEffect(() => { window.OfficeAPI.analyticsDebtors().then(setDeb).catch((e) => setErr(String(e.message || e))); }, []); anUseEffect(() => { window.OfficeAPI.analyticsSuppliers().then(setSup).catch((e) => setErr(String(e.message || e))); }, []); return (
live from Aurora

Financial analytics

{err && anErr(err)} {tab === "debtors" && deb && ( <>

Top debtors

{deb.note}
Account
Customer
Balance
Last activity
Last payment
{deb.topDebtors.map((d) => (
{d.accountNumber || "—"}
{d.name}
{anM(d.balanceCents)}
{d.lastActivity || "—"}
{d.lastPayment || "—"}
))}
)} {tab === "suppliers" && sup && ( <>

Spend by supplier

all-time, GST-inclusive
Supplier
Invoices
Spend
GST
Active
{sup.bySupplier.map((s, i) => (
{s.supplier}
{anN(s.invoices)}
{anM(s.spendCents)}
{anM(s.gstCents)}
{s.firstInvoice} → {s.lastInvoice}
))}
)}
); } window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, { salesAnalytics: SalesAnalytics, inventoryAnalytics: InventoryAnalytics, financialAnalytics: FinancialAnalytics, });