From 5856acf5ed9cc991686041b1b0bc25194926b5ce Mon Sep 17 00:00:00 2001 From: kdeterme Date: Wed, 9 Sep 2026 14:14:35 +0200 Subject: [PATCH] fix: restrict future team member display to explicitly scheduled join dates in calendar view --- loko/interventions/tests/test_general.py | 56 ++++++++++++++++++++++++ loko/interventions/views/calendar.py | 10 ++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/loko/interventions/tests/test_general.py b/loko/interventions/tests/test_general.py index 6b682d4..09c01ea 100644 --- a/loko/interventions/tests/test_general.py +++ b/loko/interventions/tests/test_general.py @@ -1258,6 +1258,62 @@ class InterventionAssignmentTests(TestCase): self.assertIn('John Doe', [m['name'] if isinstance(m, dict) else m for m in day_06_11_a['members']]) self.assertIn('John Doe', [m['name'] if isinstance(m, dict) else m for m in day_06_11_b['members']]) + @mock.patch('django.utils.timezone.now') + def test_teams_daily_future_days_only_explicitly_planned(self, mock_now): + from datetime import datetime, date + from contracts.models import CompanyMemberHistory, CompanyMember + import pytz + + # Fix today to Wednesday 2026-06-10 + # Monday is 2026-06-08, Tuesday 2026-06-09, Wednesday 2026-06-10 (today) + # Thursday 2026-06-11 (future), Friday 2026-06-12 (future) + mock_now.return_value = datetime(2026, 6, 10, 12, 0, 0, tzinfo=pytz.UTC) + + CompanyMemberHistory.objects.all().delete() + + # Member 1 has ongoing history in team_a starting Monday 2026-06-08 (no explicit future planning) + CompanyMemberHistory.objects.create( + member=self.member, + team=self.team_a, + join_date=date(2026, 6, 8), + leave_date=None, + ) + + # Member 2 is explicitly planned in team_b ONLY on Thursday 2026-06-11 + member2 = CompanyMember.objects.create(name='Jane Smith', user=self.user) + CompanyMemberHistory.objects.create( + member=member2, + team=self.team_b, + join_date=date(2026, 6, 11), + leave_date=None, + ) + + url = reverse('interventions:interventions_events') + '?view_mode=teams_daily&date=2026-06-10' + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + data = response.json() + + teams = data['teams'] + team_a_entry = next((t for t in teams if t['id'] == self.team_a.id), None) + team_b_entry = next((t for t in teams if t['id'] == self.team_b.id), None) + + # On Wednesday (today), team_a has John Doe + day_wed_a = team_a_entry['days']['2026-06-10'] + self.assertIn('John Doe', [m['name'] if isinstance(m, dict) else m for m in day_wed_a['members']]) + + # On Thursday (future), team_a does NOT repeat John Doe (theoretical carry-over not shown in advance) + day_thu_a = team_a_entry['days']['2026-06-11'] + self.assertEqual(day_thu_a['members'], []) + + # On Thursday (future), team_b HAS Jane Smith (explicitly planned for Thursday) + day_thu_b = team_b_entry['days']['2026-06-11'] + self.assertIn('Jane Smith', [m['name'] if isinstance(m, dict) else m for m in day_thu_b['members']]) + + # On Friday (future), team_b does NOT have Jane Smith (not explicitly planned for Friday) + day_fri_b = team_b_entry['days']['2026-06-12'] + self.assertEqual(day_fri_b['members'], []) + + diff --git a/loko/interventions/views/calendar.py b/loko/interventions/views/calendar.py index e47634b..392f3f2 100644 --- a/loko/interventions/views/calendar.py +++ b/loko/interventions/views/calendar.py @@ -967,6 +967,7 @@ def _interventions_events_by_teams_daily( team_compositions_sets = defaultdict(set) # For each day of the week + today = timezone.now().date() for i in range(7): d = monday + timedelta(days=i) @@ -975,8 +976,13 @@ def _interventions_events_by_teams_daily( # Find which histories are active on day d active = [] for h in m_data['histories']: - if h['join_date'] <= d and (h['leave_date'] is None or h['leave_date'] >= d): - active.append(h) + if d <= today: + if h['join_date'] <= d and (h['leave_date'] is None or h['leave_date'] >= d): + active.append(h) + else: + # Pour les jours futurs : affiché uniquement si explicitement planifié pour ce jour (join_date == d) + if h['join_date'] == d: + active.append(h) if not active: continue