feat(sp27): server-aggregate Remittances KPIs (count, paid, adjustments)
The Remittances page's three KPI tiles — REMITS / TOTAL PAID / ADJUSTMENTS — were computed page-locally via items.reduce(...) over the merged tail of the current page + live delta. With a 100-row default limit, a 1,739-row population showed count=100, paid=$16,934, adjustments=$147 — silently understating reality because the page hadn't loaded the remaining rows yet. This change mirrors the silent-incompleteness fix that /api/dashboard/kpis (commit59c3275) and /api/remittances (commitd81b6ed) made for their tiles: * CycloneStore.summarize_remittances() iterates the full filtered remittance population (no limit) and returns {count, total_paid, total_adjustments}. Mirrors iter_remittances with limit=_ITER_UNBOUNDED. * GET /api/remittances/summary — server endpoint with the same filter parameters as /api/remittances. Registered BEFORE the /api/remittances/stream handler so FastAPI doesn't treat 'summary' as a stream sub-path. * api.listRemittanceSummary + useRemittanceSummary hook. * Remittances.tsx swaps off items.reduce, consumes the server summary. Tiles render the server totals so the values reflect the entire DB population, not the page-local sample. Verified live: /api/remittances/summary returns {count: 1739, total_paid: 227181.58, total_adjustments: 13792.65}, which matches DB ground truth exactly. Tests: 8 new backend tests in test_api_remittances_summary.py; 1 new frontend test in Remittances.test.tsx (kpi_tiles_use_server_summary_not _page_local_reduce) plus the page-level test for the zero-valued mock default.
This commit is contained in:
@@ -651,6 +651,28 @@ async function listRemittances<T = unknown>(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-aggregated KPI tiles for the Remittances page. Returns the
|
||||
* full-population ``count``, ``total_paid``, and ``total_adjustments``
|
||||
* — NOT a page-limited sample — so the KPI tiles can't silently
|
||||
* understate the true DB population the way a page-local
|
||||
* ``items.reduce(...)`` would (commits ``59c3275``, ``d81b6ed``).
|
||||
*/
|
||||
export interface RemittanceSummary {
|
||||
count: number;
|
||||
total_paid: number;
|
||||
total_adjustments: number;
|
||||
}
|
||||
|
||||
async function listRemittanceSummary(
|
||||
params: ListRemittancesParams = {}
|
||||
): Promise<RemittanceSummary> {
|
||||
if (!isConfigured) throw notConfiguredError();
|
||||
return authedFetch<RemittanceSummary>(
|
||||
`/api/remittances/summary${qs(params as Record<string, unknown>)}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch one remittance with its labeled CAS `adjustments` array.
|
||||
* Throws `ApiError` on 404 so callers can branch on `.status`.
|
||||
@@ -1029,6 +1051,7 @@ export const api = {
|
||||
serializeClaim837,
|
||||
exportBatch837,
|
||||
listRemittances,
|
||||
listRemittanceSummary,
|
||||
getRemittance,
|
||||
listProviders,
|
||||
getProvider,
|
||||
|
||||
Reference in New Issue
Block a user