fix(leave) : do not cap from at phase.startDate for non-forfait phases
The CP exercise (Juin N-1 → Mai N) is annual and continuous across contract-signature changes within the same leave rule (e.g. 35h → 39h, isDriver flip, weeklyHours bump). Capping `from` at the phase start truncated the accrual to just the months under the latest phase, producing wrong "en cours d'acquisition" values and dropping presence days from earlier months on the leave-tab calendar. For Damien GUILLOT (35h until 2025-10-31, then 39h), this gave 15 days acquired (6 months Nov→Apr) instead of the expected 27.5 days (11 months Jun→Apr at 2.5/month). After this fix, the H39 view shows the full annual accrual as expected. FORFAIT phases keep the from cap: the 218-day target is calendar-year scoped and only counts the FORFAIT portion of the year. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -943,16 +943,24 @@ final readonly class EmployeeLeaveSummaryProvider implements ProviderInterface
|
||||
{
|
||||
if (ContractType::FORFAIT === $phase->contractType) {
|
||||
[$from, $to] = $this->resolveForfaitYearBounds($employee, $year, $phase);
|
||||
|
||||
// For FORFAIT, cap from at phase.startDate: the 218-day FORFAIT accrual
|
||||
// is calendar-year scoped and only counts the FORFAIT portion of the year.
|
||||
if ($phase->startDate > $from) {
|
||||
$from = $phase->startDate;
|
||||
}
|
||||
} else {
|
||||
[$from, $to] = $this->resolveLeavePeriodBounds($year);
|
||||
|
||||
// For non-forfait, do NOT cap from at phase.startDate: CP accrual is
|
||||
// annual (Juin→Mai) and continuous across signature changes within the
|
||||
// same leave rule (e.g. 35h → 39h, driver flag flip, weeklyHours bump).
|
||||
// The contract-entry-date cap is handled by resolveEffectivePeriodStart().
|
||||
}
|
||||
|
||||
// Cap to the phase boundaries (applies to both modes).
|
||||
// The end cap is skipped when the phase was not explicitly provided (legacy callers),
|
||||
// to preserve pre-phase-cap behavior for terminated employees.
|
||||
if ($phase->startDate > $from) {
|
||||
$from = $phase->startDate;
|
||||
}
|
||||
// End cap applies to both modes. Skipped when the phase was not explicitly
|
||||
// provided (legacy callers) to preserve pre-phase-cap behavior for
|
||||
// terminated employees.
|
||||
if ($applyPhaseEndCap && null !== $phase->endDate && $phase->endDate < $to) {
|
||||
$to = $phase->endDate;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user