feat(leave) : phase-aware leave tab loading

This commit is contained in:
2026-05-19 11:46:24 +02:00
parent ac53bbd5a1
commit 2730e34f31

View File

@@ -1,5 +1,6 @@
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { Absence } from '~/services/dto/absence' import type { Absence } from '~/services/dto/absence'
import type { ContractPhase } from '~/services/dto/contract-phase'
import type { EmployeeLeaveSummary } from '~/services/dto/employee-leave-summary' import type { EmployeeLeaveSummary } from '~/services/dto/employee-leave-summary'
import type { Employee } from '~/services/dto/employee' import type { Employee } from '~/services/dto/employee'
import { CONTRACT_TYPES } from '~/services/dto/contract' import { CONTRACT_TYPES } from '~/services/dto/contract'
@@ -12,7 +13,11 @@ export type LeaveYearOption = {
label: string label: string
} }
export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee: () => Promise<void>) => { export const useEmployeeLeave = (
employee: Ref<Employee | null>,
reloadEmployee: () => Promise<void>,
selectedPhase: Ref<ContractPhase | null>,
) => {
const employeeAbsences = ref<Absence[]>([]) const employeeAbsences = ref<Absence[]>([])
const leaveSummary = ref<EmployeeLeaveSummary | null>(null) const leaveSummary = ref<EmployeeLeaveSummary | null>(null)
const publicHolidays = ref<Record<string, string>>({}) const publicHolidays = ref<Record<string, string>>({})
@@ -20,17 +25,18 @@ export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee:
const leaveDataLoaded = ref(false) const leaveDataLoaded = ref(false)
const selectedLeaveYear = ref<number | null>(null) const selectedLeaveYear = ref<number | null>(null)
const isForfaitContract = (emp: Employee | null) => const isForfaitOnPhase = computed(() =>
emp?.contract?.type === CONTRACT_TYPES.FORFAIT selectedPhase.value?.contractType === CONTRACT_TYPES.FORFAIT
)
const computeLeaveYearForDate = (emp: Employee | null, date: Date): number => { const computeLeaveYearForDate = (date: Date): number => {
if (isForfaitContract(emp)) return date.getFullYear() if (isForfaitOnPhase.value) return date.getFullYear()
return date.getMonth() >= 5 ? date.getFullYear() + 1 : date.getFullYear() return date.getMonth() >= 5 ? date.getFullYear() + 1 : date.getFullYear()
} }
const currentLeaveYear = computed<number | null>(() => { const currentLeaveYear = computed<number | null>(() => {
if (!employee.value) return null if (!employee.value) return null
return computeLeaveYearForDate(employee.value, new Date()) return computeLeaveYearForDate(new Date())
}) })
const formatLeaveYearLabel = (year: number, isForfait: boolean): string => { const formatLeaveYearLabel = (year: number, isForfait: boolean): string => {
@@ -39,23 +45,15 @@ export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee:
} }
const availableLeaveYears = computed<LeaveYearOption[]>(() => { const availableLeaveYears = computed<LeaveYearOption[]>(() => {
if (!employee.value || currentLeaveYear.value === null) return [] if (!employee.value || !selectedPhase.value || currentLeaveYear.value === null) return []
const isForfait = isForfaitContract(employee.value) const isForfait = isForfaitOnPhase.value
const current = currentLeaveYear.value const phase = selectedPhase.value
const startDates: string[] = [] // Plage = exercices intersectant la phase.
for (const period of employee.value.contractHistory ?? []) { const phaseStartYear = computeLeaveYearForDate(new Date(`${phase.startDate}T00:00:00`))
if (period.startDate) startDates.push(period.startDate) const phaseEndYear = phase.endDate
} ? computeLeaveYearForDate(new Date(`${phase.endDate}T00:00:00`))
if (employee.value.entryDate) startDates.push(employee.value.entryDate) : currentLeaveYear.value
let contractFloor = current
for (const raw of startDates) {
const date = new Date(`${raw.substring(0, 10)}T00:00:00`)
if (Number.isNaN(date.getTime())) continue
const leaveYear = computeLeaveYearForDate(employee.value, date)
if (leaveYear < contractFloor) contractFloor = leaveYear
}
// Hard floor : data-start-date (env RTT_START_DATE) — le logiciel n'a pas // Hard floor : data-start-date (env RTT_START_DATE) — le logiciel n'a pas
// d'historique avant cette date, inutile de proposer des années antérieures. // d'historique avant cette date, inutile de proposer des années antérieures.
@@ -64,14 +62,15 @@ export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee:
if (dataStart) { if (dataStart) {
const dataStartDate = new Date(`${dataStart.substring(0, 10)}T00:00:00`) const dataStartDate = new Date(`${dataStart.substring(0, 10)}T00:00:00`)
if (!Number.isNaN(dataStartDate.getTime())) { if (!Number.isNaN(dataStartDate.getTime())) {
dataFloor = computeLeaveYearForDate(employee.value, dataStartDate) dataFloor = computeLeaveYearForDate(dataStartDate)
} }
} }
const minYear = dataFloor !== null ? Math.max(contractFloor, dataFloor) : contractFloor const minYear = dataFloor !== null ? Math.max(phaseStartYear, dataFloor) : phaseStartYear
const maxYear = phaseEndYear
const years: LeaveYearOption[] = [] const years: LeaveYearOption[] = []
for (let y = current; y >= minYear; y -= 1) { for (let y = maxYear; y >= minYear; y -= 1) {
years.push({ value: y, label: formatLeaveYearLabel(y, isForfait) }) years.push({ value: y, label: formatLeaveYearLabel(y, isForfait) })
} }
return years return years
@@ -90,7 +89,7 @@ export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee:
if (selectedLeaveYear.value === null) return if (selectedLeaveYear.value === null) return
isLeaveLoading.value = true isLeaveLoading.value = true
try { try {
const isForfait = isForfaitContract(employee.value) const isForfait = isForfaitOnPhase.value
const leaveYear = selectedLeaveYear.value const leaveYear = selectedLeaveYear.value
const from = isForfait ? `${leaveYear}-01-01` : `${leaveYear - 1}-06-01` const from = isForfait ? `${leaveYear}-01-01` : `${leaveYear - 1}-06-01`
const to = isForfait ? `${leaveYear}-12-31` : `${leaveYear}-05-31` const to = isForfait ? `${leaveYear}-12-31` : `${leaveYear}-05-31`
@@ -98,7 +97,7 @@ export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee:
const [absences, summary, ...holidayResults] = await Promise.all([ const [absences, summary, ...holidayResults] = await Promise.all([
listAbsences({ from, to, employeeId: employee.value.id }), listAbsences({ from, to, employeeId: employee.value.id }),
getEmployeeLeaveSummary(employee.value.id, leaveYear), getEmployeeLeaveSummary(employee.value.id, leaveYear, selectedPhase.value?.id),
...holidayYears.map((y) => listPublicHolidays('metropole', y)) ...holidayYears.map((y) => listPublicHolidays('metropole', y))
]) ])
employeeAbsences.value = absences employeeAbsences.value = absences
@@ -122,6 +121,13 @@ export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee:
selectedLeaveYear.value = null selectedLeaveYear.value = null
} }
watch(() => selectedPhase.value?.id, () => {
// Reset l'année car la plage a peut-être changé.
selectedLeaveYear.value = null
leaveDataLoaded.value = false
// Le rechargement effectif est piloté par useEmployeeDetailPage.
})
const submitFractionedDays = async (days: number) => { const submitFractionedDays = async (days: number) => {
if (!employee.value) return if (!employee.value) return
const year = leaveSummary.value?.year ?? undefined const year = leaveSummary.value?.year ?? undefined