diff --git a/README.md b/README.md index 7fbafb1ae..07914c8a7 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ See [INSTALL.md](INSTALL.md) for setup instructions. This application can be translated in to different languages. -This is done using [Django's standard translation system](https://docs.djangoproject.com/en/3.2/topics/i18n/translation/). +This is done using [Django's standard translation system](https://docs.djangoproject.com/en/4.2/topics/i18n/translation/). ## TranslatedTemplateView diff --git a/locale/cy/LC_MESSAGES/django.po b/locale/cy/LC_MESSAGES/django.po index 0b88ee4f9..c87fd4185 100644 --- a/locale/cy/LC_MESSAGES/django.po +++ b/locale/cy/LC_MESSAGES/django.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-01 17:19+0100\n" +"POT-Creation-Date: 2023-09-19 15:01+0100\n" "PO-Revision-Date: 2022-03-24 09:04+0000\n" "Last-Translator: Sym Roe , 2022\n" "Language-Team: Welsh (https://www.transifex.com/democracy-club/teams/61326/" @@ -29,21 +29,21 @@ msgstr "" msgid "Enter your postcode" msgstr "Rhowch eich cod post" -#: wcivf/apps/elections/models.py:656 +#: wcivf/apps/elections/models.py:672 msgid "First-past-the-post" msgstr "Y Cyntaf i’r Felin" -#: wcivf/apps/elections/models.py:658 +#: wcivf/apps/elections/models.py:674 #, fuzzy #| msgid "The Additional Member System" msgid "Additional Member System" msgstr "Y System Aelodau Ychwanegol" -#: wcivf/apps/elections/models.py:660 +#: wcivf/apps/elections/models.py:676 msgid "Supplementary Vote" msgstr "Pleidlais Atodol" -#: wcivf/apps/elections/models.py:662 +#: wcivf/apps/elections/models.py:678 msgid "Single Transferable Vote" msgstr "Pleidlais Sengl Drosglwyddadwy" @@ -228,7 +228,7 @@ msgstr "Rydych chi yma" #: wcivf/apps/parties/templates/parties/independent_candidate.html:17 #: wcivf/apps/parties/templates/parties/party_detail.html:17 #: wcivf/apps/parties/templates/parties/speaker_seeking_reelection.html:17 -#: wcivf/apps/people/templates/people/person_detail.html:27 +#: wcivf/apps/people/templates/people/person_detail.html:32 #: wcivf/templates/base.html:101 msgid "Home" msgstr "Cartref" @@ -752,7 +752,23 @@ msgstr "" "helpu i wella'r dudalen hon: ychwanegwch wybodaeth " "am ymgeiswyr i'n cronfa ddata." -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:136 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:130 +msgid "Electorate" +msgstr "Nifer etholwyr" + +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:137 +msgid "Ballot Papers Issued" +msgstr "Bapurau pleidleisio" + +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:144 +msgid "Spoilt Ballots" +msgstr "Nifer y bleidleisiau a ddifethwyd" + +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:151 +msgid "Turnout" +msgstr "Cyfrif pleidleisiau" + +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:171 #, python-format msgid "" "The official candidate list has been published." @@ -760,32 +776,32 @@ msgstr "" "Mae'r rhestr swyddogol o ymgeiswyr wedi'i " "chyhoeddi." -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:141 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:176 msgid "The official candidate list should have been published on" msgstr "Dylai'r rhestr swyddogol o ymgeiswyr fod wedi'i chyhoeddi ar " -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:143 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:178 msgid "The official candidate list should be published on" msgstr "Dylai'r rhestr swyddogol o ymgeiswyr gael ei chyhoeddi ar" -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:151 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:186 msgid "Read the official candidate booklet for this election." msgstr "Darllenwch y llyfryn ymgeiswyr swyddogol ar gyfer yr etholiad hwn." -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:155 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:190 #, python-format msgid " %(description)s " msgstr " %(description)s " -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:163 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:198 msgid "Can you vote in this election?" msgstr "A allwch chi bleidleisio yn yr etholiad hwn?" -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:164 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:199 msgid "Age" msgstr "Oedran" -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:166 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:201 #, python-format msgid "" "You need to be over %(voter_age)s on the %(voter_age_date)s of " @@ -794,16 +810,16 @@ msgstr "" "Mae angen i chi fod dros %(voter_age)s ar %(voter_age_date)s " "%(election_date)s i bleidleisio yn yr etholiad hwn." -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:171 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:206 msgid "Citizenship" msgstr "Dinasyddiaeth" -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:191 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:226 #: wcivf/apps/people/templates/people/includes/_person_about_card.html:9 msgid "Wikipedia" msgstr "Wikipedia" -#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:193 +#: wcivf/apps/elections/templates/elections/includes/_single_ballot.html:228 #: wcivf/apps/people/templates/people/includes/_person_about_card.html:11 msgid "Read more on Wikipedia" msgstr "Darllenwch fwy ar Wikipedia" @@ -841,15 +857,37 @@ msgstr "Gweld y canlyniadau" msgid "We don't know of any upcoming elections in your area." msgstr "Ni wyddwn am unrhyw etholiadau sydd i ddod" -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:12 +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:7 +msgid "" +"Local and devolved elections in the UK typically happen on the first " +"Thursday in May. By-elections and parliamentary general elections can happen " +"at any time. Not all areas have elections each year." +msgstr "" + +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:8 +#, fuzzy +#| msgid "" +#| "For more information, visit The Electoral Commission's website or ask an official at your polling station." +msgid "" +"Learn more about elections in the UK on the Electoral " +"Commission website." +msgstr "" +"Am fwy o wybodaeth, ewch i Wefan y Comisiwn Etholiadol neu " +"gofynnwch i swyddog yn eich gorsaf bleidleisio." + +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:14 msgid "Elections in your area" msgstr "Etholiadau yn eich ardal" -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:30 +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:32 msgid "Recently past elections" msgstr "Etholiadau diweddar yn y gorffennol" -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:43 +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:45 #, python-format msgid "" "You will have %(num_ballots)s ballot paper%(ballots_pluralised)s to fill out." @@ -857,16 +895,16 @@ msgstr "" "Bydd gennych %(num_ballots)s papur pleidleisio%(ballots_pluralised)s i'w " "lenwi." -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:59 +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:61 #, python-format msgid "%(ballot.short_cancelled_message_html)s" msgstr "%(ballot.short_cancelled_message_html)s" -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:69 +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:71 msgid "(uncontested)" msgstr "(dim cystadleuaeth)" -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:70 +#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:72 msgid "(may be contested)" msgstr "(efallai y bydd cystadleuaeth)" @@ -880,28 +918,6 @@ msgstr "" "Efallai y bydd etholiadau cyngor plwyf, tref neu gymunedol mewn rhai " "ardaloedd." -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:86 -msgid "" -"Local and devolved elections in the UK typically happen on the first " -"Thursday in May. By-elections and parliamentary general elections can happen " -"at any time. Not all areas have elections each year." -msgstr "" - -#: wcivf/apps/elections/templates/elections/includes/inline_elections_nav_list.html:87 -#, fuzzy -#| msgid "" -#| "For more information, visit The Electoral Commission's website or ask an official at your polling station." -msgid "" -"Learn more about elections in the UK on the Electoral " -"Commission website." -msgstr "" -"Am fwy o wybodaeth, ewch i Wefan y Comisiwn Etholiadol neu " -"gofynnwch i swyddog yn eich gorsaf bleidleisio." - #: wcivf/apps/elections/templates/elections/party_list_view.html:14 msgid "emblem" msgstr "symbol" @@ -949,11 +965,11 @@ msgstr "Trydariadau gan" msgid "Candidates" msgstr "Ymgeiswyr" -#: wcivf/apps/elections/templates/elections/post_view.html:27 +#: wcivf/apps/elections/templates/elections/post_view.html:31 msgid "Next election" msgstr "Yr etholiad nesaf" -#: wcivf/apps/elections/templates/elections/post_view.html:29 +#: wcivf/apps/elections/templates/elections/post_view.html:33 #, python-format msgid "" "The next election for %(postelection)s " @@ -962,11 +978,11 @@ msgstr "" "Cynhelir yr etholiad nesaf ar gyfer " "%(postelection)s" -#: wcivf/apps/elections/templates/elections/post_view.html:31 +#: wcivf/apps/elections/templates/elections/post_view.html:35 msgid "being held today" msgstr "heddiw" -#: wcivf/apps/elections/templates/elections/post_view.html:33 +#: wcivf/apps/elections/templates/elections/post_view.html:37 msgid "due to take place on" msgstr "Mae disgwyl iddo gael ei gynnal ar" @@ -1784,11 +1800,6 @@ msgstr "" msgid "Position" msgstr "" -#: wcivf/apps/people/templates/people/includes/_person_previous_elections_card.html:25 -#, python-format -msgid "%(post_label)s: %(election)s" -msgstr "%(post_label)s: %(election)s" - #: wcivf/apps/people/templates/people/includes/intros/_constituency.html:5 #, python-format msgid "" @@ -1967,11 +1978,11 @@ msgstr "" msgid "profile photo of %(object.name)s" msgstr "Llun proffil %(object.name)s" -#: wcivf/apps/people/templates/people/person_detail.html:24 +#: wcivf/apps/people/templates/people/person_detail.html:29 msgid "You are here:" msgstr "Rydych chi yma:" -#: wcivf/apps/people/templates/people/person_detail.html:58 +#: wcivf/apps/people/templates/people/person_detail.html:65 msgid "Back to candidates in" msgstr "Dychwelyd at ymgeiswyr yn" @@ -2173,6 +2184,26 @@ msgstr "Etholiadau i ddod" msgid "Join our mailing list" msgstr "Ymunwch â'n rhestr bostio" +#, fuzzy +#~| msgid "Elected (vote count not available)" +#~ msgid "Electorate not available" +#~ msgstr "Etholwyr ddim ar gael" + +#, fuzzy +#~| msgid "Elected (vote count not available)" +#~ msgid "Turnout not available" +#~ msgstr "Nid yw'r cyfrif pleidleisiau ar gael" + +#~ msgid "Number of ballot papers issued not available" +#~ msgstr "Nid yw nifer y papurau pleidleisio a roddwyd ar gael" + +#~ msgid "Number of spoilt ballots not available" +#~ msgstr "Nifer y pleidleisiau a ddifethwyd ddim ar gael" + +#, python-format +#~ msgid "%(post_label)s: %(election)s" +#~ msgstr "%(post_label)s: %(election)s" + #~ msgid "Where do I vote?" #~ msgstr "Ble rydw i'n pleidleisio?" diff --git a/wcivf/apps/elections/import_helpers.py b/wcivf/apps/elections/import_helpers.py index f0454a6b8..241702ccc 100644 --- a/wcivf/apps/elections/import_helpers.py +++ b/wcivf/apps/elections/import_helpers.py @@ -103,6 +103,24 @@ def update_or_create_from_ballot_dict(self, ballot_dict): }, ) + if ballot_dict["results"]: + election, created = Election.objects.update_or_create( + slug=slug, + election_type=election_type, + defaults={ + "ballot_papers_issued": ballot_dict["results"][ + "num_turnout_reported" + ], + "electorate": ballot_dict["results"][ + "total_electorate" + ], + "turnout": ballot_dict["results"]["turnout_percentage"], + "spoilt_ballots": ballot_dict["results"][ + "num_spoilt_ballots" + ], + }, + ) + self.import_metadata_from_ee(election) self.election_cache[election.slug] = election return self.election_cache[slug] diff --git a/wcivf/apps/elections/migrations/0041_election_ballot_papers_issued_election_electorate_and_more.py b/wcivf/apps/elections/migrations/0041_election_ballot_papers_issued_election_electorate_and_more.py new file mode 100644 index 000000000..318eb5cc6 --- /dev/null +++ b/wcivf/apps/elections/migrations/0041_election_ballot_papers_issued_election_electorate_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.3 on 2023-09-06 11:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("elections", "0040_postelection_requires_voter_id"), + ] + + operations = [ + migrations.AddField( + model_name="election", + name="ballot_papers_issued", + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name="election", + name="electorate", + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name="election", + name="spoilt_ballots", + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name="election", + name="turnout", + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/wcivf/apps/elections/models.py b/wcivf/apps/elections/models.py index 53640be42..d86373df6 100644 --- a/wcivf/apps/elections/models.py +++ b/wcivf/apps/elections/models.py @@ -48,6 +48,10 @@ class Election(models.Model): election_weight = models.IntegerField(default=10) metadata = JSONField(null=True) any_non_by_elections = models.BooleanField(default=False) + ballot_papers_issued = models.IntegerField(blank=True, null=True) + electorate = models.IntegerField(blank=True, null=True) + turnout = models.IntegerField(blank=True, null=True) + spoilt_ballots = models.IntegerField(blank=True, null=True) objects = ElectionManager() @@ -239,6 +243,19 @@ def pluralized_division_name(self): return pluralise.get(suffix, f"{suffix}s") + @property + def has_results(self): + """ + Returns a boolean for if the election has results + """ + return bool( + self.spoilt_ballots + or self.ballot_papers_issued + or self.turnout + or self.electorate + or self.postelection_set.filter(personpost__elected=True).exists() + ) + class Post(models.Model): """ diff --git a/wcivf/apps/elections/templates/elections/includes/_people_list.html b/wcivf/apps/elections/templates/elections/includes/_people_list.html index dcf4534f9..3a1d69ca9 100644 --- a/wcivf/apps/elections/templates/elections/includes/_people_list.html +++ b/wcivf/apps/elections/templates/elections/includes/_people_list.html @@ -1,4 +1,4 @@ -
    +
      {% for person_post in people %} {% include "elections/includes/_person_card.html" with person_post=person_post %} {% endfor %} diff --git a/wcivf/apps/elections/templates/elections/includes/_single_ballot.html b/wcivf/apps/elections/templates/elections/includes/_single_ballot.html index 1e2926656..d4ed6790a 100644 --- a/wcivf/apps/elections/templates/elections/includes/_single_ballot.html +++ b/wcivf/apps/elections/templates/elections/includes/_single_ballot.html @@ -129,7 +129,42 @@

      {% if postelection.is_london_assembly_additional %}{% trans "Additional memb {% endif %}

      {% endif %} + {% if postelection.election.in_past and postelection.election.has_results %} +
      +
      + + {% if postelection.election.electorate %} + + + + + {% endif %} + + {% if postelection.election.ballot_papers_issued %} + + + + + {% endif %} + + {% if postelection.election.spoilt_ballots %} + + + + + {% endif %} + {% if postelection.election.turnout %} + + + + + {% endif %} + +
      {% trans "Electorate" %}{{ postelection.election.electorate }}
      {% trans "Ballot Papers Issued" %}{{ postelection.election.ballot_papers_issued}}
      {% trans "Spoilt Ballots" %}{{ postelection.election.spoilt_ballots }}
      {% trans "Turnout" %}{{ postelection.election.turnout|stringformat:"d%%" }}
      +
      +
      + {% endif %} {% if postelection.people and postelection.should_show_candidates %} {% if postelection.display_as_party_list %} {% include "elections/includes/_people_list_with_lists.html" with people=postelection.people %} diff --git a/wcivf/apps/elections/tests/test_election_views.py b/wcivf/apps/elections/tests/test_election_views.py index aceec0d5f..34cf76336 100644 --- a/wcivf/apps/elections/tests/test_election_views.py +++ b/wcivf/apps/elections/tests/test_election_views.py @@ -176,6 +176,25 @@ def test_pre_sopn_text_with_candidates(self): """Once nomination papers are published, we will manually verify each candidate.""", ) + def test_results_table(self): + """check that the table containing the electorate, + turnout, spoilt ballots, ballot papers exist + for past elections""" + self.election.electorate = 100 + self.election.spoilt_ballots = 5 + self.election.save() + + response = self.client.get( + self.post_election.get_absolute_url(), follow=True + ) + self.assertEqual(response.status_code, 200) + + self.assertTrue(self.post_election.election.has_results) + self.assertContains(response, "Electorate") + self.assertNotContains(response, "Turnout") + self.assertContains(response, "Spoilt Ballots") + self.assertNotContains(response, "Ballot Papers Issued") + def test_zero_candidates(self): response = self.client.get( self.post_election.get_absolute_url(), follow=True diff --git a/wcivf/apps/elections/tests/test_models.py b/wcivf/apps/elections/tests/test_models.py index f3a14a036..9395a25d3 100644 --- a/wcivf/apps/elections/tests/test_models.py +++ b/wcivf/apps/elections/tests/test_models.py @@ -31,6 +31,26 @@ def test_in_past(self): assert election.in_past is True + def test_electorate(self): + election = Election(electorate=1000) + assert election.electorate == 1000 + assert type(election.electorate) == int + + def test_turnout(self): + election = Election(turnout=1000) + assert election.turnout == 1000 + assert type(election.turnout) == int + + def test_spoilt_ballots(self): + election = Election(spoilt_ballots=1000) + assert election.spoilt_ballots == 1000 + assert type(election.spoilt_ballots) == int + + def test_ballot_papers_issued(self): + election = Election(ballot_papers_issued=1000) + assert election.ballot_papers_issued == 1000 + assert type(election.ballot_papers_issued) == int + def test_is_city_of_london(self, election, city_of_london_election): assert election.is_city_of_london is False assert city_of_london_election.is_city_of_london is True diff --git a/wcivf/assets/scss/style.scss b/wcivf/assets/scss/style.scss index e10a5ecdc..fe67ef107 100644 --- a/wcivf/assets/scss/style.scss +++ b/wcivf/assets/scss/style.scss @@ -156,3 +156,10 @@ input[type=radio] { .ds-status-message p { color: $white; } + +#results-table { + td:nth-child(2) { + text-align: right; + } + th, td { border: 1px solid black; } +}