fix: allow direct deletion of future team assignments and remove redundant confirmation dialog

This commit is contained in:
kdeterme 2026-09-02 11:47:21 +02:00
parent 71b445797d
commit efdafa43de
3 changed files with 65 additions and 4 deletions

View file

@ -94,8 +94,12 @@ def set_member_team_schedule(
# 2. Clôturer ou ajuster l'historique courant (actif à target_date) # 2. Clôturer ou ajuster l'historique courant (actif à target_date)
if current_at_target: if current_at_target:
if current_at_target.join_date == target_date: if current_at_target.join_date == target_date:
current_at_target.leave_date = target_date if target_date > today or team_id is None:
current_at_target.save(update_fields=['leave_date']) # Sur une date future ou lors d'une désassignation, on supprime directement l'affectation du jour
current_at_target.delete()
else:
current_at_target.leave_date = target_date
current_at_target.save(update_fields=['leave_date'])
else: else:
# L'historique commençait avant target_date : on le clôture la veille # L'historique commençait avant target_date : on le clôture la veille
prev_leave = target_date - timedelta(days=1) prev_leave = target_date - timedelta(days=1)

View file

@ -1718,8 +1718,6 @@ function filterSidebarMembers() {
} }
function unassignMemberFromDate(memberId, dateStr) { function unassignMemberFromDate(memberId, dateStr) {
if (!confirm("{% trans 'Désassigner ce membre à partir de cette date ?'|escapejs %}")) return;
postJSON( postJSON(
'/contracts/teams/planning/assign/', '/contracts/teams/planning/assign/',
{ {

View file

@ -264,3 +264,62 @@ class TeamPlanningAjaxViewsTests(TestCase):
self.assertEqual(resp_dup.status_code, 400) self.assertEqual(resp_dup.status_code, 400)
self.assertIn('passé', resp_dup.json().get('error', '').lower()) self.assertIn('passé', resp_dup.json().get('error', '').lower())
def test_reassign_future_member_to_same_team_as_previous_day(self):
"""
Vérifie qu'un membre présent dans Team 1 le vendredi (J) et Team 2 le samedi (J+1)
peut être replanifié dans Team 1 le samedi (J+1).
"""
today = timezone.now().date()
friday = today + timedelta(days=2)
saturday = today + timedelta(days=3)
# 1. Vendredi dans Team A, Samedi dans Team B
set_member_team_schedule(self.member_alice, self.team_a.id, friday)
set_member_team_schedule(self.member_alice, self.team_b.id, saturday)
comp1 = get_teams_composition_for_period({self.team_a.id, self.team_b.id}, friday, saturday)
self.assertIn(self.member_alice.id, [m['id'] for m in comp1.get((self.team_a.id, friday), [])])
self.assertIn(self.member_alice.id, [m['id'] for m in comp1.get((self.team_b.id, saturday), [])])
# 2. Replanifier Alice dans Team A le samedi via AJAX
url = reverse('contracts:team_planning_assign_member_ajax')
resp = self.client.post(url, data=json.dumps({
'member_id': self.member_alice.id,
'team_id': self.team_a.id,
'date': saturday.isoformat(),
}), content_type='application/json')
self.assertEqual(resp.status_code, 200)
# 3. Vérifier la composition : Alice est dans Team A le vendredi ET le samedi
comp2 = get_teams_composition_for_period({self.team_a.id, self.team_b.id}, friday, saturday)
team_a_friday = [m['id'] for m in comp2.get((self.team_a.id, friday), [])]
team_a_saturday = [m['id'] for m in comp2.get((self.team_a.id, saturday), [])]
team_b_saturday = [m['id'] for m in comp2.get((self.team_b.id, saturday), [])]
self.assertIn(self.member_alice.id, team_a_friday)
self.assertIn(self.member_alice.id, team_a_saturday)
self.assertNotIn(self.member_alice.id, team_b_saturday)
def test_unassign_member_for_specific_date(self):
"""Vérifie que la désassignation supprime le membre uniquement pour la date cliquée."""
today = timezone.now().date()
target_d = today + timedelta(days=2)
# 1. Assigner Alice sur target_d
set_member_team_schedule(self.member_alice, self.team_a.id, target_d)
comp1 = get_teams_composition_for_period({self.team_a.id}, target_d, target_d)
self.assertIn(self.member_alice.id, [m['id'] for m in comp1.get((self.team_a.id, target_d), [])])
# 2. Désassigner Alice pour target_d (team_id=None)
url = reverse('contracts:team_planning_assign_member_ajax')
resp = self.client.post(url, data=json.dumps({
'member_id': self.member_alice.id,
'team_id': None,
'date': target_d.isoformat(),
}), content_type='application/json')
self.assertEqual(resp.status_code, 200)
# 3. Vérifier que la cellule est désormais vide
comp2 = get_teams_composition_for_period({self.team_a.id}, target_d, target_d)
self.assertNotIn(self.member_alice.id, [m['id'] for m in comp2.get((self.team_a.id, target_d), [])])