109 lines
3.2 KiB
TypeScript
109 lines
3.2 KiB
TypeScript
import { getInvoicePeriodDate, matchesInvoicePeriod } from "./invoicePeriod";
|
|
|
|
export type AnalyticsInvoice = {
|
|
invoiceDate?: Date | string | number | null;
|
|
createdAt?: Date | string | number | null;
|
|
isSubscription?: number | null;
|
|
status?: string | null;
|
|
supplierName?: string | null;
|
|
totalAmount?: number | string | null;
|
|
};
|
|
|
|
export type AnnualInvoiceSummary = {
|
|
year: number;
|
|
bapCount: number;
|
|
bapAmount: number;
|
|
subscriptionCount: number;
|
|
subscriptionAmount: number;
|
|
totalAmount: number;
|
|
};
|
|
|
|
export type SupplierBudgetSummary = {
|
|
supplierName: string;
|
|
subscriptionCount: number;
|
|
subscriptionAmount: number;
|
|
nonSubscriptionCount: number;
|
|
nonSubscriptionAmount: number;
|
|
totalAmount: number;
|
|
};
|
|
|
|
function getAmount(value: AnalyticsInvoice["totalAmount"]): number {
|
|
const amount = Number(value);
|
|
return Number.isFinite(amount) ? amount : 0;
|
|
}
|
|
|
|
/**
|
|
* Agrège les factures finalisées par année métier. « BAP » désigne ici les
|
|
* factures hors abonnement, éligibles au circuit BAP, validées ou non.
|
|
*/
|
|
export function buildAnnualInvoiceSummary(invoices: AnalyticsInvoice[]): AnnualInvoiceSummary[] {
|
|
const summaryByYear = new Map<number, AnnualInvoiceSummary>();
|
|
|
|
for (const invoice of invoices) {
|
|
if (invoice.status !== "completed") continue;
|
|
const date = getInvoicePeriodDate(invoice);
|
|
if (!date) continue;
|
|
|
|
const year = date.getFullYear();
|
|
const current = summaryByYear.get(year) ?? {
|
|
year,
|
|
bapCount: 0,
|
|
bapAmount: 0,
|
|
subscriptionCount: 0,
|
|
subscriptionAmount: 0,
|
|
totalAmount: 0,
|
|
};
|
|
const amount = getAmount(invoice.totalAmount);
|
|
|
|
if (invoice.isSubscription === 1) {
|
|
current.subscriptionCount += 1;
|
|
current.subscriptionAmount += amount;
|
|
} else {
|
|
current.bapCount += 1;
|
|
current.bapAmount += amount;
|
|
}
|
|
current.totalAmount += amount;
|
|
summaryByYear.set(year, current);
|
|
}
|
|
|
|
return Array.from(summaryByYear.values()).sort((a, b) => b.year - a.year);
|
|
}
|
|
|
|
/** Agrège le budget réellement facturé par fournisseur sur la période choisie. */
|
|
export function buildSupplierBudgetSummary(
|
|
invoices: AnalyticsInvoice[],
|
|
year: string,
|
|
month: string,
|
|
): SupplierBudgetSummary[] {
|
|
const summaryBySupplier = new Map<string, SupplierBudgetSummary>();
|
|
|
|
for (const invoice of invoices) {
|
|
if (invoice.status !== "completed" || !matchesInvoicePeriod(invoice, year, month)) continue;
|
|
|
|
const supplierName = invoice.supplierName?.trim() || "Fournisseur inconnu";
|
|
const current = summaryBySupplier.get(supplierName) ?? {
|
|
supplierName,
|
|
subscriptionCount: 0,
|
|
subscriptionAmount: 0,
|
|
nonSubscriptionCount: 0,
|
|
nonSubscriptionAmount: 0,
|
|
totalAmount: 0,
|
|
};
|
|
const amount = getAmount(invoice.totalAmount);
|
|
|
|
if (invoice.isSubscription === 1) {
|
|
current.subscriptionCount += 1;
|
|
current.subscriptionAmount += amount;
|
|
} else {
|
|
current.nonSubscriptionCount += 1;
|
|
current.nonSubscriptionAmount += amount;
|
|
}
|
|
current.totalAmount += amount;
|
|
summaryBySupplier.set(supplierName, current);
|
|
}
|
|
|
|
return Array.from(summaryBySupplier.values()).sort((a, b) =>
|
|
b.totalAmount - a.totalAmount || a.supplierName.localeCompare(b.supplierName, "fr"),
|
|
);
|
|
}
|