/* ============================================================= CoreIQ Office — Legacy archive retrieval (LIVE · legacy archive) Read-only back-office views over the Z (APSS) 7-year retention archive (z_archive.*, non-synced). Lets staff / an auditor pull up a historical receipt, a supplier tax invoice, an account statement, or a stock movement trail. Every figure is queried live from Aurora via /archive/*. ============================================================= */ const { useState: aUseState, useEffect: aUseEffect, useCallback: aUseCallback } = React; const aMoney = (c) => "$" + (Number(c || 0) / 100).toLocaleString("en-AU", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const aNum = (n) => Number(n || 0).toLocaleString("en-AU"); const aDate = (s) => (s ? String(s).slice(0, 10) : "—"); const aDateTime = (s) => (s ? String(s).replace("T", " ").slice(0, 16) : "—"); const aHuman = (s) => String(s || "").replace(/_/g, " "); // Generic list fetch hook: re-runs when `key` changes, exposes data/loading/err. function useArchive(fetcher, key) { const [data, setData] = aUseState(null); const [loading, setLoading] = aUseState(true); const [err, setErr] = aUseState(null); aUseEffect(() => { let alive = true; setLoading(true); setErr(null); Promise.resolve(fetcher()) .then((d) => { if (alive) { setData(d); setLoading(false); } }) .catch((e) => { if (alive) { setErr(String((e && e.message) || e)); setLoading(false); } }); return () => { alive = false; }; }, [key]); return { data, loading, err }; } function AHeader({ eyebrow, title, actions, back }) { return (
{back ? <>{back} · : null}{eyebrow}

{title}

{actions ?
{actions}
: null}
); } function ABackBtn({ onClick }) { return ; } function AErr({ err }) { return
{err}
; } function AEmpty({ children }) { return
{children}
; } function APager({ total, limit, offset, onPage }) { if (!total) return null; const from = offset + 1, to = Math.min(offset + limit, total); return (
Showing {aNum(from)}–{aNum(to)} of {aNum(total)}
); } function ASearch({ value, onChange, placeholder, extra }) { return (
onChange(e.target.value)} placeholder={placeholder} style={{flex:1, height:34, border:"none", background:"transparent", padding:0}}/> {extra}
); } // Clickable column header → server-side sort. `num` right-aligns + defaults desc. function SortHead({ label, col, sort, onSort, num, def }) { const active = sort.col === col; return (
onSort(col, def || (num ? "desc" : "asc"))} title="Sort" style={Object.assign({ cursor: "pointer", userSelect: "none" }, num ? { justifyContent: "flex-end" } : {})}> {label}{active ? (sort.dir === "asc" ? " ↑" : " ↓") : ""}
); } const nextSort = (sort, col, def) => (sort.col === col ? { col, dir: sort.dir === "asc" ? "desc" : "asc" } : { col, dir: def || "asc" }); // ----------------------------------------------------------------- // 1) SALES HISTORY — receipts → lines + tenders + EFTPOS detail // ----------------------------------------------------------------- function ArchiveSales() { const [q, setQ] = aUseState(""); const [from, setFrom] = aUseState(""); const [to, setTo] = aUseState(""); const [offset, setOffset] = aUseState(0); const [applied, setApplied] = aUseState({ q: "", from: "", to: "", offset: 0 }); const [sel, setSel] = aUseState(null); const [sort, setSort] = aUseState({ col: "date", dir: "desc" }); const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); }; aUseEffect(() => { setApplied({ q, from, to, offset }); }, [offset]); const apply = () => { setOffset(0); setApplied({ q, from, to, offset: 0 }); }; const key = JSON.stringify(applied) + "|" + sort.col + sort.dir; const { data, loading, err } = useArchive( () => window.OfficeAPI.archiveSales({ limit: 50, offset: applied.offset, sort: sort.col, dir: sort.dir, ...(applied.q ? { q: applied.q } : {}), ...(applied.from ? { from: applied.from } : {}), ...(applied.to ? { to: applied.to } : {}) }), key, ); if (sel) return setSel(null)}/>; return (
setFrom(e.target.value)} style={{height:34, width:150}} title="From"/> setTo(e.target.value)} style={{height:34, width:150}} title="To"/> }/> {err && }

Receipts

