function PoBuilder({ open, onClose, sup0 }) {
  const { L, lang, fmt, D, O, inv, invMap, pos, setPos, ops, toast } = useMizo();
  const [sup, setSup] = React.useState(sup0 || 's3');
  const [lines, setLines] = React.useState([]);
  const [exp, setExp] = React.useState('2026-10-30');
  const [note, setNote] = React.useState('');
  const [add, setAdd] = React.useState('');
  React.useEffect(() => { if (open) { setSup(sup0 || 's3'); setLines([]); setNote(''); } }, [open]);
  const info = ops.supInfo[sup] || {};
  const price = (ing) => { const q = (D.quotes[ing] || []).find((x) => x.sup === sup); return invMap[ing].sup === sup ? invMap[ing].cost : q ? q.p : invMap[ing].cost; };
  const theirs = inv.filter((i) => i.sup === sup || (D.quotes[i.id] || []).some((q) => q.sup === sup));
  const total = lines.reduce((s, l) => s + (Number(l.q) || 0) * l.p, 0);
  const needsOk = total > O.approval.limit;
  const save = (status) => {
    const n = Math.max(...pos.map((p) => Number(p.id.split('-')[1]))) + 1;
    setPos([{ id: 'PO-' + n, sup, created: TODAY, expected: exp, status, lines: lines.filter((l) => Number(l.q) > 0).map((l) => [l.ing, Number(l.q)]), by: 'Eleni', note: note ? { en: note, fr: note } : null }, ...pos]);
    toast(status === 'draft' ? L(`PO-${n} saved as draft`, `BC-${n} enregistré en brouillon`) : status === 'pending' ? L(`PO-${n} sent for approval`, `BC-${n} envoyé pour approbation`) : L(`PO-${n} marked as sent`, `BC-${n} marqué comme envoyé`)); onClose();
  };
  return (
    <Modal open={open} onClose={onClose} wide title={<span className="wiz-title"><Icon n="file-plus" />{L('New purchase order', 'Nouveau bon de commande')}</span>} actions={<>
      <span className="muted sm" style={{ marginRight: 'auto' }}>{needsOk ? L(`Over ${fmt.money0(O.approval.limit)} — needs ${O.approval.approver}’s approval`, `Plus de ${fmt.money0(O.approval.limit)} — approbation de ${O.approval.approver}`) : L('Under the approval limit', 'Sous la limite d’approbation')}</span>
      <button className="btn btn-secondary" disabled={!lines.length} onClick={() => save('draft')}>{L('Save draft', 'Brouillon')}</button>
      <button className="btn btn-primary" disabled={!lines.length || total <= 0} onClick={() => save(needsOk ? 'pending' : 'sent')}><Icon n={needsOk ? 'seal-check' : 'paper-plane-tilt'} />{needsOk ? L('Submit for approval', 'Soumettre') : L('Mark as sent', 'Marquer envoyé')}</button>
    </>}>
      <div className="form-grid">
        <div className="field"><label>{L('Supplier', 'Fournisseur')}</label><select className="input" value={sup} onChange={(e) => { setSup(e.target.value); setLines([]); }}>{D.suppliers.map((s) => <option key={s.id} value={s.id}>{s.name}</option>)}</select></div>
        <div className="field"><label>{L('Delivery date', 'Date de livraison')}</label><input className="input" type="date" value={exp} onChange={(e) => setExp(e.target.value)} /></div>
      </div>
      <div className="po-info muted sm"><span><Icon n="truck" /> {info.days ? info.days[lang] : '—'}</span><span><Icon n="clock" /> {L('Order by', 'Commander avant')} {info.cutoff ? info.cutoff[lang] : '—'}</span><span><Icon n="coins" /> {L('Minimum', 'Minimum')} {fmt.money0(info.min || 0)}</span><span><Icon n="calendar-check" /> {L('Net', 'Net')} {info.terms} {L('days', 'jours')}</span></div>
      <div className="table-scroll">
        <table className="table mtable reditor">
          <thead><tr><th>{L('Item', 'Article')}</th><th>{L('Qty', 'Qté')}</th><th className="num">{L('Price', 'Prix')}</th><th className="num">{L('Total', 'Total')}</th><th></th></tr></thead>
          <tbody>
            {lines.map((l, i) => (
              <tr key={l.ing}><td><div className="cell-main">{invMap[l.ing].name[lang]}</div><div className="cell-sub">{L('On hand', 'En stock')} {fmt.num(invMap[l.ing].onHand)} · {L('par', 'niveau')} {fmt.num(invMap[l.ing].par)} {invMap[l.ing].unit}</div></td>
                <td><div className="portion"><input className="input" type="number" min="0" value={l.q} onChange={(e) => setLines(lines.map((x, j) => (j === i ? { ...x, q: e.target.value } : x)))} /><span className="muted">{invMap[l.ing].unit}</span></div></td>
                <td className="num tnum">{fmt.money(l.p)}</td><td className="num tnum">{fmt.money((Number(l.q) || 0) * l.p)}</td>
                <td><button className="btn btn-icon btn-ghost" aria-label={L('Remove', 'Retirer')} onClick={() => setLines(lines.filter((_, j) => j !== i))}><Icon n="x" /></button></td></tr>
            ))}
            {!lines.length ? <tr><td colSpan="5" className="empty">{L('Add the first item below.', 'Ajoutez un premier article ci-dessous.')}</td></tr> : null}
          </tbody>
          <tfoot><tr><td colSpan="3"><b>{L('Order total', 'Total de la commande')}</b>{info.min && total < info.min && lines.length ? <span className="txt-warn sm"> · {L('below supplier minimum', 'sous le minimum')}</span> : null}</td><td className="num tnum"><b>{fmt.money(total)}</b></td><td></td></tr></tfoot>
        </table>
      </div>
      <div className="add-line dr-row" style={{ justifyContent: 'flex-start', gap: '.6rem' }}>
        <select className="input" value={add} onChange={(e) => setAdd(e.target.value)}><option value="">{L('Add an item from this supplier…', 'Ajouter un article…')}</option>{theirs.filter((i) => !lines.some((l) => l.ing === i.id)).map((i) => <option key={i.id} value={i.id}>{i.name[lang]} · {fmt.money(price(i.id))}/{i.unit}</option>)}</select>
        <button className="btn btn-secondary" disabled={!add} onClick={() => { const i = invMap[add]; setLines([...lines, { ing: add, q: Math.max(1, Math.ceil(i.par - i.onHand)), p: price(add) }]); setAdd(''); }}><Icon n="plus" />{L('Add', 'Ajouter')}</button>
      </div>
      <div className="field"><label>{L('Note to supplier (optional)', 'Note au fournisseur (facultatif)')}</label><input className="input" value={note} onChange={(e) => setNote(e.target.value)} placeholder={L('e.g. Please deliver before 10 am', 'ex. Livrer avant 10 h')} /></div>
      <span className="muted sm">{L('Orders are recorded in MIZO. Emailing them to suppliers comes in a later phase — for now, call or email as usual.', 'Les commandes sont enregistrées dans MIZO. L’envoi par courriel viendra plus tard — commandez comme d’habitude pour l’instant.')}</span>
    </Modal>
  );
}

