Fixed #1102 (New config option to set percent base for polls)
Use locale format for poll percentage decimal number.
This commit is contained in:
parent
579c9d49f0
commit
fa6c7d9d86
@ -21,6 +21,7 @@ Participants:
|
||||
Files:
|
||||
- Enabled update and delete view for uploader refering to his own files.
|
||||
Other:
|
||||
- New config option to set the 100% base for polls (motions/elections).
|
||||
- Changed widget api. Used new metaclass.
|
||||
- Changed api for plugins. Used entry points to detect them automaticly.
|
||||
- Renamed config api classes.
|
||||
|
@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
from openslides.agenda.models import Item, Speaker
|
||||
from openslides.config.api import config
|
||||
from openslides.poll.models import (BaseOption, BasePoll, BaseVote,
|
||||
CollectInvalid, CollectVotesCast,
|
||||
CollectDefaultVotesMixin,
|
||||
PublishPollMixin)
|
||||
from openslides.projector.models import RelatedModelMixin, SlideMixin
|
||||
from openslides.utils.exceptions import OpenSlidesError
|
||||
@ -271,7 +271,7 @@ class AssignmentOption(BaseOption):
|
||||
return unicode(self.candidate)
|
||||
|
||||
|
||||
class AssignmentPoll(RelatedModelMixin, CollectInvalid, CollectVotesCast,
|
||||
class AssignmentPoll(RelatedModelMixin, CollectDefaultVotesMixin,
|
||||
PublishPollMixin, AbsoluteUrlMixin, BasePoll):
|
||||
option_class = AssignmentOption
|
||||
assignment = models.ForeignKey(Assignment, related_name='poll_set')
|
||||
@ -319,6 +319,9 @@ class AssignmentPoll(RelatedModelMixin, CollectInvalid, CollectVotesCast,
|
||||
def get_ballot(self):
|
||||
return self.assignment.poll_set.filter(id__lte=self.id).count()
|
||||
|
||||
def get_percent_base_choice(self):
|
||||
return config['assignment_poll_100_percent_base']
|
||||
|
||||
def append_pollform_fields(self, fields):
|
||||
fields.append('description')
|
||||
super(AssignmentPoll, self).append_pollform_fields(fields)
|
||||
|
@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
|
||||
from openslides.config.api import ConfigGroup, ConfigGroupedCollection, ConfigVariable
|
||||
from openslides.config.signals import config_signal
|
||||
from openslides.poll.models import PERCENT_BASE_CHOICES
|
||||
|
||||
|
||||
@receiver(config_signal, dispatch_uid='setup_assignment_config')
|
||||
@ -26,6 +27,14 @@ def setup_assignment_config(sender, **kwargs):
|
||||
('auto', ugettext_lazy('Automatic assign of method')),
|
||||
('votes', ugettext_lazy('Always one option per candidate')),
|
||||
('yesnoabstain', ugettext_lazy('Always Yes-No-Abstain per candidate')))))
|
||||
assignment_poll_100_percent_base = ConfigVariable(
|
||||
name='assignment_poll_100_percent_base',
|
||||
default_value='WITHOUT_INVALID',
|
||||
form_field=forms.ChoiceField(
|
||||
widget=forms.Select(),
|
||||
required=False,
|
||||
label=ugettext_lazy('The 100 % base of an election result consists of'),
|
||||
choices=PERCENT_BASE_CHOICES))
|
||||
assignment_pdf_ballot_papers_selection = ConfigVariable(
|
||||
name='assignment_pdf_ballot_papers_selection',
|
||||
default_value='CUSTOM_NUMBER',
|
||||
@ -55,6 +64,7 @@ def setup_assignment_config(sender, **kwargs):
|
||||
group_ballot = ConfigGroup(
|
||||
title=ugettext_lazy('Ballot and ballot papers'),
|
||||
variables=(assignment_poll_vote_values,
|
||||
assignment_poll_100_percent_base,
|
||||
assignment_pdf_ballot_papers_selection,
|
||||
assignment_pdf_ballot_papers_number,
|
||||
assignment_publish_winner_results_only))
|
||||
|
@ -187,8 +187,8 @@
|
||||
<td>
|
||||
{% if candidate in assignment.elected %}
|
||||
{% if perms.assignment.can_manage_assignment %}
|
||||
<a class="election_link elected" href="{% url 'assignment_user_not_elected' assignment.id candidate.person_id %}"
|
||||
rel="tooltip" data-original-title="{% trans 'Mark candidate as elected' %}"></a>
|
||||
<a class="election_link elected tooltip-bottom" href="{% url 'assignment_user_not_elected' assignment.id candidate.person_id %}"
|
||||
data-original-title="{% trans 'Mark candidate as elected' %}"></a>
|
||||
{% else %}
|
||||
<a class="elected">
|
||||
<img src="{% static 'img/voting-yes.png' %}" class="tooltip-bottom" data-original-title="{% trans 'Candidate is elected' %}">
|
||||
@ -196,7 +196,8 @@
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if perms.assignment.can_manage_assignment %}
|
||||
<a class="election_link" href="{% url 'assignment_user_elected' assignment.id candidate.person_id %}"></a>
|
||||
<a class="election_link tooltip-bottom" href="{% url 'assignment_user_elected' assignment.id candidate.person_id %}"
|
||||
data-original-title="{% trans 'Mark candidate as elected' %}"></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<a href="{{ candidate|absolute_url }}">{{ candidate }}</a>
|
||||
@ -221,13 +222,29 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>{% trans 'Valid votes' %}</td>
|
||||
{% for poll in polls %}
|
||||
{% if poll.published or perms.assignment.can_manage_assignment %}
|
||||
<td style="white-space:nowrap;">
|
||||
{% if poll.has_votes %}
|
||||
<img src="{% static 'img/voting-yes-grey.png' %}" class="tooltip-left" data-original-title="{% trans 'Valid votes' %}">
|
||||
{{ poll.print_votesvalid }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Invalid votes' %}</td>
|
||||
{% for poll in polls %}
|
||||
{% if poll.published or perms.assignment.can_manage_assignment %}
|
||||
<td style="white-space:nowrap;">
|
||||
{% if poll.has_votes %}
|
||||
<img src="{% static 'img/voting-invalid.png' %}" class="tooltip-left" data-original-title="{% trans 'Invalid' %}">
|
||||
<img src="{% static 'img/voting-invalid.png' %}" class="tooltip-left" data-original-title="{% trans 'Invalid votes' %}">
|
||||
{{ poll.print_votesinvalid }}
|
||||
{% endif %}
|
||||
</td>
|
||||
@ -238,13 +255,13 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr class="info total">
|
||||
<td><strong>{% trans 'Votes cast' %}</strong></td>
|
||||
<td>{% trans 'Votes cast' %}</td>
|
||||
{% for poll in polls %}
|
||||
{% if poll.published or perms.assignment.can_manage_assignment %}
|
||||
<td style="white-space:nowrap;">
|
||||
{% if poll.has_votes %}
|
||||
<img src="{% static 'img/voting-total.png' %}" class="tooltip-left" data-original-title="{% trans 'Votes cast' %}">
|
||||
<strong>{{ poll.print_votescast }}</strong>
|
||||
{{ poll.print_votescast }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
@ -50,6 +50,16 @@
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>{% trans "Valid votes" %}</td>
|
||||
{% for value in poll.get_vote_values %}
|
||||
{% if forloop.first %}
|
||||
<td>{{ pollform.votesvalid.errors }}{{ pollform.votesvalid }}</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans "Invalid votes" %}</td>
|
||||
{% for value in poll.get_vote_values %}
|
||||
|
@ -80,12 +80,23 @@
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr class="total">
|
||||
<td>{% trans 'Valid votes' %}</td>
|
||||
{% for poll in polls %}
|
||||
<td style="white-space:nowrap;">
|
||||
{% if poll.has_votes %}
|
||||
<img src="{% static 'img/voting-yes-grey.png' %}" title="{% trans 'Valid votes' %}">
|
||||
{{ poll.print_votesvalid }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Invalid votes' %}</td>
|
||||
{% for poll in polls %}
|
||||
<td style="white-space:nowrap;">
|
||||
{% if poll.has_votes %}
|
||||
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid' %}">
|
||||
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid votes' %}">
|
||||
{{ poll.print_votesinvalid }}
|
||||
{% endif %}
|
||||
</td>
|
||||
@ -94,13 +105,13 @@
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td>
|
||||
<strong>{% trans 'Votes cast' %}</strong>
|
||||
{% trans 'Votes cast' %}
|
||||
</td>
|
||||
{% for poll in polls %}
|
||||
<td style="white-space:nowrap;">
|
||||
{% if poll.has_votes %}
|
||||
<img src="{% static 'img/voting-total.png' %}" title="{% trans 'Votes cast' %}">
|
||||
<strong>{{ poll.print_votescast }}</strong>
|
||||
{{ poll.print_votescast }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
|
@ -423,20 +423,30 @@ class AssignmentPDF(PDFView):
|
||||
pass
|
||||
data_votes.append(row)
|
||||
|
||||
# Add votes invalid row
|
||||
# Add valid votes row
|
||||
if poll.votesvalid is not None:
|
||||
footrow_one = []
|
||||
footrow_one.append(_("Invalid votes"))
|
||||
footrow_one.append(_("Valid votes"))
|
||||
for poll in polls:
|
||||
footrow_one.append(poll.print_votesinvalid())
|
||||
footrow_one.append(poll.print_votesvalid())
|
||||
data_votes.append(footrow_one)
|
||||
|
||||
# Add votes cast row
|
||||
# Add invalid votes row
|
||||
if poll.votesinvalid is not None:
|
||||
footrow_two = []
|
||||
footrow_two.append(_("Votes cast"))
|
||||
footrow_two.append(_("Invalid votes"))
|
||||
for poll in polls:
|
||||
footrow_two.append(poll.print_votescast())
|
||||
footrow_two.append(poll.print_votesinvalid())
|
||||
data_votes.append(footrow_two)
|
||||
|
||||
# Add votes cast row
|
||||
if poll.votescast is not None:
|
||||
footrow_three = []
|
||||
footrow_three.append(_("Votes cast"))
|
||||
for poll in polls:
|
||||
footrow_three.append(poll.print_votescast())
|
||||
data_votes.append(footrow_three)
|
||||
|
||||
table_votes = Table(data_votes)
|
||||
table_votes.setStyle(
|
||||
TableStyle([
|
||||
|
@ -9,8 +9,7 @@ from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
|
||||
from openslides.config.api import config
|
||||
from openslides.mediafile.models import Mediafile
|
||||
from openslides.poll.models import (BaseOption, BasePoll, BaseVote,
|
||||
CollectInvalid, CollectVotesCast)
|
||||
from openslides.poll.models import (BaseOption, BasePoll, BaseVote, CollectDefaultVotesMixin)
|
||||
from openslides.projector.models import RelatedModelMixin, SlideMixin
|
||||
from jsonfield import JSONField
|
||||
from openslides.utils.models import AbsoluteUrlMixin
|
||||
@ -694,8 +693,7 @@ class MotionOption(BaseOption):
|
||||
"""The VoteClass, to witch this Class links."""
|
||||
|
||||
|
||||
class MotionPoll(RelatedModelMixin, CollectInvalid, CollectVotesCast,
|
||||
AbsoluteUrlMixin, BasePoll):
|
||||
class MotionPoll(RelatedModelMixin, CollectDefaultVotesMixin, AbsoluteUrlMixin, BasePoll):
|
||||
"""The Class to saves the poll results for a motion poll."""
|
||||
|
||||
motion = models.ForeignKey(Motion, related_name='polls')
|
||||
@ -746,6 +744,9 @@ class MotionPoll(RelatedModelMixin, CollectInvalid, CollectVotesCast,
|
||||
def get_related_model(self):
|
||||
return self.motion
|
||||
|
||||
def get_percent_base_choice(self):
|
||||
return config['motion_poll_100_percent_base']
|
||||
|
||||
|
||||
class State(models.Model):
|
||||
"""
|
||||
|
@ -113,17 +113,21 @@ def motion_to_pdf(pdf, motion):
|
||||
for poll in polls:
|
||||
ballotcounter += 1
|
||||
option = poll.get_options()[0]
|
||||
yes, no, abstain, invalid, votecast = (
|
||||
option['Yes'], option['No'], option['Abstain'],
|
||||
poll.print_votesinvalid(), poll.print_votescast())
|
||||
|
||||
yes, no, abstain = (option['Yes'], option['No'], option['Abstain'])
|
||||
valid, invalid, votescast = ('', '', '')
|
||||
if poll.votesvalid is not None:
|
||||
valid = "<br/>%s: %s" % (_("Valid votes"), poll.print_votesvalid())
|
||||
if poll.votesinvalid is not None:
|
||||
invalid = "<br/>%s: %s" % (_("Invalid votes"), poll.print_votesinvalid())
|
||||
if poll.votescast is not None:
|
||||
votescast = "<br/>%s: %s" % (_("Votes cast"), poll.print_votescast())
|
||||
if len(polls) > 1:
|
||||
cell6b.append(Paragraph("%s. %s" % (ballotcounter, _("Vote")),
|
||||
stylesheet['Bold']))
|
||||
cell6b.append(Paragraph(
|
||||
"%s: %s <br/> %s: %s <br/> %s: %s <br/> %s: %s <br/> %s: %s" %
|
||||
(_("Yes"), yes, _("No"), no, _("Abstention"), abstain, _("Invalid"),
|
||||
invalid, _("Votes cast"), votecast), stylesheet['Normal']))
|
||||
"%s: %s <br/> %s: %s <br/> %s: %s <br/> %s %s %s" %
|
||||
(_("Yes"), yes, _("No"), no, _("Abstention"), abstain, valid, invalid, votescast),
|
||||
stylesheet['Normal']))
|
||||
cell6b.append(Spacer(0, 0.2 * cm))
|
||||
motion_data.append([cell6a, cell6b])
|
||||
|
||||
|
@ -8,6 +8,7 @@ from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
from openslides.config.api import ConfigGroup, ConfigGroupedCollection, ConfigVariable
|
||||
from openslides.config.signals import config_signal
|
||||
from openslides.core.signals import post_database_setup
|
||||
from openslides.poll.models import PERCENT_BASE_CHOICES
|
||||
|
||||
from .models import State, Workflow
|
||||
|
||||
@ -85,7 +86,15 @@ def setup_motion_config(sender, **kwargs):
|
||||
title=ugettext_lazy('Supporters'),
|
||||
variables=(motion_min_supporters, motion_remove_supporters))
|
||||
|
||||
# Ballot papers
|
||||
# Voting and ballot papers
|
||||
motion_poll_100_percent_base = ConfigVariable(
|
||||
name='motion_poll_100_percent_base',
|
||||
default_value='WITHOUT_INVALID',
|
||||
form_field=forms.ChoiceField(
|
||||
widget=forms.Select(),
|
||||
required=False,
|
||||
label=ugettext_lazy('The 100 % base of a voting result consists of'),
|
||||
choices=PERCENT_BASE_CHOICES))
|
||||
motion_pdf_ballot_papers_selection = ConfigVariable(
|
||||
name='motion_pdf_ballot_papers_selection',
|
||||
default_value='CUSTOM_NUMBER',
|
||||
@ -106,8 +115,8 @@ def setup_motion_config(sender, **kwargs):
|
||||
min_value=1,
|
||||
label=ugettext_lazy('Custom number of ballot papers')))
|
||||
group_ballot_papers = ConfigGroup(
|
||||
title=ugettext_lazy('Ballot papers'),
|
||||
variables=(motion_pdf_ballot_papers_selection, motion_pdf_ballot_papers_number))
|
||||
title=ugettext_lazy('Voting and ballot papers'),
|
||||
variables=(motion_poll_100_percent_base, motion_pdf_ballot_papers_selection, motion_pdf_ballot_papers_number))
|
||||
|
||||
# PDF
|
||||
motion_pdf_title = ConfigVariable(
|
||||
|
@ -50,3 +50,9 @@ td.diff_header {
|
||||
#motion-vote-results img {
|
||||
margin-top: -4px;
|
||||
}
|
||||
#motion-vote-results .resultline {
|
||||
border-top: 1px solid;
|
||||
padding-top: 5px;
|
||||
margin: 5px 0;
|
||||
width: 10em;
|
||||
}
|
||||
|
@ -221,10 +221,21 @@
|
||||
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Yes' %}"> {{ option.Yes }}<br>
|
||||
<img src="{% static 'img/voting-no.png' %}" title="{% trans 'No' %}"> {{ option.No }}<br>
|
||||
<img src="{% static 'img/voting-abstention.png' %}" title="{% trans 'Abstention' %}"> {{ option.Abstain }}<br>
|
||||
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid' %}"> {{ poll.print_votesinvalid }}<br>
|
||||
<div style="border-top: 1px solid; padding-top: 5px; margin: 5px 0; width: 10em;">
|
||||
{% if poll.votesvalid != None or poll.votesinvalid != None %}
|
||||
<div class="resultline">
|
||||
{% if poll.votesvalid != None %}
|
||||
<img src="{% static 'img/voting-yes-grey.png' %}" title="{% trans 'Valid votes' %}"> {{ poll.print_votesvalid }}<br>
|
||||
{% endif %}
|
||||
{% if poll.votesinvalid != None %}
|
||||
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid votes' %}"> {{ poll.print_votesinvalid }}<br>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if poll.votescast != None %}
|
||||
<div class="resultline">
|
||||
<img src="{% static 'img/voting-total.png' %}" title="{% trans 'Votes cast' %}"> {{ poll.print_votescast }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
{% if perms.motion.can_manage_motion %}
|
||||
|
@ -45,6 +45,10 @@
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr class="total">
|
||||
<td>{% trans "Valid votes" %}</td>
|
||||
<td>{{ pollform.votesvalid.errors }}{{ pollform.votesvalid }}</td>
|
||||
</tr>
|
||||
<tr class="">
|
||||
<td>{% trans "Invalid votes" %}</td>
|
||||
<td>{{ pollform.votesinvalid.errors }}{{ pollform.votesinvalid }}</td>
|
||||
</tr>
|
||||
|
@ -23,9 +23,19 @@
|
||||
<img src="{% static 'img/voting-yes.png' %}" title="{% trans 'Yes' %}"> {{ option.Yes }} <br>
|
||||
<img src="{% static 'img/voting-no.png' %}" title="{% trans 'No' %}"> {{ option.No }} <br>
|
||||
<img src="{% static 'img/voting-abstention.png' %}" title="{% trans 'Abstention' %}"> {{ option.Abstain }}<br>
|
||||
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid' %}"> {{ poll.print_votesinvalid }}<br>
|
||||
<hr>
|
||||
{% if poll.votesvalid != None or poll.votesinvalid != None %}
|
||||
<div class="resultline"></div>
|
||||
{% if poll.votesvalid != None %}
|
||||
<img src="{% static 'img/voting-yes-grey.png' %}" title="{% trans 'Valid votes' %}"> {{ poll.print_votesvalid }}<br>
|
||||
{% endif %}
|
||||
{% if poll.votesinvalid != None %}
|
||||
<img src="{% static 'img/voting-invalid.png' %}" title="{% trans 'Invalid votes' %}"> {{ poll.print_votesinvalid }}<br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if poll.votescast != None %}
|
||||
<div class="resultline"></div>
|
||||
<img src="{% static 'img/voting-total.png' %}" title="{% trans 'Votes cast' %}"> {{ poll.print_votescast }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
|
@ -1,5 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import locale
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext as _
|
||||
@ -60,17 +62,28 @@ class BaseVote(models.Model):
|
||||
if raw:
|
||||
return self.weight
|
||||
try:
|
||||
percent_base = self.option.poll.percent_base()
|
||||
percent_base = self.option.poll.get_percent_base()
|
||||
except AttributeError:
|
||||
# The poll class is no child of CollectVotesCast
|
||||
percent_base = 0
|
||||
return print_value(self.weight, percent_base)
|
||||
|
||||
|
||||
class CollectVotesCast(models.Model):
|
||||
PERCENT_BASE_CHOICES = (
|
||||
('WITHOUT_INVALID', ugettext_lazy('All valid votes (Yes + No + Abstention)')),
|
||||
('WITH_INVALID', ugettext_lazy('All votes casts (valid + invalid votes)')),
|
||||
('DISABLED', ugettext_lazy('Disabled (no percents)')))
|
||||
|
||||
|
||||
class CollectDefaultVotesMixin(models.Model):
|
||||
"""
|
||||
Mixin for a poll to collect the votes cast.
|
||||
Mixin for a poll to collect the default vote values for valid votes,
|
||||
invalid votes and votes cast.
|
||||
"""
|
||||
votesvalid = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
||||
verbose_name=ugettext_lazy('Votes valid'))
|
||||
votesinvalid = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
||||
verbose_name=ugettext_lazy('Votes invalid'))
|
||||
votescast = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
||||
verbose_name=ugettext_lazy('Votes cast'))
|
||||
|
||||
@ -78,39 +91,46 @@ class CollectVotesCast(models.Model):
|
||||
abstract = True
|
||||
|
||||
def append_pollform_fields(self, fields):
|
||||
fields.append('votescast')
|
||||
super(CollectVotesCast, self).append_pollform_fields(fields)
|
||||
|
||||
def print_votescast(self):
|
||||
return print_value(self.votescast, self.percent_base())
|
||||
|
||||
def percent_base(self):
|
||||
if self.votescast > 0:
|
||||
return 100 / float(self.votescast)
|
||||
return 0
|
||||
|
||||
|
||||
class CollectInvalid(models.Model):
|
||||
"""
|
||||
Mixin for a poll to collect invalid votes.
|
||||
"""
|
||||
votesinvalid = MinMaxIntegerField(null=True, blank=True, min_value=-2,
|
||||
verbose_name=ugettext_lazy('Votes invalid'))
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def append_pollform_fields(self, fields):
|
||||
fields.append('votesvalid')
|
||||
fields.append('votesinvalid')
|
||||
super(CollectInvalid, self).append_pollform_fields(fields)
|
||||
fields.append('votescast')
|
||||
super(CollectDefaultVotesMixin, self).append_pollform_fields(fields)
|
||||
|
||||
def get_percent_base_choice(self):
|
||||
"""
|
||||
Returns one of the three strings in PERCENT_BASE_CHOICES.
|
||||
"""
|
||||
raise NotImplementedError('You have to provide a get_percent_base_choice() method.')
|
||||
|
||||
def print_votesvalid(self):
|
||||
if self.get_percent_base_choice() == 'DISABLED':
|
||||
value = print_value(self.votesvalid, None)
|
||||
else:
|
||||
value = print_value(self.votesvalid, self.get_percent_base())
|
||||
return value
|
||||
|
||||
def print_votesinvalid(self):
|
||||
try:
|
||||
percent_base = self.percent_base()
|
||||
except AttributeError:
|
||||
# The poll class is no child of CollectVotesCast
|
||||
percent_base = 0
|
||||
return print_value(self.votesinvalid, percent_base)
|
||||
if self.get_percent_base_choice() == 'WITH_INVALID':
|
||||
value = print_value(self.votesinvalid, self.get_percent_base())
|
||||
else:
|
||||
value = print_value(self.votesinvalid, None)
|
||||
return value
|
||||
|
||||
def print_votescast(self):
|
||||
if self.get_percent_base_choice() == 'WITH_INVALID':
|
||||
value = print_value(self.votescast, self.get_percent_base())
|
||||
else:
|
||||
value = print_value(self.votescast, None)
|
||||
return value
|
||||
|
||||
def get_percent_base(self):
|
||||
if self.get_percent_base_choice() == "WITHOUT_INVALID" and self.votesvalid > 0:
|
||||
base = 100 / float(self.votesvalid)
|
||||
elif self.get_percent_base_choice() == "WITH_INVALID" and self.votescast > 0:
|
||||
base = 100 / float(self.votescast)
|
||||
else:
|
||||
base = None
|
||||
return base
|
||||
|
||||
|
||||
class PublishPollMixin(models.Model):
|
||||
@ -251,7 +271,8 @@ def print_value(value, percent_base=0):
|
||||
verbose_value = _('undocumented')
|
||||
else:
|
||||
if percent_base:
|
||||
verbose_value = u'%d (%.2f %%)' % (value, value * percent_base)
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
verbose_value = u'%d (%s %%)' % (value, locale.format('%.1f', value * percent_base))
|
||||
else:
|
||||
verbose_value = u'%s' % value
|
||||
return verbose_value
|
||||
|
@ -104,9 +104,10 @@ li {
|
||||
.well h4.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
.well .results hr {
|
||||
.resultline {
|
||||
border-top: 1px solid;
|
||||
margin: 5px 0;
|
||||
border: 1px solid #E3E3E3;
|
||||
width: 10em;
|
||||
}
|
||||
hr {
|
||||
margin: 10px 0;
|
||||
|
@ -86,10 +86,10 @@ class TestMotionDetailView(MotionViewTestCase):
|
||||
response = self.staff_client.post(
|
||||
'/motion/1/poll/1/edit/',
|
||||
{'option-1-Yes': '10',
|
||||
'pollform-votescast': '50'})
|
||||
'pollform-votesvalid': '50'})
|
||||
self.assertRedirects(response, '/motion/1/')
|
||||
response = self.staff_client.get('/motion/1/')
|
||||
self.assertContains(response, '100.00 %')
|
||||
self.assertContains(response, '50 (100')
|
||||
|
||||
def test_deleted_supporter(self):
|
||||
config['motion_min_supporters'] = 1
|
||||
|
Loading…
Reference in New Issue
Block a user