From 6f5731d0ffef8c8cfb6641e4a3af8b43e31b83d1 Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Mon, 24 Jul 2023 18:17:38 +0300
Subject: [PATCH] add default vote outcome to nomination decision

---
 scipost_django/colleges/forms.py             |  4 ++++
 scipost_django/colleges/models/nomination.py | 22 ++++++++++++++++++++
 scipost_django/colleges/views.py             |  6 +++---
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/scipost_django/colleges/forms.py b/scipost_django/colleges/forms.py
index 10b0dd99a..aefa515b3 100644
--- a/scipost_django/colleges/forms.py
+++ b/scipost_django/colleges/forms.py
@@ -552,6 +552,7 @@ class FellowshipNominationDecisionForm(forms.ModelForm):
         ]
 
     def __init__(self, *args, **kwargs):
+        voting_round = kwargs.pop("voting_round", None)
         super().__init__(*args, **kwargs)
         self.helper = FormHelper()
         self.helper.layout = Layout(
@@ -568,6 +569,9 @@ class FellowshipNominationDecisionForm(forms.ModelForm):
             ),
         )
 
+        if voting_round:
+            self.fields["outcome"].initial = voting_round.vote_outcome
+
 
 class FellowshipInvitationResponseForm(forms.ModelForm):
     class Meta:
diff --git a/scipost_django/colleges/models/nomination.py b/scipost_django/colleges/models/nomination.py
index 6487d2a84..1db4b616d 100644
--- a/scipost_django/colleges/models/nomination.py
+++ b/scipost_django/colleges/models/nomination.py
@@ -218,6 +218,28 @@ class FellowshipNominationVotingRound(models.Model):
     def is_open(self):
         return self.voting_opens <= timezone.now() <= self.voting_deadline
 
+    @property
+    def vote_outcome(self):
+        """The outcome as determined by the votes."""
+        if self.votes.veto():
+            return FellowshipNominationDecision.OUTCOME_NOT_ELECTED
+
+        nr_votes_agree = self.votes.agree().count()
+        nr_votes_disagree = self.votes.disagree().count()
+        nr_non_abstaining_votes = nr_votes_agree + nr_votes_disagree
+
+        # Guard division by zero
+        if nr_non_abstaining_votes == 0:
+            return FellowshipNominationDecision.OUTCOME_NOT_ELECTED
+
+        # By-laws 1.3.4 grand fellowship if there is a majority of non-abstaining votes.
+        # Agree is counted as +1, disagree as -1
+        agree_ratio = (nr_votes_agree - nr_votes_disagree) / nr_non_abstaining_votes
+        if agree_ratio >= 0.5:
+            return FellowshipNominationDecision.OUTCOME_ELECTED
+        else:
+            return FellowshipNominationDecision.OUTCOME_NOT_ELECTED
+
 
 class FellowshipNominationVote(models.Model):
     VOTE_AGREE = "agree"
diff --git a/scipost_django/colleges/views.py b/scipost_django/colleges/views.py
index ec3c3c627..8cc95efe4 100644
--- a/scipost_django/colleges/views.py
+++ b/scipost_django/colleges/views.py
@@ -961,7 +961,9 @@ def _hx_nomination_vote(request, voting_round_id):
 def _hx_nomination_decision_form(request, round_id):
     voting_round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
     nomination = voting_round.nomination
-    decision_form = FellowshipNominationDecisionForm(request.POST or None)
+    decision_form = FellowshipNominationDecisionForm(
+        request.POST or None, voting_round=voting_round
+    )
     if decision_form.is_valid():
         decision = decision_form.save()
         nomination.add_event(description="Decision fixed", by=request.user.contributor)
@@ -974,8 +976,6 @@ def _hx_nomination_decision_form(request, round_id):
             nomination.add_event(
                 description="Invitation created", by=request.user.contributor
             )
-    else:
-        decision_form.fields["voting_round"].initial = voting_round
     context = {
         "voting_round": voting_round,
         "decision_form": decision_form,
-- 
GitLab