refactor: optimize intervention assignment logic and enforce strict deduplication by ID

This commit is contained in:
kdeterme 2026-09-02 12:40:59 +02:00
parent 32053f3635
commit 0a745be17c

View file

@ -1506,19 +1506,7 @@ def member_history_ajax(request, member_id):
) )
company_str = ", ".join(sorted(company_names)) if company_names else '—' company_str = ", ".join(sorted(company_names)) if company_names else '—'
# Filter assignments: # 1. Équipes et périodes valides du membre selon CompanyMemberHistory
# 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() team_periods_q = Q()
for h in team_history_qs: for h in team_history_qs:
if h.team_id and h.join_date: if h.team_id and h.join_date:
@ -1527,10 +1515,8 @@ def member_history_ajax(request, member_id):
tq &= Q(date__lte=h.leave_date) tq &= Q(date__lte=h.leave_date)
team_periods_q |= tq team_periods_q |= tq
for t in member.teams.all(): # 2. Récupérer les affectations d'interventions liées au membre
if not team_history_qs.filter(team=t).exists(): assignment_q = Q(member=member)
team_periods_q |= Q(team=t)
if team_periods_q: if team_periods_q:
assignment_q |= team_periods_q assignment_q |= team_periods_q
@ -1538,26 +1524,31 @@ def member_history_ajax(request, member_id):
InterventionAssignment.objects InterventionAssignment.objects
.filter(assignment_q) .filter(assignment_q)
.select_related('intervention', 'team') .select_related('intervention', 'team')
.order_by('-date', '-intervention__code', '-intervention__id')[:100] .order_by('-date', '-intervention__id')
) )
interventions_list = [ # 3. Dédoublonnage strict par ID d'intervention
{ seen_itv_ids = set()
'id': a.intervention.id, interventions_dict = {}
'code': a.intervention.code,
'title': a.intervention.title, for a in assignments_qs:
itv = a.intervention
if not itv or itv.id in seen_itv_ids:
continue
seen_itv_ids.add(itv.id)
interventions_dict[itv.id] = {
'id': itv.id,
'code': itv.code,
'title': itv.title,
'date': a.date.strftime('%d/%m/%Y') if a.date else '', 'date': a.date.strftime('%d/%m/%Y') if a.date else '',
'raw_date': a.date.isoformat() if a.date else '', 'raw_date': a.date.isoformat() if a.date else '',
'team_name': a.team.name if a.team else (a.intervention.assigned_team.name if a.intervention.assigned_team else '—'), 'team_name': a.team.name if a.team else (itv.assigned_team.name if itv.assigned_team else '—'),
'status_code': a.intervention.status, 'status_code': itv.status,
'status_display': a.intervention.get_status_display(), 'status_display': itv.get_status_display(),
'detail_url': reverse('interventions:intervention_detail', args=[a.intervention.id]), 'detail_url': reverse('interventions:intervention_detail', args=[itv.id]),
} }
for a in assignments_qs
]
# Include any extra interventions directly assigned/realized by member without an InterventionAssignment # 4. Interventions directement assignées ou réalisées personnellement par le membre
assigned_itv_ids = set(a.intervention.id for a in assignments_qs)
direct_itvs_q = Q(assigned_member=member) direct_itvs_q = Q(assigned_member=member)
if member.user_id: if member.user_id:
direct_itvs_q |= Q(realized_events__event_user=member.user) | Q(occupations__member=member) direct_itvs_q |= Q(realized_events__event_user=member.user) | Q(occupations__member=member)
@ -1565,10 +1556,16 @@ def member_history_ajax(request, member_id):
extra_itvs = ( extra_itvs = (
Intervention.objects Intervention.objects
.filter(direct_itvs_q) .filter(direct_itvs_q)
.exclude(id__in=assigned_itv_ids) .exclude(id__in=seen_itv_ids)
.select_related('assigned_team')[:50] .select_related('assigned_team')
.distinct()[:50]
) )
for itv in extra_itvs: for itv in extra_itvs:
if itv.id in seen_itv_ids:
continue
seen_itv_ids.add(itv.id)
itv_date = (itv.end_time or itv.begin_time or itv.planned_begin_time or itv.creation_time) itv_date = (itv.end_time or itv.begin_time or itv.planned_begin_time or itv.creation_time)
if itv_date: if itv_date:
itv_date_local = timezone.localtime(itv_date) if timezone.is_aware(itv_date) else itv_date itv_date_local = timezone.localtime(itv_date) if timezone.is_aware(itv_date) else itv_date
@ -1578,7 +1575,7 @@ def member_history_ajax(request, member_id):
date_str = '' date_str = ''
raw_date_str = '' raw_date_str = ''
interventions_list.append({ interventions_dict[itv.id] = {
'id': itv.id, 'id': itv.id,
'code': itv.code, 'code': itv.code,
'title': itv.title, 'title': itv.title,
@ -1588,10 +1585,11 @@ def member_history_ajax(request, member_id):
'status_code': itv.status, 'status_code': itv.status,
'status_display': itv.get_status_display(), 'status_display': itv.get_status_display(),
'detail_url': reverse('interventions:intervention_detail', args=[itv.id]), 'detail_url': reverse('interventions:intervention_detail', args=[itv.id]),
}) }
interventions_list = list(interventions_dict.values())
interventions_list.sort(key=lambda x: (x['raw_date'], x['code'] or '', x['id']), reverse=True) interventions_list.sort(key=lambda x: (x['raw_date'], x['code'] or '', x['id']), reverse=True)
interventions_list = interventions_list[:100] interventions_list = interventions_list[:50]
return JsonResponse({ return JsonResponse({
'member': { 'member': {