Retour RH: vue jour par date, RTT mi-semaine, récap salaire & exports, panier de nuit (#21)
Auto Tag Develop / tag (push) Successful in 11s
Auto Tag Develop / tag (push) Successful in 11s
## Correctifs RH (branche fix/retour-rh) ### Vue Jour (Heures) - Mode saisie/présence, libellé de contrat et sauvegarde résolus **à la date affichée** (et non au contrat courant). Corrige les salariés passés 39h/35h → Forfait. ### RTT — heures supplémentaires - Proratisation du **plafond 25%/50%** pour les embauches en milieu de semaine (la bande +25% se décale au lieu de rester bloquée à 43h). Témoin Dylan : 4h à 25% + 3h à 50%. ### Récap salaire (PDF mensuel) - Forfait : congés imputés **N-1** non affichés et comptés en présence. - Colonne « Heures payés » **scindée 25% / 50%** (en-tête fusionné). - **Exclusion des salariés sans contrat** sur le mois (ex. Marine, contrat terminé). ### Exports heures annuelles (par salarié + tous) - **Tous les jours sous contrat** affichés, même vides/non saisis (corrige les lignes manquantes). - Samedis/dimanches en **gris plus foncé**. ### Panier de nuit - **Ne s'applique pas aux conducteurs** (vue semaine + récap salaire). ## Tests - 11 tests ajoutés. Suite verte hors un test legacy pré-existant dépendant de la date (`EmployeeRttSummaryProviderTest::testNoQueryParamsKeepsLegacyYearDefaulting`, non modifié par cette branche). ## À noter (hors scope) - L'export heures annuelles *tous salariés* peut dépasser `memory_limit=256M` (Dompdf) — limitation **pré-existante**, non corrigée ici. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #21 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #21.
This commit is contained in:
@@ -236,13 +236,19 @@ final readonly class RttRecoveryComputationService
|
||||
? $this->computeWeeklyCustomReferenceMinutes($weekDays, $employeeContractsByDate)
|
||||
: $this->computeWeeklyOvertimeReferenceMinutes($weekDays, $employeeContractsByDate);
|
||||
$overtime25StartMinutes = $this->computeWeeklyOvertime25StartMinutes($weekDays, $employeeContractsByDate);
|
||||
// Plafond séparant 25 %/50 % : seuil de départ proraté + largeur de la bande +25 %
|
||||
// (4h pour un 39h, 8h pour un 35h). Il se décale ainsi avec une embauche en milieu
|
||||
// de semaine au lieu de rester bloqué à 43h, ce qui ouvre la tranche 50 %.
|
||||
$overtime50StartMinutes = $overtime25StartMinutes + $this->resolveOvertime25BandWidthMinutes($weekAnchorContract);
|
||||
$weeklyOvertimeTotalMinutes = $isWeekPresenceTracking
|
||||
? 0
|
||||
: $weeklyTotalMinutes - $overtimeReferenceMinutes;
|
||||
|
||||
$base25 = ($isWeekPresenceTracking || $disableOvertimeBonuses || $isCustomContract) ? 0 : max(0, min($weeklyTotalMinutes, 43 * 60) - $overtime25StartMinutes);
|
||||
[$rawBase25, $rawBase50] = $this->computeOvertimeBaseMinutes($weeklyTotalMinutes, $overtime25StartMinutes, $overtime50StartMinutes);
|
||||
|
||||
$base25 = ($isWeekPresenceTracking || $disableOvertimeBonuses || $isCustomContract) ? 0 : $rawBase25;
|
||||
$bonus25 = ($isWeekPresenceTracking || $disableOvertimeBonuses || $isCustomContract) ? 0 : (int) round($base25 * 0.25);
|
||||
$base50 = ($isWeekPresenceTracking || $disableOvertimeBonuses || $isCustomContract) ? 0 : max(0, $weeklyTotalMinutes - 43 * 60);
|
||||
$base50 = ($isWeekPresenceTracking || $disableOvertimeBonuses || $isCustomContract) ? 0 : $rawBase50;
|
||||
$bonus50 = ($isWeekPresenceTracking || $disableOvertimeBonuses || $isCustomContract) ? 0 : (int) round($base50 * 0.5);
|
||||
|
||||
if ($isWeekPresenceTracking || $disableOvertimeBonuses) {
|
||||
@@ -452,18 +458,31 @@ final readonly class RttRecoveryComputationService
|
||||
return $total;
|
||||
}
|
||||
|
||||
private function computeOvertime25BonusMinutes(int $weeklyTotalMinutes, int $startMinutes): int
|
||||
/**
|
||||
* Largeur (en minutes) de la tranche +25 % pour le contrat d'ancrage de la semaine :
|
||||
* 4h pour un 39h (39→43), 8h pour un 35h (35→43). Ajoutée au seuil de départ proraté
|
||||
* pour obtenir le plafond 25 %/50 %.
|
||||
*/
|
||||
private function resolveOvertime25BandWidthMinutes(?Contract $contract): int
|
||||
{
|
||||
$trancheMinutes = max(0, min($weeklyTotalMinutes, 43 * 60) - $startMinutes);
|
||||
$hours = $contract?->getWeeklyHours();
|
||||
$startHours = (null !== $hours && $hours >= 39) ? 39 : 35;
|
||||
|
||||
return (int) round($trancheMinutes * 0.25);
|
||||
return (43 - $startHours) * 60;
|
||||
}
|
||||
|
||||
private function computeOvertime50BonusMinutes(int $weeklyTotalMinutes): int
|
||||
/**
|
||||
* Répartit les heures supplémentaires hebdomadaires entre les bases 25 % et 50 %.
|
||||
* La tranche 25 % court du seuil de départ au plafond ; au-delà du plafond, c'est du 50 %.
|
||||
*
|
||||
* @return array{int, int} [base25Minutes, base50Minutes]
|
||||
*/
|
||||
private function computeOvertimeBaseMinutes(int $weeklyTotalMinutes, int $overtime25StartMinutes, int $overtime50StartMinutes): array
|
||||
{
|
||||
$trancheMinutes = max(0, $weeklyTotalMinutes - (43 * 60));
|
||||
$base25 = max(0, min($weeklyTotalMinutes, $overtime50StartMinutes) - $overtime25StartMinutes);
|
||||
$base50 = max(0, $weeklyTotalMinutes - $overtime50StartMinutes);
|
||||
|
||||
return (int) round($trancheMinutes * 0.5);
|
||||
return [$base25, $base50];
|
||||
}
|
||||
|
||||
private function hasDisabledOvertimeBonuses(?Contract $contract, ContractNature $contractNature): bool
|
||||
|
||||
Reference in New Issue
Block a user