Compare commits

...

4 Commits

Author SHA1 Message Date
gitea-actions
b5e7395760 chore: bump version to v0.1.16
All checks were successful
Auto Tag Develop / tag (push) Successful in 4s
Build Release Artefact / build (push) Successful in 1m26s
2026-03-02 09:34:21 +00:00
380c72c242 fix : règle de calcule des heures travaillées sur les contrats Forfait
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-03-02 10:33:42 +01:00
gitea-actions
107417a571 chore: bump version to v0.1.15
All checks were successful
Auto Tag Develop / tag (push) Successful in 4s
Build Release Artefact / build (push) Successful in 1m16s
2026-02-27 09:22:05 +00:00
5ff7e356be fix : validation RH qui invalidé les sites
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-02-27 10:21:54 +01:00
6 changed files with 31 additions and 14 deletions

View File

@@ -1,2 +1,2 @@
parameters: parameters:
app.version: '0.1.14' app.version: '0.1.16'

View File

@@ -427,8 +427,11 @@ export const useHoursPage = () => {
const getPresenceDayValue = (employeeId: number) => { const getPresenceDayValue = (employeeId: number) => {
const row = rows.value[employeeId] const row = rows.value[employeeId]
const basePresence = (row?.isPresentMorning ? 0.5 : 0) + (row?.isPresentAfternoon ? 0.5 : 0) const dayRow = dayContextByEmployeeId.value.get(employeeId)
const creditedPresence = dayContextByEmployeeId.value.get(employeeId)?.creditedPresenceUnits ?? 0 const absentMorning = dayRow?.absentMorning ?? false
const absentAfternoon = dayRow?.absentAfternoon ?? false
const basePresence = ((row?.isPresentMorning && !absentMorning) ? 0.5 : 0) + ((row?.isPresentAfternoon && !absentAfternoon) ? 0.5 : 0)
const creditedPresence = dayRow?.creditedPresenceUnits ?? 0
const total = Math.min(1, basePresence + creditedPresence) const total = Math.min(1, basePresence + creditedPresence)
return Number.isInteger(total) ? String(total) : total.toFixed(1) return Number.isInteger(total) ? String(total) : total.toFixed(1)
} }

View File

@@ -60,11 +60,6 @@ final readonly class WorkedHoursCreditPolicy
bool $absentMorning, bool $absentMorning,
bool $absentAfternoon bool $absentAfternoon
): float { ): float {
$type = $absence->getType();
if (!$type?->getCountAsWorkedHours()) {
return 0.0;
}
$employee = $absence->getEmployee(); $employee = $absence->getEmployee();
if (null === $employee) { if (null === $employee) {
return 0.0; return 0.0;
@@ -74,9 +69,14 @@ final readonly class WorkedHoursCreditPolicy
return 0.0; return 0.0;
} }
$halfUnits = ($absentMorning ? 1 : 0) + ($absentAfternoon ? 1 : 0); // Règle forfait:
// - demi-journée d'absence => 0.5 travaillé
// - journée complète d'absence => 0 travaillé
if ($absentMorning xor $absentAfternoon) {
return 0.5;
}
return $halfUnits * 0.5; return 0.0;
} }
public function resolveContractDayMinutes(?int $weeklyHours, int $isoWeekDay): int public function resolveContractDayMinutes(?int $weeklyHours, int $isoWeekDay): int

View File

