diff --git a/loko/interventions/locale/en/LC_MESSAGES/django.mo b/loko/interventions/locale/en/LC_MESSAGES/django.mo index 0ca6d19..07332df 100644 Binary files a/loko/interventions/locale/en/LC_MESSAGES/django.mo and b/loko/interventions/locale/en/LC_MESSAGES/django.mo differ diff --git a/loko/interventions/locale/en/LC_MESSAGES/django.po b/loko/interventions/locale/en/LC_MESSAGES/django.po index 6c11a24..3525d7a 100644 --- a/loko/interventions/locale/en/LC_MESSAGES/django.po +++ b/loko/interventions/locale/en/LC_MESSAGES/django.po @@ -5444,31 +5444,31 @@ msgstr "View intervention" #: interventions/templates/interventions/interventions_calendar.html:660 msgid "Historique du membre" -msgstr "Sending history" +msgstr "Member history" #: interventions/templates/interventions/interventions_calendar.html:675 msgid "Technicien / Membre" -msgstr "Technician" +msgstr "Technician / Member" #: interventions/templates/interventions/interventions_calendar.html:681 msgid "Entreprise" -msgstr "Maintenance" +msgstr "Company / Organization" #: interventions/templates/interventions/interventions_calendar.html:694 msgid "Historique des équipes" -msgstr "Sending history" +msgstr "Team history" #: interventions/templates/interventions/interventions_calendar.html:702 msgid "Entrée" -msgstr "Maintenance" +msgstr "Joined" #: interventions/templates/interventions/interventions_calendar.html:703 msgid "Sortie" -msgstr "Sortie" +msgstr "Left" #: interventions/templates/interventions/interventions_calendar.html:718 msgid "Dernières interventions réalisées / assignées" -msgstr "Export selected interventions" +msgstr "Recent realized / assigned interventions" #: interventions/templates/interventions/interventions_index.html:420 msgid "Choisir le type d’intervention" diff --git a/loko/interventions/locale/fr/LC_MESSAGES/django.mo b/loko/interventions/locale/fr/LC_MESSAGES/django.mo index beb2ff2..3e19297 100644 Binary files a/loko/interventions/locale/fr/LC_MESSAGES/django.mo and b/loko/interventions/locale/fr/LC_MESSAGES/django.mo differ diff --git a/loko/interventions/locale/fr/LC_MESSAGES/django.po b/loko/interventions/locale/fr/LC_MESSAGES/django.po index 45b1a94..665fdca 100644 --- a/loko/interventions/locale/fr/LC_MESSAGES/django.po +++ b/loko/interventions/locale/fr/LC_MESSAGES/django.po @@ -5502,15 +5502,15 @@ msgstr "Technicien" #: interventions/templates/interventions/interventions_calendar.html:681 msgid "Entreprise" -msgstr "Entretien" +msgstr "Entreprise / Organisme" #: interventions/templates/interventions/interventions_calendar.html:694 msgid "Historique des équipes" -msgstr "Historique des envois" +msgstr "Historique des équipes" #: interventions/templates/interventions/interventions_calendar.html:702 msgid "Entrée" -msgstr "Entretien" +msgstr "Entrée" #: interventions/templates/interventions/interventions_calendar.html:703 msgid "Sortie" @@ -5518,7 +5518,7 @@ msgstr "Sortie" #: interventions/templates/interventions/interventions_calendar.html:718 msgid "Dernières interventions réalisées / assignées" -msgstr "Exporter les interventions sélectionnées" +msgstr "Dernières interventions réalisées / assignées" #: interventions/templates/interventions/interventions_index.html:420 msgid "Choisir le type d’intervention" diff --git a/loko/interventions/locale/nl/LC_MESSAGES/django.mo b/loko/interventions/locale/nl/LC_MESSAGES/django.mo index a7b7663..d732deb 100644 Binary files a/loko/interventions/locale/nl/LC_MESSAGES/django.mo and b/loko/interventions/locale/nl/LC_MESSAGES/django.mo differ diff --git a/loko/interventions/locale/nl/LC_MESSAGES/django.po b/loko/interventions/locale/nl/LC_MESSAGES/django.po index c341457..1ded47e 100644 --- a/loko/interventions/locale/nl/LC_MESSAGES/django.po +++ b/loko/interventions/locale/nl/LC_MESSAGES/django.po @@ -5458,31 +5458,31 @@ msgstr "Interventie bekijken" #: interventions/templates/interventions/interventions_calendar.html:660 msgid "Historique du membre" -msgstr "Verzendgeschiedenis" +msgstr "Geschiedenis van het lid" #: interventions/templates/interventions/interventions_calendar.html:675 msgid "Technicien / Membre" -msgstr "Technicus" +msgstr "Technicus / Lid" #: interventions/templates/interventions/interventions_calendar.html:681 msgid "Entreprise" -msgstr "Onderhoud" +msgstr "Bedrijf / Organisatie" #: interventions/templates/interventions/interventions_calendar.html:694 msgid "Historique des équipes" -msgstr "Verzendgeschiedenis" +msgstr "Ploegengeschiedenis" #: interventions/templates/interventions/interventions_calendar.html:702 msgid "Entrée" -msgstr "Onderhoud" +msgstr "Instroom" #: interventions/templates/interventions/interventions_calendar.html:703 msgid "Sortie" -msgstr "" +msgstr "Uitstroom" #: interventions/templates/interventions/interventions_calendar.html:718 msgid "Dernières interventions réalisées / assignées" -msgstr "Geselecteerde interventies exporteren" +msgstr "Laatste uitgevoerde / toegewezen interventies" #: interventions/templates/interventions/interventions_index.html:420 msgid "Choisir le type d’intervention" diff --git a/loko/interventions/models.py b/loko/interventions/models.py index 2b776ec..c039b67 100644 --- a/loko/interventions/models.py +++ b/loko/interventions/models.py @@ -639,6 +639,10 @@ class Intervention(models.Model): while curr <= end_date: active_dates.add(curr) curr += timedelta(days=1) + if self.begin_time: + active_dates.add(self.begin_time.date()) + if self.end_time: + active_dates.add(self.end_time.date()) today = timezone.now().date() diff --git a/loko/interventions/tests/test_calendar.py b/loko/interventions/tests/test_calendar.py index 2fcdaeb..172c58f 100644 --- a/loko/interventions/tests/test_calendar.py +++ b/loko/interventions/tests/test_calendar.py @@ -272,13 +272,45 @@ class CalendarEventsTests(TestCase): def test_member_history_ajax_permissions_and_data(self): from contracts.models import CompanyMember, CompanyMemberHistory + from interventions.models import Intervention member = CompanyMember.objects.create(name="Jean Dupont", user=self.user) member.teams.add(self.team_a) + + ten_days_ago = timezone.now().date() - timedelta(days=10) + two_days_ago = timezone.now().date() - timedelta(days=2) + CompanyMemberHistory.objects.create( member=member, team=self.team_a, - join_date=timezone.now().date() - timedelta(days=10) + join_date=ten_days_ago, + leave_date=two_days_ago, ) + + # 1. Intervention assigned to team_a 5 days ago (during membership), finished by someone else + itv1 = Intervention.objects.create( + title='Team Task Finished by Manager', + status='finished', + maintain_type='corrective', + assigned_provider=self.company, + assigned_team=self.team_a, + begin_time=timezone.now() - timedelta(days=5), + end_time=timezone.now() - timedelta(days=5), + ) + + # 2. Intervention directly processed today + itv2 = Intervention.objects.create( + title='Directly Processed Task', + status='processed', + maintain_type='corrective', + assigned_provider=self.company, + assigned_member=member, + begin_time=timezone.now(), + end_time=timezone.now(), + ) + + # Clear active teams to simulate removed member + member.teams.clear() + url = reverse('interventions:member_history_ajax', args=[member.id]) response = self.client.get(url) self.assertEqual(response.status_code, 200) @@ -286,10 +318,26 @@ class CalendarEventsTests(TestCase): self.assertIn('member', data) self.assertEqual(data['member']['name'], "Jean Dupont") + # Company name should still be resolved from history + self.assertEqual(data['member']['company'], self.company.name) + self.assertIn('team_history', data) self.assertTrue(len(data['team_history']) >= 1) self.assertEqual(data['team_history'][0]['team_name'], self.team_a.name) + # Interventions list should include both team task and directly processed task + self.assertIn('interventions', data) + itv_ids = [itv['id'] for itv in data['interventions']] + self.assertIn(itv1.id, itv_ids) + self.assertIn(itv2.id, itv_ids) + + # Check status display and codes + itv1_entry = next(item for item in data['interventions'] if item['id'] == itv1.id) + self.assertEqual(itv1_entry['status_code'], 'finished') + + itv2_entry = next(item for item in data['interventions'] if item['id'] == itv2.id) + self.assertEqual(itv2_entry['status_code'], 'processed') + def test_unassign_sans_equipe_reverts_status_to_backlog(self): itv = Intervention.objects.create( title='Unassigned Test', diff --git a/loko/interventions/views/calendar.py b/loko/interventions/views/calendar.py index 38a765f..4750146 100644 --- a/loko/interventions/views/calendar.py +++ b/loko/interventions/views/calendar.py @@ -1371,13 +1371,11 @@ def member_history_ajax(request, member_id): return JsonResponse({'error': _("Permission refusée.")}, status=403) member = get_object_or_404(CompanyMember.objects.prefetch_related('teams__company'), id=member_id) - company_names = set(t.company.name for t in member.teams.all() if getattr(t, 'company', None)) - company_str = ", ".join(sorted(company_names)) if company_names else '' team_history_qs = ( CompanyMemberHistory.objects .filter(member=member) - .select_related('team') + .select_related('team__company') .order_by('-join_date') ) team_history = [ @@ -1390,12 +1388,51 @@ def member_history_ajax(request, member_id): for h in team_history_qs ] + company_names = set(t.company.name for t in member.teams.all() if getattr(t, 'company', None)) + if not company_names: + company_names = set(h.team.company.name for h in team_history_qs if h.team and getattr(h.team, 'company', None)) + if not company_names and member.user_id: + company_names = set( + uca.contract.company.name for uca in UserContractAccess.objects.filter(user_config__user=member.user) + if uca.contract and getattr(uca.contract, 'company', None) + ) + company_str = ", ".join(sorted(company_names)) if company_names else '—' + + # Filter assignments: + # 1. Directly assigned to this member in InterventionAssignment + assignment_q = Q(member=member) + + # 2. Directly assigned / acted upon by member user on Intervention + if member.user_id: + assignment_q |= ( + Q(intervention__assigned_member=member) | + Q(intervention__realized_events__event_user=member.user) | + Q(intervention__occupations__member=member) + ) + + # 3. Interventions assigned to teams during the periods member was in that team + team_periods_q = Q() + for h in team_history_qs: + if h.team_id and h.join_date: + tq = Q(team_id=h.team_id, date__gte=h.join_date) + if h.leave_date: + tq &= Q(date__lte=h.leave_date) + team_periods_q |= tq + + for t in member.teams.all(): + if not team_history_qs.filter(team=t).exists(): + team_periods_q |= Q(team=t) + + if team_periods_q: + assignment_q |= team_periods_q + assignments_qs = ( InterventionAssignment.objects - .filter(member=member) + .filter(assignment_q) .select_related('intervention', 'team') .order_by('-date', '-intervention__code', '-intervention__id')[:100] ) + interventions_list = [ { 'id': a.intervention.id, @@ -1403,14 +1440,50 @@ def member_history_ajax(request, member_id): 'title': a.intervention.title, 'date': a.date.strftime('%d/%m/%Y') if a.date else '', 'raw_date': a.date.isoformat() if a.date else '', - 'team_name': a.team.name if a.team else '—', - 'status_code': a.status or a.intervention.status, - 'status_display': dict(STATUS_CHOICES).get(a.status or a.intervention.status, a.status or a.intervention.status), + 'team_name': a.team.name if a.team else (a.intervention.assigned_team.name if a.intervention.assigned_team else '—'), + 'status_code': a.intervention.status, + 'status_display': a.intervention.get_status_display(), 'detail_url': reverse('interventions:intervention_detail', args=[a.intervention.id]), } for a in assignments_qs ] + + # Include any extra interventions directly assigned/realized by member without an InterventionAssignment + assigned_itv_ids = set(a.intervention.id for a in assignments_qs) + direct_itvs_q = Q(assigned_member=member) + if member.user_id: + direct_itvs_q |= Q(realized_events__event_user=member.user) | Q(occupations__member=member) + + extra_itvs = ( + Intervention.objects + .filter(direct_itvs_q) + .exclude(id__in=assigned_itv_ids) + .select_related('assigned_team')[:50] + ) + for itv in extra_itvs: + itv_date = (itv.end_time or itv.begin_time or itv.planned_begin_time or itv.creation_time) + if itv_date: + itv_date_local = timezone.localtime(itv_date) if timezone.is_aware(itv_date) else itv_date + date_str = itv_date_local.strftime('%d/%m/%Y') + raw_date_str = itv_date_local.date().isoformat() + else: + date_str = '' + raw_date_str = '' + + interventions_list.append({ + 'id': itv.id, + 'code': itv.code, + 'title': itv.title, + 'date': date_str, + 'raw_date': raw_date_str, + 'team_name': itv.assigned_team.name if itv.assigned_team else '—', + 'status_code': itv.status, + 'status_display': itv.get_status_display(), + 'detail_url': reverse('interventions:intervention_detail', args=[itv.id]), + }) + interventions_list.sort(key=lambda x: (x['raw_date'], x['code'] or '', x['id']), reverse=True) + interventions_list = interventions_list[:100] return JsonResponse({ 'member': {