From a6378eee90ece144396bb09052cdc65cbc6e7be8 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Sat, 10 Oct 2026 14:47:28 +0200 Subject: [PATCH] feat(contracts): add column sorting by code and dates to contracts list --- .../static/contracts/js/contracts_index.js | 1 + .../templates/contracts/contracts_index.html | 35 ++++++++++-- loko/contracts/tests.py | 16 ++++++ loko/contracts/views.py | 53 +++++++++++++++++-- 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/loko/contracts/static/contracts/js/contracts_index.js b/loko/contracts/static/contracts/js/contracts_index.js index 5231145..62d79eb 100644 --- a/loko/contracts/static/contracts/js/contracts_index.js +++ b/loko/contracts/static/contracts/js/contracts_index.js @@ -60,6 +60,7 @@ document.addEventListener('DOMContentLoaded', function() { const url = new URL(window.location.href); url.searchParams.set('page_size', this.value); url.searchParams.delete('page'); + url.searchParams.delete('contracts_page'); window.location.href = url.toString(); }); } diff --git a/loko/contracts/templates/contracts/contracts_index.html b/loko/contracts/templates/contracts/contracts_index.html index d5de0b6..a2d784f 100644 --- a/loko/contracts/templates/contracts/contracts_index.html +++ b/loko/contracts/templates/contracts/contracts_index.html @@ -394,12 +394,37 @@ - {% translate "Numéro" %} - {% translate "Description" %} + + + {% translate "Numéro" %} + + + + + + {% translate "Description" %} + + + {% translate "Thématiques" %} - {% translate "Prestataire" %} - {% translate "Début" %} - {% translate "Fin" %} + + + {% translate "Prestataire" %} + + + + + + {% translate "Début" %} + + + + + + {% translate "Fin" %} + + + diff --git a/loko/contracts/tests.py b/loko/contracts/tests.py index 7859d55..d7aaa9d 100644 --- a/loko/contracts/tests.py +++ b/loko/contracts/tests.py @@ -915,6 +915,22 @@ class ContractsIndexViewTests(TestCase): # Premier élément doit être CMD-002 car CMD-001 est cancelled self.assertEqual(resp.context['orders_page'][0].order_code, 'CMD-002') + def test_contracts_index_contracts_sorting_code_asc(self): + url = reverse('contracts:contracts_index') + resp = self.client.get(url, {'tab': 'contracts', 'contracts_sort': 'code', 'contracts_dir': 'asc'}) + self.assertEqual(resp.status_code, 200) + contracts_page = resp.context['contracts_page'] + self.assertEqual(contracts_page[0].contract_number, self.contract_green.contract_number) + self.assertEqual(contracts_page[1].contract_number, self.contract_roads.contract_number) + + def test_contracts_index_contracts_sorting_code_desc(self): + url = reverse('contracts:contracts_index') + resp = self.client.get(url, {'tab': 'contracts', 'contracts_sort': 'code', 'contracts_dir': 'desc'}) + self.assertEqual(resp.status_code, 200) + contracts_page = resp.context['contracts_page'] + self.assertEqual(contracts_page[0].contract_number, self.contract_roads.contract_number) + self.assertEqual(contracts_page[1].contract_number, self.contract_green.contract_number) + diff --git a/loko/contracts/views.py b/loko/contracts/views.py index 39dc3cf..be78803 100644 --- a/loko/contracts/views.py +++ b/loko/contracts/views.py @@ -146,6 +146,30 @@ def contracts_index(request): orders_page = orders_paginator.get_page(orders_page_num) orders_elided_range = orders_paginator.get_elided_page_range(orders_page.number, on_each_side=2, on_ends=1) + # Tri des marchés + contracts_sort_field = request.GET.get('contracts_sort', '') + if not contracts_sort_field and active_tab == 'contracts': + contracts_sort_field = request.GET.get('sort', '') + if not contracts_sort_field: + contracts_sort_field = 'start_date' + + contracts_sort_dir = request.GET.get('contracts_dir', '') + if not contracts_sort_dir and active_tab == 'contracts': + contracts_sort_dir = request.GET.get('dir', '') + if contracts_sort_dir not in ('asc', 'desc'): + contracts_sort_dir = 'desc' if contracts_sort_field in ('start_date', 'date', 'end_date') else 'asc' + + contracts_sort_mapping = { + 'code': 'contract_number', + 'description': 'description', + 'company': 'company__name', + 'start_date': 'start_date', + 'date': 'start_date', + 'end_date': 'end_date', + } + db_contracts_sort_col = contracts_sort_mapping.get(contracts_sort_field, 'start_date') + contracts_order_by_arg = db_contracts_sort_col if contracts_sort_dir == 'asc' else f"-{db_contracts_sort_col}" + # Construction de la requête marchés/contrats contracts_qs = contracts if search_query: @@ -159,9 +183,9 @@ def contracts_index(request): Q(thematics__id__in=selected_thematics) | Q(thematics__code__in=selected_thematics) ) - contracts_qs = contracts_qs.distinct().order_by('-start_date') + contracts_qs = contracts_qs.distinct().order_by(contracts_order_by_arg, '-id') - contracts_paginator = Paginator(contracts_qs, 25) + contracts_paginator = Paginator(contracts_qs, page_size) contracts_page_num = request.GET.get('contracts_page', 1) contracts_page = contracts_paginator.get_page(contracts_page_num) contracts_elided_range = contracts_paginator.get_elided_page_range(contracts_page.number, on_each_side=2, on_ends=1) @@ -229,11 +253,12 @@ def contracts_index(request): orders_querystring = p_orders.urlencode() p_contracts = request.GET.copy() + p_contracts['tab'] = 'contracts' if 'contracts_page' in p_contracts: del p_contracts['contracts_page'] contracts_querystring = p_contracts.urlencode() - # Générateur d'URLs de tri + # Générateur d'URLs de tri des commandes def build_sort_url(col): next_dir = 'asc' if (sort_field == col and sort_dir == 'desc') else 'desc' p = request.GET.copy() @@ -245,6 +270,25 @@ def contracts_index(request): sort_urls = {col: build_sort_url(col) for col in ('code', 'description', 'date', 'status', 'contract', 'amount')} + # Générateur d'URLs de tri des marchés + def build_contracts_sort_url(col): + if contracts_sort_field == col: + next_dir = 'desc' if contracts_sort_dir == 'asc' else 'asc' + else: + next_dir = 'desc' if col in ('start_date', 'end_date', 'date') else 'asc' + p = request.GET.copy() + p['tab'] = 'contracts' + p['contracts_sort'] = col + p['contracts_dir'] = next_dir + if 'contracts_page' in p: + del p['contracts_page'] + return f"?{p.urlencode()}" + + contracts_sort_urls = { + col: build_contracts_sort_url(col) + for col in ('code', 'description', 'company', 'start_date', 'end_date') + } + # Vérification des droits pour voir les prix can_view_prices = False if request.user.is_superuser: @@ -279,6 +323,9 @@ def contracts_index(request): 'sort_field': sort_field, 'sort_dir': sort_dir, 'sort_urls': sort_urls, + 'contracts_sort_field': contracts_sort_field, + 'contracts_sort_dir': contracts_sort_dir, + 'contracts_sort_urls': contracts_sort_urls, 'active_tab': active_tab, 'active_filters_list': active_filters_list, 'active_filters_count': active_filters_count,