From 01f8058f560963f866fd444fe69a737e014eeb47 Mon Sep 17 00:00:00 2001 From: tristan Date: Mon, 16 Mar 2026 09:13:35 +0100 Subject: [PATCH] =?UTF-8?q?fix=20:=20redirection=20apr=C3=A8s=20login=20+?= =?UTF-8?q?=20=C3=A9cran=20des=20heures=20chauffeurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/functional-rules.md | 12 +-- .../driver-hours/DriverHoursDayView.vue | 16 ++++ .../driver-hours/DriverHoursWeekView.vue | 16 +++- frontend/composables/useDriverHoursPage.ts | 27 ++++-- frontend/layouts/default.vue | 8 +- frontend/pages/login.vue | 3 +- frontend/services/dto/work-hour.ts | 10 +++ migrations/Version20260316100000.php | 26 ++++++ migrations/Version20260316100100.php | 26 ++++++ src/Dto/WorkHours/WeeklyDaySummary.php | 2 + src/Dto/WorkHours/WeeklySummaryRow.php | 2 + src/Entity/WorkHour.php | 32 +++++++ src/State/WorkHourBulkUpsertProcessor.php | 86 ++++++++++++------- src/State/WorkHourWeeklySummaryProvider.php | 66 ++++++++------ 14 files changed, 255 insertions(+), 77 deletions(-) create mode 100644 migrations/Version20260316100000.php create mode 100644 migrations/Version20260316100100.php diff --git a/doc/functional-rules.md b/doc/functional-rules.md index 4ae479d..b41f978 100644 --- a/doc/functional-rules.md +++ b/doc/functional-rules.md @@ -124,18 +124,20 @@ Documents complementaires: - Colonnes spécifiques (vue jour): - Heure de jour (durée HH:MM via TimeSelect) - Heure de nuit (durée HH:MM via TimeSelect) - - Total (somme jour + nuit, calculé) + - Heure atelier (durée HH:MM via TimeSelect) + - Total (somme jour + nuit + atelier, calculé) - Petit déjeuner (checkbox) - Déjeuner (checkbox) + - Dîner (checkbox) - Nuitée (checkbox) - Stockage backend: - - `dayHoursMinutes` et `nightHoursMinutes` (entiers, minutes) sur `WorkHour` - - `hasBreakfast`, `hasLunch`, `hasOvernight` (booleans) sur `WorkHour` + - `dayHoursMinutes`, `nightHoursMinutes` et `workshopHoursMinutes` (entiers, minutes) sur `WorkHour` + - `hasBreakfast`, `hasLunch`, `hasDinner`, `hasOvernight` (booleans) sur `WorkHour` - les champs time classiques (morning/afternoon/evening) sont mis à null pour les chauffeurs - Validation: même logique que les heures classiques (`isValid`, `isSiteValid`, bulk) - Vue semaine: - - jour/nuit par jour + indicateurs repas/nuitée - - totaux hebdo: jour, nuit, total, compteurs petit déj/déjeuner/nuitée + - jour/nuit/atelier par jour + indicateurs repas/dîner/nuitée + - totaux hebdo: jour, nuit, atelier, total, compteurs petit déj/déjeuner/dîner/nuitée - pas de calcul d'heures supplémentaires pour les conducteurs - Le flag `isDriver` est sur `EmployeeContractPeriod` (un employé peut changer de statut chauffeur selon la période) - Exposé en API via un getter virtuel sur `Employee` (`employee:read`) qui résout depuis la période active diff --git a/frontend/components/driver-hours/DriverHoursDayView.vue b/frontend/components/driver-hours/DriverHoursDayView.vue index 90162b2..9b8ec00 100644 --- a/frontend/components/driver-hours/DriverHoursDayView.vue +++ b/frontend/components/driver-hours/DriverHoursDayView.vue @@ -9,9 +9,11 @@ Absence Heure de jour Heure de nuit + Heure atelier Total Petit déj. Déjeuner + Dîner Nuitée Valider @@ -96,6 +98,12 @@ :disabled="!hasContractAtSelectedDate(employee.id) || isRowLocked(employee.id)" /> +
+ +
{{ formatMinutes(getRowMetrics(employee.id).totalMinutes) }}
@@ -115,6 +123,14 @@ :disabled="!hasContractAtSelectedDate(employee.id) || isRowLocked(employee.id)" /> +
+ +
Nom - {{ day.label }} + {{ day.weekday }}
{{ day.dayDate }}
Jour/Nuit
sem.
+ Atelier
sem.
Total
sem.
Total
h. supp.
+25% @@ -16,7 +17,8 @@ Total
récup.
Petit
déj.
Déj. - Nuitée + Dîner + Nuit.
@@ -44,9 +46,11 @@ >
J {{ formatMinutes(daily.dayMinutes) }}
N {{ formatMinutes(daily.nightMinutes) }}
-
+
A {{ formatMinutes(daily.workshopMinutes) }}
+
PD DJ + DI NU
@@ -55,6 +59,9 @@
J {{ formatMinutes(row.weeklyDayMinutes) }}
N {{ formatMinutes(row.weeklyNightMinutes) }}
+
+ {{ formatMinutes(row.weeklyWorkshopMinutes ?? 0) }} +
{{ formatMinutes(row.weeklyTotalMinutes) }}
@@ -72,6 +79,7 @@
{{ row.weeklyBreakfastCount ?? 0 }}
{{ row.weeklyLunchCount ?? 0 }}
+
{{ row.weeklyDinnerCount ?? 0 }}
{{ row.weeklyOvernightCount ?? 0 }}
@@ -94,7 +102,7 @@ defineProps<{ isWeekLoading: boolean weekGridCols: string weeklySummary: WeeklyWorkHourSummary | null - weekDayHeaders: Array<{ date: string; label: string }> + weekDayHeaders: Array<{ date: string; weekday: string; dayDate: string }> formatMinutes: (minutes: number) => string }>() diff --git a/frontend/composables/useDriverHoursPage.ts b/frontend/composables/useDriverHoursPage.ts index c4b2ac1..b05619b 100644 --- a/frontend/composables/useDriverHoursPage.ts +++ b/frontend/composables/useDriverHoursPage.ts @@ -22,7 +22,6 @@ import { } from '~/services/work-hours' import { formatDateLongFr, - formatWeekDayHeaderFr, formatWeekRangeFr, getIsoWeekNumber, getOffsetFromTodayYmd, @@ -73,10 +72,10 @@ export const useDriverHoursPage = () => { const dayGridCols = computed(() => { const metricCol = '0.4fr' const validationCols = isAdmin.value ? `${metricCol}` : `${metricCol} ${metricCol}` - return `1.2fr 0.6fr 0.8fr 0.8fr ${metricCol} ${metricCol} ${metricCol} ${metricCol} ${validationCols}` + return `1.2fr 0.6fr 0.8fr 0.8fr 0.8fr ${metricCol} ${metricCol} ${metricCol} ${metricCol} ${metricCol} ${validationCols}` }) - const weekGridCols = '1.6fr repeat(7, 1fr) repeat(6, 0.6fr) repeat(3, 0.4fr)' + const weekGridCols = '1.6fr repeat(7, 0.6fr) repeat(7, 0.6fr) repeat(4, 0.4fr)' const sites = computed(() => { const siteMap = new Map() @@ -265,7 +264,13 @@ export const useDriverHoursPage = () => { const weekDayHeaders = computed(() => { const days = weeklySummary.value?.days ?? [] - return days.map((date) => ({ date, label: formatWeekDayHeaderFr(date) })) + return days.map((date) => { + const parsed = parseYmd(date) + if (!parsed) return { date, weekday: '', dayDate: '' } + const weekday = new Intl.DateTimeFormat('fr-FR', { weekday: 'short' }).format(parsed) + const dayDate = new Intl.DateTimeFormat('fr-FR', { day: '2-digit', month: '2-digit' }).format(parsed) + return { date, weekday, dayDate } + }) }) const shiftDate = (steps: number) => { @@ -331,8 +336,10 @@ export const useDriverHoursPage = () => { workHourId: null, dayHours: '', nightHours: '', + workshopHours: '', hasBreakfast: false, hasLunch: false, + hasDinner: false, hasOvernight: false, isSiteValid: false, isValid: false, @@ -357,8 +364,9 @@ export const useDriverHoursPage = () => { const row = rows.value[employeeId] ?? emptyRow() const dayMinutes = toMinutes(row.dayHours) const nightMinutes = toMinutes(row.nightHours) - const totalMinutes = dayMinutes + nightMinutes - return { dayMinutes, nightMinutes, totalMinutes } + const workshopMinutes = toMinutes(row.workshopHours) + const totalMinutes = dayMinutes + nightMinutes + workshopMinutes + return { dayMinutes, nightMinutes, workshopMinutes, totalMinutes } } const getRowAbsenceLabel = (employeeId: number) => { @@ -412,8 +420,10 @@ export const useDriverHoursPage = () => { workHourId: workHour?.id ?? null, dayHours: minutesToTimeString(workHour?.dayHoursMinutes), nightHours: minutesToTimeString(workHour?.nightHoursMinutes), + workshopHours: minutesToTimeString(workHour?.workshopHoursMinutes), hasBreakfast: workHour?.hasBreakfast ?? false, hasLunch: workHour?.hasLunch ?? false, + hasDinner: workHour?.hasDinner ?? false, hasOvernight: workHour?.hasOvernight ?? false, isSiteValid: workHour?.isSiteValid ?? false, isValid: workHour?.isValid ?? false, @@ -556,8 +566,10 @@ export const useDriverHoursPage = () => { isPresentAfternoon: false, dayHoursMinutes: null, nightHoursMinutes: null, + workshopHoursMinutes: null, hasBreakfast: false, hasLunch: false, + hasDinner: false, hasOvernight: false }) @@ -859,6 +871,7 @@ export const useDriverHoursPage = () => { const row = rows.value[employeeId] ?? emptyRow() const dayMin = toMinutes(row.dayHours) const nightMin = toMinutes(row.nightHours) + const workshopMin = toMinutes(row.workshopHours) return { employeeId, @@ -872,8 +885,10 @@ export const useDriverHoursPage = () => { isPresentAfternoon: false, dayHoursMinutes: dayMin || null, nightHoursMinutes: nightMin || null, + workshopHoursMinutes: workshopMin || null, hasBreakfast: row.hasBreakfast, hasLunch: row.hasLunch, + hasDinner: row.hasDinner, hasOvernight: row.hasOvernight } }) diff --git a/frontend/layouts/default.vue b/frontend/layouts/default.vue index 2ff6436..fa1ad72 100644 --- a/frontend/layouts/default.vue +++ b/frontend/layouts/default.vue @@ -21,14 +21,16 @@

Heures

addCreditedMinutes($creditedMinutes); - $dayMinutes = $metrics->dayMinutes; - $nightMinutes = $metrics->nightMinutes; - $totalMinutes = $metrics->totalMinutes; + $dayMinutes = $metrics->dayMinutes; + $nightMinutes = $metrics->nightMinutes; + $workshopMinutes = 0; + $totalMinutes = $metrics->totalMinutes; } $present = null; @@ -256,6 +267,7 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface $weeklyDayMinutes += $dayMinutes; $weeklyNightMinutes += $nightMinutes; + $weeklyWorkshopMinutes += $workshopMinutes; $weeklyTotalMinutes += $totalMinutes; if (null !== $present) { $weeklyPresenceCount += $present; @@ -265,6 +277,7 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface date: $date, dayMinutes: $dayMinutes, nightMinutes: $nightMinutes, + workshopMinutes: $workshopMinutes, totalMinutes: $totalMinutes, present: $present, hasAbsence: $absenceByEmployeeDate[$employeeId][$date] ?? false, @@ -272,6 +285,7 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface absenceColor: $absenceColorByEmployeeDate[$employeeId][$date] ?? null, hasBreakfast: $hasBreakfast, hasLunch: $hasLunch, + hasDinner: $hasDinner, hasOvernight: $hasOvernight, ); } @@ -304,6 +318,7 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface daily: $daily, weeklyDayMinutes: $weeklyDayMinutes, weeklyNightMinutes: $weeklyNightMinutes, + weeklyWorkshopMinutes: $weeklyWorkshopMinutes, weeklyTotalMinutes: $weeklyTotalMinutes, weeklyPresenceCount: $weeklyPresenceCount, weeklyOvertimeTotalMinutes: $weeklyOvertimeTotalMinutes, @@ -313,6 +328,7 @@ final readonly class WorkHourWeeklySummaryProvider implements ProviderInterface isDriver: $isDriver, weeklyBreakfastCount: $weeklyBreakfastCount, weeklyLunchCount: $weeklyLunchCount, + weeklyDinnerCount: $weeklyDinnerCount, weeklyOvernightCount: $weeklyOvernightCount, ); }