Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
struan committed Feb 18, 2025
1 parent f2361bb commit 5c51cbd
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 44 deletions.
27 changes: 26 additions & 1 deletion scoring/management/commands/import_actions_scores.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,21 @@ class Command(BaseCommand):
"IND": "Independent",
}

previous_year = None

def add_arguments(self, parser):
parser.add_argument(
"--update_questions",
action="store_true",
help="Updates/creates the text of questions",
)

parser.add_argument(
"--previous_year",
action="store",
help="year of previous actions scorecards, for linking",
)

def create_sections(self):
for code, desc in self.SECTIONS.items():
section, created = PlanSection.objects.get_or_create(
Expand Down Expand Up @@ -115,6 +123,16 @@ def import_section_scores(self):
council=council, year=self.YEAR
)

if self.previous_year:
try:
prev = PlanScore.objects.get(
council=council, year=self.previous_year
)
plan_score.previous_year = prev
plan_score.save()
except PlanScore.DoesNotExist:
pass

score = 0
if not pd.isnull(row["score"]):
score = integer_from_text(row["score"])
Expand Down Expand Up @@ -307,7 +325,14 @@ def import_question_scores(self):
to_create.append(score_obj)
PlanQuestionScore.objects.bulk_create(to_create)

def handle(self, update_questions: bool = False, *args, **options):
def handle(
self,
update_questions: bool = False,
previous_year: int = None,
*args,
**options,
):
self.previous_year = previous_year
if not update_questions:
self.stdout.write(
f"{YELLOW}Not creating or updating questions, call with --update_questions to do so{NOBOLD}"
Expand Down
24 changes: 24 additions & 0 deletions scoring/migrations/0018_planscore_previous_year.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.17 on 2025-02-18 14:00

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("scoring", "0017_alter_planquestionscore_score"),
]

operations = [
migrations.AddField(
model_name="planscore",
name="previous_year",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="scoring.planscore",
),
),
]
26 changes: 21 additions & 5 deletions scoring/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ class PlanScore(models.Model):
max_length=100, choices=RUC_TYPES, null=True, blank=True
)
political_control = models.CharField(max_length=100, null=True, blank=True)
previous_year = models.ForeignKey(
"PlanScore", null=True, blank=True, on_delete=models.SET_NULL
)

def questions_answered(self):
# do this in raw SQL as otherwise we need an extra query
Expand Down Expand Up @@ -345,7 +348,7 @@ def make_section_object(cls, section, previous_year=None):
obj["change"] = 0
if section.previous_score:
obj["change"] = (
(section.previous_score - section.weighted_score)
(section.weighted_score - section.previous_score)
/ section.previous_score
) * 100

Expand All @@ -362,9 +365,8 @@ def sections_for_council(cls, council=None, plan_year=None, previous_year=None):
.annotate(
previous_score=Subquery(
cls.objects.filter(
plan_score__council=OuterRef("plan_score__council"),
plan_score=OuterRef("plan_score__previous_year"),
plan_section__code=OuterRef("plan_section__code"),
plan_score__year=previous_year,
).values("weighted_score")
)
)
Expand All @@ -379,7 +381,9 @@ def sections_for_council(cls, council=None, plan_year=None, previous_year=None):
return sections

