feat(offers,invoices): per-currency 'Celkem' totals beneath the lists (consistent with orders)
Mirrors the orders totals exactly: /stats (offers) + /list-totals (issued + received invoices) endpoints sum each doc's total per currency across the active filter (reusing extracted where-builders so they stay in sync with the lists), rendered as the identical 'Celkem: …' block via the shared formatMultiCurrency. Existing invoice/received KPI stats untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -192,6 +192,31 @@ export const invoiceStatsOptions = (month: number, year: number) =>
|
||||
),
|
||||
});
|
||||
|
||||
// Per-currency total over the WHOLE filtered set of the ISSUED-invoice list.
|
||||
// Distinct from `invoiceStatsOptions` (the KPI cards) — hits /list-totals and
|
||||
// passes the same filters the issued list uses (search/status/month/year).
|
||||
export const invoiceTotalsOptions = (filters: {
|
||||
search?: string;
|
||||
status?: string;
|
||||
month?: number;
|
||||
year?: number;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: ["invoices", "list-totals", filters],
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams();
|
||||
if (filters.search) params.set("search", filters.search);
|
||||
if (filters.status) params.set("status", filters.status);
|
||||
if (filters.month) params.set("month", String(filters.month));
|
||||
if (filters.year) params.set("year", String(filters.year));
|
||||
const qs = params.toString();
|
||||
const data = await jsonQuery<{ totals?: CurrencyAmount[] }>(
|
||||
`/api/admin/invoices/list-totals${qs ? `?${qs}` : ""}`,
|
||||
);
|
||||
return data.totals ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
export const receivedInvoiceStatsOptions = (month: number, year: number) =>
|
||||
queryOptions({
|
||||
queryKey: ["invoices", "received", "stats", month, year],
|
||||
@@ -201,6 +226,30 @@ export const receivedInvoiceStatsOptions = (month: number, year: number) =>
|
||||
),
|
||||
});
|
||||
|
||||
// Per-currency total over the WHOLE filtered set of the received-invoice list.
|
||||
// Distinct from `receivedInvoiceStatsOptions` (the KPI cards) — hits
|
||||
// /list-totals and passes the same filters the received list uses
|
||||
// (month/year/search). `amount` is GROSS (VAT-inclusive).
|
||||
export const receivedInvoiceTotalsOptions = (filters: {
|
||||
month?: number;
|
||||
year?: number;
|
||||
search?: string;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: ["invoices", "received", "list-totals", filters],
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams();
|
||||
if (filters.month) params.set("month", String(filters.month));
|
||||
if (filters.year) params.set("year", String(filters.year));
|
||||
if (filters.search) params.set("search", filters.search);
|
||||
const qs = params.toString();
|
||||
const data = await jsonQuery<{ totals?: CurrencyAmount[] }>(
|
||||
`/api/admin/received-invoices/list-totals${qs ? `?${qs}` : ""}`,
|
||||
);
|
||||
return data.totals ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
export const invoiceDetailOptions = (id: string | undefined) =>
|
||||
queryOptions({
|
||||
queryKey: ["invoices", id],
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
import { jsonQuery, paginatedJsonQuery } from "../apiAdapter";
|
||||
|
||||
export interface CurrencyAmount {
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface ItemTemplate {
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -91,6 +96,27 @@ export const offerListOptions = (filters: {
|
||||
},
|
||||
});
|
||||
|
||||
export const offerStatsOptions = (filters: {
|
||||
search?: string;
|
||||
status?: string;
|
||||
customer_id?: number;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: ["offers", "stats", filters],
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams();
|
||||
if (filters.search) params.set("search", filters.search);
|
||||
if (filters.status) params.set("status", filters.status);
|
||||
if (filters.customer_id)
|
||||
params.set("customer_id", String(filters.customer_id));
|
||||
const qs = params.toString();
|
||||
const data = await jsonQuery<{ totals?: CurrencyAmount[] }>(
|
||||
`/api/admin/offers/stats${qs ? `?${qs}` : ""}`,
|
||||
);
|
||||
return data.totals ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
export interface OfferItemData {
|
||||
id?: number;
|
||||
description: string;
|
||||
|
||||
Reference in New Issue
Block a user