loko/loko/contracts/test_planning.py

204 lines
9.3 KiB
Python

import json
from datetime import date, timedelta
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils import timezone
from contracts.models import Company, CompanyTeam, CompanyMember, CompanyMemberHistory, CompanyMemberAbsence
from contracts.services_teams import (
get_member_team_for_date,
set_member_team_schedule,
get_teams_composition_for_period,
get_member_absences_for_period,
toggle_member_absence,
duplicate_day_schedule,
duplicate_week_schedule,
sync_member_current_teams,
)
User = get_user_model()
class TeamPlanningServicesTests(TestCase):
def setUp(self):
self.user = User.objects.create_user(username="alice", password="password123")
self.company = Company.objects.create(name="Acme Corp")
self.team_a = CompanyTeam.objects.create(name="Team A", company=self.company)
self.team_b = CompanyTeam.objects.create(name="Team B", company=self.company)
self.member_alice = CompanyMember.objects.create(name="Alice", user=self.user)
def test_schedule_future_team_change_preserves_today(self):
"""
Scénario clé :
- Alice est dans l'équipe A aujourd'hui (02/09).
- Le coordinateur planifie Alice dans l'équipe B pour demain (03/09).
- Alice doit rester dans l'équipe A aujourd'hui et être dans l'équipe B demain.
"""
today = date(2026, 9, 2)
tomorrow = date(2026, 9, 3)
# Alice est affectée à l'équipe A depuis le 01/09
set_member_team_schedule(self.member_alice, self.team_a.id, date(2026, 9, 1))
# Vérifier qu'elle est bien dans l'équipe A aujourd'hui
self.assertEqual(get_member_team_for_date(self.member_alice, today), self.team_a)
# Planifier l'équipe B pour demain
set_member_team_schedule(self.member_alice, self.team_b.id, tomorrow)
# Vérifier : aujourd'hui elle est TOUJOURS dans l'équipe A
self.assertEqual(get_member_team_for_date(self.member_alice, today), self.team_a)
# Vérifier : demain elle sera dans l'équipe B
self.assertEqual(get_member_team_for_date(self.member_alice, tomorrow), self.team_b)
# Vérifier : après-demain elle reste dans l'équipe B (persistance)
self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 9, 4)), self.team_b)
def test_schedule_unassign_for_future_date(self):
"""Tester la désassignation à une date future."""
d1 = date(2026, 9, 1)
d2 = date(2026, 9, 5)
set_member_team_schedule(self.member_alice, self.team_a.id, d1)
self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 9, 3)), self.team_a)
# Désassigner à partir du 5 septembre
set_member_team_schedule(self.member_alice, None, d2)
self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 9, 4)), self.team_a)
self.assertIsNone(get_member_team_for_date(self.member_alice, d2))
self.assertIsNone(get_member_team_for_date(self.member_alice, date(2026, 9, 10)))
def test_toggle_absence(self):
"""Tester l'activation et désactivation d'une absence."""
target_date = date(2026, 9, 3)
# Activer l'absence
absence = toggle_member_absence(self.member_alice, target_date, is_absent=True, reason='maladie', comment='Grippe')
self.assertIsNotNone(absence)
self.assertEqual(CompanyMemberAbsence.objects.filter(member=self.member_alice, date=target_date).count(), 1)
absences = get_member_absences_for_period({self.member_alice.id}, target_date, target_date)
self.assertIn((self.member_alice.id, target_date), absences)
self.assertEqual(absences[(self.member_alice.id, target_date)]['reason'], 'maladie')
# Désactiver l'absence
toggle_member_absence(self.member_alice, target_date, is_absent=False)
self.assertEqual(CompanyMemberAbsence.objects.filter(member=self.member_alice, date=target_date).count(), 0)
def test_duplicate_day_schedule(self):
"""Tester la duplication de configuration d'un jour vers un autre."""
monday = date(2026, 9, 7)
tuesday = date(2026, 9, 8)
# Lundi : Alice en Team A et absente
set_member_team_schedule(self.member_alice, self.team_a.id, monday)
toggle_member_absence(self.member_alice, monday, is_absent=True, reason='conge')
# Dupliquer vers mardi avec copie des absences
res = duplicate_day_schedule(monday, tuesday, copy_absences=True)
self.assertGreaterEqual(res['assigned_count'], 1)
self.assertEqual(res['absences_count'], 1)
# Vérifier l'affectation du mardi
self.assertEqual(get_member_team_for_date(self.member_alice, tuesday), self.team_a)
self.assertTrue(CompanyMemberAbsence.objects.filter(member=self.member_alice, date=tuesday).exists())
def test_duplicate_week_schedule(self):
"""Tester la duplication d'une semaine complète vers la semaine suivante."""
w1_monday = date(2026, 9, 7)
w2_monday = date(2026, 9, 14)
set_member_team_schedule(self.member_alice, self.team_a.id, w1_monday)
res = duplicate_week_schedule(w1_monday, w2_monday, copy_absences=False)
self.assertGreaterEqual(res['assigned_count'], 1)
# Vérifier que le mercredi de la semaine 2, Alice est bien en Team A
self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 9, 16)), self.team_a)
class TeamPlanningAjaxViewsTests(TestCase):
def setUp(self):
from common.models import UserConfig, Role
import json
self.user = User.objects.create_user(username="admin_user", password="password123")
self.user_config = UserConfig.objects.create(user=self.user, is_intern=True)
admin_role = Role.objects.create(name="admin")
self.user_config.roles.add(admin_role)
self.company = Company.objects.create(name="Acme Corp")
self.team_a = CompanyTeam.objects.create(name="Team A", company=self.company)
self.team_b = CompanyTeam.objects.create(name="Team B", company=self.company)
self.tech_user = User.objects.create_user(username="alice", password="password123")
self.member_alice = CompanyMember.objects.create(name="Alice", user=self.tech_user)
self.client.login(username="admin_user", password="password123")
def test_planning_data_ajax(self):
url = reverse('contracts:team_planning_data_ajax')
response = self.client.get(url, {'date': '2026-09-02', 'view_mode': 'week'})
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertIn('days', data)
self.assertEqual(len(data['days']), 7)
self.assertIn('teams', data)
self.assertIn('members', data)
def test_planning_assign_member_ajax(self):
url = reverse('contracts:team_planning_assign_member_ajax')
payload = {
'member_id': self.member_alice.id,
'team_id': self.team_b.id,
'date': '2026-09-03',
}
response = self.client.post(url, data=json.dumps(payload), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json()['success'])
# Vérifier l'affectation
self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 9, 3)), self.team_b)
def test_planning_toggle_absence_ajax(self):
url = reverse('contracts:team_planning_toggle_absence_ajax')
payload = {
'member_id': self.member_alice.id,
'date': '2026-09-04',
'is_absent': True,
'reason': 'maladie',
'comment': 'Rhume',
}
response = self.client.post(url, data=json.dumps(payload), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json()['is_absent'])
self.assertEqual(CompanyMemberAbsence.objects.filter(member=self.member_alice, date='2026-09-04').count(), 1)
def test_planning_duplicate_ajax(self):
# Assigner Alice le 07/09
set_member_team_schedule(self.member_alice, self.team_a.id, date(2026, 9, 7))
url = reverse('contracts:team_planning_duplicate_ajax')
payload = {
'mode': 'day',
'source_date': '2026-09-07',
'target_date': '2026-09-08',
'copy_absences': False,
}
response = self.client.post(url, data=json.dumps(payload), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json()['success'])
self.assertEqual(get_member_team_for_date(self.member_alice, date(2026, 9, 8)), self.team_a)
def test_teams_move_member_syncs_history(self):
url = reverse('contracts:teams_move_member', args=[self.member_alice.id])
payload = {
'team_id': self.team_a.id,
'old_team_id': None,
}
response = self.client.post(url, data=json.dumps(payload), content_type='application/json')
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json()['success'])
today = timezone.now().date()
self.assertEqual(get_member_team_for_date(self.member_alice, today), self.team_a)