function Approvals() {
  const { L, lang, fmt, D, O, invMap, pos, setPos, toast, go } = useMizo();
  const [log, setLog] = React.useState([{ id: 'PO-1046', who: 'Eleni', d: '2026-10-26', ok: true }, { id: 'PO-1042', who: 'Eleni', d: '2026-10-19', ok: false, why: L('Duplicate of PO-1041', 'Doublon du BC-1041') }]);
  const [why, setWhy] = React.useState({});
  const sup = (id) => D.suppliers.find((s) => s.id === id).name;
  const pending = pos.filter((p) => p.status === 'pending');
  const decide = (p, ok) => { setPos(pos.map((x) => (x.id === p.id ? { ...x, status: ok ? 'sent' : 'draft' } : x))); setLog([{ id: p.id, who: 'Eleni', d: TODAY, ok, why: why[p.id] }, ...log]); toast(ok ? L(`${p.id} approved and marked as sent`, `${p.id} approuvé et marqué envoyé`) : L(`${p.id} sent back to draft`, `${p.id} renvoyé en brouillon`)); };
  const checks = (p) => {
    const c = [], open = pos.filter((x) => x.id !== p.id && ['draft', 'sent', 'pending'].includes(x.status));
    p.lines.forEach(([ing, q]) => { const o = open.find((x) => x.lines.some(([j]) => j === ing)); if (o) c.push(['warn', L(`${invMap[ing].name.en} is also on ${o.id}`, `${invMap[ing].name.fr} est aussi sur ${o.id}`)]); const i = invMap[ing]; if (i.onHand + q > i.par * 2) c.push(['warn', L(`${i.name.en}: brings stock to ${fmt.num(i.onHand + q)} ${i.unit} (par ${fmt.num(i.par)})`, `${i.name.fr} : stock à ${fmt.num(i.onHand + q)} ${i.unit} (niveau ${fmt.num(i.par)})`)]); });
    if (!c.length) c.push(['pos', L('Quantities and prices look normal', 'Quantités et prix normaux')]);
    return c;
  };
  return (
    <div className="page">
      <PageHead sub={L(`Orders over ${fmt.money0(O.approval.limit)} wait here for ${O.approval.approver}. Smaller orders go straight through.`, `Les commandes de plus de ${fmt.money0(O.approval.limit)} attendent ici l’approbation de ${O.approval.approver}.`)} />
      <section className="stats">
        <Stat label={L('Waiting for you', 'En attente')} value={pending.length} tone={pending.length ? 'warn' : 'pos'}>{fmt.money0(pending.reduce((s, p) => s + poTotal(p, invMap), 0))}</Stat>
        <Stat label={L('Approval limit', 'Limite d’approbation')} value={fmt.money0(O.approval.limit)}>{L('Managers order freely below this', 'Les gérants commandent librement sous ce montant')}</Stat>
        <Stat label={L('Decided this month', 'Décisions ce mois-ci')} value={log.length}>{log.filter((x) => !x.ok).length} {L('sent back', 'renvoyées')}</Stat>
      </section>
      {pending.map((p) => (
        <section key={p.id} className="panel">
          <div className="panel-head"><div><div className="card-kicker">{p.id} · {L('from', 'de')} {p.by || 'Nikos'}</div><h3>{sup(p.sup)}</h3><p className="muted">{L('Delivery', 'Livraison')} {fmt.date(p.expected, { weekday: 'long', month: 'short', day: 'numeric' })}{p.note ? ' · ' + p.note[lang] : ''}</p></div><b className="big tnum">{fmt.money(poTotal(p, invMap))}</b></div>
          <div className="grid-1-1">
            <div>{p.lines.map(([ing, q]) => <div key={ing} className="ln"><span>{invMap[ing].name[lang]} · {fmt.num(q)} {invMap[ing].unit}</span><b>{fmt.money(invMap[ing].cost * q)}</b></div>)}</div>
            <ul className="alerts">{checks(p).map(([t, x], i) => <li key={i} className="alert"><span className={'alert-ic ' + (t === 'pos' ? 'acc' : t)}><Icon n={t === 'pos' ? 'check' : 'warning'} /></span><div className="alert-text">{x}</div></li>)}</ul>
          </div>
          <div className="dr-row" style={{ flexWrap: 'wrap', justifyContent: 'flex-end' }}>
            <input className="input" style={{ flex: '1 1 220px', maxWidth: 360 }} placeholder={L('Note for the team (optional)', 'Note pour l’équipe (facultatif)')} value={why[p.id] || ''} onChange={(e) => setWhy({ ...why, [p.id]: e.target.value })} />
            <button className="btn btn-secondary" onClick={() => decide(p, false)}><Icon n="arrow-u-up-left" />{L('Send back', 'Renvoyer')}</button>
            <button className="btn btn-primary" onClick={() => decide(p, true)}><Icon n="seal-check" />{L('Approve', 'Approuver')}</button>
          </div>
        </section>
      ))}
      {!pending.length ? <div className="panel empty">{L('Nothing waiting for approval.', 'Rien en attente.')}</div> : null}
      <div className="panel">
        <h3>{L('Decision history', 'Historique')}</h3>
        <ul className="act">{log.map((x, i) => <li key={i}><span className="act-t tnum">{fmt.date(x.d)}</span><span className="act-ic">{x.ok ? <Icon n="seal-check" /> : <Icon n="arrow-u-up-left" />}</span><span><b>{x.id}</b> {x.ok ? L('approved by', 'approuvé par') : L('sent back by', 'renvoyé par')} {x.who}{x.why ? ' — ' + x.why : ''}</span></li>)}</ul>
      </div>
    </div>
  );
}

