/** * Matches backend/app/main.py helpers used in _notify_tenant_admins_deal_won (won-deal email body). */ export function wonCurrencyLabel(raw) { const c = String(raw || 'USD').trim().toUpperCase(); return c === 'CAD' ? 'CAD' : 'USD'; } export function fmtWonMoney(amount, currencyRaw) { const lab = wonCurrencyLabel(currencyRaw); const sym = lab === 'CAD' ? 'CA$' : '$'; let n = Number(amount); if (!Number.isFinite(n)) n = 0; const s = n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); return `${sym}${s} ${lab}`; } export function wonBillingIntervalLabel(raw) { const s = String(raw || 'monthly').trim().toLowerCase(); if (['one_time', 'onetime', 'one-time', 'non-recurring'].includes(s)) return 'One-time'; if (['quarterly', 'quarter', 'every 3 months'].includes(s)) return 'Every 3 months'; if (['annual', 'year', 'yearly', 'every year'].includes(s)) return 'Every year'; return 'Every month'; } /** Python {:g}-style qty for line display */ export function fmtQtyG(qf) { if (!Number.isFinite(qf)) return '0'; return Number.isInteger(qf) ? String(qf) : String(qf); } /** * One numbered line item line, same text as the admin email (excluding leading newline). */ export function wonEmailLineItemBodyLine(index1, li) { const ps = String(li.product_service || '').trim(); const cur = wonCurrencyLabel(li.currency); let qf = Number(li.qty); let rf = Number(li.rate); let af = Number(li.amount); if (!Number.isFinite(qf)) qf = 0; if (!Number.isFinite(rf)) rf = 0; if (!Number.isFinite(af)) af = 0; const cadence = wonBillingIntervalLabel(li.billing_interval); return ` ${index1}. ${ps} | ${cadence} | Qty ${fmtQtyG(qf)} × ${fmtWonMoney(rf, cur)} = ${fmtWonMoney(af, cur)}`; } export function wonEmailSubtotalLine(lines, subtotal) { const st = Number(subtotal); const sum = Number.isFinite(st) ? st : 0; if (!lines?.length) { return `Subtotal: ${sum.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; } const distinct = new Set(lines.map((li) => wonCurrencyLabel(li.currency))); if (distinct.size === 1) { const only = distinct.values().next().value; return `Subtotal: ${fmtWonMoney(sum, only)}`; } return `Subtotal (numeric sum of line amounts; USD and CAD lines are not converted between currencies): ${sum.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; }