summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmar <100243770+aadeina@users.noreply.github.com>2026-04-08 07:46:11 +0000
committerGitHub <noreply@github.com>2026-04-08 09:46:11 +0200
commit2e150c393f13e5ec97b46d1ae8bc405f16b53ea2 (patch)
tree252611cb102b3ac24f92a3c18b1d5246b0caaa1e
parent6cb0209a41c25ffacdc25a6dd8920cf276b30ec2 (diff)
Fixed donation percentage rounding and added on-track messaging. (#2458)
-rw-r--r--djangoproject/templates/fundraising/includes/donation_form_with_heart.html9
-rw-r--r--fundraising/templatetags/fundraising_extras.py19
-rw-r--r--fundraising/tests/test_templatetags.py37
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&nbsp;${{ 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):