function Returns() {
  const { L, lang, fmt, D, O, inv, invMap, pos, setPos, ops, upd, toast } = useMizo();
  const [f, setF] = React.useState(null);
  const sup = (id) => D.suppliers.find((s) => s.id === id).name;
  const partial = pos.filter((p) => p.status === 'partial');
  const st = { requested: [L('Requested', 'Demandé'), 'warn'], approved: [L('Approved', 'Approuvé'), 'neutral'], credited: [L('Credited', 'Crédité'), 'pos'], rejected: [L('Rejected', 'Refusé'), 'neg'] };
  const next = { requested: 'approved', approved: 'credited' };
  const create = () => { const i = invMap[f.ing]; const n = Math.max(...ops.returns.map((r) => Number(r.id.split('-')[1]))) + 1; upd('returns', (r) => [{ id: 'RMA-' + n, sup: f.sup, date: TODAY, ing: f.ing, qty: Number(f.qty), reason: f.reason, amt: Number(f.qty) * i.cost, status: 'requested', po: f.po || null }, ...r]); toast(L(`Credit request RMA-${n} recorded`, `Demande de crédit RMA-${n} enregistrée`)); setF(null); };
  return (
    <div className="page">
      <PageHead sub={L('Short deliveries, damaged goods and credits you’re owed — so nothing gets forgotten.', 'Livraisons incomplètes, marchandise endommagée et crédits à recevoir — pour ne rien oublier.')}>
        <button className="btn btn-primary" onClick={() => setF({ sup: 's2', ing: 'tomato', qty: '', reason: 'damaged', po: '' })}><Icon n="arrow-u-up-left" />{L('New return', 'Nouveau retour')}</button>
      </PageHead>
      <section className="stats">
        <Stat label={L('Credits owed to you', 'Crédits à recevoir')} value={fmt.money(ops.returns.filter((r) => r.status === 'requested' || r.status === 'approved').reduce((s, r) => s + r.amt, 0))} tone="warn">{ops.returns.filter((r) => r.status !== 'credited').length} {L('open', 'ouverts')}</Stat>
        <Stat label={L('Credited this month', 'Crédité ce mois-ci')} value={fmt.money(ops.returns.filter((r) => r.status === 'credited').reduce((s, r) => s + r.amt, 0))} tone="pos">{L('Applied to invoices', 'Appliqué aux factures')}</Stat>
        <Stat label={L('Partial deliveries', 'Livraisons partielles')} value={partial.length} tone={partial.length ? 'neg' : ''}>{L('Need follow-up', 'À suivre')}</Stat>
      </section>
      {partial.map((p) => (
        <div key={p.id} className="suggest warnbox"><Icon n="package" s="1.3rem" /><div><b>{p.id} · {sup(p.sup)}</b> — {p.note ? p.note[lang] : L('Some items missing', 'Articles manquants')}</div>
          <button className="btn btn-secondary" onClick={() => { setPos(pos.map((x) => (x.id === p.id ? { ...x, status: 'received' } : x))); toast(L(`${p.id} closed`, `${p.id} fermé`)); }}>{L('Close order', 'Fermer')}</button></div>
      ))}
      <div className="panel panel-flush">
        <div className="table-scroll">
          <table className="table mtable">
            <thead><tr><th>{L('Return', 'Retour')}</th><th>{L('Item', 'Article')}</th><th className="hide-sm">{L('Reason', 'Raison')}</th><th className="num">{L('Credit', 'Crédit')}</th><th>{L('Status', 'État')}</th><th></th></tr></thead>
            <tbody>{ops.returns.map((r) => (
              <tr key={r.id}><td><div className="cell-main">{r.id}</div><div className="cell-sub">{sup(r.sup)} · {fmt.date(r.date)}{r.po ? ' · ' + r.po : ''}</div></td><td>{invMap[r.ing].name[lang]} · {fmt.num(r.qty)} {invMap[r.ing].unit}</td><td className="hide-sm">{O.returnReasons[r.reason][lang]}</td><td className="num tnum">{fmt.money(r.amt)}</td><td><Pill tone={st[r.status][1]}>{st[r.status][0]}</Pill></td>
                <td>{next[r.status] ? <button className="btn btn-ghost" onClick={() => upd('returns', (rs) => rs.map((x) => (x.id === r.id ? { ...x, status: next[r.status] } : x)))}>{r.status === 'requested' ? L('Supplier agreed', 'Accepté') : L('Credit received', 'Crédit reçu')}</button> : null}</td></tr>
            ))}</tbody>
          </table>
        </div>
      </div>
      <Modal open={!!f} onClose={() => setF(null)} title={L('New return or credit request', 'Nouveau retour ou crédit')} actions={<><button className="btn btn-secondary" onClick={() => setF(null)}>{L('Cancel', 'Annuler')}</button><button className="btn btn-primary" disabled={!f || !Number(f.qty)} onClick={create}>{L('Record request', 'Enregistrer')}</button></>}>
        {f ? <div className="form-grid">
          <div className="field"><label>{L('Supplier', 'Fournisseur')}</label><select className="input" value={f.sup} onChange={(e) => { const s = e.target.value; const first = inv.find((i) => i.sup === s); setF({ ...f, sup: s, ing: first ? first.id : f.ing, po: '' }); }}>{D.suppliers.map((s) => <option key={s.id} value={s.id}>{s.name}</option>)}</select></div>
          <div className="field"><label>{L('Linked order', 'Commande liée')}</label><select className="input" value={f.po} onChange={(e) => setF({ ...f, po: e.target.value })}><option value="">{L('None', 'Aucune')}</option>{pos.filter((p) => p.sup === f.sup).map((p) => <option key={p.id}>{p.id}</option>)}</select></div>
          <div className="field span-2"><label>{L('Item', 'Article')}</label><select className="input" value={f.ing} onChange={(e) => setF({ ...f, ing: e.target.value })}>{inv.filter((i) => i.sup === f.sup).map((i) => <option key={i.id} value={i.id}>{i.name[lang]}</option>)}</select></div>
          <div className="field"><label>{L('Quantity', 'Quantité')} ({invMap[f.ing].unit})</label><input className="input" type="number" min="0" step="0.1" value={f.qty} onChange={(e) => setF({ ...f, qty: e.target.value })} /></div>
          <div className="field"><label>{L('Reason', 'Raison')}</label><select className="input" value={f.reason} onChange={(e) => setF({ ...f, reason: e.target.value })}>{Object.entries(O.returnReasons).map(([k, v]) => <option key={k} value={k}>{v[lang]}</option>)}</select></div>
          <div className="span-2 muted sm">{L('Credit expected', 'Crédit prévu')}: <b className="tnum">{fmt.money((Number(f.qty) || 0) * invMap[f.ing].cost)}</b> · {L('Photo upload arrives with the mobile app.', 'L’ajout de photo viendra avec l’app mobile.')}</div>
        </div> : null}
      </Modal>
    </div>
  );
}

