fix(rtt) : skip non-contracted days in overtime 25% threshold

computeWeeklyOvertime25StartMinutes used a ternary that fell back to 35h
when a day had no active contract. Once periodFrom was uncapped (so the
RTT week iterates the full exercise), pre-hire days were silently
contributing 7h each to the weekly threshold, erasing the 25% overtime
for the employee's first partial week.

Dylan CHABOISSON week 12 (Mar 19 hire, worked Thu 9h + Fri 9h30 +
Sat 3h30 = 22h): threshold was 36h (incorrect), now back to 15h (Thu 8h
+ Fri 7h) so the 7h above threshold + 1h45 bonus are correctly credited.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 15:10:51 +02:00
parent 653845655f
commit 750f2bffa8

View File

@@ -413,10 +413,17 @@ final readonly class RttRecoveryComputationService
{
$total = 0;
foreach ($days as $date) {
$isoDay = (int) new DateTimeImmutable($date)->format('N');
$contract = $contractsByDate[$date] ?? null;
$hours = $contract?->getWeeklyHours();
$startHours = (null !== $hours && $hours >= 39) ? 39 : 35;
$isoDay = (int) new DateTimeImmutable($date)->format('N');
$contract = $contractsByDate[$date] ?? null;
$hours = $contract?->getWeeklyHours();
// Days without an active contract (pre-hire, post-termination, contract
// gaps) must NOT contribute to the weekly 25% overtime threshold —
// otherwise hiring mid-week artificially inflates the threshold and
// erases legitimate overtime.
if (null === $hours || $hours <= 0) {
continue;
}
$startHours = $hours >= 39 ? 39 : 35;
$total += $this->resolveDailyReferenceMinutes($startHours, $isoDay);
}