From 5e9fced68f07c28e78f1826c4fcfc3178883ad97 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Fri, 25 Sep 2026 09:27:32 +0200 Subject: [PATCH] feat: add 7j view mode to team planning --- .../templates/contracts/teams_index.html | 19 ++++++++------- loko/contracts/test_planning.py | 12 ++++++++++ loko/contracts/views_teams.py | 24 +++++++++++++++++-- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/loko/contracts/templates/contracts/teams_index.html b/loko/contracts/templates/contracts/teams_index.html index efa6b82..e6cc038 100644 --- a/loko/contracts/templates/contracts/teams_index.html +++ b/loko/contracts/templates/contracts/teams_index.html @@ -726,9 +726,10 @@
{% trans "Vue :" %}
- - - + + + +
@@ -1650,7 +1651,7 @@ const initialDate = (function() { const initialViewMode = (function() { const saved = getStoredSetting('view_mode', 'week'); - if (['work_week', 'week', 'two_weeks', 'month'].includes(saved)) return saved; + if (['work_week', 'days_7', '7_days', 'week', 'two_weeks', 'month'].includes(saved)) return saved; return 'week'; })(); @@ -1719,7 +1720,7 @@ document.addEventListener('DOMContentLoaded', function() { loadPlanningData(); }); - // Changement de mode de vue (5j / Semaine / Mois) + // Changement de mode de vue (5j / 7j / Semaine / Mois) $('#planning-viewmode-group button').on('click', function() { $('#planning-viewmode-group button').removeClass('btn-primary').addClass('btn-outline-primary'); $(this).removeClass('btn-outline-primary').addClass('btn-primary'); @@ -1736,7 +1737,7 @@ document.addEventListener('DOMContentLoaded', function() { setStoredSetting('assign_scope', 'week'); $('#planning-assign-scope-group button').removeClass('btn-primary').addClass('btn-outline-primary'); $('#planning-assign-scope-group button[data-scope="week"]').removeClass('btn-outline-primary').addClass('btn-primary'); - } else if (_planningState.viewMode === 'work_week') { + } else if (_planningState.viewMode === 'work_week' || _planningState.viewMode === 'days_7' || _planningState.viewMode === '7_days') { _planningState.assignScope = 'day'; setStoredSetting('assign_scope', 'day'); $('#planning-assign-scope-group button').removeClass('btn-primary').addClass('btn-outline-primary'); @@ -1941,10 +1942,12 @@ function renderPlanningMatrix(data) { quickDupTitle = "{% trans 'Dupliquer vers le mois suivant (avec absences)'|escapejs %}"; optionsTitle = "{% trans 'Options du mois'|escapejs %}"; dupCustomTitle = "{% trans 'Dupliquer ce mois…'|escapejs %}"; - } else if (_planningState.viewMode === 'work_week') { + } else if (_planningState.viewMode === 'work_week' || _planningState.viewMode === 'days_7' || _planningState.viewMode === '7_days') { const dParts = day.date.split('-'); const dateObj = new Date(parseInt(dParts[0], 10), parseInt(dParts[1], 10) - 1, parseInt(dParts[2], 10)); - if (dateObj.getDay() === 5) { + if (_planningState.viewMode === 'work_week' && dateObj.getDay() === 5) { + quickDupTitle = "{% trans 'Dupliquer vers le lundi suivant (avec absences)'|escapejs %}"; + } else if (dateObj.getDay() === 0) { quickDupTitle = "{% trans 'Dupliquer vers le lundi suivant (avec absences)'|escapejs %}"; } } diff --git a/loko/contracts/test_planning.py b/loko/contracts/test_planning.py index 45ee94a..f6c1556 100644 --- a/loko/contracts/test_planning.py +++ b/loko/contracts/test_planning.py @@ -622,6 +622,18 @@ class TeamPlanningAjaxViewsTests(TestCase): self.assertEqual(len(data['days']), 5) self.assertEqual(data['days'][0]['col_type'], 'day') + def test_planning_data_ajax_days_7_view(self): + """Tester le retour du mode 'days_7' (7 jours complets avec week-end) dans team_planning_data_ajax.""" + url = reverse('contracts:team_planning_data_ajax') + response = self.client.get(url, {'date': '2026-09-02', 'view_mode': 'days_7'}) + self.assertEqual(response.status_code, 200) + data = response.json() + self.assertEqual(len(data['days']), 7) + self.assertEqual(data['days'][0]['col_type'], 'day') + self.assertFalse(data['days'][0]['is_weekend']) # Lundi + self.assertTrue(data['days'][5]['is_weekend']) # Samedi + self.assertTrue(data['days'][6]['is_weekend']) # Dimanche + def test_planning_assign_member_ajax_week_scope(self): """Tester l'assignation avec portée 'week' via l'API AJAX.""" # Prendre un lundi dans le futur diff --git a/loko/contracts/views_teams.py b/loko/contracts/views_teams.py index e02acec..de3ff83 100644 --- a/loko/contracts/views_teams.py +++ b/loko/contracts/views_teams.py @@ -436,7 +436,7 @@ def team_planning_data_ajax(request): Retourne la matrice complète de planification des équipes sur une période. Paramètres GET : - date : date d'ancrage (YYYY-MM-DD), par défaut aujourd'hui - - view_mode : 'week' (7j, défaut), 'two_weeks' (14j), 'work_week' (5j) + - view_mode : 'work_week' (5j), 'days_7' (7j), 'week' (5 semaines), 'month' (6 mois), 'two_weeks' (14j) - company_id : filtrer sur une société spécifique (optionnel) """ if not user_can_view_teams(request.user): @@ -477,6 +477,24 @@ def team_planning_data_ajax(request): 'is_weekend': False, 'col_type': 'day', }) + elif view_mode in ('days_7', '7_days'): + num_days = 7 + start_date = monday + end_date = monday + timedelta(days=6) + for i in range(num_days): + d = start_date + timedelta(days=i) + w_idx = d.weekday() + days_list.append({ + 'date': d.isoformat(), + 'day_name': DAYS_FR_FULL[w_idx], + 'day_short': DAYS_FR_SHORT[w_idx], + 'day_num': f"{d.day:02d}/{d.month:02d}", + 'formatted': f"{DAYS_FR_SHORT[w_idx]} {d.day:02d} {MONTHS_FR[d.month]}", + 'is_today': d == today, + 'is_past': d < today, + 'is_weekend': w_idx >= 5, + 'col_type': 'day', + }) elif view_mode == 'two_weeks': num_days = 14 start_date = monday @@ -643,13 +661,15 @@ def team_planning_data_ajax(request): }) # 7. Structurer les membres pour le volet latéral (Sidebar) - if view_mode == 'week': + if view_mode in ('week', 'days_7', '7_days'): absent_member_ids = {mid for (mid, d) in absences.keys() if monday <= d <= monday + timedelta(days=6)} elif view_mode == 'month': _, d_in_m = calendar.monthrange(anchor_date.year, anchor_date.month) m_s = date(anchor_date.year, anchor_date.month, 1) m_e = date(anchor_date.year, anchor_date.month, d_in_m) absent_member_ids = {mid for (mid, d) in absences.keys() if m_s <= d <= m_e} + elif view_mode == 'work_week': + absent_member_ids = {mid for (mid, d) in absences.keys() if monday <= d <= monday + timedelta(days=4)} else: absent_member_ids = {mid for (mid, d) in absences.keys() if d == anchor_date} members_data = []