@@ -125,6 +125,14 @@ final readonly class WorkHourBulkUpsertProcessor implements ProcessorInterface
continue; continue;
} }
// Si aucune donnée n'a changé, on ne touche pas la ligne:
// cela évite de perdre les validations existantes (site/RH) sur un simple enregistrement.
if (null !== $existing && $this->isSameAsExisting($existing, $normalized)) {
++$result->processed;
continue;
}
if ($this->isEntryEmpty($normalized)) { if ($this->isEntryEmpty($normalized)) {
// Convention choisie: une ligne vide supprime l'enregistrement existant. // Convention choisie: une ligne vide supprime l'enregistrement existant.
if ($existing) { if ($existing) {

View File

@@ -135,6 +135,8 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface
$creditedByEmployeeDate = []; $creditedByEmployeeDate = [];
$creditedPresenceByEmployeeDate = []; $creditedPresenceByEmployeeDate = [];
$absenceByEmployeeDate = []; $absenceByEmployeeDate = [];
$absentMorningByEmployeeDate = [];
$absentAfternoonByEmployeeDate = [];
$absenceLabelByEmployeeDate = []; $absenceLabelByEmployeeDate = [];
$absenceColorByEmployeeDate = []; $absenceColorByEmployeeDate = [];
foreach ($absences as $absence) { foreach ($absences as $absence) {
@@ -153,7 +155,9 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface
[$absentMorning, $absentAfternoon] = $this->absenceSegmentsResolver->resolveForDate($absence, $date); [$absentMorning, $absentAfternoon] = $this->absenceSegmentsResolver->resolveForDate($absence, $date);
if ($absentMorning || $absentAfternoon) { if ($absentMorning || $absentAfternoon) {
$absenceByEmployeeDate[$employeeId][$date] = true; $absenceByEmployeeDate[$employeeId][$date] = true;
$absentMorningByEmployeeDate[$employeeId][$date] = ($absentMorningByEmployeeDate[$employeeId][$date] ?? false) || $absentMorning;
$absentAfternoonByEmployeeDate[$employeeId][$date] = ($absentAfternoonByEmployeeDate[$employeeId][$date] ?? false) || $absentAfternoon;
if (!isset($absenceLabelByEmployeeDate[$employeeId][$date])) { if (!isset($absenceLabelByEmployeeDate[$employeeId][$date])) {
$absenceLabelByEmployeeDate[$employeeId][$date] = $absence->getType()?->getLabel(); $absenceLabelByEmployeeDate[$employeeId][$date] = $absence->getType()?->getLabel();
} }
@@ -202,8 +206,10 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface
$metrics->addCreditedMinutes($creditedMinutes); $metrics->addCreditedMinutes($creditedMinutes);
$present = null; $present = null;
if ($isPresenceTracking) { if ($isPresenceTracking) {
$morning = ($entry['isPresentMorning'] ?? false) ? 0.5 : 0.0; $absentMorning = $absentMorningByEmployeeDate[$employeeId][$date] ?? false;
$afternoon = ($entry['isPresentAfternoon'] ?? false) ? 0.5 : 0.0; $absentAfternoon = $absentAfternoonByEmployeeDate[$employeeId][$date] ?? false;
$morning = (($entry['isPresentMorning'] ?? false) && !$absentMorning) ? 0.5 : 0.0;
$afternoon = (($entry['isPresentAfternoon'] ?? false) && !$absentAfternoon) ? 0.5 : 0.0;
$creditedPresence = $creditedPresenceByEmployeeDate[$employeeId][$date] ?? 0.0; $creditedPresence = $creditedPresenceByEmployeeDate[$employeeId][$date] ?? 0.0;
$present = min(1.0, $morning + $afternoon + $creditedPresence); $present = min(1.0, $morning + $afternoon + $creditedPresence);
} }

View File

@@ -135,7 +135,7 @@ final class WorkHourWeeklySummaryProviderTest extends TestCase
self::assertSame(210, $result->rows[0]->weeklyOvertime50Minutes); self::assertSame(210, $result->rows[0]->weeklyOvertime50Minutes);
self::assertSame(1230, $result->rows[0]->weeklyRecoveryMinutes); self::assertSame(1230, $result->rows[0]->weeklyRecoveryMinutes);
self::assertSame(1.0, $result->rows[1]->weeklyPresenceCount); self::assertSame(0.0, $result->rows[1]->weeklyPresenceCount);
self::assertTrue($result->rows[1]->daily[0]->hasAbsence); self::assertTrue($result->rows[1]->daily[0]->hasAbsence);
self::assertSame('Congé', $result->rows[1]->daily[0]->absenceLabel); self::assertSame('Congé', $result->rows[1]->daily[0]->absenceLabel);
self::assertSame('#000', $result->rows[1]->daily[0]->absenceColor); self::assertSame('#000', $result->rows[1]->daily[0]->absenceColor);