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 = []