feat(platform): checkpoint current implementation state
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildReportWorkbookSheets,
|
||||
buildResourceMonthExplainabilitySheetRows,
|
||||
} from "./reportBuilderExplainability.js";
|
||||
|
||||
describe("reportBuilderExplainability", () => {
|
||||
it("builds a readable explainability sheet for resource month reports", () => {
|
||||
const rows = buildResourceMonthExplainabilitySheetRows(
|
||||
{
|
||||
entity: "resource_month",
|
||||
periodMonth: "2026-01",
|
||||
locationContextColumns: ["countryCode", "federalState"],
|
||||
holidayMetricColumns: ["monthlyPublicHolidayCount"],
|
||||
absenceMetricColumns: ["monthlyAbsenceHoursDeduction"],
|
||||
capacityMetricColumns: ["monthlyBaseAvailableHours", "monthlySahHours"],
|
||||
chargeabilityMetricColumns: ["monthlyActualChargeabilityPct"],
|
||||
missingRecommendedColumns: ["countryName", "monthlyTargetHours"],
|
||||
notes: ["SAH is holiday-adjusted."],
|
||||
},
|
||||
(column) => ({
|
||||
countryCode: "Country Code",
|
||||
federalState: "Federal State",
|
||||
monthlyPublicHolidayCount: "Holiday Dates",
|
||||
monthlyAbsenceHoursDeduction: "Absence Hours Deduction",
|
||||
monthlyBaseAvailableHours: "Base Available Hours",
|
||||
monthlySahHours: "SAH",
|
||||
monthlyActualChargeabilityPct: "Actual Chargeability (%)",
|
||||
countryName: "Country",
|
||||
monthlyTargetHours: "Target Hours",
|
||||
}[column] ?? column),
|
||||
);
|
||||
|
||||
expect(rows).toEqual([
|
||||
["Resource Month Explainability"],
|
||||
["Period Month", "2026-01"],
|
||||
["Location Context Columns", "Country Code", "Federal State"],
|
||||
["Holiday Metric Columns", "Holiday Dates"],
|
||||
["Absence Metric Columns", "Absence Hours Deduction"],
|
||||
["Capacity Metric Columns", "Base Available Hours", "SAH"],
|
||||
["Chargeability Metric Columns", "Actual Chargeability (%)"],
|
||||
["Missing Recommended Columns", "Country", "Target Hours"],
|
||||
[],
|
||||
["Notes"],
|
||||
["SAH is holiday-adjusted."],
|
||||
]);
|
||||
});
|
||||
|
||||
it("adds grouped report rows and an explainability sheet to workbook output", () => {
|
||||
const sheets = buildReportWorkbookSheets({
|
||||
columns: ["displayName", "monthlySahHours"],
|
||||
rows: [
|
||||
{ displayName: "Alice", monthlySahHours: 160 },
|
||||
{ displayName: "Bob", monthlySahHours: 152 },
|
||||
],
|
||||
groups: [{ key: "BY", label: "Bayern", rowCount: 2, startIndex: 0 }],
|
||||
groupBy: "federalState",
|
||||
explainability: {
|
||||
entity: "resource_month",
|
||||
periodMonth: "2026-01",
|
||||
locationContextColumns: [],
|
||||
holidayMetricColumns: [],
|
||||
absenceMetricColumns: [],
|
||||
capacityMetricColumns: [],
|
||||
chargeabilityMetricColumns: [],
|
||||
missingRecommendedColumns: [],
|
||||
notes: [],
|
||||
},
|
||||
resolveColumnLabel: (column) => ({
|
||||
displayName: "Name",
|
||||
monthlySahHours: "SAH",
|
||||
federalState: "Federal State",
|
||||
}[column] ?? column),
|
||||
});
|
||||
|
||||
expect(sheets[0]).toEqual({
|
||||
name: "Report",
|
||||
rows: [
|
||||
["Name", "SAH"],
|
||||
["Federal State: Bayern (2)", ""],
|
||||
["Alice", 160],
|
||||
["Bob", 152],
|
||||
],
|
||||
});
|
||||
expect(sheets[1]?.name).toBe("Explainability");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
type WorkbookCellValue = boolean | Date | number | string | null | undefined;
|
||||
|
||||
export type ResourceMonthReportExplainability = {
|
||||
entity: "resource_month";
|
||||
periodMonth: string | null;
|
||||
locationContextColumns: string[];
|
||||
holidayMetricColumns: string[];
|
||||
absenceMetricColumns: string[];
|
||||
capacityMetricColumns: string[];
|
||||
chargeabilityMetricColumns: string[];
|
||||
missingRecommendedColumns: string[];
|
||||
notes: string[];
|
||||
};
|
||||
|
||||
export type ReportExplainability = ResourceMonthReportExplainability;
|
||||
|
||||
export type ReportExportSheet = {
|
||||
name: string;
|
||||
rows: WorkbookCellValue[][];
|
||||
};
|
||||
|
||||
type BuildReportWorkbookSheetsInput = {
|
||||
columns: string[];
|
||||
rows: Record<string, unknown>[];
|
||||
groups: Array<{ key: string; label: string; rowCount: number; startIndex: number }>;
|
||||
groupBy?: string;
|
||||
explainability?: ReportExplainability;
|
||||
resolveColumnLabel: (column: string) => string;
|
||||
};
|
||||
|
||||
export function buildResourceMonthExplainabilitySheetRows(
|
||||
explainability: ReportExplainability,
|
||||
resolveColumnLabel: (column: string) => string,
|
||||
): WorkbookCellValue[][] {
|
||||
const mapLabels = (columns: string[]) => (
|
||||
columns.length > 0 ? columns.map(resolveColumnLabel) : ["none"]
|
||||
);
|
||||
|
||||
return [
|
||||
["Resource Month Explainability"],
|
||||
["Period Month", explainability.periodMonth ?? "current month"],
|
||||
["Location Context Columns", ...mapLabels(explainability.locationContextColumns)],
|
||||
["Holiday Metric Columns", ...mapLabels(explainability.holidayMetricColumns)],
|
||||
["Absence Metric Columns", ...mapLabels(explainability.absenceMetricColumns)],
|
||||
["Capacity Metric Columns", ...mapLabels(explainability.capacityMetricColumns)],
|
||||
["Chargeability Metric Columns", ...mapLabels(explainability.chargeabilityMetricColumns)],
|
||||
["Missing Recommended Columns", ...mapLabels(explainability.missingRecommendedColumns)],
|
||||
[],
|
||||
["Notes"],
|
||||
...explainability.notes.map((note) => [note]),
|
||||
];
|
||||
}
|
||||
|
||||
export function buildReportWorkbookSheets(
|
||||
input: BuildReportWorkbookSheetsInput,
|
||||
): ReportExportSheet[] {
|
||||
const headerRow = input.columns.map(input.resolveColumnLabel);
|
||||
const groupStartByIndex = new Map(
|
||||
input.groups.map((group) => [group.startIndex, group] as const),
|
||||
);
|
||||
const groupByLabel = input.groupBy ? input.resolveColumnLabel(input.groupBy) : null;
|
||||
|
||||
const reportRows: WorkbookCellValue[][] = [headerRow];
|
||||
input.rows.forEach((row, index) => {
|
||||
const group = groupStartByIndex.get(index);
|
||||
if (group && groupByLabel) {
|
||||
reportRows.push([
|
||||
`${groupByLabel}: ${group.label} (${group.rowCount})`,
|
||||
...Array.from({ length: Math.max(0, input.columns.length - 1) }, () => ""),
|
||||
]);
|
||||
}
|
||||
|
||||
reportRows.push(input.columns.map((column) => {
|
||||
const value = row[column];
|
||||
if (value === undefined) {
|
||||
return "";
|
||||
}
|
||||
return value as WorkbookCellValue;
|
||||
}));
|
||||
});
|
||||
|
||||
const sheets: ReportExportSheet[] = [{ name: "Report", rows: reportRows }];
|
||||
if (input.explainability?.entity === "resource_month") {
|
||||
sheets.push({
|
||||
name: "Explainability",
|
||||
rows: buildResourceMonthExplainabilitySheetRows(input.explainability, input.resolveColumnLabel),
|
||||
});
|
||||
}
|
||||
|
||||
return sheets;
|
||||
}
|
||||
Reference in New Issue
Block a user