function InvoiceScan() {
  const { L, lang, fmt, D, inv, setInv, invMap, ops, upd, invoices, setInvoices, toast, go } = useMizo();
  const [sel, setSel] = React.useState(ops.scans[0].id);
  const s = ops.scans.find((x) => x.id === sel);
  const sup = (id) => D.suppliers.find((x) => x.id === id).name;
  const flags = (sc) => { const out = []; sc.lines.forEach((l) => { if (!l.poQ) out.push({ ing: l.ing, k: 'extra', v: l.qty * l.price }); else { if (l.price > l.poP + 0.001) out.push({ ing: l.ing, k: 'price', v: (l.price - l.poP) * l.qty }); if (l.recv != null && l.recv < l.qty) out.push({ ing: l.ing, k: 'qty', v: (l.qty - l.recv) * l.price }); } }); if (sc.fee) out.push({ k: 'fee', v: sc.fee.v }); return out; };
  const total = (sc) => sc.lines.reduce((a, l) => a + l.qty * l.price, 0) + (sc.fee ? sc.fee.v : 0);
  const fl = flags(s);
  const all = ops.scans.filter((x) => x.status === 'review').flatMap(flags);
  const label = { price: L('Price higher than ordered', 'Prix plus élevé que commandé'), extra: L('Not on the purchase order', 'Absent du bon de commande'), qty: L('Billed more than received', 'Facturé plus que reçu'), fee: L('Fee not agreed', 'Frais non convenus') };
  const stl = { review: [L('To review', 'À vérifier'), 'warn'], disputed: [L('Disputed', 'Contesté'), 'neg'], posted: [L('Posted', 'Enregistrée'), 'pos'] };
  const setStatus = (status) => upd('scans', (sc) => sc.map((x) => (x.id === s.id ? { ...x, status } : x)));
  const post = () => {
    if (!invoices.some((v) => v.id === s.inv)) setInvoices([{ id: s.inv, sup: s.sup, date: s.date, amount: Math.round(total(s) * 100) / 100, lines: s.lines.length, status: 'due', dueIn: ops.supInfo[s.sup].terms }, ...invoices]);
    setInv(inv.map((i) => { const l = s.lines.find((x) => x.ing === i.id); return l && Math.abs(l.price - i.cost) > 0.001 ? { ...i, cost: l.price, hist: [...i.hist.slice(1), l.price], trend: Math.round(((l.price - i.hist[0]) / i.hist[0]) * 100) } : i; }));
    setStatus('posted'); toast(L(`${s.inv} posted to Invoices · costs updated`, `${s.inv} enregistrée · coûts mis à jour`));
  };
  return (
    <div className="page">
      <PageHead sub={L('Snap or forward an invoice, MIZO reads the lines and checks them against your order and what was received. This demo shows sample scans — reading your own invoices comes in Phase 2.', 'Photographiez ou transférez une facture, MIZO lit les lignes et les compare à la commande et à la réception. Démo : exemples de lecture — la lecture de vos factures arrive en phase 2.')}><SimTag /></PageHead>
      <section className="stats">
        <Stat label={L('To review', 'À vérifier')} value={ops.scans.filter((x) => x.status === 'review').length} tone="warn">{L('Read and matched', 'Lues et jumelées')}</Stat>
        <Stat label={L('Discrepancies', 'Écarts')} value={all.length} tone={all.length ? 'neg' : 'pos'}>{fmt.money(all.reduce((a, x) => a + x.v, 0))} {L('in question', 'en jeu')}</Stat>
        <Stat label={L('Forwarding address', 'Adresse de transfert')} value={<span className="sm-val">factures@souvlakivillage.ca</span>}>{L('Email inbox connects next phase', 'Boîte courriel : prochaine phase')}</Stat>
      </section>
      <section className="grid-1-2">
        <div className="panel panel-flush">
          <div className="drop" style={{ margin: '1rem', padding: '1.5rem 1rem' }}><Icon n="file-arrow-up" s="1.8rem" /><div className="drop-t">{L('Drop an invoice photo or PDF', 'Déposez une photo ou un PDF')}</div><div className="muted sm">{L('Reading uploaded files is part of the next phase. The examples below show how results will look.', 'La lecture des fichiers viendra à la prochaine phase. Les exemples montrent le résultat.')}</div></div>
          <ul className="opps">{ops.scans.map((x) => <li key={x.id}><button className={'opp' + (x.id === sel ? ' on' : '')} onClick={() => setSel(x.id)}><span className="rlist-main">{sup(x.sup)}<span className="muted sm">{x.inv} · {fmt.date(x.date)}</span></span><Pill tone={stl[x.status][1]}>{stl[x.status][0]}</Pill></button></li>)}</ul>
        </div>
        <div className="panel">
          <div className="panel-head"><div><div className="card-kicker">{s.file} · {L('read with', 'lu avec')} {s.conf}% {L('confidence', 'de confiance')}</div><h3>{sup(s.sup)} · {s.inv}</h3><p className="muted">{L('Matched to', 'Jumelé à')} {s.po} · {fmt.date(s.date, { weekday: 'short', month: 'short', day: 'numeric' })}</p></div><b className="big tnum">{fmt.money(total(s))}</b></div>
          <div className="table-scroll">
            <table className="table mtable reditor">
              <thead><tr><th>{L('Line', 'Ligne')}</th><th className="num">{L('Invoiced', 'Facturé')}</th><th className="num hide-sm">{L('Ordered', 'Commandé')}</th><th></th></tr></thead>
              <tbody>
                {s.lines.map((l) => { const f = fl.filter((x) => x.ing === l.ing); return (
                  <tr key={l.ing}><td><div className="cell-main">{invMap[l.ing].name[lang]}</div>{f.map((x) => <div key={x.k} className="cell-sub txt-neg">{label[x.k]} · {fmt.money(x.v)}</div>)}</td>
                    <td className="num tnum">{fmt.num(l.qty)} × {fmt.money(l.price)}{l.recv != null ? <div className="cell-sub">{L('received', 'reçu')} {fmt.num(l.recv)}</div> : null}</td><td className="num tnum hide-sm">{l.poQ ? `${fmt.num(l.poQ)} × ${fmt.money(l.poP)}` : '—'}</td>
                    <td>{f.length ? <Pill tone="neg"><Icon n="warning" /></Pill> : <Pill tone="pos"><Icon n="check" /></Pill>}</td></tr>
                ); })}
                {s.fee ? <tr><td><div className="cell-main">{s.fee.name[lang]}</div><div className="cell-sub txt-neg">{label.fee}</div></td><td className="num tnum">{fmt.money(s.fee.v)}</td><td className="num hide-sm">—</td><td><Pill tone="neg"><Icon n="warning" /></Pill></td></tr> : null}
              </tbody>
            </table>
          </div>
          {fl.length ? <div className="suggest warnbox"><Icon n="warning" /><div>{L(`${fl.length} issue${fl.length > 1 ? 's' : ''} worth ${fmt.money(fl.reduce((a, x) => a + x.v, 0))}. Call ${sup(s.sup)} before paying, or post it and accept the new prices.`, `${fl.length} écart(s) de ${fmt.money(fl.reduce((a, x) => a + x.v, 0))}. Appelez ${sup(s.sup)} avant de payer, ou acceptez les nouveaux prix.`)}</div></div> : <div className="suggest"><Icon n="check-circle" /><div>{L('Everything matches the order and the delivery.', 'Tout correspond à la commande et à la livraison.')}</div></div>}
          {s.status === 'posted' ? <span className="muted sm"><Icon n="check-circle" className="txt-pos" /> {L('Posted to Invoices', 'Enregistrée dans Factures')} · <button className="btn btn-ghost" onClick={() => go('purchasing', { tab: 'invoices' })}>{L('Open', 'Ouvrir')}</button></span> : (
            <div className="dr-row" style={{ justifyContent: 'flex-end', flexWrap: 'wrap' }}>
              {s.status !== 'disputed' && fl.length ? <button className="btn btn-secondary" onClick={() => { setStatus('disputed'); toast(L('Marked as disputed', 'Marquée contestée')); }}><Icon n="flag" />{L('Dispute', 'Contester')}</button> : null}
              <button className="btn btn-primary" onClick={post}><Icon n="check-circle" />{fl.some((x) => x.k === 'price') ? L('Accept prices and post', 'Accepter et enregistrer') : L('Approve and post', 'Approuver et enregistrer')}</button>
            </div>
          )}
        </div>
      </section>
    </div>
  );
}

