feat: prevent automatic intervention re-creation in Observation model using ref check
This commit is contained in:
parent
107575aa60
commit
8c4556a34c
2 changed files with 93 additions and 1 deletions
|
|
@ -438,6 +438,28 @@ class Observation(models.Model):
|
|||
intervention = models.ForeignKey('interventions.Intervention', on_delete=models.SET_NULL, null=True, blank=True, related_name='observations')
|
||||
project = models.ForeignKey('projects.Project', on_delete=models.SET_NULL, null=True, blank=True, related_name='observations', verbose_name=_("Projet lié"))
|
||||
|
||||
def has_existing_intervention(self):
|
||||
"""
|
||||
Vérifie si une intervention est déjà liée à cette observation,
|
||||
ou si une intervention a déjà été créée à partir de cette observation (ex. via source_ref).
|
||||
Permet d'éviter de ré-instancier automatiquement une intervention en boucle
|
||||
lorsqu'une intervention existante est annulée et que l'observation repasse au statut 'À traiter'.
|
||||
"""
|
||||
if self.intervention_id is not None:
|
||||
return True
|
||||
if not self.pk:
|
||||
return False
|
||||
|
||||
from interventions.models import Intervention
|
||||
possible_refs = [str(self.pk)]
|
||||
if self.code:
|
||||
possible_refs.append(self.code)
|
||||
possible_refs.append(f"OBS{self.pk:05d}")
|
||||
|
||||
return Intervention.objects.filter(
|
||||
models.Q(observations=self) | models.Q(source_ref__in=possible_refs)
|
||||
).exists()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
is_new = self.pk is None
|
||||
old_status = None
|
||||
|
|
@ -459,7 +481,7 @@ class Observation(models.Model):
|
|||
if (self.symptom_id and
|
||||
self.symptom.auto_create_intervention and
|
||||
self.status == 'to_process' and
|
||||
not self.intervention_id):
|
||||
not self.has_existing_intervention()):
|
||||
|
||||
status_changed_to_to_process = (old_status != 'to_process' and self.status == 'to_process')
|
||||
symptom_changed_to_auto = (old_symptom_id != self.symptom_id and self.symptom.auto_create_intervention)
|
||||
|
|
|
|||
|
|
@ -502,3 +502,73 @@ class ObservationPermissionTests(TestCase):
|
|||
self.assertContains(response, "Une intervention liée à cette observation a été annulée")
|
||||
self.assertContains(response, "INT-TEST-CANCEL")
|
||||
|
||||
def test_no_auto_intervention_loop_on_cancellation(self):
|
||||
from contracts.models import Contract, Company
|
||||
from interventions.models import Symptom, Intervention
|
||||
from interventions.views.workflow import attempt_status_update
|
||||
from django.utils import timezone
|
||||
|
||||
company = Company.objects.create(name='Provider Co Loop')
|
||||
contract = Contract.objects.create(
|
||||
contract_number='C-LOOP',
|
||||
company=company,
|
||||
start_date=timezone.now().date(),
|
||||
end_date=timezone.now().date() + timezone.timedelta(days=365)
|
||||
)
|
||||
|
||||
symptom = Symptom.objects.create(
|
||||
name_fr='Symptome Auto Loop Test',
|
||||
name_nl='Symptoom Auto Loop Test',
|
||||
thematic=self.thematic_a,
|
||||
auto_create_intervention=True,
|
||||
contract=contract,
|
||||
provider=company,
|
||||
)
|
||||
|
||||
# 1. Create observation in 'to_process' -> auto-creates intervention
|
||||
obs = Observation.objects.create(
|
||||
description='Loop test observation',
|
||||
latitude=50.5,
|
||||
longitude=4.5,
|
||||
created_by=self.internal_user,
|
||||
thematic=self.thematic_a,
|
||||
symptom=symptom,
|
||||
status='to_process',
|
||||
)
|
||||
|
||||
obs.refresh_from_db()
|
||||
self.assertIsNotNone(obs.intervention)
|
||||
self.assertEqual(obs.status, 'in_progress')
|
||||
first_intervention = obs.intervention
|
||||
|
||||
# 2. Cancel the intervention
|
||||
success, msg, _ = attempt_status_update(
|
||||
request=None,
|
||||
intervention=first_intervention,
|
||||
user=self.admin_user,
|
||||
new_status='canceled',
|
||||
cancellation_type='other',
|
||||
cancellation_reason='Test cancellation reason',
|
||||
)
|
||||
self.assertTrue(success, msg)
|
||||
|
||||
# 3. Observation status is reset to 'to_process'
|
||||
obs.refresh_from_db()
|
||||
self.assertEqual(obs.status, 'to_process')
|
||||
|
||||
# 4. Save observation again (or unlink and save) - MUST NOT create a new intervention
|
||||
obs.save()
|
||||
obs.refresh_from_db()
|
||||
self.assertEqual(obs.status, 'to_process')
|
||||
|
||||
# Unlink intervention and save observation again
|
||||
obs.intervention = None
|
||||
obs.save()
|
||||
obs.refresh_from_db()
|
||||
|
||||
# Total interventions with source_ref equal to obs.code or obs.pk must still be 1
|
||||
possible_refs = [str(obs.pk), obs.code, f"OBS{obs.pk:05d}"]
|
||||
total_interventions = Intervention.objects.filter(source_ref__in=possible_refs).count()
|
||||
self.assertEqual(total_interventions, 1)
|
||||
self.assertEqual(obs.status, 'to_process')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue