fix: initialize missing member history and handle bidirectional m2m team updates in signals

This commit is contained in:
kdeterme 2026-09-02 17:38:26 +02:00
parent 9702a19db8
commit d131fcb0d6
2 changed files with 56 additions and 25 deletions

View file

@ -125,6 +125,21 @@ def sync_member_current_teams(member: CompanyMember, for_date: Optional[date] =
if for_date is None: if for_date is None:
for_date = timezone.now().date() for_date = timezone.now().date()
has_history = CompanyMemberHistory.objects.filter(member=member).exists()
if not has_history:
# Si le membre n'a aucun historique d'assignation mais a des équipes configurées dans member.teams,
# on initialise son historique pour préserver ses affectations.
current_teams = list(member.teams.all())
if current_teams:
for t in current_teams:
CompanyMemberHistory.objects.get_or_create(
member=member,
team=t,
leave_date__isnull=True,
defaults={'join_date': for_date}
)
return
active_team = get_member_team_for_date(member, for_date) active_team = get_member_team_for_date(member, for_date)
current_team_ids = set(member.teams.values_list('id', flat=True)) current_team_ids = set(member.teams.values_list('id', flat=True))
target_team_ids = {active_team.id} if active_team else set() target_team_ids = {active_team.id} if active_team else set()

View file

@ -51,34 +51,50 @@ from django.utils import timezone
@receiver(m2m_changed, sender=CompanyMember.teams.through) @receiver(m2m_changed, sender=CompanyMember.teams.through)
def update_member_team_history(sender, instance, action, reverse, pk_set, **kwargs): def update_member_team_history(sender, instance, action, reverse, pk_set, **kwargs):
if reverse:
return
today = timezone.now().date() today = timezone.now().date()
if action == "post_add": if not reverse:
# Pour chaque équipe ajoutée, on crée un enregistrement d'historique s'il n'existe pas déjà de période active # instance est CompanyMember, pk_set contient les team_id
for team_id in pk_set: if action == "post_add" and pk_set:
CompanyMemberHistory.objects.get_or_create( for team_id in pk_set:
member=instance, CompanyMemberHistory.objects.get_or_create(
team_id=team_id, member=instance,
leave_date__isnull=True, team_id=team_id,
defaults={'join_date': today} leave_date__isnull=True,
) defaults={'join_date': today}
)
elif action == "post_remove": elif action == "post_remove" and pk_set:
# Pour chaque équipe retirée, on clôture la période d'appartenance active for team_id in pk_set:
for team_id in pk_set: CompanyMemberHistory.objects.filter(
member=instance,
team_id=team_id,
leave_date__isnull=True
).update(leave_date=today)
elif action == "pre_clear":
CompanyMemberHistory.objects.filter( CompanyMemberHistory.objects.filter(
member=instance, member=instance,
team_id=team_id, leave_date__isnull=True
).update(leave_date=today)
else:
# instance est CompanyTeam, pk_set contient les member_id
if action == "post_add" and pk_set:
for member_id in pk_set:
CompanyMemberHistory.objects.get_or_create(
member_id=member_id,
team=instance,
leave_date__isnull=True,
defaults={'join_date': today}
)
elif action == "post_remove" and pk_set:
for member_id in pk_set:
CompanyMemberHistory.objects.filter(
member_id=member_id,
team=instance,
leave_date__isnull=True
).update(leave_date=today)
elif action == "pre_clear":
CompanyMemberHistory.objects.filter(
team=instance,
leave_date__isnull=True leave_date__isnull=True
).update(leave_date=today) ).update(leave_date=today)
elif action == "pre_clear":
# Avant d'effacer toutes les équipes d'un membre, on clôture toutes les périodes actives
CompanyMemberHistory.objects.filter(
member=instance,
leave_date__isnull=True
).update(leave_date=today)