Give the analytics overview a per-parent, per-year balance series

Each parent projection now carries one entry per calendar year from
birth to the fourth birthday: vacation earned, carried in, planned,
left, carried out and expiring under Semesterlagen's 20-day floor and
5-year carry-over, plus parental-leave days used and left at year end
with the age-4 clamp applied in the birthday year. The overview sums
them into per-year totals. Frontend types, mapper and fixtures follow.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBRLomdLK9jF7wU7a8AA6H
This commit is contained in:
2026-09-19 19:02:02 +02:00
parent dbef997da4
commit 4b802ba0be
14 changed files with 1365 additions and 37 deletions
+84
View File
@@ -38,6 +38,10 @@ import type {
PersonalData,
CalendarWindow,
CalendarDayEntry,
VacationYearBalance,
ParentalLeaveYearBalance,
ParentYearBalance,
YearTotals,
} from '@/types'
const BASE = '/api'
@@ -106,6 +110,82 @@ function toParentalLeaveFetch(raw: RawParentalLeaveFetch): ParentalLeaveFetch {
}
}
export interface RawVacationYearBalance {
year: number
earned: number
is_assumed: boolean
carried_in: number
planned_use: number
left: number
carried_out: number
expiring: number
}
function toVacationYearBalance(raw: RawVacationYearBalance): VacationYearBalance {
return {
year: raw.year,
earned: raw.earned,
isAssumed: raw.is_assumed,
carriedIn: raw.carried_in,
plannedUse: raw.planned_use,
left: raw.left,
carriedOut: raw.carried_out,
expiring: raw.expiring,
}
}
export interface RawParentalLeaveYearBalance {
year: number
sjukpenning_used: number
lagsta_used: number
sjukpenning_left: number
lagsta_left: number
}
function toParentalLeaveYearBalance(
raw: RawParentalLeaveYearBalance,
): ParentalLeaveYearBalance {
return {
year: raw.year,
sjukpenningUsed: raw.sjukpenning_used,
lagstaUsed: raw.lagsta_used,
sjukpenningLeft: raw.sjukpenning_left,
lagstaLeft: raw.lagsta_left,
}
}
export interface RawParentYearBalance {
personal_data_uuid: string
child_id: string
year: number
vacation: RawVacationYearBalance
parental_leave: RawParentalLeaveYearBalance
}
function toParentYearBalance(raw: RawParentYearBalance): ParentYearBalance {
return {
personalDataUuid: raw.personal_data_uuid,
childId: raw.child_id,
year: raw.year,
vacation: toVacationYearBalance(raw.vacation),
parentalLeave: toParentalLeaveYearBalance(raw.parental_leave),
}
}
export interface RawYearTotals {
year: number
pl_left: number
vacation_left: number
}
function toYearTotals(raw: RawYearTotals): YearTotals {
return {
year: raw.year,
plLeft: raw.pl_left,
vacationLeft: raw.vacation_left,
}
}
export interface RawAge4Projection {
personal_data_uuid: string
child_id: string
@@ -118,6 +198,7 @@ export interface RawAge4Projection {
savable_after_b4: number
expiring_at_b4: number
savable_cap_at_b4: number
year_balances: RawParentYearBalance[]
}
function toAge4Projection(raw: RawAge4Projection): Age4Projection {
@@ -133,6 +214,7 @@ function toAge4Projection(raw: RawAge4Projection): Age4Projection {
savableAfterB4: raw.savable_after_b4,
expiringAtB4: raw.expiring_at_b4,
savableCapAtB4: raw.savable_cap_at_b4,
yearBalances: raw.year_balances.map(toParentYearBalance),
}
}
@@ -143,6 +225,7 @@ export interface RawWorkspaceOverview {
combined_days_used: number
combined_days_left: number
combined_expiring_at_b4: number
year_totals: RawYearTotals[]
}
function toWorkspaceOverview(raw: RawWorkspaceOverview): WorkspaceOverview {
@@ -153,6 +236,7 @@ function toWorkspaceOverview(raw: RawWorkspaceOverview): WorkspaceOverview {
combinedDaysUsed: raw.combined_days_used,
combinedDaysLeft: raw.combined_days_left,
combinedExpiringAtB4: raw.combined_expiring_at_b4,
yearTotals: raw.year_totals.map(toYearTotals),
}
}