/* =============================================================
CoreIQ Office — Major expansion
Buying · Staff · Clinical · Customer · Finance · Gov programs · Ops · Admin
============================================================= */
const { useState: xUseState, useMemo: xUseMemo } = React;
const STX = { "S-001": "var(--teal-700)", "S-002": "var(--navy-600)", "S-003": "var(--violet-600)" };
// Generic screen shell helper
function Screen({ eyebrow, title, actions, subtabs, activeTab, onTab, children }) {
return (
{eyebrow}
{title}
{actions}
{subtabs && (
{subtabs.map(s => (
))}
)}
{children}
);
}
function StatusPill({ kind, label }) {
const map = { paid:"badge--paid", hold:"badge--hold", void:"badge--void", brand:"badge--brand", sched:"badge--sched", neutral:"badge--neutral" };
return {label};
}
// =================================================================
// BUYING — Purchase Orders (formal, separate from Ordering)
// =================================================================
function PurchaseOrders() {
const { setScreen, setScreenState } = window.useOffice();
const PO = [
{ id:"PO-4426", supplier:"CSL Seqirus", ws:"ws-csl", channel:"Direct (DHL)", store:"S-001", lines:3, units:600, value:9420.00, status:"received", sent:"12/04/2026", expected:"20/04/2026", received:"20/04/2026", auth:"Suni Kapoor", contractRef:"FLU-2026" },
{ id:"PO-4422", supplier:"Sigma", ws:"ws-sigma", channel:"PharmX", store:"S-001", lines:4, units:158, value:412.40, status:"received", sent:"25/05/2026 22:00", expected:"Today 09:00", received:"Today 09:14", auth:"auto", contractRef:"Q2-2026" },
{ id:"PO-4423", supplier:"Symbion", ws:"ws-symbion", channel:"PharmX", store:"S-001", lines:2, units:70, value:624.60, status:"received", sent:"25/05/2026 22:00", expected:"Today 11:30", received:"Today 11:30", auth:"auto", contractRef:"Q2-2026" },
{ id:"PO-4424", supplier:"API", ws:"ws-api", channel:"EDI", store:"S-001", lines:6, units:240, value:1142.20, status:"in-transit", sent:"Today 06:30", expected:"Today 16:00", received:null, auth:"Suni Kapoor" },
{ id:"PO-4425", supplier:"GSK Australia",ws:"ws-gsk", channel:"Direct (DHL)", store:"S-002", lines:1, units:24, value:380.20, status:"in-transit", sent:"25/05/2026", expected:"Today 14:00", received:null, auth:"Rachel Pham" },
{ id:"PO-4429", supplier:"Webstercare", ws:"ws-webster", channel:"Direct (DHL)", store:"S-003", lines:1, units:50, value:600.00, status:"submitted", sent:"Today 11:48", expected:"Tomorrow", received:null, auth:"James Liu" },
{ id:"PO-4430", supplier:"Symbion", ws:"ws-symbion", channel:"PharmX", store:"S-003", lines:6, units:188, value:712.30, status:"submitted", sent:"Today 12:14", expected:"Tomorrow 09:30", received:null, auth:"James Liu" },
{ id:"PO-4427", supplier:"Diabetes Aust",ws:"ws-ndss", channel:"EDI", store:"S-003", lines:5, units:144, value:410.20, status:"open", sent:"—", expected:"—", received:null, auth:"—" },
{ id:"PO-4428", supplier:"Sigma", ws:"ws-sigma", channel:"PharmX", store:"S-002", lines:8, units:220, value:884.50, status:"open", sent:"—", expected:"—", received:null, auth:"—" },
];
const [filter, setFilter] = xUseState("all");
const FILTERS = [
{k:"all", l:"All"}, {k:"open", l:"Draft"}, {k:"submitted", l:"Submitted"},
{k:"in-transit", l:"In transit"}, {k:"received", l:"Received"},
];
const list = PO.filter(o => filter === "all" || o.status === filter);
return (
>}>
o.status === "open" || o.status === "submitted").length} delta={{text:"Draft + submitted"}}/>
o.status === "in-transit").length} delta={{text:"Awaiting receipt"}}/>
s + o.value, 0))} delta={{dir:"up", text:"▲ 9.1% vs prior 30d"}}/>
{FILTERS.map(f => )}
PO
Supplier · contract
Channel
Store
Lines
Units
Value
Authorised by
Status
{list.map(o => (
{ if (["in-transit","received","submitted"].includes(o.status)) setScreen("receiving"); }}>
{o.id}
{o.supplier}
{o.contractRef &&
Contract {o.contractRef}
}
{o.channel}
{findS(o.store)?.code}
{o.lines}
{o.units}
{oMoney(o.value)}
{o.auth}
{o.status === "open" && }
{o.status === "submitted" && }
{o.status === "in-transit" && }
{o.status === "received" && }
))}
);
}
// =================================================================
// BUYING — Supplier price lists & contract pricing
// =================================================================
function PriceLists() {
const [supplier, setSupplier] = xUseState("ws-sigma");
const supList = [
{id:"ws-sigma", name:"Sigma Healthcare", contract:"Q2-2026", validUntil:"30/06/2026", lines:1402, version:"v18", uploaded:"01/04/2026"},
{id:"ws-symbion", name:"Symbion", contract:"Q2-2026", validUntil:"30/06/2026", lines:1118, version:"v12", uploaded:"01/04/2026"},
{id:"ws-api", name:"API", contract:"Annual 2026", validUntil:"31/12/2026", lines:884, version:"v8", uploaded:"15/01/2026"},
{id:"ws-gsk", name:"GSK Australia", contract:"Direct", validUntil:"open", lines:42, version:"v3", uploaded:"22/05/2026"},
{id:"ws-csl", name:"CSL Seqirus", contract:"FLU-2026", validUntil:"31/08/2026", lines:8, version:"v1", uploaded:"12/04/2026"},
];
const current = supList.find(s => s.id === supplier);
const SAMPLE_LINES = [
{sku:"9319912445221", name:"Metformin XR 500mg", listCost:5.20, contractCost:4.20, savings:19, qty:30, moq:60, eff:"01/04/2026"},
{sku:"9333091001284", name:"Atorvastatin 40mg", listCost:9.10, contractCost:8.10, savings:11, qty:30, moq:60, eff:"01/04/2026"},
{sku:"9333091002145", name:"Sertraline 50mg", listCost:10.40, contractCost:9.20, savings:12, qty:30, moq:30, eff:"01/04/2026"},
{sku:"9333091015223", name:"Esomeprazole 20mg", listCost:5.80, contractCost:5.00, savings:14, qty:30, moq:60, eff:"01/04/2026"},
{sku:"9333091003121", name:"Amoxicillin 500mg", listCost:5.10, contractCost:4.30, savings:16, qty:20, moq:40, eff:"01/04/2026"},
{sku:"9333091022774", name:"Insulin Glargine 100u/ml", listCost:21.40, contractCost:18.60, savings:13, qty:5, moq:10, eff:"01/04/2026"},
{sku:"9325113022113", name:"Endone 5mg", listCost:7.90, contractCost:6.80, savings:14, qty:20, moq:20, eff:"01/04/2026"},
];
return (
>}>
{supList.map(s => (
))}
{current.name}
Contract {current.contract} · Valid to {current.validUntil} · {current.version} · Uploaded {current.uploaded}
SKU
Product
List cost
Contract cost
Savings
Pack
MOQ
Effective
{SAMPLE_LINES.map(l => (
{l.sku}
{l.name}
{oMoney(l.listCost)}
{oMoney(l.contractCost)}
−{l.savings}%
{l.qty}
{l.moq}
{l.eff}
))}
);
}
// =================================================================
// BUYING — Backorders
// =================================================================
function Backorders() {
const BO = [
{id:"BO-118", productId:"p008", supplier:"Sigma", store:"S-002", qty:24, original:"PO-4395", ordered:"10/05/2026", eta:"Tomorrow", reason:"Manufacturer shortage", status:"in-transit", waiting:18},
{id:"BO-117", productId:"p012", supplier:"Sigma", store:"S-001", qty:10, original:"PO-4423", ordered:"Yesterday", eta:"05/06/2026", reason:"Cold-chain shipping delay", status:"delayed", waiting:1},
{id:"BO-116", productId:"p005", supplier:"Sigma", store:"S-001", qty:40, original:"PO-4422", ordered:"Yesterday", eta:"Resolved", reason:"Short-shipped 2 units", status:"resolved", waiting:0},
{id:"BO-115", productId:"p019", supplier:"NDSS", store:"S-001", qty:6, original:"PO-4408", ordered:"08/05/2026", eta:"31/05/2026", reason:"National sensor shortage", status:"delayed", waiting:14},
{id:"BO-114", productId:"p001", supplier:"GSK", store:"S-003", qty:24, original:"PO-4412", ordered:"20/05/2026", eta:"Today 14:00", reason:"Direct shipment in flight", status:"in-transit", waiting:8},
{id:"BO-113", productId:"p010", supplier:"Symbion", store:"S-002", qty:60, original:"PO-4395", ordered:"10/05/2026", eta:"Substituted", reason:"Generic substituted with Amoxil", status:"substituted", waiting:0},
];
return (
>}>
b.status === "in-transit" || b.status === "delayed").length} delta={{dir:"down", text:"Open with suppliers"}}/>
s + b.waiting, 0)} delta={{dir:"down", text:"Waiting on scripts"}}/>
ID
Product
Supplier
Store
Qty
Reason
Expected
Patients
Status
{BO.map(b => {
const p = findP(b.productId);
return (
{b.id}
{p?.name} · {p?.strength}
{b.supplier}
{findS(b.store)?.code}
{b.qty}
{b.reason}
{b.eta}
5 ? 'var(--void-text)' : 'var(--text)'}}>
{b.waiting > 0 ? b.waiting + " waiting" : "—"}
{b.status === "in-transit" && }
{b.status === "delayed" && }
{b.status === "resolved" && }
{b.status === "substituted" && }
);
})}
);
}
// =================================================================
// BUYING — Buying groups & formulary
// =================================================================
function BuyingGroups() {
const [tab, setTab] = xUseState("groups");
const GROUPS = [
{id:"BG-PSA", name:"Pharmacy Guild · Buying Group", scope:"National", members:1240, spendQ:2940000, rebate:"2.4% quarterly", joinedOn:"2014", primary:true, contact:"buying@guild.org.au"},
{id:"BG-CSO", name:"CSO · Community Service Obligation", scope:"Federal", members:"All approved pharmacies", spendQ:0, rebate:"Subsidised wholesale margin", joinedOn:"Mandatory", primary:false, contact:"—"},
{id:"BG-IND", name:"Independent Pharmacy Co-op", scope:"Victoria", members:118, spendQ:184200, rebate:"1.8% biannual + volume", joinedOn:"2019", primary:false, contact:"co-op@indyphvic.au"},
];
const FORMULARY = [
{name:"Statins", drug:"Atorvastatin", preferred:"Generic · Sigma", approved:["Generic · Sigma","Lipitor · Pfizer","Generic · Apotex"], on:["S-001","S-002","S-003"]},
{name:"PPIs", drug:"Esomeprazole", preferred:"Generic · Sandoz", approved:["Generic · Sandoz","Nexium · AstraZeneca","Generic · Apotex"], on:["S-001","S-002","S-003"]},
{name:"SSRIs", drug:"Sertraline", preferred:"Generic · Mylan", approved:["Generic · Mylan","Zoloft · Pfizer"], on:["S-001","S-002"]},
{name:"Inhaled corticosteroids", drug:"Salbutamol", preferred:"Ventolin · GSK", approved:["Ventolin · GSK","Asmol · Alphapharm"], on:["S-001","S-002","S-003"]},
{name:"Metformin", drug:"Metformin XR", preferred:"Generic · Sigma", approved:["Generic · Sigma","Diabex · Alphapharm","Glucophage · Merck"], on:["S-001","S-002","S-003"]},
];
return (
{tab === "groups" && (
{GROUPS.map(g => (
{g.name}
{g.primary && }
{g.scope} · Joined {g.joinedOn} · {typeof g.members === "number" ? g.members.toLocaleString() + " members" : g.members}
Spend through group · Q
{g.spendQ > 0 ? oMoney(g.spendQ) : "—"}
Rebate / benefit
{g.rebate}
))}
)}
{tab === "formulary" && (
Class
Drug
Approved alternatives
Preferred
In stores
{FORMULARY.map(f => (
{f.name}
{f.drug}
{f.approved.length} · {f.approved.slice(0,2).join("; ")}{f.approved.length > 2 ? "…" : ""}
{f.preferred}
{f.on.length === 3 ? "All" : f.on.map(id => findS(id)?.code).join(", ")}
))}
)}
{tab === "approvedSuppliers" && (
Supplier
Approved on
Last audit
TGA licence
SKUs
Status
{OD.SUPPLIERS.map(s => (
{s.name}
2014
22/04/2026
VIC-{s.id.slice(-4)}
{OD.PRODUCTS.filter(p => p.supplier === s.id).length || "—"}
))}
)}
);
}
// =================================================================
// BUYING — EDI status & message log
// =================================================================
function EDIStatus() {
const FEEDS = [
{id:"PharmX-Sigma", partner:"Sigma", channel:"PharmX", status:"healthy", lastOk:"12s ago", msgs24:142, errors24:0, cutoff:"16:00 daily"},
{id:"PharmX-Symbion",partner:"Symbion", channel:"PharmX", status:"healthy", lastOk:"24s ago", msgs24:118, errors24:1, cutoff:"15:30 daily"},
{id:"EDI-API", partner:"API", channel:"EDI X12", status:"healthy", lastOk:"2m ago", msgs24:42, errors24:0, cutoff:"Twice weekly"},
{id:"EDI-NDSS", partner:"NDSS", channel:"EDI X12", status:"warning", lastOk:"4h ago", msgs24:8, errors24:2, cutoff:"Daily", warning:"Slow ack"},
{id:"DHL-GSK", partner:"GSK", channel:"Direct API",status:"healthy",lastOk:"18m ago", msgs24:12, errors24:0, cutoff:"Order ahead"},
{id:"DHL-CSL", partner:"CSL", channel:"Direct API",status:"healthy",lastOk:"3h ago", msgs24:3, errors24:0, cutoff:"Seasonal"},
{id:"PBS-Online", partner:"Services AU",channel:"PBS Online",status:"healthy",lastOk:"4m ago",msgs24:248,errors24:1, cutoff:"Realtime"},
];
const RECENT = [
{ts:"14:32:18", feed:"PharmX-Sigma", type:"855 PO Ack", ref:"PO-4422", status:"ok"},
{ts:"14:18:04", feed:"EDI-API", type:"856 ASN", ref:"PO-4424", status:"ok"},
{ts:"13:48:22", feed:"PBS-Online", type:"Claim submit", ref:"Rx 894-221", status:"ok"},
{ts:"13:42:10", feed:"PharmX-Symbion",type:"810 Invoice", ref:"INV-SYM-2204", status:"ok"},
{ts:"12:14:48", feed:"PharmX-Symbion",type:"850 PO submit", ref:"PO-4430", status:"ok"},
{ts:"11:48:18", feed:"PharmX-Sigma", type:"850 PO submit", ref:"PO-4428", status:"ok"},
{ts:"10:18:42", feed:"EDI-NDSS", type:"855 PO Ack", ref:"PO-4408", status:"warning", note:"Late ack · 4h after submit"},
{ts:"09:14:08", feed:"PharmX-Sigma", type:"856 ASN", ref:"PO-4422", status:"ok"},
{ts:"08:42:22", feed:"EDI-NDSS", type:"850 PO submit", ref:"PO-4427", status:"error", note:"Schema validation · field 'lot' missing"},
{ts:"08:30:14", feed:"PBS-Online", type:"Handshake", ref:"—", status:"ok"},
];
return (
>}>
f.status === "healthy").length + " healthy"}}/>
s + f.msgs24, 0)} delta={{text:"PO + ASN + invoice + claims"}}/>
s + f.errors24, 0)} delta={{dir:"down", text:"Schema or ack issues"}}/>
f.status === "warning").length} delta={{dir:"down", text:"Slow ack feeds"}}/>
Feeds
Feed
Channel
Last OK
Cutoff
Msgs 24h
Errors
Status
{FEEDS.map(f => (
{f.channel}
{f.lastOk}
{f.cutoff}
{f.msgs24}
0 ? 'var(--void-text)' : 'var(--text-muted)'}}>{f.errors24}
{f.status === "healthy" && }
{f.status === "warning" && }
))}
Recent messages
Timestamp
Feed
Type
Reference / note
Result
{RECENT.map((m, i) => (
{m.ts}
{m.feed}
{m.type}
{m.ref}
{m.note &&
{m.note}
}
{m.status === "ok" && }
{m.status === "warning" && }
{m.status === "error" && }
))}
);
}
// =================================================================
// STAFF — profiles, schedules, performance, training
// =================================================================
function Staff() {
const [tab, setTab] = xUseState("profiles");
return (
>}>
{tab === "profiles" && }
{tab === "roster" && }
{tab === "performance" && }
{tab === "training" && }
);
}
function StaffProfiles() {
return (
Name
Email
Role
Stores
AHPRA
2FA
Status
{OD.USERS.map(u => (
{(u.first[0]+u.last[0]).toUpperCase()}
{u.first} {u.last}
{u.email}
{u.role}
{u.stores[0] === "—" ? "Org-wide" : u.stores.map(id => findS(id)?.code).join(", ")}
{u.role.toLowerCase().includes("pharmacist") ? "PHA0001" + u.id.slice(-3) : "—"}
{u.twoFA ? : }
{u.status === "active" && }
{u.status === "leave" && }
{u.status === "pending" && }
))}
);
}
function StaffRoster() {
const DAYS = ["Mon 26", "Tue 27", "Wed 28", "Thu 29", "Fri 30", "Sat 31", "Sun 01"];
const SHIFTS = [
{staff:"SK", store:"S-001", day:0, start:"08:30", end:"17:00"},
{staff:"RP", store:"S-001", day:0, start:"12:00", end:"19:00"},
{staff:"JL", store:"S-003", day:0, start:"09:00", end:"18:00"},
{staff:"PS", store:"S-002", day:0, start:"09:00", end:"15:00"},
{staff:"SK", store:"S-001", day:1, start:"08:30", end:"17:00"},
{staff:"DP", store:"S-001", day:1, start:"12:00", end:"19:00"},
{staff:"RP", store:"S-002", day:1, start:"08:30", end:"17:00"},
{staff:"JL", store:"S-003", day:1, start:"09:00", end:"18:00"},
{staff:"SK", store:"S-001", day:2, start:"08:30", end:"17:00"},
{staff:"RP", store:"S-002", day:2, start:"08:30", end:"15:00"},
{staff:"JL", store:"S-003", day:2, start:"09:00", end:"18:00"},
{staff:"DP", store:"S-001", day:2, start:"12:00", end:"19:00"},
{staff:"SK", store:"S-001", day:3, start:"08:30", end:"17:00"},
{staff:"RP", store:"S-001", day:3, start:"12:00", end:"19:00"},
{staff:"JL", store:"S-003", day:3, start:"09:00", end:"18:00"},
{staff:"PS", store:"S-002", day:3, start:"09:00", end:"15:00"},
{staff:"SK", store:"S-001", day:4, start:"08:30", end:"17:00"},
{staff:"DP", store:"S-001", day:4, start:"12:00", end:"19:00"},
{staff:"RP", store:"S-002", day:4, start:"08:30", end:"19:00"},
{staff:"JL", store:"S-003", day:4, start:"09:00", end:"18:00"},
{staff:"DP", store:"S-001", day:5, start:"09:00", end:"17:00"},
{staff:"JL", store:"S-003", day:5, start:"09:00", end:"15:00"},
{staff:"PS", store:"S-002", day:6, start:"10:00", end:"14:00"},
{staff:"JL", store:"S-003", day:6, start:"10:00", end:"15:00"},
];
const STAFF = ["SK", "RP", "JL", "DP", "PS"];
return (
Week of 26 May 2026
{SHIFTS.length} shifts · {SHIFTS.reduce((s, sh) => s + (parseInt(sh.end) - parseInt(sh.start)), 0)}h scheduled
Staff
{DAYS.map(d =>
{d}
)}
{STAFF.map(initials => (
{DAYS.map((_, dayIdx) => {
const shifts = SHIFTS.filter(s => s.staff === initials && s.day === dayIdx);
return (
{shifts.map((sh, i) => (
{findS(sh.store)?.code}
{sh.start}–{sh.end}
))}
);
})}
))}
);
}
function StaffPerformance() {
const PERF = [
{init:"SK", role:"PIC", sales30d:48420, scripts30d:184, basket:42.10, txTime:"1m 48s", refundRate:0.4, rxAccuracy:99.8},
{init:"RP", role:"PIC", sales30d:38240, scripts30d:148, basket:38.90, txTime:"2m 02s", refundRate:0.6, rxAccuracy:99.6},
{init:"JL", role:"Pharm", sales30d:42180, scripts30d:162, basket:39.40, txTime:"1m 54s", refundRate:0.5, rxAccuracy:99.7},
{init:"DP", role:"Pharm", sales30d:28140, scripts30d:118, basket:35.20, txTime:"2m 18s", refundRate:0.8, rxAccuracy:99.4},
{init:"PS", role:"Asst.", sales30d:18420, scripts30d:0, basket:24.80, txTime:"1m 32s", refundRate:0.4, rxAccuracy:null},
];
return (
Staff
Role
Sales 30d
Scripts 30d
Avg basket
Avg tx time
Refund rate
Rx accuracy
{PERF.map(p => (
{p.init}
{p.role}
{oMoney(p.sales30d)}
{p.scripts30d || "—"}
{oMoney(p.basket)}
{p.txTime}
0.7 ? 'var(--hold-text)' : 'var(--text)'}}>{p.refundRate.toFixed(1)}%
{p.rxAccuracy !== null ? p.rxAccuracy.toFixed(1) + "%" : "—"}
))}
);
}
function StaffTraining() {
const REC = [
{init:"SK", name:"Suni Kapoor", course:"AHPRA registration · renewal", status:"current", due:"30/09/2026", required:true},
{init:"SK", name:"Suni Kapoor", course:"Vaccination training (level 4)", status:"current", due:"31/12/2026", required:true},
{init:"SK", name:"Suni Kapoor", course:"S8 controlled drug handling", status:"current", due:"30/06/2027", required:true},
{init:"RP", name:"Rachel Pham", course:"AHPRA registration · renewal", status:"current", due:"30/09/2026", required:true},
{init:"RP", name:"Rachel Pham", course:"Vaccination training (level 4)", status:"due-soon", due:"22/06/2026", required:true},
{init:"RP", name:"Rachel Pham", course:"MedsCheck accreditation", status:"current", due:"15/03/2027", required:true},
{init:"JL", name:"James Liu", course:"AHPRA registration · renewal", status:"current", due:"30/09/2026", required:true},
{init:"JL", name:"James Liu", course:"Naloxone training", status:"current", due:"01/08/2027", required:false},
{init:"DP", name:"Daniel Park", course:"AHPRA registration · renewal", status:"overdue", due:"01/05/2026", required:true},
{init:"DP", name:"Daniel Park", course:"Vaccination training (level 4)", status:"current", due:"31/12/2026", required:true},
{init:"PS", name:"Priya Sharma",course:"Pharmacy assistant cert IV", status:"in-progress", due:"31/12/2026", required:true},
{init:"PS", name:"Priya Sharma",course:"First aid", status:"current", due:"22/04/2027", required:true},
];
return (
<>
r.status === "current").length / REC.length * 100) + "%"} delta={{dir:"up", text:"Across required courses"}}/>
r.status === "overdue").length} delta={{dir:"down", text:"Action required"}}/>
r.status === "due-soon").length} delta={{text:"Schedule renewal"}}/>
r.status === "in-progress").length} delta={{text:"Currently studying"}}/>
Staff
Course / certification
Required
Due
Status
{REC.map((r, i) => (
{r.name}
{r.course}
{r.required ? : Optional}
{r.due}
{r.status === "current" && }
{r.status === "due-soon" && }
{r.status === "overdue" && }
{r.status === "in-progress" && }
))}
>
);
}
window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, {
purchaseOrders: PurchaseOrders,
priceLists: PriceLists,
backorders: Backorders,
buyingGroups: BuyingGroups,
ediStatus: EDIStatus,
staff: Staff,
});
// Export shared helpers for sibling Babel scripts
Object.assign(window, { Screen, StatusPill });