Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: #6 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
372 lines
14 KiB
TypeScript
372 lines
14 KiB
TypeScript
import type { Contract } from '~/services/dto/contract'
|
|
import type { Absence } from '~/services/dto/absence'
|
|
import type { EmployeeLeaveSummary } from '~/services/dto/employee-leave-summary'
|
|
import type { EmployeeRttSummary } from '~/services/dto/employee-rtt-summary'
|
|
import type { ContractHistoryItem, Employee } from '~/services/dto/employee'
|
|
import { CONTRACT_TYPES } from '~/services/dto/contract'
|
|
import { listAbsences } from '~/services/absences'
|
|
import { listContracts } from '~/services/contracts'
|
|
import { getEmployeeLeaveSummary, updateFractionedDays } from '~/services/employee-leave-summary'
|
|
import { getEmployeeRttSummary, createRttPayment } from '~/services/employee-rtt-summary'
|
|
import { getEmployee, updateEmployee } from '~/services/employees'
|
|
import { listPublicHolidays } from '~/services/public-holidays'
|
|
import { formatNullableYmdToFr, getTodayYmd, shiftYmd } from '~/utils/date'
|
|
import { contractNatureLabel, isContractNature, requiresContractEndDate } from '~/utils/contract'
|
|
|
|
export const useEmployeeDetailPage = () => {
|
|
const route = useRoute()
|
|
const toast = useToast()
|
|
const employee = ref<Employee | null>(null)
|
|
const isLoading = ref(false)
|
|
const activeTab = ref<'contract' | 'leave' | 'rtt'>('contract')
|
|
const contracts = ref<Contract[]>([])
|
|
const employeeAbsences = ref<Absence[]>([])
|
|
const leaveSummary = ref<EmployeeLeaveSummary | null>(null)
|
|
const rttSummary = ref<EmployeeRttSummary | null>(null)
|
|
const publicHolidays = ref<Record<string, string>>({})
|
|
const isContractDrawerOpen = ref(false)
|
|
const isContractSubmitting = ref(false)
|
|
const isCreateContractDrawerOpen = ref(false)
|
|
const isCreateContractSubmitting = ref(false)
|
|
|
|
const contractForm = reactive({
|
|
contractId: '' as number | '',
|
|
contractName: '',
|
|
weeklyHours: null as number | null,
|
|
contractNature: 'CDI' as 'CDI' | 'CDD' | 'INTERIM',
|
|
startDate: '',
|
|
endDate: '',
|
|
paidLeaveSettled: false,
|
|
comment: ''
|
|
})
|
|
|
|
const validationTouched = reactive({
|
|
endDate: false
|
|
})
|
|
|
|
const createContractForm = reactive({
|
|
contractId: '' as number | '',
|
|
contractNature: 'CDI' as 'CDI' | 'CDD' | 'INTERIM',
|
|
startDate: '',
|
|
endDate: ''
|
|
})
|
|
|
|
const createValidationTouched = reactive({
|
|
contractId: false,
|
|
contractNature: false,
|
|
startDate: false,
|
|
endDate: false
|
|
})
|
|
|
|
const contractHistory = computed(() => employee.value?.contractHistory ?? [])
|
|
const showLeaveTab = computed(() => employee.value?.currentContractNature !== 'INTERIM')
|
|
const employeeContractWorkLabel = computed(() => {
|
|
const contract = employee.value?.contract
|
|
if (!contract) return '-'
|
|
if (contract.type === CONTRACT_TYPES.FORFAIT) return 'Forfait'
|
|
if (contract.weeklyHours !== null && contract.weeklyHours !== undefined) return `${contract.weeklyHours} heures`
|
|
return contract.name || '-'
|
|
})
|
|
|
|
const formatDate = (value?: string | null) => formatNullableYmdToFr(value)
|
|
|
|
const contractHistoryLabel = (item: ContractHistoryItem) => {
|
|
if (item.weeklyHours !== null && item.weeklyHours !== undefined) {
|
|
return `${item.weeklyHours} heures`
|
|
}
|
|
return item.contractName ?? '-'
|
|
}
|
|
|
|
const currentActiveContractPeriod = computed(() => {
|
|
const today = getTodayYmd()
|
|
const history = employee.value?.contractHistory ?? []
|
|
return history.find((item) => item.startDate <= today && (!item.endDate || item.endDate >= today)) ?? null
|
|
})
|
|
|
|
const canCloseCurrentContract = computed(() => {
|
|
const active = currentActiveContractPeriod.value
|
|
if (!active) return false
|
|
if (!active.endDate) return true
|
|
return active.endDate > getTodayYmd()
|
|
})
|
|
|
|
const canCreateContract = computed(() => {
|
|
const active = currentActiveContractPeriod.value
|
|
if (!active) return true
|
|
return !!active.endDate
|
|
})
|
|
|
|
const isContractEndDateValid = computed(() => contractForm.endDate !== '')
|
|
const showContractEndDateError = computed(() => validationTouched.endDate && !isContractEndDateValid.value)
|
|
|
|
const requiresCreateContractEndDate = computed(() => requiresContractEndDate(createContractForm.contractNature))
|
|
const isCreateContractValid = computed(() => createContractForm.contractId !== '')
|
|
const isCreateContractNatureValid = computed(() => isContractNature(createContractForm.contractNature))
|
|
const isCreateContractStartDateValid = computed(() => createContractForm.startDate !== '')
|
|
const isCreateContractEndDateValid = computed(() => !requiresCreateContractEndDate.value || createContractForm.endDate !== '')
|
|
const isCreateContractFormValid = computed(() =>
|
|
isCreateContractValid.value &&
|
|
isCreateContractNatureValid.value &&
|
|
isCreateContractStartDateValid.value &&
|
|
isCreateContractEndDateValid.value
|
|
)
|
|
|
|
const baseInputClass =
|
|
'mt-2 w-full rounded-md border px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20'
|
|
const readonlyFieldClass = `${baseInputClass} border-neutral-300 bg-neutral-100 text-neutral-700`
|
|
const contractEndDateFieldClass = computed(() => showContractEndDateError.value ? `${baseInputClass} border-red-500` : `${baseInputClass} border-neutral-300`)
|
|
const baseSelectClass = 'mt-2 w-full rounded-md border bg-white px-3 py-2 text-md text-neutral-900'
|
|
const createContractFieldClass = computed(() => createValidationTouched.contractId && !isCreateContractValid.value ? `${baseSelectClass} border-red-500` : `${baseSelectClass} border-neutral-300`)
|
|
const createContractNatureFieldClass = computed(() => createValidationTouched.contractNature && !isCreateContractNatureValid.value ? `${baseSelectClass} border-red-500` : `${baseSelectClass} border-neutral-300`)
|
|
const createContractStartDateFieldClass = computed(() => createValidationTouched.startDate && !isCreateContractStartDateValid.value ? `${baseInputClass} border-red-500` : `${baseInputClass} border-neutral-300`)
|
|
const createContractEndDateFieldClass = computed(() => createValidationTouched.endDate && !isCreateContractEndDateValid.value ? `${baseInputClass} border-red-500` : `${baseInputClass} border-neutral-300`)
|
|
const closeContractWorkedHoursLabel = computed(() => {
|
|
if (contractForm.weeklyHours !== null && contractForm.weeklyHours !== undefined) return `${contractForm.weeklyHours} heures`
|
|
return contractForm.contractName || '-'
|
|
})
|
|
|
|
const resetContractValidation = () => {
|
|
validationTouched.endDate = false
|
|
}
|
|
|
|
const hydrateContractFormFromCurrent = () => {
|
|
const current = employee.value
|
|
const active = currentActiveContractPeriod.value
|
|
if (!current || !active) return
|
|
|
|
contractForm.contractId = active.contractId ?? current.contract?.id ?? ''
|
|
contractForm.contractName = active.contractName ?? current.contract?.name ?? ''
|
|
contractForm.weeklyHours = active.weeklyHours ?? current.contract?.weeklyHours ?? null
|
|
contractForm.contractNature = active.contractNature
|
|
contractForm.startDate = active.startDate
|
|
contractForm.endDate = getTodayYmd()
|
|
contractForm.paidLeaveSettled = false
|
|
contractForm.comment = ''
|
|
}
|
|
|
|
const openCloseContractDrawer = () => {
|
|
if (!employee.value || !canCloseCurrentContract.value) return
|
|
hydrateContractFormFromCurrent()
|
|
resetContractValidation()
|
|
isContractDrawerOpen.value = true
|
|
}
|
|
|
|
const setContractDrawerOpen = (open: boolean) => {
|
|
isContractDrawerOpen.value = open
|
|
}
|
|
|
|
const resetCreateValidation = () => {
|
|
createValidationTouched.contractId = false
|
|
createValidationTouched.contractNature = false
|
|
createValidationTouched.startDate = false
|
|
createValidationTouched.endDate = false
|
|
}
|
|
|
|
const openCreateContractDrawer = () => {
|
|
if (!employee.value || !canCreateContract.value) return
|
|
createContractForm.contractId = ''
|
|
createContractForm.contractNature = 'CDI'
|
|
createContractForm.endDate = ''
|
|
createContractForm.startDate = currentActiveContractPeriod.value?.endDate
|
|
? (shiftYmd(currentActiveContractPeriod.value.endDate, 1) ?? currentActiveContractPeriod.value.endDate)
|
|
: getTodayYmd()
|
|
resetCreateValidation()
|
|
isCreateContractDrawerOpen.value = true
|
|
}
|
|
|
|
const setCreateContractDrawerOpen = (open: boolean) => {
|
|
isCreateContractDrawerOpen.value = open
|
|
}
|
|
|
|
const loadEmployee = async () => {
|
|
const idParam = Array.isArray(route.params.id) ? route.params.id[0] : route.params.id
|
|
const employeeId = Number(idParam)
|
|
if (!Number.isInteger(employeeId) || employeeId <= 0) {
|
|
return
|
|
}
|
|
|
|
isLoading.value = true
|
|
try {
|
|
const loadedEmployee = await getEmployee(employeeId)
|
|
employee.value = loadedEmployee
|
|
|
|
const now = new Date()
|
|
const isForfait = loadedEmployee.contract?.type === CONTRACT_TYPES.FORFAIT
|
|
const leaveYear = isForfait
|
|
? now.getFullYear()
|
|
: (now.getMonth() >= 5 ? now.getFullYear() + 1 : now.getFullYear())
|
|
const rttYear = now.getMonth() >= 5 ? now.getFullYear() + 1 : now.getFullYear()
|
|
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, rtt, ...holidayResults] = await Promise.all([
|
|
listAbsences({
|
|
from,
|
|
to,
|
|
employeeId: loadedEmployee.id
|
|
}),
|
|
showLeaveTab.value
|
|
? getEmployeeLeaveSummary(loadedEmployee.id, leaveYear)
|
|
: Promise.resolve(null),
|
|
getEmployeeRttSummary(loadedEmployee.id, rttYear),
|
|
...holidayYears.map((y) => listPublicHolidays('metropole', y))
|
|
])
|
|
employeeAbsences.value = absences
|
|
leaveSummary.value = summary
|
|
rttSummary.value = rtt
|
|
publicHolidays.value = Object.assign({}, ...holidayResults)
|
|
if (!showLeaveTab.value && activeTab.value === 'leave') {
|
|
activeTab.value = 'contract'
|
|
}
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
const submitContractUpdate = async () => {
|
|
if (!employee.value || isContractSubmitting.value || !currentActiveContractPeriod.value) return
|
|
|
|
validationTouched.endDate = true
|
|
if (!isContractEndDateValid.value) return
|
|
|
|
if (contractForm.endDate < currentActiveContractPeriod.value.startDate) {
|
|
toast.error({
|
|
title: 'Erreur',
|
|
message: `La date de fin doit être postérieure au ${formatDate(currentActiveContractPeriod.value.startDate)}.`
|
|
})
|
|
return
|
|
}
|
|
|
|
isContractSubmitting.value = true
|
|
try {
|
|
await updateEmployee(employee.value.id, {
|
|
firstName: employee.value.firstName,
|
|
lastName: employee.value.lastName,
|
|
siteId: employee.value.site?.id ?? null,
|
|
contractId: Number(contractForm.contractId),
|
|
contractEndDate: contractForm.endDate || null,
|
|
contractPaidLeaveSettled: contractForm.paidLeaveSettled,
|
|
contractComment: contractForm.comment || null
|
|
})
|
|
|
|
isContractDrawerOpen.value = false
|
|
await loadEmployee()
|
|
} finally {
|
|
isContractSubmitting.value = false
|
|
}
|
|
}
|
|
|
|
const submitCreateContract = async () => {
|
|
if (!employee.value || isCreateContractSubmitting.value) return
|
|
|
|
createValidationTouched.contractId = true
|
|
createValidationTouched.contractNature = true
|
|
createValidationTouched.startDate = true
|
|
createValidationTouched.endDate = true
|
|
if (!isCreateContractFormValid.value) return
|
|
|
|
if (currentActiveContractPeriod.value?.endDate) {
|
|
const minStartDate = shiftYmd(currentActiveContractPeriod.value.endDate, 1) ?? currentActiveContractPeriod.value.endDate
|
|
if (createContractForm.startDate < minStartDate) {
|
|
toast.error({
|
|
title: 'Erreur',
|
|
message: `La date de début doit être au moins le ${formatDate(minStartDate)}.`
|
|
})
|
|
return
|
|
}
|
|
}
|
|
|
|
isCreateContractSubmitting.value = true
|
|
try {
|
|
await updateEmployee(employee.value.id, {
|
|
firstName: employee.value.firstName,
|
|
lastName: employee.value.lastName,
|
|
siteId: employee.value.site?.id ?? null,
|
|
contractId: Number(createContractForm.contractId),
|
|
contractNature: createContractForm.contractNature,
|
|
contractStartDate: createContractForm.startDate,
|
|
contractEndDate: createContractForm.endDate || null
|
|
})
|
|
isCreateContractDrawerOpen.value = false
|
|
await loadEmployee()
|
|
} finally {
|
|
isCreateContractSubmitting.value = false
|
|
}
|
|
}
|
|
|
|
const submitFractionedDays = async (days: number) => {
|
|
if (!employee.value) return
|
|
const year = leaveSummary.value?.year ?? undefined
|
|
await updateFractionedDays(employee.value.id, days, year)
|
|
await loadEmployee()
|
|
}
|
|
|
|
const submitRttPayment = async (month: number, minutes: number, rate: '25' | '50') => {
|
|
if (!employee.value) return
|
|
const year = rttSummary.value?.year ?? undefined
|
|
await createRttPayment(employee.value.id, month, minutes, rate, year)
|
|
await loadEmployee()
|
|
}
|
|
|
|
watch(requiresCreateContractEndDate, (required) => {
|
|
if (!required) {
|
|
createContractForm.endDate = ''
|
|
}
|
|
})
|
|
|
|
onMounted(async () => {
|
|
contracts.value = await listContracts()
|
|
await loadEmployee()
|
|
})
|
|
|
|
return {
|
|
employee,
|
|
isLoading,
|
|
activeTab,
|
|
contracts,
|
|
employeeAbsences,
|
|
leaveSummary,
|
|
rttSummary,
|
|
publicHolidays,
|
|
showLeaveTab,
|
|
contractHistory,
|
|
employeeContractWorkLabel,
|
|
contractForm,
|
|
createContractForm,
|
|
isContractDrawerOpen,
|
|
isContractSubmitting,
|
|
isCreateContractDrawerOpen,
|
|
isCreateContractSubmitting,
|
|
canCloseCurrentContract,
|
|
canCreateContract,
|
|
readonlyFieldClass,
|
|
closeContractWorkedHoursLabel,
|
|
contractEndDateFieldClass,
|
|
showContractEndDateError,
|
|
isContractEndDateValid,
|
|
createContractNatureFieldClass,
|
|
createContractFieldClass,
|
|
createContractStartDateFieldClass,
|
|
requiresCreateContractEndDate,
|
|
createContractEndDateFieldClass,
|
|
isCreateContractFormValid,
|
|
contractNatureLabel,
|
|
contractHistoryLabel,
|
|
formatDate,
|
|
openCloseContractDrawer,
|
|
openCreateContractDrawer,
|
|
setContractDrawerOpen,
|
|
setCreateContractDrawerOpen,
|
|
submitContractUpdate,
|
|
submitCreateContract,
|
|
submitFractionedDays,
|
|
submitRttPayment
|
|
}
|
|
}
|