diff options
| author | Amar <100243770+aadeina@users.noreply.github.com> | 2026-04-08 07:46:11 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-08 09:46:11 +0200 |
| commit | 2e150c393f13e5ec97b46d1ae8bc405f16b53ea2 (patch) | |
| tree | 252611cb102b3ac24f92a3c18b1d5246b0caaa1e | |
| parent | 6cb0209a41c25ffacdc25a6dd8920cf276b30ec2 (diff) | |
Fixed donation percentage rounding and added on-track messaging. (#2458)
| -rw-r--r-- | djangoproject/templates/fundraising/includes/donation_form_with_heart.html | 9 | ||||
| -rw-r--r-- | fundraising/templatetags/fundraising_extras.py | 19 | ||||
| -rw-r--r-- | fundraising/tests/test_templatetags.py | 37 |
3 files changed, 59 insertions, 6 deletions
diff --git a/djangoproject/templates/fundraising/includes/donation_form_with_heart.html b/djangoproject/templates/fundraising/includes/donation_form_with_heart.html index f59a1784..af62151a 100644 --- a/djangoproject/templates/fundraising/includes/donation_form_with_heart.html +++ b/djangoproject/templates/fundraising/includes/donation_form_with_heart.html @@ -10,7 +10,7 @@ <g transform="translate(4, 2)" id="pixels"> <path d="M 71 0 L 213 0 L 213 71 L 284 71 L 284 0 L 426 0 L 426 71 L 497 71 L 497 213 L 426 213 L 426 284 L 355 284 L 355 355 L 284 355 L 284 426 L 213 426 L 213 355 L 142 355 L 142 284 L 71 284 L 71 213 L 0 213 L 0 71 L 71 71 L 71 0" fill="#f8f8f8" stroke="#c0c0c0" stroke-width="1" /> </g> - <text x="50%" y="43%" alignment-baseline="middle" text-anchor="middle">{{ goal_percent|floatformat:'0' }}%</text> + <text x="50%" y="43%" alignment-baseline="middle" text-anchor="middle">{{ goal_percent }}%</text> </g> <foreignObject> <img src="{% static 'img/fundraising-heart.svg' %}" /> @@ -24,7 +24,12 @@ <li><strong>{% blocktranslate trimmed %}{{ goal_percent }}% funded{% endblocktranslate %}</strong></li> <li> {% blocktranslate trimmed with amount=donated_amount|intcomma goal=goal_amount|intcomma start_date=goal_start_date|date:"Y" %} - <strong>${{ amount }} donated</strong> of US ${{ goal }} goal for {{ start_date }} + <strong>${{ amount }} donated</strong> of a ${{ goal }} USD goal for {{ start_date }} + {% endblocktranslate %} + </li> + <li> + {% blocktranslate trimmed with expected=expected_amount|intcomma %} + To reach our goal, we should have raised ${{ expected }} by this point {% endblocktranslate %} </li> <li> diff --git a/fundraising/templatetags/fundraising_extras.py b/fundraising/templatetags/fundraising_extras.py index bed1708a..1c7b1ff0 100644 --- a/fundraising/templatetags/fundraising_extras.py +++ b/fundraising/templatetags/fundraising_extras.py @@ -1,9 +1,11 @@ +import datetime +import math +from calendar import isleap from decimal import Decimal from django import template from django.conf import settings from django.db import models -from django.template.defaultfilters import floatformat from fundraising.forms import DonateForm from fundraising.models import ( @@ -24,12 +26,12 @@ register = template.Library() @register.filter def as_percentage(part, total): if total is None or part is None: - return "0.00" + return "0" try: - return floatformat((part / total) * Decimal("100.0")) + return str(math.floor((part / total) * 100)) except ZeroDivisionError: - return "0.00" + return "0" @register.inclusion_tag("fundraising/includes/donation_snippet.html") @@ -79,6 +81,14 @@ def donation_form_with_heart(context): } ) + # Calculate expected amount based on day of year. + today = datetime.date.today() + day_of_year = today.timetuple().tm_yday + days_in_year = 366 if isleap(today.year) else 365 + expected_amount = ( + GOAL_AMOUNT * Decimal(day_of_year) / Decimal(days_in_year) + ).quantize(Decimal("1")) + return { "goal_amount": GOAL_AMOUNT, "goal_start_date": GOAL_START_DATE, @@ -88,6 +98,7 @@ def donation_form_with_heart(context): "display_logo_amount": LEADERSHIP_LEVEL_AMOUNT, "stripe_publishable_key": settings.STRIPE_PUBLISHABLE_KEY, "user": user, + "expected_amount": expected_amount, } diff --git a/fundraising/tests/test_templatetags.py b/fundraising/tests/test_templatetags.py index 10f3958b..6bd6711c 100644 --- a/fundraising/tests/test_templatetags.py +++ b/fundraising/tests/test_templatetags.py @@ -1,6 +1,8 @@ from datetime import date, datetime, timedelta from decimal import Decimal +from unittest.mock import patch +import time_machine from django.test import TestCase from django.utils.crypto import get_random_string @@ -15,12 +17,32 @@ from ..models import ( Payment, ) from ..templatetags.fundraising_extras import ( + as_percentage, display_django_heroes, donation_form_with_heart, top_corporate_members, ) +class TestAsPercentage(TestCase): + def test_floor_rounding(self): + with self.subTest(case="2.8% should show as 2%, not 3%"): + self.assertEqual(as_percentage(Decimal("8400"), Decimal("300000")), "2") + with self.subTest(case="99.9% should show as 99%, not 100%"): + self.assertEqual(as_percentage(Decimal("299700"), Decimal("300000")), "99") + with self.subTest(case="Exact percentage should remain the same"): + self.assertEqual(as_percentage(Decimal("150000"), Decimal("300000")), "50") + + def test_zero_and_none_values(self): + self.assertEqual(as_percentage(None, Decimal("300000")), "0") + self.assertEqual(as_percentage(Decimal("0"), Decimal("300000")), "0") + self.assertEqual(as_percentage(Decimal("100"), None), "0") + self.assertEqual(as_percentage(Decimal("100"), Decimal("0")), "0") + + def test_over_100_percent(self): + self.assertEqual(as_percentage(Decimal("350000"), Decimal("300000")), "116") + + class TestDonationFormWithHeart(TestCase): def test_donors_count(self): # Donor with a Payment after GOAL_START_DATE @@ -42,6 +64,21 @@ class TestDonationFormWithHeart(TestCase): self.assertEqual(response["total_donors"], 1) self.assertEqual(response["donated_amount"], Decimal("8.00")) + @patch("fundraising.templatetags.fundraising_extras.GOAL_AMOUNT", 500000) + def test_expected_amount_calculation(self): + test_cases = [ + # (date, expected_amount) + ("2026-01-01", Decimal("1370")), # Day 1: 500000 * 1/365 + ("2026-07-02", Decimal("250685")), # Day 183: 500000 * 183/365 + ("2026-12-31", Decimal("500000")), # Day 365: 500000 * 365/365 + ("2024-01-01", Decimal("1366")), # Day 1 leap year: 500000 * 1/366 + ] + for date_str, expected in test_cases: + with self.subTest(date=date_str): + with time_machine.travel(date_str): + response = donation_form_with_heart({"user": None}) + self.assertEqual(response["expected_amount"], expected) + class TestDisplayDjangoHeroes(TestCase): def test_display_django_heroes(self): |
