refactor: restrict contract blocked warning to specific intervention statuses and add test coverage
This commit is contained in:
parent
7f257a2ca3
commit
3a241e3d03
6 changed files with 77 additions and 10 deletions
|
|
@ -738,11 +738,21 @@ class Intervention(models.Model):
|
|||
return self.assigned_team.company.name
|
||||
return ""
|
||||
|
||||
BLOCKED_CONTRACT_DISPLAY_STATUSES = ('in_preparation', 'to_be_approved', 'to_be_planned')
|
||||
|
||||
@property
|
||||
def is_contract_blocked(self):
|
||||
"""Retourne True si l'intervention est marquée bloquée ou si son contrat est actuellement bloqué."""
|
||||
return bool(self.is_blocked_due_to_contract or (self.contract and getattr(self.contract, 'is_blocked', False)))
|
||||
|
||||
@property
|
||||
def show_contract_blocked_warning(self):
|
||||
"""
|
||||
Indique si l'avertissement / badge de marché bloqué doit être affiché.
|
||||
Uniquement affiché pour les interventions en préparation, à approuver ou à planifier.
|
||||
"""
|
||||
return bool(self.is_contract_blocked and self.status in self.BLOCKED_CONTRACT_DISPLAY_STATUSES)
|
||||
|
||||
def get_status_color(self):
|
||||
return {
|
||||
"in_preparation": "secondary",
|
||||
|
|
|
|||
|
|
@ -496,8 +496,9 @@ function statusFormatter(value, row) {
|
|||
html += ` <span class="badge text-bg-${prepEntry.color}" title="${prepEntry.label}"><i class="bi ${prepEntry.icon}"></i></span>`;
|
||||
}
|
||||
|
||||
// Add blocked due to contract indicator if present
|
||||
if (row && (row.is_blocked_due_to_contract || (row.contract && row.contract.is_blocked))) {
|
||||
// Add blocked due to contract indicator if present (only for in_preparation, to_be_approved, to_be_planned)
|
||||
const blockedStatuses = ['in_preparation', 'to_be_approved', 'to_be_planned'];
|
||||
if (row && (row.is_blocked_due_to_contract || (row.contract && row.contract.is_blocked)) && blockedStatuses.includes(row.status || value)) {
|
||||
html += ` <span class="badge text-bg-danger" title="${gettext('Marché temporairement bloqué')}"><i class="bi bi-slash-circle"></i></span>`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
<a href="{% url 'mobile:intervention_detail_mobile' intervention.id %}" class="me-2">{{ intervention.code }}</a> {{ intervention.title }}
|
||||
</h6>
|
||||
<span class="badge bg-{{ intervention.get_status_color }} status-{{ intervention.status }}">{{ intervention.get_status_display }}</span>
|
||||
{% if intervention.is_contract_blocked %}
|
||||
{% if intervention.show_contract_blocked_warning %}
|
||||
<span class="badge bg-danger" title="{% translate 'Marché temporairement bloqué' %}">
|
||||
<i class="bi bi-slash-circle"></i> {% translate "Marché bloqué" %}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
<span class="field-value" style="color: var(--brand-color);">{{ intervention.title }}</span>
|
||||
{% if intervention.is_contract_blocked %}
|
||||
{% if intervention.show_contract_blocked_warning %}
|
||||
<span class="badge bg-danger text-white ms-2" title="{% translate 'Marché temporairement bloqué pour raisons budgétaires' %}">
|
||||
<i class="bi bi-slash-circle"></i> {% translate "Marché bloqué" %}
|
||||
</span>
|
||||
|
|
@ -84,7 +84,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if intervention.is_contract_blocked %}
|
||||
{% if intervention.show_contract_blocked_warning %}
|
||||
<div class="alert alert-danger d-flex align-items-center mt-3 mb-2 py-2 px-3 shadow-sm border-danger" role="alert">
|
||||
<i class="bi bi-slash-circle-fill fs-4 me-2 text-danger"></i>
|
||||
<div>
|
||||
|
|
@ -107,7 +107,7 @@
|
|||
<h4>{% translate "Recommandations" %}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if intervention.is_contract_blocked %}
|
||||
{% if intervention.show_contract_blocked_warning %}
|
||||
<div class="alert alert-warning d-flex align-items-center mb-3 py-2 px-3">
|
||||
<i class="bi bi-telephone-x-fill fs-4 me-2 text-danger"></i>
|
||||
<div>
|
||||
|
|
@ -121,7 +121,7 @@
|
|||
<li class="list-group-item list-group-item-info d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<i class="bi {{recommendation.icon}} me-2"></i>
|
||||
{% if intervention.is_contract_blocked and recommendation.confirm_call %}
|
||||
{% if intervention.show_contract_blocked_warning and recommendation.confirm_call %}
|
||||
<span class="text-decoration-line-through text-muted">
|
||||
{% render_recommendation recommendation intervention.contract as rendered_text %}
|
||||
{{ rendered_text|safe }}
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
{{ rendered_text|safe }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if recommendation.confirm_call and not intervention.is_contract_blocked %}
|
||||
{% if recommendation.confirm_call and not intervention.show_contract_blocked_warning %}
|
||||
<button class="btn btn-outline-success btn-sm confirm-call"
|
||||
data-call-id="{{recommendation.order_number}}"
|
||||
data-confirmed-at="{{ intervention.init_call_confirmed_time|date:'c' }}"
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if intervention.is_contract_blocked %}
|
||||
{% if intervention.show_contract_blocked_warning %}
|
||||
<div class="alert alert-danger d-flex align-items-center mb-3 py-2 px-3 shadow-sm border-danger" role="alert">
|
||||
<i class="bi bi-slash-circle-fill fs-4 me-2 text-danger"></i>
|
||||
<div>
|
||||
|
|
@ -488,7 +488,7 @@
|
|||
<div class="d-flex justify-content-between align-items-center mb-2 flex-wrap gap-2">
|
||||
<div class="code d-flex align-items-center gap-2">
|
||||
<span><i class="bi bi-tools"></i> {{ intervention.code }}</span>
|
||||
{% if intervention.is_contract_blocked %}
|
||||
{% if intervention.show_contract_blocked_warning %}
|
||||
<span class="badge bg-danger text-white ms-1" title="{% translate 'Marché bloqué' %}">
|
||||
<i class="bi bi-slash-circle"></i> {% translate "Marché bloqué" %}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -255,3 +255,59 @@ class BlockedContractsTests(TestCase):
|
|||
itv.refresh_from_db()
|
||||
self.assertEqual(itv.status, 'to_be_processed')
|
||||
|
||||
def test_show_contract_blocked_warning_only_for_prep_approval_planning(self):
|
||||
"""
|
||||
Vérifie que show_contract_blocked_warning est True uniquement pour :
|
||||
- in_preparation
|
||||
- to_be_approved
|
||||
- to_be_planned
|
||||
Et False pour tous les autres statuts (ex: validated, finished, in_progress, etc.).
|
||||
"""
|
||||
allowed_warning_statuses = {'in_preparation', 'to_be_approved', 'to_be_planned'}
|
||||
other_statuses = {
|
||||
'to_be_processed', 'assigned', 'in_progress', 'on_pause', 'finished',
|
||||
'processed', 'to_be_corrected', 'corrected', 'validated', 'invoiced',
|
||||
'closed', 'canceled'
|
||||
}
|
||||
|
||||
# Pour une intervention sur contrat bloqué
|
||||
for status in allowed_warning_statuses:
|
||||
itv = Intervention(
|
||||
title=f'Test {status}',
|
||||
contract=self.contract_blocked,
|
||||
status=status,
|
||||
thematic=self.thematic,
|
||||
asset_category=self.category,
|
||||
)
|
||||
self.assertTrue(
|
||||
itv.show_contract_blocked_warning,
|
||||
f"show_contract_blocked_warning devrait être True pour le statut {status}"
|
||||
)
|
||||
|
||||
for status in other_statuses:
|
||||
itv = Intervention(
|
||||
title=f'Test {status}',
|
||||
contract=self.contract_blocked,
|
||||
status=status,
|
||||
thematic=self.thematic,
|
||||
asset_category=self.category,
|
||||
)
|
||||
self.assertFalse(
|
||||
itv.show_contract_blocked_warning,
|
||||
f"show_contract_blocked_warning devrait être False pour le statut {status}"
|
||||
)
|
||||
|
||||
# Pour une intervention sur contrat actif (non bloqué)
|
||||
for status in allowed_warning_statuses | other_statuses:
|
||||
itv = Intervention(
|
||||
title=f'Test {status} active',
|
||||
contract=self.contract_active,
|
||||
status=status,
|
||||
thematic=self.thematic,
|
||||
asset_category=self.category,
|
||||
)
|
||||
self.assertFalse(
|
||||
itv.show_contract_blocked_warning,
|
||||
f"show_contract_blocked_warning devrait être False sur contrat actif pour le statut {status}"
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue