feat: calculation rules engine for decoupled cost attribution and chargeability
Introduces an admin-configurable rules engine that determines per-day cost attribution (CHARGE/ZERO/REDUCE) and chargeability reporting (COUNT/SKIP) for absence types (sick, vacation, public holiday). Includes shared types, Zod schemas, Prisma model, rule matching with specificity scoring, default rules, calculator integration, CRUD API router, seed data, chargeability report integration, and admin UI. 283/283 engine tests, 209/209 API tests, 0 TS errors. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -23,6 +23,9 @@ export interface AssignmentSlice {
|
||||
workingDays: number;
|
||||
/** Utilization category code (e.g. "Chg", "BD", "MD&I", "M&O", "PD&R"). */
|
||||
categoryCode: string;
|
||||
/** Override total hours for this slice (e.g. when rules adjust chargeable hours).
|
||||
* When set, used instead of hoursPerDay * workingDays. */
|
||||
totalChargeableHours?: number;
|
||||
}
|
||||
|
||||
export interface ResourceForecast {
|
||||
@@ -58,10 +61,10 @@ export function deriveResourceForecast(input: ResourceForecastInput): ResourceFo
|
||||
return { chg: 0, bd: 0, mdi: 0, mo: 0, pdr: 0, absence: 0, unassigned: 1 };
|
||||
}
|
||||
|
||||
// Sum hours per category
|
||||
// Sum hours per category (use totalChargeableHours when available for rules-adjusted values)
|
||||
const categoryHours: Record<string, number> = {};
|
||||
for (const a of assignments) {
|
||||
const hours = a.hoursPerDay * a.workingDays;
|
||||
const hours = a.totalChargeableHours ?? (a.hoursPerDay * a.workingDays);
|
||||
const key = a.categoryCode.toLowerCase();
|
||||
categoryHours[key] = (categoryHours[key] ?? 0) + hours;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user