mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-01 08:53:27 +00:00
fix(invoices): count every currency in total collected
"Total collected" added ETB to USD-converted-to-ETB and stopped there, so
money collected in any third currency was absent from the headline figure
while still sitting in the invoice list underneath. Same shape as the
overview dashboards fixed in 829918126.
Converts each non-birr currency at the live rate, falling back to that
currency's own stored rate when CBE is down, and adds the DJF tile beside
the existing ETB and USD ones.
A currency with no usable rate is left OUT of the total and the hint says
so, rather than being added at face value — treating 1 DJF as 1 ETB would
overstate it about a hundredfold, which is worse than an obviously
incomplete number.
This commit is contained in:
@@ -235,8 +235,33 @@ export default function InvoicesPanel() {
|
||||
const { data: exchangeSettings } = useExchangeSettingsQuery();
|
||||
const etbCollected = summary?.ETB ?? 0;
|
||||
const usdCollected = summary?.USD ?? 0;
|
||||
const rate = exchangeSettings?.feed?.rate ?? exchangeSettings?.fallbackRate;
|
||||
const etbFromUsd = rate ? usdCollected * rate : null;
|
||||
const djfCollected = summary?.DJF ?? 0;
|
||||
|
||||
/** Live rate when CBE is answering, this currency's stored fallback when it is not. */
|
||||
const rateFor = (code: string): number | null =>
|
||||
exchangeSettings?.feed?.rates?.[code] ??
|
||||
exchangeSettings?.currencies.find((c) => c.currency === code)?.fallbackRate ??
|
||||
null;
|
||||
|
||||
// Every non-birr currency converted into birr, so one headline figure covers the whole
|
||||
// book. A currency with no usable rate is left OUT of the total rather than added at
|
||||
// face value — silently treating 1 DJF as 1 ETB would overstate it ~100x.
|
||||
const foreign = [
|
||||
{ code: "USD", amount: usdCollected },
|
||||
{ code: "DJF", amount: djfCollected },
|
||||
]
|
||||
.filter((row) => row.amount > 0)
|
||||
.map((row) => ({ ...row, rate: rateFor(row.code) }));
|
||||
|
||||
const convertible = foreign.filter(
|
||||
(row): row is typeof row & { rate: number } => (row.rate ?? 0) > 0,
|
||||
);
|
||||
const etbFromForeign = convertible.reduce(
|
||||
(sum, row) => sum + row.amount * row.rate,
|
||||
0,
|
||||
);
|
||||
const totalHint = ["ETB", ...convertible.map((r) => r.code)].join(" + ");
|
||||
const unconverted = foreign.length - convertible.length;
|
||||
|
||||
const columns: ColumnDef<Invoice>[] = useMemo(
|
||||
() => [
|
||||
@@ -356,8 +381,11 @@ export default function InvoicesPanel() {
|
||||
items={[
|
||||
{
|
||||
label: "Total collected",
|
||||
hint: etbFromUsd !== null ? "ETB + USD" : "ETB only",
|
||||
value: formatMoney(etbCollected + (etbFromUsd ?? 0), "ETB"),
|
||||
hint:
|
||||
unconverted > 0
|
||||
? `${totalHint} — ${unconverted} currency without a rate excluded`
|
||||
: totalHint,
|
||||
value: formatMoney(etbCollected + etbFromForeign, "ETB"),
|
||||
icon: CircleDollarSign,
|
||||
color: "edr-green",
|
||||
},
|
||||
@@ -373,6 +401,12 @@ export default function InvoicesPanel() {
|
||||
icon: Landmark,
|
||||
color: "violet",
|
||||
},
|
||||
{
|
||||
label: "Collected in DJF",
|
||||
value: formatMoney(djfCollected, "DJF"),
|
||||
icon: Landmark,
|
||||
color: "grape",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user