feat(api): explain chargeability derivation inputs
This commit is contained in:
@@ -168,12 +168,62 @@ export const chargeabilityReportDetailInputSchema = chargeabilityReportInputSche
|
||||
|
||||
type ChargeabilityReportInput = z.infer<typeof chargeabilityReportInputSchema>;
|
||||
type ChargeabilityReportDetailInput = z.infer<typeof chargeabilityReportDetailInputSchema>;
|
||||
type ChargeabilityExplainabilityInput = ChargeabilityReportInput & {
|
||||
resourceQuery?: string | undefined;
|
||||
resourceLimit?: number | undefined;
|
||||
};
|
||||
|
||||
type ChargeabilityReportDbClient = Pick<
|
||||
PrismaClient,
|
||||
"assignment" | "resource" | "project" | "vacation" | "holidayCalendar" | "systemSettings"
|
||||
>;
|
||||
|
||||
const CHARGEABILITY_LOCATION_FIELDS = [
|
||||
"country",
|
||||
"federalState",
|
||||
"city",
|
||||
"orgUnit",
|
||||
"managementLevelGroup",
|
||||
"managementLevel",
|
||||
] as const;
|
||||
|
||||
const CHARGEABILITY_DERIVATION_FIELDS = [
|
||||
"baseAvailableHours",
|
||||
"publicHolidayCount",
|
||||
"publicHolidayWorkdayCount",
|
||||
"publicHolidayHoursDeduction",
|
||||
"absenceDayEquivalent",
|
||||
"absenceHoursDeduction",
|
||||
"effectiveAvailableHours",
|
||||
] as const;
|
||||
|
||||
function buildChargeabilityExplainability(input: ChargeabilityExplainabilityInput) {
|
||||
const activeFilters = [
|
||||
...(input.orgUnitId ? ["orgUnitId"] : []),
|
||||
...(input.managementLevelGroupId ? ["managementLevelGroupId"] : []),
|
||||
...(input.countryId ? ["countryId"] : []),
|
||||
...(input.resourceQuery ? ["resourceQuery"] : []),
|
||||
...(input.includeProposed ? ["includeProposed"] : []),
|
||||
];
|
||||
|
||||
return {
|
||||
locationFields: [...CHARGEABILITY_LOCATION_FIELDS],
|
||||
monthDerivationFields: [...CHARGEABILITY_DERIVATION_FIELDS],
|
||||
activeFilters,
|
||||
formulas: {
|
||||
sah: "baseAvailableHours - publicHolidayHoursDeduction - absenceHoursDeduction = effectiveAvailableHours",
|
||||
chargeabilityPct: "chargeabilityHours / sahHours",
|
||||
targetHours: "sahHours * targetPct",
|
||||
gapHours: "chargeabilityHours - targetHours",
|
||||
},
|
||||
notes: [
|
||||
"Location fields explain why two resources can have different SAH in the same month because country, federal state, and city holidays may differ.",
|
||||
"Holiday deductions and absence deductions are tracked separately; absence does not deduct days that are already public holidays.",
|
||||
"Include proposed work changes chargeability ratios and hours, but it does not change holiday or absence-based SAH derivation.",
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
async function queryChargeabilityReport(
|
||||
db: ChargeabilityReportDbClient,
|
||||
input: ChargeabilityReportInput,
|
||||
@@ -227,6 +277,7 @@ async function queryChargeabilityReport(
|
||||
chargeabilityRatio: 0,
|
||||
targetRatio: 0,
|
||||
})),
|
||||
explainability: buildChargeabilityExplainability(input),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -388,6 +439,7 @@ async function queryChargeabilityReport(
|
||||
monthKeys,
|
||||
resources: anonymizeResources(resourceRows, directory),
|
||||
groupTotals,
|
||||
explainability: buildChargeabilityExplainability(input),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -462,6 +514,7 @@ export function buildChargeabilityReportDetail(
|
||||
resourceCount: matchingResources.length,
|
||||
returnedResourceCount: resources.length,
|
||||
truncated: resources.length < matchingResources.length,
|
||||
explainability: buildChargeabilityExplainability(input),
|
||||
resources,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user