@classmethod
def sections_for_plans(cls, plans=None, plan_year=None, plan_sections=None):
def sections_for_plans(
cls, plans=None, plan_year=None, plan_sections=None, previous_year=None
):
sections = {}
section_qs = (
cls.objects.select_related("plan_section", "plan_score__council")
Expand All @@ -390,9 +394,21 @@ def sections_for_plans(cls, plans=None, plan_year=None, plan_sections=None):
if plan_sections is not None:
section_qs = section_qs.filter(plan_section__in=plan_sections)

if previous_year is not None:
section_qs = section_qs.annotate(
previous_score=Subquery(
cls.objects.filter(
plan_score=OuterRef("plan_score__previous_year"),
plan_section__code=OuterRef("plan_section__code"),
).values("weighted_score")
)
)

sections = defaultdict(list)
for section in section_qs.all():
sections[section.plan_section.code].append(cls.make_section_object(section))
sections[section.plan_section.code].append(
cls.make_section_object(section, previous_year)
)

return sections

Expand Down
39 changes: 15 additions & 24 deletions scoring/templates/scoring/council.html
Original file line number Diff line number Diff line change
Expand Up @@ -372,16 +372,9 @@ <h3 class="exclamation text-white">Visit us again on a bigger screen</h3>
<td class="display-only-large-up score border-bottom border-opacity-25 border-primary is--section-score {% if comparison.top_performer %}top-performer{% endif %}">
{{ comparison.weighted_score|floatformat:0 }}%
</td>
{% comment %} TODO: Include previous scorecards score(2023) {% endcomment %}
<td class="js-previous-year-score display-only-large-up border-bottom border-opacity-25 border-primary">{{ section.weighted_score|floatformat:0 }}%</td>
<td class="js-previous-year-score display-only-large-up border-bottom border-opacity-25 border-primary">{{ comparison.previous_score|floatformat:0 }}%</td>
<td class="display-only-large-up border-end border-bottom border-opacity-25 border-primary text-center">
{% comment %} TODO: IF Negative difference: Change bg-green-100 to bg-red-100 {% endcomment %}
{% comment %} TODO: IF Negative difference: Change text-success to text-danger {% endcomment %}
{% comment %} TODO: IF Negative difference: Change &#9652; to &#9662; {% endcomment %}
{% comment %} TODO: IF No difference: Change bg-green-100 to bg-gray-300 {% endcomment %}
{% comment %} TODO: IF No difference: Change text-success to text-dark {% endcomment %}
{% comment %} TODO: IF No difference: display '--' {% endcomment %}
<span class="badge align-text-bottom bg-green-100 text-success">&#9652; 5%</span>
{% include "scoring/includes/percentage_score_change.html" with change=comparison.change %}
</td>
{% endfor %}

Expand All @@ -404,10 +397,12 @@ <h3 class="exclamation text-white">Visit us again on a bigger screen</h3>
{{ answer.score|format_mark }}/{{ answer.max }}
</td>

{% comment %} TODO: Include previous scorecards score(2023) {% endcomment %}
{% comment %} TODO: IF NA(Question didn't exist previous version): display "NA" {% endcomment %}
<td class="js-previous-year-score display-only-large-up border-bottom">
{{ answer.score|format_mark }}/{{ answer.max }}
{% if answer.previous_score is not None %}
{{ answer.previous_score|format_mark }}/{{ answer.previous_max }}
{% else %}
NA
{% endif %}
</td>

<td class="border-end border-bottom border-opacity-25 text-center display-only-large-up">
Expand All @@ -419,14 +414,16 @@ <h3 class="exclamation text-white">Visit us again on a bigger screen</h3>
{{ comparison.score|format_mark }}/{{ comparison.max }}
</td>

{% comment %} TODO: Include previous scorecards score(2023) {% endcomment %}
{% comment %} TODO: IF NA(Question didn't exist previous version): display "NA" {% endcomment %}
<td class="js-previous-year-score display-only-large-up border-bottom">
{{ comparison.score|format_mark }}/{{ comparison.max }}
{% if comparison.previous_score %}
{{ comparison.previous_score|format_mark }}/{{ comparison.previous_max }}
{% else %}
NA
{% endif %}
</td>

<td class="border-end border-bottom border-opacity-25 text-center display-only-large-up">
{% include "scoring/includes/percentage_score_change.html" with change=comparison.change %}
{% include "scoring/includes/integer_score_change.html" with change=comparison.change %}
</td>
{% endfor %}

Expand Down Expand Up @@ -479,17 +476,11 @@ <h3 class="exclamation text-white">Visit us again on a bigger screen</h3>

{% comment %} TODO: Include previous scorecards score(2023) {% endcomment %}
<td class="js-previous-year-score display-only-large-up score border-bottom border-opacity-25 border-primary is--section-score">
{{ comparison.weighted_total|floatformat:0 }}%
{{ comparison.previous_total|floatformat:0 }}%
</td>

<td class="display-only-large-up text-center border-bottom border-opacity-25 border-primary">
{% comment %} TODO: IF Negative difference: Change bg-green-100 to bg-red-100 {% endcomment %}
{% comment %} TODO: IF Negative difference: Change text-success to text-danger {% endcomment %}
{% comment %} TODO: IF Negative difference: Change &#9652; to &#9662; {% endcomment %}
{% comment %} TODO: IF No difference: Change bg-green-100 to bg-gray-300 {% endcomment %}
{% comment %} TODO: IF No difference: Change text-success to text-dark {% endcomment %}
{% comment %} TODO: IF No difference: display '--' {% endcomment %}
<span class="badge align-text-bottom bg-green-100 text-success">&#9652; 5%</span>
{% include "scoring/includes/percentage_score_change.html" with change=comparison.change %}
</td>
{% endfor %}

Expand Down
6 changes: 1 addition & 5 deletions scoring/templates/scoring/includes/scoring_url.html
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
{% if current_plan_year %}
{% if slug == 'single'%}{% url 'scoring:home' %}{% else %}{% url 'scoring:scoring' slug %}{% endif %}
{% else %}
{% if slug == 'single'%}{% url 'year_scoring:home' plan_year %}{% else %}{% url 'year_scoring:scoring' plan_year slug %}{% endif %}
{% endif %}
{% if current_plan_year %}{% if slug == 'single'%}{% url 'scoring:home' %}{% else %}{% url 'scoring:scoring' slug %}{% endif %}{% else %}{% if slug == 'single'%}{% url 'year_scoring:home' plan_year %}{% else %}{% url 'year_scoring:scoring' plan_year slug %}{% endif %}{% endif %}
73 changes: 64 additions & 9 deletions scoring/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def get_context_data(self, **kwargs):
sections = PlanSectionScore.sections_for_council(
council=council,
plan_year=self.request.year,
previous_year=2025,
previous_year=plan_score.previous_year,
)

try:
Expand All @@ -327,15 +327,13 @@ def get_context_data(self, **kwargs):
except PlanScore.DoesNotExist:
context["original_plan_score"] = False

try:
previous_total = PlanScore.objects.get(
council=council, year=2023
).weighted_total
context["previous_total"] = previous_total
if plan_score.previous_year is not None:
prev = plan_score.previous_year
context["previous_total"] = prev.weighted_total
context["previous_diff"] = (
(previous_total - plan_score.weighted_total) / previous_total
(plan_score.weighted_total - prev.weighted_total) / prev.weighted_total
) * 100
except PlanScore.DoesNotExist:
else:
context["previous_total"] = False

for section in sections.keys():
Expand Down Expand Up @@ -370,10 +368,28 @@ def get_context_data(self, **kwargs):
comparisons = (
PlanScore.objects.select_related("council")
.filter(council__slug__in=comparison_slugs, year=self.request.year)
.annotate(
previous_total=Subquery(
PlanScore.objects.filter(
id=OuterRef("previous_year__id"),
).values("weighted_total")
)
)
.annotate(
change=(
(
(F("weighted_total") - F("previous_total"))
/ F("previous_total")
)
* 100
)
)
.order_by("council__name")
)
comparison_sections = PlanSectionScore.sections_for_plans(
plans=comparisons, plan_year=self.request.year
plans=comparisons,
plan_year=self.request.year,
previous_year=True,
)
for section, details in comparison_sections.items():
sections[section]["comparisons"] = details
Expand All @@ -385,11 +401,50 @@ def get_context_data(self, **kwargs):
):
q = self.make_question_obj(question)
comparison_answers[question.code][question.council_name] = q
prev_plans = PlanScore.objects.filter(id__in=comparison_ids).values(
"previous_year_id", "previous_year__year"
)
ids = []
year = None
for plan in prev_plans:
ids.append(plan["previous_year_id"])
year = plan["previous_year__year"]

for question in PlanScore.questions_answered_for_councils(
plan_ids=ids, plan_year=year
):
if comparison_answers[question.code].get(question.council_name):
comparison_answers[question.code][question.council_name][
"previous_score"
] = question.score
comparison_answers[question.code][question.council_name][
"previous_max"
] = question.max_score
comparison_answers[question.code][question.council_name][
"change"
] = (
comparison_answers[question.code][question.council_name][
"score"
]
- question.score
)

previous_questions = defaultdict(dict)
if plan_score.previous_year is not None:
prev_answers = plan_score.previous_year.questions_answered()
for pa in prev_answers:
previous_questions[pa.section_code][pa.code] = pa

for question in plan_score.questions_answered():
section = question.section_code

q = self.make_question_obj(question)
if previous_questions[section].get(q["code"]):
pq = previous_questions[section][q["code"]]
q["previous_score"] = pq.score
q["previous_max"] = pq.max_score
q["change"] = q["score"] - q["previous_score"]

q["council_count"] = question_max_counts.get(question.code, 0)
q["comparisons"] = []
# not all councils have answers for all questions so make sure we
Expand Down

0 comments on commit 5c51cbd

Please sign in to comment.