Changeset - 79361cdf97dd
[Not reviewed]
0 3 0
Ben Sturmfels (bsturmfels) - 1 month ago 2024-03-21 02:20:30
ben@sturm.com.au
Move fundraiser calculations to model

This changes simplifies the template and adds correct pluralisation of
hours/hour remaining.
3 files changed with 58 insertions and 73 deletions:
0 comments (0 inline, 0 general)
conservancy/fundgoal/models.py
Show inline comments
 
import datetime
 
import math
 
import random
 

	
 
from django.db import models
...
 
@@ -10,6 +12,9 @@ class FundraisingGoal(models.Model):
 
    fundraiser_goal_amount = models.DecimalField(max_digits=10, decimal_places=2)
 
    fundraiser_so_far_amount = models.DecimalField(max_digits=10, decimal_places=2)
 
    fundraiser_donation_count = models.IntegerField()
 
    # The number of new Sustainers that can be double-matched this fundraiser.
 
    # (No, this name makes no sense. We're repurposing an existing model field
 
    # for this new reason.)
 
    fundraiser_donation_count_disclose_threshold = models.IntegerField()
 
    fundraiser_endtime = models.DateTimeField(null=True)
 

	
...
 
@@ -34,6 +39,20 @@ class FundraisingGoal(models.Model):
 
        else:
 
            return random.sample(providers, k)
 

	
 
    def days_remaining(self):
 
        now = datetime.datetime.now()
 
        return (self.fundraiser_endtime - now).days
 

	
 
    def hours_remaining(self):
 
        now = datetime.datetime.now()
 
        return int(math.ceil((self.fundraiser_endtime - now).seconds / 3600))
 

	
 
    def match_remaining(self):
 
        return self.fundraiser_goal_amount - self.fundraiser_so_far_amount
 

	
 
    def match_exceeded_by(self):
 
        return self.fundraiser_so_far_amount - self.fundraiser_goal_amount
 

	
 

	
 
