feat: track status changes in InterventionTimeLine when generating contract documents
This commit is contained in:
parent
ce79d913ea
commit
1df0c1b8c1
2 changed files with 133 additions and 3 deletions
|
|
@ -232,3 +232,111 @@ class ContractDisplayNameTests(TestCase):
|
|||
def test_display_name_long_description_truncated(self):
|
||||
self.assertTrue(self.contract_long_desc.display_name.startswith("CTR-003 (Travaux et maintenance préventive et correct"))
|
||||
self.assertTrue(self.contract_long_desc.display_name.endswith("…)"))
|
||||
|
||||
|
||||
class GenerateClaimDeclarationTimelineTests(TestCase):
|
||||
def setUp(self):
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
from contracts.models import Contract, ContractOrder, ContractPost
|
||||
from common.models import UserContractAccess
|
||||
from interventions.models import Intervention, InterventionTimeLine, InterventionContractPost, InterventionPostPeriodQuantity
|
||||
|
||||
self.client = Client()
|
||||
self.user = User.objects.create_user(username="admin_user", password="password")
|
||||
self.user_config = UserConfig.objects.create(user=self.user, is_intern=True)
|
||||
self.admin_role, _ = Role.objects.get_or_create(name="admin")
|
||||
self.user_config.roles.add(self.admin_role)
|
||||
self.client.login(username="admin_user", password="password")
|
||||
|
||||
self.company = Company.objects.create(name="Company A")
|
||||
self.contract = Contract.objects.create(
|
||||
company=self.company,
|
||||
contract_number="CTR-TEST-001",
|
||||
start_date=date(2025, 1, 1),
|
||||
end_date=date(2026, 1, 1),
|
||||
)
|
||||
UserContractAccess.objects.create(
|
||||
user_config=self.user_config,
|
||||
contract=self.contract,
|
||||
can_view_interventions=True,
|
||||
)
|
||||
self.order = ContractOrder.objects.create(
|
||||
contract=self.contract,
|
||||
order_code="ORD-TEST-01",
|
||||
order_status="pending",
|
||||
order_date=date(2025, 1, 1),
|
||||
delivery_date=date(2025, 1, 15),
|
||||
description="Commande test",
|
||||
)
|
||||
self.post = ContractPost.objects.create(
|
||||
contract=self.contract,
|
||||
order_number=1,
|
||||
code="P1",
|
||||
description_fr="Poste 1",
|
||||
description_nl="Post 1",
|
||||
unit="u",
|
||||
unit_price=Decimal("10.00"),
|
||||
)
|
||||
self.intervention_validated = Intervention.objects.create(
|
||||
title="Intervention Validated",
|
||||
contract=self.contract,
|
||||
order=self.order,
|
||||
status="validated",
|
||||
)
|
||||
InterventionContractPost.objects.create(
|
||||
intervention=self.intervention_validated,
|
||||
contract_post=self.post,
|
||||
quantity=Decimal("2.00"),
|
||||
control_status="validated",
|
||||
)
|
||||
|
||||
self.intervention_period = Intervention.objects.create(
|
||||
title="Intervention with Validated Period",
|
||||
contract=self.contract,
|
||||
order=self.order,
|
||||
status="to_be_processed",
|
||||
)
|
||||
InterventionPostPeriodQuantity.objects.create(
|
||||
intervention=self.intervention_period,
|
||||
contract_post=self.post,
|
||||
period_number=1,
|
||||
quantity=Decimal("3.00"),
|
||||
validated_at=timezone.now(),
|
||||
validated_by=self.user,
|
||||
status="validated",
|
||||
)
|
||||
|
||||
def test_generate_documents_creates_timeline_events(self):
|
||||
from interventions.models import InterventionTimeLine
|
||||
|
||||
url = reverse("contracts:generate_documents_for_order", args=[self.order.id])
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# 1. Check validated intervention status & timeline
|
||||
self.intervention_validated.refresh_from_db()
|
||||
self.assertEqual(self.intervention_validated.status, "invoiced")
|
||||
|
||||
timeline_event_1 = InterventionTimeLine.objects.filter(
|
||||
intervention=self.intervention_validated,
|
||||
to_status="invoiced",
|
||||
).first()
|
||||
self.assertIsNotNone(timeline_event_1)
|
||||
self.assertEqual(timeline_event_1.from_status, "validated")
|
||||
self.assertEqual(timeline_event_1.event_type, "status_change")
|
||||
self.assertEqual(timeline_event_1.event_user, self.user)
|
||||
|
||||
# 2. Check intervention with period status & timeline
|
||||
self.intervention_period.refresh_from_db()
|
||||
self.assertEqual(self.intervention_period.status, "invoiced")
|
||||
|
||||
timeline_event_2 = InterventionTimeLine.objects.filter(
|
||||
intervention=self.intervention_period,
|
||||
to_status="invoiced",
|
||||
).first()
|
||||
self.assertIsNotNone(timeline_event_2)
|
||||
self.assertEqual(timeline_event_2.from_status, "to_be_processed")
|
||||
self.assertEqual(timeline_event_2.event_type, "status_change")
|
||||
self.assertEqual(timeline_event_2.event_user, self.user)
|
||||
|
||||
|
|
|
|||
|
|
@ -1372,7 +1372,7 @@ def generate_documents_for_order(request, order_id):
|
|||
messages.error(request, _("Vous n'avez pas la permission de générer des documents pour cette commande."))
|
||||
return redirect("contracts:contracts_orders_detail", order_id=order.id)
|
||||
|
||||
from interventions.models import InterventionContractPost, InterventionPostPeriodQuantity
|
||||
from interventions.models import InterventionContractPost, InterventionPostPeriodQuantity, InterventionTimeLine
|
||||
|
||||
# Collecter les commandes directes validées AVANT génération des documents (pour les inclure
|
||||
# dans l'état de travaux/Excel et les réinitialiser seulement après)
|
||||
|
|
@ -1454,20 +1454,42 @@ def generate_documents_for_order(request, order_id):
|
|||
)
|
||||
|
||||
# Mettre à jour le statut des interventions :
|
||||
now = timezone.now()
|
||||
event_user = request.user if request.user.is_authenticated else None
|
||||
|
||||
# 1. Toutes les interventions validées (même sans postes validés)
|
||||
validated_interventions = order.interventions.filter(status='validated')
|
||||
for intervention in validated_interventions:
|
||||
old_status = intervention.status
|
||||
intervention.status = 'invoiced'
|
||||
intervention.save()
|
||||
InterventionTimeLine.objects.create(
|
||||
intervention=intervention,
|
||||
event_user=event_user,
|
||||
event_time=now,
|
||||
event_type='status_change',
|
||||
from_status=old_status,
|
||||
to_status='invoiced',
|
||||
)
|
||||
|
||||
# 2. Toutes les interventions avec périodes validées (quel que soit leur statut)
|
||||
intervention_ids_with_validated_periods = validated_periods.values_list('intervention_id', flat=True).distinct()
|
||||
interventions_with_periods = order.interventions.filter(id__in=intervention_ids_with_validated_periods)
|
||||
interventions_with_periods = order.interventions.filter(
|
||||
id__in=intervention_ids_with_validated_periods
|
||||
).exclude(status='invoiced')
|
||||
for intervention in interventions_with_periods:
|
||||
# Passer à 'invoiced' seulement si pas déjà dans cet état
|
||||
if intervention.status != 'invoiced':
|
||||
old_status = intervention.status
|
||||
intervention.status = 'invoiced'
|
||||
intervention.save()
|
||||
InterventionTimeLine.objects.create(
|
||||
intervention=intervention,
|
||||
event_user=event_user,
|
||||
event_time=now,
|
||||
event_type='status_change',
|
||||
from_status=old_status,
|
||||
to_status='invoiced',
|
||||
)
|
||||
|
||||
# Marquer les périodes validées comme 'invoiced'
|
||||
validated_periods.update(status='invoiced')
|
||||
|
|
|
|||
Loading…
Reference in a new issue