function SupplierManager() {
  const { L, lang, fmt, D, inv, invMap, pos, invoices, ops, upd, toast } = useMizo();
  const [sel, setSel] = React.useState(null);
  const [build, setBuild] = React.useState(null);
  const [add, setAdd] = React.useState(null);
  const s = D.suppliers.find((x) => x.id === sel);
  const owed = (id) => invoices.filter((v) => v.sup === id && v.status !== 'paid').reduce((a, v) => a + v.amount, 0);
  const create = () => { const id = 's' + (D.suppliers.length + 1) + Date.now() % 100; D.suppliers.push({ id, name: add.name, cat: { en: add.cat, fr: add.cat }, contact: add.contact, phone: add.phone, city: 'Montréal', spend: 0, onTime: 100, next: { en: '—', fr: '—' } }); upd('supInfo', (si) => ({ ...si, [id]: { email: add.email, terms: Number(add.terms), min: Number(add.min), days: { en: '—', fr: '—' }, cutoff: { en: '—', fr: '—' }, rating: 0 } })); toast(L('Supplier added', 'Fournisseur ajouté')); setAdd(null); };
  return (
    <div className="page">
      <PageHead sub={L('Who you buy from, their terms, delivery days and what you owe them.', 'À qui vous achetez, leurs conditions, jours de livraison et ce que vous leur devez.')}>
        <button className="btn btn-primary" onClick={() => setAdd({ name: '', cat: '', contact: '', phone: '', email: '', terms: 15, min: 0 })}><Icon n="plus" />{L('Add supplier', 'Ajouter')}</button>
      </PageHead>
      <div className="panel panel-flush">
        <div className="table-scroll">
          <table className="table mtable">
            <thead><tr><th>{L('Supplier', 'Fournisseur')}</th><th className="hide-sm">{L('Delivers', 'Livre')}</th><th className="num hide-md">{L('Terms', 'Conditions')}</th><th className="num">{L('Spend · 30 days', 'Achats · 30 j')}</th><th className="num hide-sm">{L('On time', 'À l’heure')}</th><th className="num">{L('You owe', 'À payer')}</th></tr></thead>
            <tbody>{D.suppliers.map((x) => { const si = ops.supInfo[x.id] || {}; return (
              <tr key={x.id} className="clickable" onClick={() => setSel(x.id)}>
                <td><div className="emp-cell"><span className="sup-mono">{x.name.split(' ').map((w) => w[0]).join('').slice(0, 2)}</span><div><div className="cell-main">{x.name}</div><div className="cell-sub">{x.cat[lang]} · {x.contact}</div></div></div></td>
                <td className="hide-sm">{si.days ? si.days[lang] : '—'}</td><td className="num hide-md">{L('Net', 'Net')} {si.terms}</td><td className="num tnum">{fmt.money0(x.spend)}</td>
                <td className="num hide-sm"><Pill tone={x.onTime >= 95 ? 'pos' : x.onTime >= 90 ? 'warn' : 'neg'}>{x.onTime}%</Pill></td><td className="num tnum">{owed(x.id) ? fmt.money(owed(x.id)) : '—'}</td>
              </tr>
            ); })}</tbody>
          </table>
        </div>
      </div>
      <Drawer open={!!s} onClose={() => setSel(null)}>
        {s ? (() => { const si = ops.supInfo[s.id] || {}; const items = inv.filter((i) => i.sup === s.id); const orders = pos.filter((p) => p.sup === s.id).slice(0, 4); return (
          <div className="dr">
            <div className="dr-head"><div><div className="card-kicker">{s.cat[lang]}</div><h2>{s.name}</h2></div><button className="btn btn-icon btn-secondary" onClick={() => setSel(null)} aria-label="Close"><Icon n="x" /></button></div>
            <div className="dr-sec">
              <div className="dr-row"><span className="muted">{L('Contact', 'Contact')}</span><b>{s.contact}</b></div>
              <div className="dr-row"><span className="muted">{L('Phone', 'Téléphone')}</span><a href={'tel:' + s.phone}>{s.phone}</a></div>
              <div className="dr-row"><span className="muted">{L('Email', 'Courriel')}</span><a href={'mailto:' + si.email}>{si.email}</a></div>
            </div>
            <div className="dr-sec">
              <div className="dr-label">{L('Ordering', 'Commandes')}</div>
              <div className="dr-row"><span className="muted">{L('Delivery days', 'Jours de livraison')}</span><b>{si.days ? si.days[lang] : '—'}</b></div>
              <div className="dr-row"><span className="muted">{L('Order cut-off', 'Heure limite')}</span><b>{si.cutoff ? si.cutoff[lang] : '—'}</b></div>
              <div className="dr-row"><span className="muted">{L('Minimum order', 'Commande minimum')}</span><b className="tnum">{fmt.money0(si.min || 0)}</b></div>
              <div className="dr-row"><span className="muted">{L('Payment terms', 'Conditions')}</span><b>{L('Net', 'Net')} {si.terms} {L('days', 'jours')}</b></div>
              <button className="btn btn-primary" onClick={() => setBuild(s.id)}><Icon n="file-plus" />{L('New order', 'Nouvelle commande')}</button>
            </div>
            <div className="dr-sec"><div className="dr-label">{L('Items you buy here', 'Articles achetés ici')}</div>{items.map((i) => <div key={i.id} className="ln"><span>{i.name[lang]}</span><b>{fmt.money(i.cost)} / {i.unit}</b></div>)}{!items.length ? <span className="muted sm">—</span> : null}</div>
            <div className="dr-sec"><div className="dr-label">{L('Recent orders', 'Commandes récentes')}</div>{orders.map((p) => <div key={p.id} className="ln"><span>{p.id} · {fmt.date(p.expected)}</span><b>{fmt.money(poTotal(p, invMap))}</b></div>)}</div>
          </div>
        ); })() : null}
      </Drawer>
      <PoBuilder open={!!build} sup0={build} onClose={() => setBuild(null)} />
      <Modal open={!!add} onClose={() => setAdd(null)} title={L('Add supplier', 'Ajouter un fournisseur')} actions={<><button className="btn btn-secondary" onClick={() => setAdd(null)}>{L('Cancel', 'Annuler')}</button><button className="btn btn-primary" disabled={!add || !add.name.trim()} onClick={create}>{L('Add supplier', 'Ajouter')}</button></>}>
        {add ? <div className="form-grid">
          <div className="field span-2"><label>{L('Company name', 'Entreprise')}</label><input className="input" value={add.name} onChange={(e) => setAdd({ ...add, name: e.target.value })} /></div>
          <div className="field"><label>{L('What they supply', 'Ce qu’ils fournissent')}</label><input className="input" value={add.cat} onChange={(e) => setAdd({ ...add, cat: e.target.value })} placeholder={L('e.g. Seafood', 'ex. Poissonnerie')} /></div>
          <div className="field"><label>{L('Contact person', 'Personne-ressource')}</label><input className="input" value={add.contact} onChange={(e) => setAdd({ ...add, contact: e.target.value })} /></div>
          <div className="field"><label>{L('Phone', 'Téléphone')}</label><input className="input" value={add.phone} onChange={(e) => setAdd({ ...add, phone: e.target.value })} /></div>
          <div className="field"><label>{L('Email', 'Courriel')}</label><input className="input" type="email" value={add.email} onChange={(e) => setAdd({ ...add, email: e.target.value })} /></div>
          <div className="field"><label>{L('Payment terms (days)', 'Conditions (jours)')}</label><input className="input" type="number" value={add.terms} onChange={(e) => setAdd({ ...add, terms: e.target.value })} /></div>
          <div className="field"><label>{L('Minimum order (CAD)', 'Minimum (CAD)')}</label><input className="input" type="number" value={add.min} onChange={(e) => setAdd({ ...add, min: e.target.value })} /></div>
        </div> : null}
      </Modal>
    </div>
  );
}

Object.assign(window, { PoBuilder, Approvals, Returns, InvoiceScan, SupplierManager });