{loading ? "loading…" : aNum(data?.total) + " matching · newest first"}
{!loading && data && data.items.length === 0 && No receipts match.} {data && data.items.length > 0 && (
{data.items.map((r) => (
setSel(r.id)}>
{aDateTime(r.date)}
{r.number}
{r.customerName || "—"}
{r.status === "voided" ? voided : r.status}
{aMoney(r.totalCents)}
))}
)} {data && }
); } function ArchiveSaleDetail({ id, onBack }) { const { data, loading, err } = useArchive(() => window.OfficeAPI.archiveSale(id), id); const [showCard, setShowCard] = aUseState(false); if (loading) return
} eyebrow="loading…" title="Receipt"/>
; if (err || !data) return
} eyebrow="error" title="Receipt"/>
; const t = data.transaction; return (
} eyebrow={`${aDateTime(t.date)}${t.customerName ? " · " + t.customerName : ""}`} title={"Receipt #" + t.number}/>

Lines

Item
Qty
Unit
PBS subsidy
Line total
{data.lines.map((l) => (
{l.name || l.sku || "—"}{l.status === "C" ? cancelled : null}
{l.quantity}
{aMoney(l.unitPriceCents)}
{l.govtContributionCents ? aMoney(l.govtContributionCents) : "—"}
{aMoney(l.lineTotalCents)}
))}

Tenders

{data.tenders.length === 0 && No tender lines.} {data.tenders.map((t2) => (
{aHuman(t2.type)}{t2.accountId ? · on account : null}
{aMoney(t2.amountCents)}
))}

Card / EFTPOS

{data.cards.length ? : null}
{data.cards.length === 0 && No card-present auth on this sale.} {data.cards.map((c) => (
Sale ref
{c.saleReference}
{showCard && c.merchantReceipt && (
{c.merchantReceipt}
)}
))}
); } // ----------------------------------------------------------------- // 2) PURCHASING — wholesaler tax invoices + purchase orders // ----------------------------------------------------------------- function ArchivePurchasing() { const [tab, setTab] = aUseState("invoices"); const [q, setQ] = aUseState(""); const [applied, setApplied] = aUseState(""); const [offset, setOffset] = aUseState(0); const [sel, setSel] = aUseState(null); const [sort, setSort] = aUseState({ col: "date", dir: "desc" }); const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); }; aUseEffect(() => { setOffset(0); setSel(null); setSort({ col: "date", dir: "desc" }); }, [tab]); const key = tab + "|" + applied + "|" + offset + "|" + sort.col + sort.dir; const { data, loading, err } = useArchive( () => (tab === "invoices" ? window.OfficeAPI.archiveInvoices({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied ? { q: applied } : {}) }) : window.OfficeAPI.archivePurchaseOrders({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied ? { q: applied } : {}) })), key, ); if (sel) return setSel(null)}/>; const supName = (it) => it.supplierName || (it.notes ? String(it.notes).split(" / ")[0] : null) || "—"; return (
{ setOffset(0); setApplied(q); }}>Search}/> {err && }

{tab === "invoices" ? "Supplier tax invoices" : "Purchase orders"}

{loading ? "loading…" : aNum(data?.total) + " total · newest first"}
{!loading && data && data.items.length === 0 && Nothing matches.} {tab === "invoices" && data && data.items.length > 0 && (
Ex-GST
GST
{data.items.map((r) => (
setSel(r.id)}>
{aDate(r.date)}
{r.number || "—"}
{supName(r)}
{aMoney(r.subtotalCents)}
{aMoney(r.gstCents)}
{aMoney(r.totalCents)}
))}
)} {tab === "orders" && data && data.items.length > 0 && (
Source
{data.items.map((r) => (
{aDate(r.date)}
{r.number}
{r.supplierName || "—"}
{r.sourceType === "pharmx" ? PharmX : aHuman(r.sourceType)}
{aHuman(r.status)}
))}
)} {data && }
); } function ArchiveInvoiceDetail({ id, onBack }) { const { data, loading, err } = useArchive(() => window.OfficeAPI.archiveInvoice(id), id); if (loading) return
} eyebrow="loading…" title="Invoice"/>
; if (err || !data) return
} eyebrow="error" title="Invoice"/>
; const i = data.invoice; const sup = i.supplierName || (i.notes ? String(i.notes).split(" / ")[0] : "—"); return (
} eyebrow={`${aDate(i.date)} · ${sup}`} title={"Invoice #" + (i.number || "—")}/>

Invoice lines

