feat: allow intervention association with contracts via orders and improve order selection UI in detail view
This commit is contained in:
parent
be04a5e4c0
commit
5bfde04f1a
4 changed files with 79 additions and 9 deletions
|
|
@ -2654,6 +2654,8 @@
|
|||
|
||||
if (!orderSelect) return;
|
||||
|
||||
const initialVal = orderSelect.getAttribute('data-initial-order-id') || $(orderSelect).val() || orderSelect.value || '';
|
||||
|
||||
// Initialiser Select2 avec recherche
|
||||
$(orderSelect).select2({
|
||||
placeholder: gettext('-- Sélectionnez une commande --'),
|
||||
|
|
@ -2670,6 +2672,10 @@
|
|||
dropdownParent: $(CONFIG.selectors.modal)
|
||||
});
|
||||
|
||||
if (initialVal) {
|
||||
$(orderSelect).val(initialVal).trigger('change.select2');
|
||||
}
|
||||
|
||||
// Gérer le changement de commande
|
||||
$(orderSelect).on('change', async function() {
|
||||
const orderId = $(this).val();
|
||||
|
|
@ -2933,6 +2939,7 @@
|
|||
fixTableColumnWidths(CONFIG.selectors.table);
|
||||
const orderSelect = document.getElementById('orderSelect');
|
||||
if (orderSelect && $.fn.select2) {
|
||||
const currentVal = $(orderSelect).val() || orderSelect.getAttribute('data-initial-order-id') || orderSelect.value || '';
|
||||
$(orderSelect).select2('destroy');
|
||||
$(orderSelect).select2({
|
||||
placeholder: gettext('-- Sélectionnez une commande --'),
|
||||
|
|
@ -2950,7 +2957,11 @@
|
|||
});
|
||||
|
||||
// S'assurer que la valeur sélectionnée est correcte
|
||||
$(orderSelect).trigger('change.select2');
|
||||
if (currentVal) {
|
||||
$(orderSelect).val(currentVal).trigger('change.select2');
|
||||
} else {
|
||||
$(orderSelect).trigger('change.select2');
|
||||
}
|
||||
}
|
||||
|
||||
// Initialiser la visibilité du bouton d'ajout du devis
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@
|
|||
</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<select class="form-select" id="orderSelect" style="width: 100%;">
|
||||
<select class="form-select" id="orderSelect" style="width: 100%;" data-initial-order-id="{% if intervention.order_id %}{{ intervention.order_id }}{% endif %}">
|
||||
<option value="">-- {% translate "Sélectionnez une commande" %} --</option>
|
||||
{% for order in orders %}
|
||||
<option value="{{ order.id }}"
|
||||
|
|
@ -363,7 +363,7 @@
|
|||
data-order-code="{{ order.order_code }}"
|
||||
data-has-quote="{% if order.quote %}true{% else %}false{% endif %}"
|
||||
data-contract-posts-count="{{ order.contract.posts.count }}"
|
||||
{% if intervention.order and order.id == intervention.order.id %}selected{% endif %}>
|
||||
{% if intervention.order_id and order.id == intervention.order_id %}selected{% endif %}>
|
||||
{{ order.contract.contract_number }} - {{ order.order_code }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -907,6 +907,11 @@ class ContractOperationTemplatePostTests(TestCase):
|
|||
)
|
||||
self.contract.thematics.add(self.thematic)
|
||||
self.user_config.contracts.add(self.contract)
|
||||
uca = UserContractAccess.objects.get(user_config=self.user_config, contract=self.contract)
|
||||
uca.can_edit_interventions = True
|
||||
uca.can_view_posts = True
|
||||
uca.can_view_interventions = True
|
||||
uca.save()
|
||||
UserThematics.objects.create(user_config=self.user_config, thematic=self.thematic, can_edit_interventions=True)
|
||||
|
||||
self.contract_other = Contract.objects.create(
|
||||
|
|
@ -1162,6 +1167,46 @@ class ContractOperationTemplatePostTests(TestCase):
|
|||
self.assertEqual(posts[0].quantity, Decimal('4.00'))
|
||||
self.assertEqual(posts[0].comment, 'Auto Post')
|
||||
|
||||
def test_detail_view_includes_associated_order_and_posts_modal(self):
|
||||
"""Test that the detail view context includes orders and correctly preselects the associated order."""
|
||||
admin_role, _ = Role.objects.get_or_create(name='admin')
|
||||
self.user_config.roles.add(admin_role)
|
||||
from contracts.models import ContractOrder
|
||||
order = ContractOrder.objects.create(
|
||||
contract=self.contract,
|
||||
order_code='CMD-2026-001',
|
||||
order_date=timezone.now().date(),
|
||||
delivery_date=timezone.now().date() + timedelta(days=30),
|
||||
order_status='pending',
|
||||
total_amount=Decimal('500.00'),
|
||||
)
|
||||
intervention = Intervention.objects.create(
|
||||
title='Intervention With Order',
|
||||
contract=self.contract,
|
||||
order=order,
|
||||
thematic=self.thematic,
|
||||
status='in_preparation',
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
self.client.login(username='test_user_posts', password='password123')
|
||||
detail_url = reverse('interventions:intervention_detail', kwargs={'intervention_id': intervention.id})
|
||||
response = self.client.get(detail_url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Check context
|
||||
self.assertIn('orders', response.context)
|
||||
orders = response.context['orders']
|
||||
self.assertIsNotNone(orders)
|
||||
self.assertIn(order, orders)
|
||||
self.assertEqual(response.context['contract_id'], self.contract.id)
|
||||
|
||||
# Check rendered HTML for modal selector
|
||||
content = response.content.decode('utf-8')
|
||||
self.assertIn(f'data-initial-order-id="{order.id}"', content)
|
||||
self.assertIn(f'value="{order.id}"', content)
|
||||
self.assertIn('selected', content)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ def intervention_detail(request, intervention_id):
|
|||
|
||||
lang = get_language()
|
||||
|
||||
contract = intervention.contract
|
||||
contract = intervention.contract or (intervention.order.contract if intervention.order else None)
|
||||
thematic = intervention.thematic
|
||||
|
||||
allowed_update_fields = get_allowed_update_fields(request.user, intervention)
|
||||
|
|
@ -223,11 +223,21 @@ def intervention_detail(request, intervention_id):
|
|||
else:
|
||||
has_coefficient_posts = False
|
||||
|
||||
orders = ContractOrder.objects.filter(contract=contract).exclude(order_status__in=['cancelled', 'paid'])
|
||||
orders_qs = ContractOrder.objects.filter(contract=contract)
|
||||
if intervention.order_id:
|
||||
orders = orders_qs.filter(
|
||||
Q(id=intervention.order_id) | ~Q(order_status__in=['cancelled', 'paid'])
|
||||
).distinct().select_related('contract').order_by('order_code')
|
||||
else:
|
||||
orders = orders_qs.exclude(order_status__in=['cancelled', 'paid']).select_related('contract').order_by('order_code')
|
||||
elif intervention.order_id:
|
||||
has_coefficient_posts = False
|
||||
orders = ContractOrder.objects.filter(id=intervention.order_id).select_related('contract')
|
||||
else:
|
||||
has_coefficient_posts = False
|
||||
orders = ContractOrder.objects.none()
|
||||
|
||||
contract_id = intervention.order.contract.id if intervention.order else None
|
||||
contract_id = contract.id if contract else None
|
||||
|
||||
# Limiter les providers et contracts selon les permissions de l'utilisateur
|
||||
if user_config.is_intern and not user_config.limit_interventions_to_contracts:
|
||||
|
|
@ -2188,10 +2198,12 @@ def intervention_link_order(request, intervention_id):
|
|||
intervention = Intervention.objects.get(pk=intervention_id)
|
||||
allowed_update_fields = get_allowed_update_fields(request.user, intervention)
|
||||
|
||||
if data['order_id'] == '':
|
||||
if not data.get('order_id'):
|
||||
intervention.order = None
|
||||
else:
|
||||
intervention.order = ContractOrder.objects.get(pk=data['order_id'])
|
||||
if intervention.order and not intervention.contract:
|
||||
intervention.contract = intervention.order.contract
|
||||
intervention.save()
|
||||
|
||||
quote_items = []
|
||||
|
|
@ -2227,13 +2239,15 @@ def intervention_link_order(request, intervention_id):
|
|||
|
||||
quote_total = format_decimal(intervention.order.get_quote_total_amount())
|
||||
|
||||
active_contract = intervention.contract or (intervention.order.contract if intervention.order else None)
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'contract_id': intervention.order.contract.id if intervention.order else None,
|
||||
'contract_posts_count': intervention.order.contract.posts.count() if intervention.order and intervention.order.contract else 0,
|
||||
'contract_id': active_contract.id if active_contract else None,
|
||||
'contract_posts_count': active_contract.posts.count() if active_contract else 0,
|
||||
'quote_items': quote_items,
|
||||
'quote_total': quote_total,
|
||||
'can_manage_posts': 'posts' in allowed_update_fields,
|
||||
'order_display': f"{intervention.order.contract.contract_number} - {intervention.order.order_code}" if intervention.order else None,
|
||||
})
|
||||
except (Intervention.DoesNotExist, ContractOrder.DoesNotExist) as e:
|
||||
return JsonResponse({'success': False, 'message': str(e)})
|
||||
|
|
|
|||
Loading…
Reference in a new issue