Permet de consulter les exercices passés (calendrier + compteurs) sur l'onglet Congés. La plage proposée est bornée par max(début historique contrat, RTT_START_DATE) pour ne pas remonter avant la mise en service du logiciel. Édition des stocks N-1 et fractionnés verrouillée sur exercices clos. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
155 lines
5.5 KiB
TypeScript
155 lines
5.5 KiB
TypeScript
import type { Ref } from 'vue'
|
|
import type { Absence } from '~/services/dto/absence'
|
|
import type { EmployeeLeaveSummary } from '~/services/dto/employee-leave-summary'
|
|
import type { Employee } from '~/services/dto/employee'
|
|
import { CONTRACT_TYPES } from '~/services/dto/contract'
|
|
import { listAbsences } from '~/services/absences'
|
|
import { getEmployeeLeaveSummary, updateFractionedDays, updatePaidLeaveDays } from '~/services/employee-leave-summary'
|
|
import { listPublicHolidays } from '~/services/public-holidays'
|
|
|
|
export type LeaveYearOption = {
|
|
value: number
|
|
label: string
|
|
}
|
|
|
|
export const useEmployeeLeave = (employee: Ref<Employee | null>, reloadEmployee: () => Promise<void>) => {
|
|
const employeeAbsences = ref<Absence[]>([])
|
|
const leaveSummary = ref<EmployeeLeaveSummary | null>(null)
|
|
const publicHolidays = ref<Record<string, string>>({})
|
|
const isLeaveLoading = ref(false)
|
|
const leaveDataLoaded = ref(false)
|
|
const selectedLeaveYear = ref<number | null>(null)
|
|
|
|
const isForfaitContract = (emp: Employee | null) =>
|
|
emp?.contract?.type === CONTRACT_TYPES.FORFAIT
|
|
|
|
const computeLeaveYearForDate = (emp: Employee | null, date: Date): number => {
|
|
if (isForfaitContract(emp)) return date.getFullYear()
|
|
return date.getMonth() >= 5 ? date.getFullYear() + 1 : date.getFullYear()
|
|
}
|
|
|
|
const currentLeaveYear = computed<number | null>(() => {
|
|
if (!employee.value) return null
|
|
return computeLeaveYearForDate(employee.value, new Date())
|
|
})
|
|
|
|
const formatLeaveYearLabel = (year: number, isForfait: boolean): string => {
|
|
if (isForfait) return String(year)
|
|
return `Juin ${year - 1} → Mai ${year}`
|
|
}
|
|
|
|
const availableLeaveYears = computed<LeaveYearOption[]>(() => {
|
|
if (!employee.value || currentLeaveYear.value === null) return []
|
|
const isForfait = isForfaitContract(employee.value)
|
|
const current = currentLeaveYear.value
|
|
|
|
const startDates: string[] = []
|
|
for (const period of employee.value.contractHistory ?? []) {
|
|
if (period.startDate) startDates.push(period.startDate)
|
|
}
|
|
if (employee.value.entryDate) startDates.push(employee.value.entryDate)
|
|
|
|
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
|
|
// d'historique avant cette date, inutile de proposer des années antérieures.
|
|
let dataFloor: number | null = null
|
|
const dataStart = leaveSummary.value?.dataStartDate
|
|
if (dataStart) {
|
|
const dataStartDate = new Date(`${dataStart.substring(0, 10)}T00:00:00`)
|
|
if (!Number.isNaN(dataStartDate.getTime())) {
|
|
dataFloor = computeLeaveYearForDate(employee.value, dataStartDate)
|
|
}
|
|
}
|
|
|
|
const minYear = dataFloor !== null ? Math.max(contractFloor, dataFloor) : contractFloor
|
|
|
|
const years: LeaveYearOption[] = []
|
|
for (let y = current; y >= minYear; y -= 1) {
|
|
years.push({ value: y, label: formatLeaveYearLabel(y, isForfait) })
|
|
}
|
|
return years
|
|
})
|
|
|
|
const initSelectedLeaveYear = () => {
|
|
if (selectedLeaveYear.value !== null) return
|
|
if (currentLeaveYear.value !== null) {
|
|
selectedLeaveYear.value = currentLeaveYear.value
|
|
}
|
|
}
|
|
|
|
const loadLeaveData = async () => {
|
|
if (!employee.value || isLeaveLoading.value) return
|
|
initSelectedLeaveYear()
|
|
if (selectedLeaveYear.value === null) return
|
|
isLeaveLoading.value = true
|
|
try {
|
|
const isForfait = isForfaitContract(employee.value)
|
|
const leaveYear = selectedLeaveYear.value
|
|
const from = isForfait ? `${leaveYear}-01-01` : `${leaveYear - 1}-06-01`
|
|
const to = isForfait ? `${leaveYear}-12-31` : `${leaveYear}-05-31`
|
|
const holidayYears = isForfait ? [leaveYear] : [leaveYear - 1, leaveYear]
|
|
|
|
const [absences, summary, ...holidayResults] = await Promise.all([
|
|
listAbsences({ from, to, employeeId: employee.value.id }),
|
|
getEmployeeLeaveSummary(employee.value.id, leaveYear),
|
|
...holidayYears.map((y) => listPublicHolidays('metropole', y))
|
|
])
|
|
employeeAbsences.value = absences
|
|
leaveSummary.value = summary
|
|
publicHolidays.value = Object.assign({}, ...holidayResults)
|
|
leaveDataLoaded.value = true
|
|
} finally {
|
|
isLeaveLoading.value = false
|
|
}
|
|
}
|
|
|
|
const setSelectedLeaveYear = async (year: number) => {
|
|
if (selectedLeaveYear.value === year) return
|
|
selectedLeaveYear.value = year
|
|
leaveDataLoaded.value = false
|
|
await loadLeaveData()
|
|
}
|
|
|
|
const resetLoaded = () => {
|
|
leaveDataLoaded.value = false
|
|
selectedLeaveYear.value = null
|
|
}
|
|
|
|
const submitFractionedDays = async (days: number) => {
|
|
if (!employee.value) return
|
|
const year = leaveSummary.value?.year ?? undefined
|
|
await updateFractionedDays(employee.value.id, days, year)
|
|
await reloadEmployee()
|
|
}
|
|
|
|
const submitPaidLeaveDays = async (days: number) => {
|
|
if (!employee.value) return
|
|
const year = leaveSummary.value?.year ?? undefined
|
|
await updatePaidLeaveDays(employee.value.id, days, year)
|
|
await reloadEmployee()
|
|
}
|
|
|
|
return {
|
|
employeeAbsences,
|
|
leaveSummary,
|
|
publicHolidays,
|
|
isLeaveLoading,
|
|
leaveDataLoaded,
|
|
selectedLeaveYear,
|
|
currentLeaveYear,
|
|
availableLeaveYears,
|
|
setSelectedLeaveYear,
|
|
loadLeaveData,
|
|
resetLoaded,
|
|
submitFractionedDays,
|
|
submitPaidLeaveDays
|
|
}
|
|
}
|