From 096886a1941cabf2806177e9cb779408ca42fd96 Mon Sep 17 00:00:00 2001 From: Karl Determe Date: Thu, 24 Sep 2026 11:33:53 +0200 Subject: [PATCH] feat: add Django admin configuration, team services, and test planning for contracts --- loko/contracts/admin.py | 4 ++-- loko/contracts/services_teams.py | 4 ++++ loko/contracts/test_planning.py | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/loko/contracts/admin.py b/loko/contracts/admin.py index 710ba28..4ca4c1f 100644 --- a/loko/contracts/admin.py +++ b/loko/contracts/admin.py @@ -427,14 +427,14 @@ class CompanyMemberHistoryAdmin(admin.ModelAdmin): list_display = ('member', 'team', 'join_date', 'leave_date', 'changed_by') list_filter = ('team__company', 'team') search_fields = ('member__name', 'team__name') - readonly_fields = ('member', 'team', 'join_date', 'leave_date', 'changed_by') + readonly_fields = ('member', 'team', 'join_date', 'changed_by') date_hierarchy = 'join_date' def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): - return False + return True @admin.register(CompanyMemberAbsence) diff --git a/loko/contracts/services_teams.py b/loko/contracts/services_teams.py index 1159efe..4191a2c 100644 --- a/loko/contracts/services_teams.py +++ b/loko/contracts/services_teams.py @@ -98,6 +98,8 @@ def set_member_team_schedule( ).filter( Q(leave_date__isnull=True) | Q(leave_date__gte=target_date) ).update(leave_date=prev_leave) + if target_date <= today: + member.teams.remove(unassign_team_id) else: # Désassignation globale de toutes les équipes if target_date > today: @@ -117,6 +119,8 @@ def set_member_team_schedule( ).filter( Q(leave_date__isnull=True) | Q(leave_date__gte=target_date) ).update(leave_date=prev_leave) + if target_date <= today: + member.teams.clear() _sync_teams_if_needed(member, target_date, today, sync_current) return None diff --git a/loko/contracts/test_planning.py b/loko/contracts/test_planning.py index 958526c..d96dc46 100644 --- a/loko/contracts/test_planning.py +++ b/loko/contracts/test_planning.py @@ -654,5 +654,43 @@ class TeamPlanningAjaxViewsTests(TestCase): self.assertGreaterEqual(data['assigned_count'], 1) self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 11, 1)), self.team_b) + def test_planning_unassign_member_for_today_removes_from_team_and_planning(self): + """ + Tester que la désassignation d'un membre pour aujourd'hui : + 1. Le retire bien de member.teams. + 2. Le retire bien de la composition d'équipe pour aujourd'hui (sans résurrection zombie). + """ + today = timezone.now().date() + member_test = CompanyMember.objects.create(name="Technicien Test", user=self.user) + member_test.teams.add(self.team_a) + + # Vérifier qu'il est bien dans l'équipe A + self.assertIn(self.team_a, member_test.teams.all()) + comp_before = get_teams_composition_for_period({self.team_a.id}, today, today) + self.assertIn(member_test.id, [m['id'] for m in comp_before.get((self.team_a.id, today), [])]) + + # Désassigner pour aujourd'hui via l'API AJAX + url = reverse('contracts:team_planning_assign_member_ajax') + payload = { + 'member_id': member_test.id, + 'team_id': None, + 'date': today.isoformat(), + 'unassign_team_id': self.team_a.id, + 'scope': 'day', + } + response = self.client.post(url, data=json.dumps(payload), content_type='application/json') + self.assertEqual(response.status_code, 200) + self.assertTrue(response.json()['success']) + + member_test.refresh_from_db() + # Le membre ne doit plus être dans l'équipe A aujourd'hui + self.assertNotIn(self.team_a, member_test.teams.all()) + self.assertEqual(member_test.teams.count(), 0) + + # Vérifier qu'il n'apparaît plus dans la composition d'aujourd'hui + comp_after = get_teams_composition_for_period({self.team_a.id}, today, today) + self.assertNotIn(member_test.id, [m['id'] for m in comp_after.get((self.team_a.id, today), [])]) + +