class GoalProvider(models.Model):
 
    fundraising_goal = models.ForeignKey(
conservancy/fundgoal/templates/fundgoal/fundraiser_goal_banner_partial.html
Show inline comments
 
{% load humanize %}
 
{% load subtract %}
 

	
 
{% comment %}
 
# FUNDRAISER VARIABLES AND CONSTANTS GUIDE
 

	
 
## From Local Context
 

	
 
* datetime_now: Current DateTime in UTC
 
* sitefundgoal: The current FundraisingGoal. Attributes:
 
  * fundraiser_goal_amount: The amount being matched
 
  * fundraiser_so_far_amount: The amount contributed so far
 
  * fundraiser_donation_count: The number of people who have contributed so far
 
  * fundraiser_donation_count_disclose_threshold: The number of new Sustainers that can be double-matched this fundraiser.
 
      (No, this name makes no sense. We're repurposing an existing model field for this new reason.)
 
* sitefundgoal_endtime: DateTime when sitefundgoal ends.
 

	
 
## Local convenience variables
 

	
 
* sitefundgoal_timeleft: TimeDelta for how much time remains in the current fundraiser
 
* this_match_goal: The amount being matched
 
* this_match_so_far: The amount contributed so far
 
* this_match_remaining: this_match_goal - this_match_so_far
 
* this_match_exceeded: this_match_so_far - this_match_goal
 

	
 
{% endcomment %}
 
{% with this_match_goal=sitefundgoal.fundraiser_goal_amount this_match_so_far=sitefundgoal.fundraiser_so_far_amount %}
 
{% with this_match_remaining=this_match_goal|subtract:this_match_so_far sitefundgoal_timeleft=sitefundgoal.fundraiser_endtime|subtract:datetime_now this_match_exceeded=this_match_so_far|subtract:this_match_goal %}
 
 {% if sitefundgoal_timeleft.total_seconds >= -604800 %}
 
    <div class="fundraiser-top-text ph3 pt2 pb3 mb2 mb3-ns">
 
      <div class="mw8 center ph2 ph4-ns">
 
{% if sitefundgoal.days_remaining >= -7 %}{# i.e. 7 days over completion #}
 
  <div class="fundraiser-top-text ph3 pt2 pb3 mb2 mb3-ns">
 
    <div class="mw8 center ph2 ph4-ns">
 
      <div class="mt2 mb3 tc">
 
      {% if datetime_now < sitefundgoal.fundraiser_endtime %}
 
        {% if this_match_remaining <= 0 %}
 
          Thanks to so many donors, we earned our full match!
 
          Help us go further to stand up for software freedom &mdash; <a href="/sustainer">sign up now</a>!
 
        {% else %}
 
          {% if sitefundgoal_timeleft.days == 0 %}
 
            For the next {% widthratio sitefundgoal_timeleft.total_seconds 3600 1 %} hours <strong>only</strong>, the
 
          {% elif sitefundgoal_timeleft.days == 1 %}
 
            Through tomorrow only, the
 
          {% elif sitefundgoal_timeleft.days < 14 %}
 
            For only {{ sitefundgoal_timeleft.days }} more days, the
 
        {% if sitefundgoal.days_remaining >= 0 %}
 
          {% if fundgoal.match_remaining <= 0 %}
 
            Thanks to so many donors, we earned our full match!
 
            Help us go further to stand up for software freedom &mdash; <a href="/sustainer">sign up now</a>!
 
          {% else %}
 
            Until January 15, the
 
            {% if sitefundgoal.days_remaining == 0 %}
 
              For the next {{ sitefundgoal.hours_remaining }} hour{{ sitefundgoal.hours_remaining|pluralize }} <strong>only</strong>, the
 
            {% elif sitefundgoal.days_remaining == 1 %}
 
              Through tomorrow only, the
 
            {% elif sitefundgoal.days_remaining < 14 %}
 
              For only {{ sitefundgoal.days_remaining }} more days, the
 
            {% else %}
 
              Until January 15, the
 
            {% endif %}
 
            next ${{ sitefundgoal.match_remaining|floatformat:0|intcomma }} of <a href="/sustainer/">support we receive</a> will be matched!
 
          {% endif %}
 
        next ${{ this_match_remaining|floatformat:0|intcomma }} of <a href="/sustainer/">support we receive</a> will be matched!
 

	
 
        {% else %}
 
          Thank you so much to all our donors who participated in our donation match challenge!  Here are the results:
 
        {% endif %}
 
       {% else %}
 
	  Thank you so much to all our donors who participated in our donation match challenge!  Here are the results:
 
       {% endif %}
 
      </div>
 

	
 
{% if 1 %}
 
<a href="/sustainer/" style="text-decoration: none !important">
 
<div id="siteprogressbar" class="flex items-stretch w-100">
 
  {% if this_match_remaining <= 0 %}
 
    <div class="progress matched pv1 b flex items-center" style="flex-basis: {{ this_match_so_far }}px">
 
      <span id="site-fundraiser-match-count" class="soFarText tc w-100">${{ this_match_goal|floatformat:0|intcomma }} fully matched!</span>
 
    </div>
 
    <div class="progress exceeded pv1 b flex items-center" style="flex-basis: {{ this_match_exceeded }}px">
 
      <span id="site-fundraiser-match-count" class="soFarText tc w-100 exceeded">${{this_match_exceeded|floatformat:0|intcomma }} additional<br> raised!<br></span>
 
    </div>
 
  {% else %}
 
    <div class="progress pv1 b flex items-center" style="flex-basis: {{ this_match_so_far }}px">
 
      <span id="site-fundraiser-match-count" class="soFarText tc w-100">${{ this_match_so_far|floatformat:0|intcomma }} matched!</span>
 
    </div>
 
    <div class="final-goal pv1 b flex items-center" style="flex-basis: {{ this_match_remaining }}px">
 
      <span id="site-fundraiser-final-goal" class="goalText tc w-100">${{ this_match_remaining|floatformat:0|intcomma }} to go!</span>
 
      <a href="/sustainer/" style="text-decoration: none !important">
 
        <div id="siteprogressbar" class="flex items-stretch w-100">
 
          {% if sitefundgoal.match_remaining <= 0 %}
 
            <div class="progress matched ph1 pv1 b flex items-center" style="flex-basis: {{ sitefundgoal.fundraiser_so_far_amount }}px">
 
              <span id="site-fundraiser-match-count" class="soFarText tc w-100 ph1">${{ sitefundgoal.fundraiser_goal_amount|floatformat:0|intcomma }} fully matched!</span>
 
            </div>
 
            <div class="progress exceeded pv1 b flex items-center" style="flex-basis: {{ sitefundgoal.match_exceeded_by }}px">
 
              <span id="site-fundraiser-match-count" class="soFarText tc w-100 exceeded ph1">${{sitefundgoal.match_exceeded_by|floatformat:0|intcomma }} additional<br> raised!<br></span>
 
            </div>
 
          {% else %}
 
            <div class="progress ph1 pv1 b flex items-center" style="flex-basis: {{ sitefundgoal.fundraiser_so_far_amount }}px">
 
              <span id="site-fundraiser-match-count" class="soFarText tc w-100">${{ sitefundgoal.fundraiser_so_far_amount|floatformat:0|intcomma }} matched!</span>
 
            </div>
 
            <div class="final-goal pv1 b flex items-center" style="flex-basis: {{ sitefundgoal.match_remaining }}px">
 
              <span id="site-fundraiser-final-goal" class="goalText tc w-100 ph1">${{ sitefundgoal.match_remaining|floatformat:0|intcomma }} to go!</span>
 
            </div>
 
          {% endif %}
 
        </div>
 
      </a>
 
    </div>
 
    {% endif %}
 
</div>
 
</a>
 
{% endif %}
 

	
 
</div>
 
</div>
 
  </div>
 
{% endif %}
 
{% endwith %}
 
{% endwith %}
conservancy/local_context_processors.py
Show inline comments
 
from datetime import datetime as DateTime
 

	
 
from .fundgoal.models import FundraisingGoal
 

	
 
SITE_FUNDGOAL = 'cy2023-end-year-match'
...
 
@@ -13,7 +11,6 @@ def fundgoal_lookup(fundraiser_sought):
 

	
 
def sitefundraiser(request):
 
    return {
 
        'datetime_now': DateTime.now(),
 
        'sitefundgoal': fundgoal_lookup(SITE_FUNDGOAL),
 
    }
 

	
0 comments (0 inline, 0 general)