{i.notes}
Description
Supplier code
Qty
Unit cost
Line ex-GST
{data.lines.map((l) => (
{l.name || l.sku || "—"}
{l.supplierCode || "—"}
{l.quantity}
{aMoney(l.unitCostCents)}
{aMoney(l.lineTotalCents)}
))}
); } // ----------------------------------------------------------------- // 3) ACCOUNT STATEMENTS — A/R ledger per debtor // ----------------------------------------------------------------- const AR_TYPE = { I: "Charge", P: "Payment", C: "Credit", A: "Adjustment", S: "Statement", D: "Discount", Z: "Migrated" }; function ArchiveAccounts() { const [q, setQ] = aUseState(""); const [applied, setApplied] = aUseState(""); const [offset, setOffset] = aUseState(0); const [sel, setSel] = aUseState(null); const [sort, setSort] = aUseState({ col: "entries", dir: "desc" }); const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); }; const key = applied + "|" + offset + "|" + sort.col + sort.dir; const { data, loading, err } = useArchive(() => window.OfficeAPI.archiveAccounts({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied ? { q: applied } : {}) }), key); if (sel) return setSel(null)}/>; return (
{ setOffset(0); setApplied(q); }}>Search}/> {err && }

Debtor accounts

{loading ? "loading…" : aNum(data?.total) + " accounts · most active first"}
{!loading && data && data.items.length === 0 && No accounts match.} {data && data.items.length > 0 && (
{data.items.map((r) => (
{ const o = new String(r.id); o._name = r.customerName; setSel(o); }}>
{r.accountNumber || "—"}
{r.customerName || "—"}
0 ? "var(--void-text)" : "inherit"}}>{aMoney(r.balanceCents)}
{aNum(r.entries)}
{aDate(r.lastActivity)}
))}
)} {data && }
); } function ArchiveStatement({ id, name, onBack }) { const [from, setFrom] = aUseState(""); const [to, setTo] = aUseState(""); const [applied, setApplied] = aUseState({ from: "", to: "" }); const key = String(id) + "|" + JSON.stringify(applied); const { data, loading, err } = useArchive( () => window.OfficeAPI.archiveAccountLedger(String(id), { ...(applied.from ? { from: applied.from } : {}), ...(applied.to ? { to: applied.to } : {}) }), key, ); if (loading) return
} eyebrow="loading…" title={String(name || "Account")}/>
; if (err || !data) return
} eyebrow="error" title="Account"/>
; const a = data.account; return (
} eyebrow={`account ${a.accountNumber || ""}`} title={a.customerName || "Account"}/>
0 ? "owing" : "clear" }}/>

Statement · ledger

setFrom(e.target.value)} style={{height:30, width:140}}/> setTo(e.target.value)} style={{height:30, width:140}}/>
{data.entries.length === 0 && No ledger entries in this window.} {data.entries.length > 0 && (
Date
Type
Narration
Amount
Balance
{data.entries.map((e) => (
{aDate(e.date)}
{AR_TYPE[e.type] || e.type}
{e.narration || "—"}
{aMoney(e.amountCents)}
{aMoney(e.runningBalanceCents)}
))}
)}
); } // ----------------------------------------------------------------- // 4) STOCK MOVEMENT HISTORY — full legacy trail incl. S8 controlled-drug // ----------------------------------------------------------------- const MOVE_TYPES = ["", "sale", "dispense", "receive_invoice", "adjustment", "refund", "transfer", "order"]; function ArchiveStock() { const { setScreenState, setScreen } = window.useOffice(); const [q, setQ] = aUseState(""); const [type, setType] = aUseState(""); const [applied, setApplied] = aUseState({ q: "", type: "" }); const [offset, setOffset] = aUseState(0); const [sort, setSort] = aUseState({ col: "date", dir: "desc" }); const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); }; const key = JSON.stringify(applied) + "|" + offset + "|" + sort.col + sort.dir; const { data, loading, err } = useArchive( () => window.OfficeAPI.archiveStockMovements({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied.q ? { q: applied.q } : {}), ...(applied.type ? { type: applied.type } : {}) }), key, ); const openProduct = (pid) => { setScreenState({ activeProductId: pid, productFrom: "stockHistory" }); setScreen("productDetail"); }; return (
}/> {err && }

Movements

{loading ? "loading…" : aNum(data?.total) + " in trail · newest first"}
{!loading && data && data.items.length === 0 && No movements match.} {data && data.items.length > 0 && (
On hand
{data.items.map((m) => { const up = m.quantityDelta >= 0; return (
{aDateTime(m.occurredAt)}
openProduct(m.productId) : undefined}> {m.productName || m.sku || "—"}{m.schedule === "S8" ? S8 : null}
{aHuman(m.movementType)}
{up ? "+" : ""}{m.quantityDelta}
{m.quantityBefore}→{m.quantityAfter}
); })}
)} {data && }
); } // ----------------------------------------------------------------- // Register // ----------------------------------------------------------------- window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, { salesHistory: ArchiveSales, invoices: ArchivePurchasing, accounts: ArchiveAccounts, stockHistory: ArchiveStock, });