From fad90d91c97d00c9c4f578300ade22a8e5f07ac9 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Wed, 2 Sep 2026 12:20:42 +0200 Subject: [PATCH] feat: add team synchronization service, management command, and improve calendar header UI --- .../commands/sync_teams_schedule.py | 30 +++++++++++++++++++ loko/contracts/services_teams.py | 17 +++++++++++ .../templates/contracts/teams_index.html | 26 ++++++++++------ loko/contracts/views_teams.py | 4 +++ 4 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 loko/contracts/management/commands/sync_teams_schedule.py diff --git a/loko/contracts/management/commands/sync_teams_schedule.py b/loko/contracts/management/commands/sync_teams_schedule.py new file mode 100644 index 0000000..f06acf2 --- /dev/null +++ b/loko/contracts/management/commands/sync_teams_schedule.py @@ -0,0 +1,30 @@ +from datetime import datetime +from django.core.management.base import BaseCommand +from django.utils import timezone +from contracts.services_teams import sync_all_members_current_teams + + +class Command(BaseCommand): + help = "Synchronise les équipes actuelles (member.teams) avec l'historique planifié pour aujourd'hui (ou une date donnée)." + + def add_arguments(self, parser): + parser.add_argument( + '--date', + type=str, + help="Date de synchronisation au format YYYY-MM-DD (défaut: aujourd'hui)", + ) + + def handle(self, *args, **options): + date_str = options.get('date') + if date_str: + try: + target_date = datetime.strptime(date_str, '%Y-%m-%d').date() + except ValueError: + self.stderr.write(self.style.ERROR(f"Format de date invalide : {date_str} (attendu YYYY-MM-DD)")) + return + else: + target_date = timezone.now().date() + + self.stdout.write(f"Synchronisation des équipes pour la date : {target_date}...") + count = sync_all_members_current_teams(target_date) + self.stdout.write(self.style.SUCCESS(f"Synchronisation terminée avec succès pour {count} membre(s).")) diff --git a/loko/contracts/services_teams.py b/loko/contracts/services_teams.py index cfddb79..72e2e11 100644 --- a/loko/contracts/services_teams.py +++ b/loko/contracts/services_teams.py @@ -134,6 +134,23 @@ def sync_member_current_teams(member: CompanyMember, for_date: Optional[date] = member.teams.set(list(target_team_ids)) +def sync_all_members_current_teams(for_date: Optional[date] = None) -> int: + """ + Synchronise le champ ManyToMany member.teams pour tous les membres + selon l'équipe active dans CompanyMemberHistory à la date donnée (aujourd'hui par défaut). + Retourne le nombre de membres synchronisés. + """ + if for_date is None: + for_date = timezone.now().date() + + members = CompanyMember.objects.all().prefetch_related('teams') + count = 0 + for m in members: + sync_member_current_teams(m, for_date) + count += 1 + return count + + def get_teams_composition_for_period( team_ids: Set[int], start_date: date, diff --git a/loko/contracts/templates/contracts/teams_index.html b/loko/contracts/templates/contracts/teams_index.html index a11cdc3..74d6164 100644 --- a/loko/contracts/templates/contracts/teams_index.html +++ b/loko/contracts/templates/contracts/teams_index.html @@ -282,10 +282,10 @@ /* Bouton de duplication rapide au bas à droite des en-têtes de jour */ .btn-quick-duplicate { position: absolute; - bottom: 4px; - right: 4px; - width: 24px; - height: 24px; + bottom: 2px; + right: 2px; + width: 22px; + height: 22px; padding: 0; display: inline-flex; align-items: center; @@ -1558,8 +1558,15 @@ function renderPlanningMatrix(data) { const optionsTitle = "{% trans 'Options de la journée'|escapejs %}"; const dupCustomTitle = "{% trans 'Dupliquer cette journée…'|escapejs %}"; + let badgeHtml = ''; + if (day.is_today) { + badgeHtml = `{% trans "Aujourd'hui"|escapejs %}`; + } else if (day.is_past) { + badgeHtml = `{% trans "Passé"|escapejs %}`; + } + th.innerHTML = ` -
+
${CAN_EDIT_TEAMS ? ` ` : ''} -
${escapeHtml(day.day_short)}
-
${escapeHtml(day.day_num)}
- ${day.is_today ? `{% trans "Aujourd'hui"|escapejs %}` : ''} - ${day.is_past ? `{% trans "Passé"|escapejs %}` : ''} +
${escapeHtml(day.day_short)}
+
${escapeHtml(day.day_num)}
+
+ ${badgeHtml} +
${CAN_EDIT_TEAMS ? `