refactor(api): extract vacation chargeability helpers

This commit is contained in:
2026-03-31 11:08:58 +02:00
parent 3e0d9d9af7
commit 656c3d0ee5
3 changed files with 219 additions and 156 deletions
@@ -0,0 +1,84 @@
import { TRPCError } from "@trpc/server";
import { countCalendarDaysInPeriod } from "../lib/vacation-day-count.js";
import {
VACATION_BALANCE_TYPES,
buildVacationDeductionSnapshotWriteData,
calculateVacationDeductionSnapshot,
type VacationChargeableInput,
} from "../lib/vacation-deduction-snapshot.js";
import type { TRPCContext } from "../trpc.js";
type VacationDb = TRPCContext["db"];
type VacationDeductionWriteData = ReturnType<typeof buildVacationDeductionSnapshotWriteData>;
export async function calculateVacationEffectiveDays(
db: VacationDb,
vacation: VacationChargeableInput,
): Promise<number> {
if (!VACATION_BALANCE_TYPES.has(vacation.type)) {
return countCalendarDaysInPeriod(vacation);
}
const snapshot = await calculateVacationDeductionSnapshot(db, vacation);
return snapshot.deductedDays;
}
export async function assertVacationStillChargeable(
db: VacationDb,
vacation: VacationChargeableInput,
): Promise<void> {
if (!VACATION_BALANCE_TYPES.has(vacation.type)) {
return;
}
const effectiveDays = await calculateVacationEffectiveDays(db, vacation);
if (effectiveDays <= 0) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Vacation no longer deducts any vacation days for the current holiday calendar and cannot be approved",
});
}
}
export async function resolveVacationCreationChargeability(
db: VacationDb,
vacation: VacationChargeableInput,
): Promise<{
effectiveDays: number | null;
deductionSnapshotWriteData: VacationDeductionWriteData | null;
}> {
if (!VACATION_BALANCE_TYPES.has(vacation.type)) {
return {
effectiveDays: null,
deductionSnapshotWriteData: null,
};
}
const deductionSnapshot = await calculateVacationDeductionSnapshot(db, vacation);
const effectiveDays = deductionSnapshot.deductedDays;
if (effectiveDays <= 0) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Selected vacation period only contains public holidays and does not deduct any vacation days",
});
}
return {
effectiveDays,
deductionSnapshotWriteData: buildVacationDeductionSnapshotWriteData(deductionSnapshot),
};
}
export async function buildVacationApprovalWriteData(
db: VacationDb,
vacation: VacationChargeableInput,
): Promise<VacationDeductionWriteData | { deductedDays: 0 }> {
if (!VACATION_BALANCE_TYPES.has(vacation.type)) {
return { deductedDays: 0 };
}
return buildVacationDeductionSnapshotWriteData(
await calculateVacationDeductionSnapshot(db, vacation),
);
}