@@ -177,7 +177,7 @@ def save(self):
177
177
self .debate .confirmed_ballot .save ()
178
178
179
179
# 2. Save ballot submission so that we can create related objects
180
- if self .ballotsub .pk is None :
180
+ if self .ballotsub .id is None :
181
181
self .ballotsub .save ()
182
182
183
183
# 3. Save the specifics of the ballot
@@ -252,6 +252,7 @@ def __init__(self, ballotsub, *args, **kwargs):
252
252
self .using_vetoes = self .tournament .pref ('motion_vetoes_enabled' )
253
253
self .using_forfeits = self .tournament .pref ('enable_forfeits' )
254
254
self .using_replies = self .tournament .pref ('reply_scores_enabled' )
255
+ self .using_declared_winner = True
255
256
self .bypassing_checks = self .tournament .pref ('disable_ballot_confirms' )
256
257
self .max_margin = self .tournament .pref ('maximum_margin' )
257
258
self .choosing_sides = (self .tournament .pref ('draw_side_allocations' ) == 'manual-ballot' and
@@ -349,6 +350,13 @@ def create_fields(self):
349
350
choices = [(side , _ ("Forfeit by the %(side)s" ) % {'side' : self ._side_name (side )}) for side in self .sides ]
350
351
self .fields ['forfeit' ] = forms .ChoiceField (widget = forms .RadioSelect , choices = choices , required = False )
351
352
353
+ def create_declared_winner_dropdown (self ):
354
+ """This method creates a drop-down with a list of the teams in the debate"""
355
+ return forms .TypedChoiceField (
356
+ label = _ ("Winner" ), required = True , empty_value = None ,
357
+ choices = [(None , _ ("---------" ))] + [(s , t .short_name ) for s , t in zip (self .sides , self .debate .teams )],
358
+ )
359
+
352
360
def initial_data (self ):
353
361
"""Generates dictionary of initial form data."""
354
362
@@ -403,7 +411,7 @@ def initial_from_result(self, result):
403
411
speaker = result .get_speaker (side , pos )
404
412
is_ghost = result .get_ghost (side , pos )
405
413
if speaker :
406
- initial [self ._fieldname_speaker (side , pos )] = speaker .pk
414
+ initial [self ._fieldname_speaker (side , pos )] = speaker .id
407
415
initial [self ._fieldname_ghost (side , pos )] = is_ghost
408
416
409
417
return initial
@@ -624,6 +632,10 @@ class SingleBallotSetForm(BaseBallotSetForm):
624
632
def _fieldname_score (side , pos ):
625
633
return '%(side)s_score_s%(pos)d' % {'side' : side , 'pos' : pos }
626
634
635
+ @staticmethod
636
+ def _fieldname_declared_winner ():
637
+ return 'declared_winner'
638
+
627
639
def get_result_class (self ):
628
640
return ConsensusDebateResultWithScores
629
641
@@ -647,13 +659,19 @@ def initial_from_result(self, result):
647
659
coerce_for_ui = self .fields [self ._fieldname_score (side , pos )].coerce_for_ui
648
660
initial [self ._fieldname_score (side , pos )] = coerce_for_ui (score )
649
661
662
+ if self .using_declared_winner :
663
+ initial [self ._fieldname_declared_winner ()] = result .get_winning_side ()
664
+
650
665
return initial
651
666
652
667
def list_score_fields (self ):
653
668
"""Lists all the score fields. Called by super().set_tab_indices()."""
654
669
order = []
655
670
for side , pos in product (self .sides , self .positions ):
656
671
order .append (self ._fieldname_score (side , pos ))
672
+
673
+ if self .using_declared_winner :
674
+ order .append (self ._fieldname_declared_winner ())
657
675
return order
658
676
659
677
# --------------------------------------------------------------------------
@@ -670,7 +688,7 @@ def clean_scoresheet(self, cleaned_data):
670
688
671
689
else :
672
690
# Check that no teams had the same total.
673
- if len (totals ) == 2 and totals [0 ] == totals [1 ]:
691
+ if len (totals ) == 2 and totals [0 ] == totals [1 ] and not hasattr ( cleaned_data , self . _fieldname_declared_winner ()) :
674
692
self .add_error (None , forms .ValidationError (
675
693
_ ("The total scores for the teams are the same (i.e. a draw)." ),
676
694
code = 'draw'
@@ -700,6 +718,10 @@ def populate_result_with_scores(self, result):
700
718
score = self .cleaned_data [self ._fieldname_score (side , pos )]
701
719
result .set_score (side , pos , score )
702
720
721
+ declared_winner = getattr (self .cleaned_data , self ._fieldname_declared_winner ())
722
+ if declared_winner is not None :
723
+ result .set_winner (declared_winner )
724
+
703
725
# --------------------------------------------------------------------------
704
726
# Template access methods
705
727
# --------------------------------------------------------------------------
@@ -718,6 +740,10 @@ class PerAdjudicatorBallotSetForm(BaseBallotSetForm):
718
740
def _fieldname_score (adj , side , pos ):
719
741
return '%(side)s_score_a%(adj)d_s%(pos)d' % {'adj' : adj .id , 'side' : side , 'pos' : pos }
720
742
743
+ @staticmethod
744
+ def _fieldname_declared_winner (adj ):
745
+ return 'declared_winner_a%(adj)d' % {'adj' : adj .id }
746
+
721
747
def get_result_class (self ):
722
748
return DebateResultByAdjudicatorWithScores
723
749
@@ -733,22 +759,32 @@ def create_score_fields(self):
733
759
tournament = self .tournament ,
734
760
required = not self .using_forfeits ,
735
761
)
762
+ for adj in self .adjudicators :
763
+ self .fields [self ._fieldname_declared_winner (adj )] = self .create_declared_winner_dropdown ()
736
764
737
765
def initial_from_result (self , result ):
738
766
initial = super ().initial_from_result (result )
739
767
740
- for adj , side , pos in product (self .adjudicators , self .sides , self .positions ):
741
- score = result .get_score (adj , side , pos )
742
- coerce_for_ui = self .fields [self ._fieldname_score (adj , side , pos )].coerce_for_ui
743
- initial [self ._fieldname_score (adj , side , pos )] = coerce_for_ui (score )
768
+ for adj in self .adjudicators :
769
+ for side , pos in product (self .sides , self .positions ):
770
+ score = result .get_score (adj , side , pos )
771
+ coerce_for_ui = self .fields [self ._fieldname_score (adj , side , pos )].coerce_for_ui
772
+ initial [self ._fieldname_score (adj , side , pos )] = coerce_for_ui (score )
773
+
774
+ if self .using_declared_winner :
775
+ initial [self ._fieldname_declared_winner (adj )] = result .get_winner (adj )
744
776
745
777
return initial
746
778
747
779
def list_score_fields (self ):
748
780
"""Lists all the score fields. Called by super().set_tab_indices()."""
749
781
order = []
750
- for adj , side , pos in product (self .adjudicators , self .sides , self .positions ):
751
- order .append (self ._fieldname_score (adj , side , pos ))
782
+ for adj in self .adjudicators :
783
+ for side , pos in product (self .sides , self .positions ):
784
+ order .append (self ._fieldname_score (adj , side , pos ))
785
+
786
+ if self .using_declared_winner :
787
+ order .append (self ._fieldname_declared_winner (adj ))
752
788
return order
753
789
754
790
# --------------------------------------------------------------------------
@@ -766,7 +802,7 @@ def clean_scoresheet(self, cleaned_data):
766
802
767
803
else :
768
804
# Check that it was not a draw.
769
- if totals [0 ] == totals [1 ]:
805
+ if totals [0 ] == totals [1 ] and not hasattr ( cleaned_data , self . _fieldname_declared_winner ( adj )) :
770
806
self .add_error (None , forms .ValidationError (
771
807
_ ("The total scores for the teams are the same (i.e. a draw) for adjudicator %(adj)s." ),
772
808
params = {'adj' : adj .name }, code = 'draw'
@@ -781,17 +817,23 @@ def clean_scoresheet(self, cleaned_data):
781
817
))
782
818
783
819
def populate_result_with_scores (self , result ):
784
- for adj , side , pos in product (self .adjudicators , self .sides , self .positions ):
785
- score = self .cleaned_data [self ._fieldname_score (adj , side , pos )]
786
- result .set_score (adj , side , pos , score )
820
+ for adj in self .adjudicators :
821
+ for side , pos in product (self .sides , self .positions ):
822
+ score = self .cleaned_data [self ._fieldname_score (adj , side , pos )]
823
+ result .set_score (adj , side , pos , score )
824
+
825
+ declared_winner = getattr (self .cleaned_data , self ._fieldname_declared_winner (adj ))
826
+ if declared_winner is not None :
827
+ result .set_winner (adj , declared_winner )
828
+
787
829
788
830
# --------------------------------------------------------------------------
789
831
# Template access methods
790
832
# --------------------------------------------------------------------------
791
833
792
834
def scoresheets (self ):
793
835
"""Generates a sequence of nested dicts that allows for easy iteration
794
- through the form. Used in the ballot_set.html.html template."""
836
+ through the form. Used in the ballot_set.html template."""
795
837
796
838
for adj in self .adjudicators :
797
839
sheet_dict = {
@@ -800,6 +842,8 @@ def scoresheets(self):
800
842
lambda side , pos : self ._fieldname_score (adj , side , pos )
801
843
),
802
844
}
845
+ if self .using_declared_winner :
846
+ sheet_dict ['declared_winner' ] = self [self ._fieldname_declared_winner (adj )]
803
847
yield sheet_dict
804
848
805
849
0 commit comments