// §3.9 Rebate Monitor — Contracts, Tiers, Accrual, Settlement, Dashboard
function RebateMonitor({ user, perms }) {
const [tab, setTab] = useState("dashboard");
const [openRebate, setOpenRebate] = useState(null);
const [openSettlement, setOpenSettlement] = useState(false);
const tabs = [
{ id: "dashboard", label: "Dashboard" },
{ id: "contracts", label: "Rebate Contracts", count: REBATES.length },
{ id: "accrual", label: "Monthly Accrual" },
{ id: "settlement", label: "Settlements", count: SETTLEMENTS.filter(s => s.status !== "Settled").length },
];
return (
Export accruals
{(perms.admin || user.role === "procurement") && (
New rebate contract
)}
>
}
/>
{tab === "dashboard" && }
{tab === "contracts" && }
{tab === "accrual" && }
{tab === "settlement" && setOpenSettlement(true)} perms={perms} />}
{openRebate && setOpenRebate(null)} perms={perms} />}
{openSettlement && setOpenSettlement(false)} />}
);
}
function RebateKPIs() {
const totalUSD = REBATES.reduce((s, r) => s + r.accruedYTD, 0);
const atRisk = REBATES.filter(r => r.atRisk || r.currentTier === 0).length;
const eoyForecast = totalUSD * 2.4;
const unsettled = SETTLEMENTS.filter(s => s.status !== "Settled").reduce((acc, s) => acc + (s.accrued / (ROE[s.ccy] || 1)), 0);
return (
0 ? "trailing tier targets" : "all on pace"} deltaDir={atRisk > 0 ? "down" : "up"} />
s.status === "Overdue").length} overdue`} />
);
}
// ============== REBATE DASHBOARD ==============
function RebateDashboard({ onOpen }) {
return (
Updated 2 hours ago}>
{REBATES.filter(r => r.currentTier >= 0).map((r, i) => {
const ytd = YTD_VOLUME[r.terminal] || 18000;
const nextTier = r.tiers[r.currentTier];
const prevTier = r.tiers[r.currentTier - 1];
const min = prevTier?.max ? prevTier.max + 1 : 0;
const max = nextTier?.max || ytd * 1.4;
const pct = ((ytd - min) / (max - min)) * 100;
const uplift = r.accruedYTD * 0.4;
return (
0 ? "1px solid var(--line)" : 0, cursor: "pointer" }} onClick={() => onOpen(r)}>
{TERMINAL_BY_CODE[r.terminal]?.name}
{r.id}
{nextTier?.name || "Maxed"} @ {nextTier?.rate || "—"}%
70 ? "var(--green)" : pct > 30 ? "var(--teal)" : "var(--amber)" }} />
{fmt.num(ytd, 0)} TEU YTD
→ {fmt.num(max, 0)} TEU (next tier)
Reach next tier: +{fmt.usd(uplift)} uplift
);
})}
{REBATES.filter(r => r.atRisk || r.currentTier === 0).map((r, i) => (
0 ? "1px solid var(--line)" : 0, display: "flex", alignItems: "center", gap: 10 }}>
{TERMINAL_BY_CODE[r.terminal]?.name}
{r.id} · {r.type}
-{fmt.usd(54200)}
if missed
))}
Adjust assumptions}>
YTD actual
{fmt.usd(403800)}
EoY projection
{fmt.usd(969100)}
{/* mini chart */}
Pace assumption: +0.5% MoM · Tier 3 reached at Shanghai by Sep 2025 (forecast)
Region
Contracts
YTD Accrual (USD)
Prior Year YTD
% Change
Pace
{REGIONS.map(r => {
const contracts = REBATES.filter(rb => TERMINAL_BY_CODE[rb.terminal]?.region === r);
const accrued = contracts.reduce((s, c) => s + c.accruedYTD, 0);
const prior = accrued * 0.85;
const pct = ((accrued - prior) / prior) * 100;
return (
{r}
{contracts.length}
{fmt.usd(accrued)}
{fmt.usd(prior)}
0 ? "var(--green)" : "var(--red)" }}>
{pct > 0 ? "↑" : "↓"} {Math.abs(pct).toFixed(1)}%
);
})}
);
}
// ============== CONTRACTS LIST ==============
function RebateContracts({ onOpen }) {
return (
ID
Terminal
Contract Ref
Type
Scope
Period
Settlement
Current Tier
YTD Accrual
Status
{REBATES.map(r => (
onOpen(r)} style={{ cursor: "pointer" }}>
{r.id}
{TERMINAL_BY_CODE[r.terminal]?.name}
{r.terminal}
{r.contractRef}
{r.type}
{r.scope}
{r.period}
{r.settlement}
{r.tiers[r.currentTier]?.name.replace(" (Base)", "").replace(" (Elite)", "") || "—"}
@ {r.tiers[r.currentTier]?.rate}%
{fmt.usd(r.accruedYTD)}
{fmt.num(r.accruedYTDLocal)} {r.currency}
e.stopPropagation()}>
))}
);
}
// ============== ACCRUAL VIEW ==============
function AccrualView() {
// Build a monthly accrual matrix per rebate
const months = ["2025-01", "2025-02", "2025-03", "2025-04", "2025-05"];
return (
Recalculate all
Export to Excel
Rebate
Terminal
{months.map(m => {m} )}
YTD Total
Notes
{REBATES.map((r, ri) => {
const monthly = months.map((m, i) => Math.round(r.accruedYTD / months.length * (0.7 + (ri + i) % 8 / 10)));
const total = monthly.reduce((a, b) => a + b, 0);
const hasUpgrade = ri === 0;
return (
{r.id}
{r.type}
{TERMINAL_BY_CODE[r.terminal]?.name}
{monthly.map((v, i) => (
{fmt.usd(v)}
{i === 2 && hasUpgrade && ↑ Tier upgrade adj.
}
))}
{fmt.usd(total)}
{hasUpgrade ? "Mar: Tier 3 crossed, retroactive uplift" : ""}
);
})}
Auto-recalculation. Accruals refresh automatically after every Volume Tracker import.
For retroactive tiers, when a threshold is crossed mid-period, the system writes a Tier Upgrade Adjustment for the prior-period delta and logs it in the audit trail.
);
}
// ============== SETTLEMENT ==============
function SettlementTracker({ onNew, perms }) {
return (
{(perms.admin || true) &&
Log settlement}
Export for ERP
ID
Rebate
Period
Calculated
Claimed
Variance
Claimed Date
Settled Date
Reference
Status
{SETTLEMENTS.map(s => (
{s.id}
{s.rebate}
{s.period}
{fmt.num(s.accrued, 0)} {s.ccy}
{fmt.num(s.claimed, 0)} {s.ccy}
5 ? "var(--amber)" : "var(--ink-mute)", fontWeight: Math.abs(s.variance) > 5 ? 600 : 400 }}>
{s.variance === 0 ? "—" : (s.variance > 0 ? "+" : "") + s.variance.toFixed(1) + "%"}
{s.claimedDate}
{s.settledDate || "—"}
{s.ref}
{s.status === "Settled" && Settled }
{s.status === "Awaiting Credit" && Awaiting Credit }
{s.status === "In Review" && In Review }
{s.status === "Overdue" && Overdue · {s.daysOverdue}d }
))}
);
}
// ============== REBATE DETAIL ==============
function RebateDetail({ rebate, onClose, perms }) {
const t = TERMINAL_BY_CODE[rebate.terminal];
const ytd = YTD_VOLUME[rebate.terminal] || 0;
return (
Close
{perms.admin && Edit terms }
{perms.admin && Log settlement }
>
}
>
YTD Accrual
{fmt.usd(rebate.accruedYTD)}
{fmt.num(rebate.accruedYTDLocal)} {rebate.currency}
YTD Volume
{fmt.num(ytd, 0)} TEU
Current Tier
{rebate.tiers[rebate.currentTier]?.name || "—"}
@ {rebate.tiers[rebate.currentTier]?.rate}%
Add tier : null}
style={{ marginBottom: 16 }}>
Tier
Min Volume
Max Volume
Rate
Type
Status
{rebate.tiers.map((t, i) => (
{t.name}
{fmt.num(t.min, 0)}
{t.max ? fmt.num(t.max, 0) : "∞"}
{t.rate.toFixed(1)}%
{t.type}
{i === rebate.currentTier ? Current : i < rebate.currentTier ? ✓ achieved : pending }
))}
{t?.name} ({rebate.terminal}) >} />
{rebate.effective} → {rebate.expiry}} />
{rebate.currency}} />
);
}
function NewSettlement({ onClose }) {
return (
Cancel
Submit for review
>
}
>
);
}
Object.assign(window, { RebateMonitor });