Skip to content

Commit

Permalink
Merge pull request #437 from onaio/hot-fix-duplicate-results-logic
Browse files Browse the repository at this point in the history
Hot fix duplicate results logic
  • Loading branch information
JohnMwashuma authored Nov 8, 2024
2 parents 753cc1e + b2ef44c commit 5259413
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

{% block content %}

<h1>{% trans 'Results Duplicated List' %}</h1>
<h1>{% trans 'Duplicate Result Forms List' %}</h1>

<br/>
<br/>
Expand Down
2 changes: 1 addition & 1 deletion tally_ho/apps/tally/templates/super_admin/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ <h3>{% trans 'Reports' %}</h3>
<li><a href="{% url 'form-duplicates' tally_id=tally_id %}">{% trans 'Form Duplicates' %}</a></li>
<li><a href="{% url 'form-clearance' tally_id=tally_id %}">{% trans 'Form Clearance' %}</a></li>
<li><a href="{% url 'form-audit' tally_id=tally_id %}">{% trans 'Form Audit' %}</a></li>
<li><a href="{% url 'form-results-duplicates' tally_id=tally_id %}">{% trans 'Form Results Duplicates' %}</a></li>
<li><a href="{% url 'form-results-duplicates' tally_id=tally_id %}">{% trans 'Duplicate Result Forms List' %}</a></li>
<li><a href="{% url 'result-export' tally_id=tally_id %}">{% trans 'Download Results' %}</a></li>
</ul>

Expand Down
18 changes: 9 additions & 9 deletions tally_ho/apps/tally/tests/views/test_super_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,10 +1160,10 @@ def test_get_result_form_with_duplicate_results(self):
# create duplicate final results
create_result(result_form_4, result.candidate, self.user, votes)
ballot_1_duplicates = views.get_result_form_with_duplicate_results(
ballot=ballot_1.pk,
ballot=ballot_1.number,
tally_id=tally.pk)
ballot_2_duplicates = views.get_result_form_with_duplicate_results(
ballot=ballot_2.pk,
ballot=ballot_2.number,
tally_id=tally.pk)
all_duplicates = views.get_result_form_with_duplicate_results(
tally_id=tally.pk)
Expand Down Expand Up @@ -1229,11 +1229,11 @@ def test_duplicate_result_form_view_get(self):
request,
tally_id=tally.pk,
barcode=barcode,
ballot_id=ballot.pk)
ballot_id=ballot.number)
response.render()
self.assertIn(("{}{}").format(
"Duplicate result forms list for ballot: ",
ballot.pk), str(response.content))
ballot.number), str(response.content))
self.assertIn(("{}{}").format("Result form barcode: ",
barcode), str(response.content))
self.assertIn("Send to clearance", str(response.content))
Expand Down Expand Up @@ -1277,7 +1277,7 @@ def test_duplicate_result_form_view_duplicate_reviewed_post(self):
request = self.factory.post('/', data=data)
request.user = self.user
configure_messages(request)
response = view(request, tally_id=tally.pk, ballot_id=ballot.pk)
response = view(request, tally_id=tally.pk, ballot_id=ballot.number)

result_form_1.reload()
result_form_2.reload()
Expand Down Expand Up @@ -1310,7 +1310,7 @@ def test_duplicate_result_form_view_send_clearance_post(self):
request.user = self.user
configure_messages(request)
request.session = {'result_form': result_form.pk}
response = view(request, tally_id=tally.pk, ballot_id=ballot.pk)
response = view(request, tally_id=tally.pk, ballot_id=ballot.number)

result_form.reload()
self.assertEqual(response.status_code, 302)
Expand Down Expand Up @@ -1339,7 +1339,7 @@ def test_duplicate_result_form_view_send_clearance_post(self):
request.user = self.user
configure_messages(request)
request.session = {'result_form': result_form_2.pk}
response = view(request, tally_id=tally.pk, ballot_id=ballot.pk)
response = view(request, tally_id=tally.pk, ballot_id=ballot.number)

result_form_2.reload()
self.assertNotEqual(result_form_2.form_state, FormState.CLEARANCE)
Expand Down Expand Up @@ -1384,7 +1384,7 @@ def test_duplicate_result_form_view_send_all_clearance_post(self):
request = self.factory.post('/', data=data)
request.user = self.user
configure_messages(request)
response = view(request, tally_id=tally.pk, ballot_id=ballot.pk)
response = view(request, tally_id=tally.pk, ballot_id=ballot.number)

