diff --git a/tally_ho/apps/tally/static/js/data_table.js b/tally_ho/apps/tally/static/js/data_table.js index 8c8726fcd..138b842ce 100644 --- a/tally_ho/apps/tally/static/js/data_table.js +++ b/tally_ho/apps/tally/static/js/data_table.js @@ -74,11 +74,13 @@ $(document).ready(function () { let data = []; let selectOneIds = $('select#centers').val(); let selectTwoIds = $('select#stations').val(); + let raceTypeNames = $('select#filter-out-race-types').val(); if (selectOneIds || selectTwoIds) { const items = { select_1_ids: selectOneIds !== null ? selectOneIds : [], select_2_ids: selectTwoIds !== null ? selectTwoIds : [], + race_type_names: raceTypeNames !== null ? raceTypeNames : [], }; data = items; @@ -148,6 +150,140 @@ $(document).ready(function () { }); }); + $('#in-report').on('click', '#filter-in-report', function () { + const table = $('.datatable').DataTable(); + + table.destroy(); + let data = []; + let selectOneIds = $('select#filter-in-centers').val(); + let selectTwoIds = $('select#filter-in-stations').val(); + let raceTypeNames = $('select#filter-in-race-types').val(); + + if (selectOneIds || selectTwoIds) { + const items = { + select_1_ids: selectOneIds !== null ? selectOneIds : [], + select_2_ids: selectTwoIds !== null ? selectTwoIds : [], + race_type_names: raceTypeNames !== null ? raceTypeNames : [], + filter_in: "True" + }; + + data = items; + } + + data = data.length + ? data.filter((item) => + Object.values(item).every((value) => typeof value !== 'undefined') + ) + : data; + + $('.datatable').dataTable({ + language: dt_language, + order: [[0, 'desc']], + lengthMenu: [ + [10, 25, 50, 100, 500], + [10, 25, 50, 100, 500], + ], + columnDefs: [ + { + orderable: true, + searchable: true, + className: 'center', + targets: [0, 1], + }, + ], + searching: true, + processing: true, + serverSide: true, + stateSave: true, + ajax: { + url: LIST_JSON_URL, + type: 'POST', + data: { data: JSON.stringify(data) }, + traditional: true, + dataType: 'json', + }, + dom: + "<'row'<'col-sm-1'B><'col-sm-6'l><'col-sm-5'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + buttons: [ + { + extend: 'csv', + filename: exportFileName, + action: exportAction, + exportOptions: { + columns: ':visible :not(.actions)', + }, + }, + ], + responsive: true, + }); + }); + $('#race-report').on('click', '#filter-race-report', function () { + const table = $('.datatable').DataTable(); + + table.destroy(); + let data = []; + let raceTypeNames = $('select#filter-in-race-types').val(); + + if (raceTypeNames ) { + const items = { + race_type_names: raceTypeNames !== null ? raceTypeNames : [], + }; + + data = items; + } + + data = data.length + ? data.filter((item) => + Object.values(item).every((value) => typeof value !== 'undefined') + ) + : data; + + $('.datatable').dataTable({ + language: dt_language, + order: [[0, 'desc']], + lengthMenu: [ + [10, 25, 50, 100, 500], + [10, 25, 50, 100, 500], + ], + columnDefs: [ + { + orderable: true, + searchable: true, + className: 'center', + targets: [0, 1], + }, + ], + searching: true, + processing: true, + serverSide: true, + stateSave: true, + ajax: { + url: LIST_JSON_URL, + type: 'POST', + data: { data: JSON.stringify(data) }, + traditional: true, + dataType: 'json', + }, + dom: + "<'row'<'col-sm-1'B><'col-sm-6'l><'col-sm-5'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + buttons: [ + { + extend: 'csv', + filename: exportFileName, + action: exportAction, + exportOptions: { + columns: ':visible :not(.actions)', + }, + }, + ], + responsive: true, + }); + }); + $('#report').on('click', '#reset', function () { const table = $('.datatable').DataTable(); diff --git a/tally_ho/apps/tally/static/js/get_centers_stations.js b/tally_ho/apps/tally/static/js/get_centers_stations.js index 88dd5579b..7f98996ec 100644 --- a/tally_ho/apps/tally/static/js/get_centers_stations.js +++ b/tally_ho/apps/tally/static/js/get_centers_stations.js @@ -1,6 +1,6 @@ $(document).ready(function () { $('#centers').change(function () { - const center_ids = $('.selectpicker').val(); + const center_ids = $('#centers').val(); if (center_ids) { $.ajax({ @@ -23,4 +23,27 @@ $(document).ready(function () { $('.center-stations').selectpicker('refresh'); } }); + $('#filter-in-centers').change(function () { + const center_ids = $('#filter-in-centers').val(); + if (center_ids) { + $.ajax({ + url: getCentersStationsUrl, + data: { + data: JSON.stringify({ + center_ids: center_ids, + tally_id: tallyId, + }), + }, + traditional: true, + dataType: 'json', + success: (data) => { + const { station_ids } = data; + $('.filter-in-center-stations').selectpicker('val', station_ids); + }, + }); + } else { + $('.filter-in-center-stations').selectpicker('deselectAll'); + $('.filter-in-center-stations').selectpicker('refresh'); + } + }); }); diff --git a/tally_ho/apps/tally/templates/reports/form_results.html b/tally_ho/apps/tally/templates/reports/form_results.html index 31754606a..3bad9ea2c 100644 --- a/tally_ho/apps/tally/templates/reports/form_results.html +++ b/tally_ho/apps/tally/templates/reports/form_results.html @@ -26,15 +26,23 @@

{% trans 'Form Results' %}

-
-

Centers

+
+

{% trans 'Races' %}

+ +
+
+

{% trans 'Centers' %}

-
+

{% trans 'Stations' %}

-
+
-

{% trans 'Filter out Centers and Stations from results.' %}

+

{% trans 'Filter Out.' %}

{% trans 'Reset' %}
+ + +
+
+

{% trans 'Races' %}

+ +
+
+

{% trans 'Centers' %}

+ +
+
+

{% trans 'Stations' %}

+ +
+
+
+
+

{% trans 'Filter In.' %}

+ + {% trans 'Reset' %} +
+
+
+

diff --git a/tally_ho/apps/tally/views/reports/administrative_areas_reports.py b/tally_ho/apps/tally/views/reports/administrative_areas_reports.py index 98fd933e0..3dca54e5a 100644 --- a/tally_ho/apps/tally/views/reports/administrative_areas_reports.py +++ b/tally_ho/apps/tally/views/reports/administrative_areas_reports.py @@ -555,26 +555,48 @@ def results_queryset( if data: selected_center_ids =\ - data['select_1_ids'] if len(data['select_1_ids']) else [0] + data['select_1_ids'] if data.get('select_1_ids') else [0] selected_station_ids =\ - data['select_2_ids'] if len(data['select_2_ids']) else [0] - - qs = qs\ + data['select_2_ids'] if data.get('select_2_ids') else [0] + race_type_names = data['race_type_names'] if data.get('race_type_names') else [] + race_types = [race_type for race_type in RaceType if race_type.name in race_type_names] + filter_in = data.get('filter_in') + qs = qs \ .annotate(station_ids=station_id_query) - qs_1 = qs\ - .filter( - ~Q(result_form__center__id__in=selected_center_ids) & - ~Q(station_ids__in=selected_station_ids))\ - .annotate(candidate_name=F('candidate__full_name'))\ - .filter(candidate_name__isnull=False) + if filter_in: + if race_types: + qs = qs.filter(Q(result_form__ballot__race_type__in=race_types)) + qs_1 = qs \ + .filter( + Q(result_form__center__id__in=selected_center_ids) & + Q(station_ids__in=selected_station_ids)) \ + .annotate(candidate_name=F('candidate__full_name')) \ + .filter(candidate_name__isnull=False) - qs_2 = qs\ - .filter( - ~Q(result_form__center__id__in=selected_center_ids) & - ~Q(station_ids__in=selected_station_ids))\ - .annotate(candidate_name=F(ballot_comp_candidate_name))\ - .filter(candidate_name__isnull=False) + qs_2 = qs \ + .filter( + Q(result_form__center__id__in=selected_center_ids) & + Q(station_ids__in=selected_station_ids)) \ + .annotate(candidate_name=F(ballot_comp_candidate_name)) \ + .filter(candidate_name__isnull=False) + + else: + if race_types: + qs = qs.filter(~Q(result_form__ballot__race_type__in=race_types)) + qs_1 = qs\ + .filter( + ~Q(result_form__center__id__in=selected_center_ids) & + ~Q(station_ids__in=selected_station_ids))\ + .annotate(candidate_name=F('candidate__full_name'))\ + .filter(candidate_name__isnull=False) + + qs_2 = qs\ + .filter( + ~Q(result_form__center__id__in=selected_center_ids) & + ~Q(station_ids__in=selected_station_ids))\ + .annotate(candidate_name=F(ballot_comp_candidate_name))\ + .filter(candidate_name__isnull=False) qs = qs_1.union(qs_2) if len(qs_2) else qs_1 @@ -652,6 +674,7 @@ def results_queryset( result_form__reconciliationform__isnull=False, then=F(reconform_num_valid_votes) ), default=V(0))).distinct() + else: qs_1 = qs\ .annotate(candidate_name=F('candidate__full_name'))\ @@ -3217,6 +3240,7 @@ class ResultFormResultsListView(LoginRequiredMixin, def get(self, request, *args, **kwargs): tally_id = kwargs.get('tally_id') stations, centers = build_station_and_centers_list(tally_id) + race_types = list(RaceType) language_de = get_datatables_language_de_from_locale(self.request) return self.render_to_response(self.get_context_data( @@ -3224,6 +3248,7 @@ def get(self, request, *args, **kwargs): tally_id=tally_id, stations=stations, centers=centers, + race_types=race_types, get_centers_stations_url='/ajax/get-centers-stations/', results_download_url='/ajax/download-results/', languageDE=language_de