result_form_1.reload()
result_form_2.reload()
Expand Down Expand Up @@ -1432,7 +1432,7 @@ def test_duplicate_archived_result_forms_send_all_clearance_post(self):
request = self.factory.post('/', data=data)
request.user = self.user
configure_messages(request)
response = view(request, tally_id=tally.pk, ballot_id=ballot.pk)
response = view(request, tally_id=tally.pk, ballot_id=ballot.number)

result_form_1.reload()
result_form_2.reload()
Expand Down
77 changes: 59 additions & 18 deletions tally_ho/apps/tally/views/super_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.db.models.deletion import ProtectedError
from django.core.exceptions import SuspiciousOperation
from django.contrib.messages.views import SuccessMessageMixin
from django.db.models import Count, Func, Q, F
from django.db.models import Count, Q, F
from django.shortcuts import get_object_or_404, redirect
from django.views.generic.edit import UpdateView, DeleteView, CreateView
from django.views.generic import FormView, TemplateView
Expand Down Expand Up @@ -180,6 +180,12 @@ def get_results_duplicates(tally_id):

return result_forms_founds

def all_candidates_have_duplicates(candidate_id_to_votes_array_map):
for votes in candidate_id_to_votes_array_map.values():
# Check if all items in the list are the same
if len(set(votes)) != 1:
return False
return True

def get_result_form_with_duplicate_results(
ballot=None,
Expand All @@ -192,24 +198,55 @@ def get_result_form_with_duplicate_results(
:returns A list of result forms in the system with duplicate results.
"""
qs = ResultForm.objects.filter(tally_id=tally_id) if not qs else qs
result_form_ids = qs.exclude(results=None).values(
'ballot',
'results__votes',
'results__candidate') \
.annotate(ids=ArrayAgg('id')) \
.annotate(duplicate_count=Count('id')) \
.annotate(ids=Func('ids', function='unnest')) \
.filter(
duplicate_count__gt=1,
duplicate_reviewed=False
).values_list('ids', flat=True).distinct()
qs =\
ResultForm.objects.filter(
tally_id=tally_id,
duplicate_reviewed=False) if not qs else qs
qs = qs.exclude(results=None)
if ballot:
qs = qs.filter(ballot__number=ballot)
result_forms_barcodes_grouped_by_ballot =\
qs.values('ballot').annotate(barcodes=ArrayAgg('barcode'))
result_forms_with_ballot =\
[
b for b in result_forms_barcodes_grouped_by_ballot\
if len(b.get('barcodes')) > 1
]
result_form_barcodes_with_duplicate_results = []
for ballot_result_form_dict in result_forms_with_ballot:
candidate_id_to_votes_array_map = {}
if ballot_result_form_dict.get('barcodes'):
for barcode in ballot_result_form_dict.get('barcodes'):
candidate_results_qs =\
Result.objects.filter(
result_form__tally__id=tally_id,
active=True,
result_form__barcode=barcode,
).values('candidate_id', 'votes')
for candidate_result in candidate_results_qs:
candidate_id = candidate_result.get('candidate_id')
candidate_votes = candidate_result.get('votes')
if candidate_id_to_votes_array_map.get(candidate_id):
candidate_id_to_votes_array_map.get(
candidate_id).append(candidate_votes)
continue
candidate_id_to_votes_array_map.setdefault(
candidate_id, []).append(candidate_votes)

if len(candidate_id_to_votes_array_map.values()):
# Check for duplicate results
duplicates_found =\
all_candidates_have_duplicates(
candidate_id_to_votes_array_map)
if duplicates_found:
result_form_barcodes_with_duplicate_results.extend(
ballot_result_form_dict.get('barcodes')
)

results_form_duplicates = \
qs.filter(id__in=result_form_ids).order_by('ballot')

if ballot:
results_form_duplicates = results_form_duplicates.filter(ballot=ballot)
qs.filter(
barcode__in=result_form_barcodes_with_duplicate_results
).order_by('ballot')

return results_form_duplicates

Expand Down Expand Up @@ -494,7 +531,11 @@ def get(self, *args, **kwargs):
ballot_id = kwargs['ballot_id']
result_form = ResultForm.objects.get(
barcode=barcode, tally_id=tally_id)
results = Result.objects.filter(result_form=result_form.id)
results =\
Result.objects.filter(
result_form=result_form,
result_form__tally__id=tally_id,
)

return self.render_to_response(self.get_context_data(
results_form_duplicates=get_result_form_with_duplicate_results(
Expand Down

0 comments on commit 5259413

Please sign in to comment.