diff options
| author | Magnus Hagander | 2020-03-31 16:13:41 +0000 |
|---|---|---|
| committer | Magnus Hagander | 2020-03-31 16:13:41 +0000 |
| commit | 6d6244a77d5f78a08d904004ef41808721ac14d1 (patch) | |
| tree | 93e455900ab5c0d76049b31a0a70b55d057e9a37 | |
| parent | 52b52f86add49409759900cea07df9fd8cac6248 (diff) | |
Create abstraction for getting "today"
This will work differently for conferences and non-conferences once we
add proper timezone support, so abstract it out into a separate couple
of functions. For now they both return the same thing, but this will
change in a later commit.
In passing, fix missing datetime.now() -> timezone.now() conversions.
22 files changed, 111 insertions, 82 deletions
diff --git a/postgresqleu/accounting/util.py b/postgresqleu/accounting/util.py index 4518caf0..8e35e2dc 100644 --- a/postgresqleu/accounting/util.py +++ b/postgresqleu/accounting/util.py @@ -7,9 +7,9 @@ from django.db.models import Max from django.conf import settings from decimal import Decimal -import datetime from postgresqleu.mailqueue.util import send_simple_mail +from postgresqleu.util.time import today_global from .models import JournalEntry, JournalItem, JournalUrl from .models import Object, Account, Year @@ -33,7 +33,7 @@ def create_accounting_entry(items, if not settings.ENABLE_AUTO_ACCOUNTING: return - date = datetime.date.today() + date = today_global() sid = transaction.savepoint() try: diff --git a/postgresqleu/accounting/views.py b/postgresqleu/accounting/views.py index 10bc390b..f2c4057d 100644 --- a/postgresqleu/accounting/views.py +++ b/postgresqleu/accounting/views.py @@ -7,10 +7,11 @@ from django.db.models import Max from django.db import connection, transaction from django.core.paginator import Paginator -from datetime import datetime, date +from datetime import datetime from postgresqleu.util.request import get_int_or_error from postgresqleu.util.auth import authenticate_backend_group +from postgresqleu.util.time import today_global from .models import JournalEntry, JournalItem, JournalUrl, Year, Object from .models import IncomingBalance, Account @@ -21,7 +22,7 @@ from .forms import CloseYearForm def index(request): authenticate_backend_group(request, 'Accounting managers') # Always redirect to the current year - return HttpResponseRedirect("%s/" % datetime.today().year) + return HttpResponseRedirect("%s/" % today_global().year) def _setup_search(request, term): @@ -75,7 +76,7 @@ def year(request, year): year = Year.objects.get(year=int(year)) except Year.DoesNotExist: # Year does not exist, but what do we do about it? - if int(year) == date.today().year: + if int(year) == today_global().year: # For current year, we automatically create the year and move on year = Year(year=int(year), isopen=True) year.save() diff --git a/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py b/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py index 9a7ae4c5..308c1112 100755 --- a/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py +++ b/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py @@ -7,7 +7,7 @@ # import logging -from datetime import datetime, timedelta +from datetime import timedelta from django.core.management.base import BaseCommand from django.db import transaction @@ -117,7 +117,7 @@ class Command(BaseCommand): accrows.append((pm.config('accounting_fee'), accstr, t.amount - t.disbursedamount, t.accounting_object)) create_accounting_entry(accrows, False) - elif datetime.today() - t.settledat > timedelta(days=10): + elif timezone.now() - t.settledat > timedelta(days=10): BraintreeLog(transid=t.transid, error=True, paymentmethod=method, diff --git a/postgresqleu/confreg/forms.py b/postgresqleu/confreg/forms.py index da0f2797..efc93d5f 100644 --- a/postgresqleu/confreg/forms.py +++ b/postgresqleu/confreg/forms.py @@ -21,10 +21,11 @@ from postgresqleu.util.widgets import EmailTextWidget, MonospaceTextarea from postgresqleu.util.db import exec_to_list from postgresqleu.util.magic import magicdb from postgresqleu.util.backendlookups import GeneralAccountLookup +from postgresqleu.util.time import today_conference from postgresqleu.countries.models import Country -from datetime import datetime, date, timedelta +from datetime import timedelta import requests @@ -84,7 +85,7 @@ class ConferenceRegistrationForm(forms.ModelForm): if newval and not newval.active: raise forms.ValidationError('Registration type "%s" is currently not available.' % newval) - if newval and newval.activeuntil and newval.activeuntil < datetime.today().date(): + if newval and newval.activeuntil and newval.activeuntil <= today_conference(): raise forms.ValidationError('Registration type "%s" was only available until %s.' % (newval, newval.activeuntil)) if self.instance and self.instance.payconfirmedat: @@ -133,7 +134,7 @@ class ConferenceRegistrationForm(forms.ModelForm): c = DiscountCode.objects.get(code=newval, conference=self.instance.conference) if c.is_invoiced: raise forms.ValidationError('This discount code is not valid anymore.') - if c.validuntil and c.validuntil < date.today(): + if c.validuntil and c.validuntil < today_conference(): raise forms.ValidationError('This discount code has expired.') if c.maxuses > 0: if c.registrations.count() >= c.maxuses: diff --git a/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py b/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py index 2f2f89b3..801689ac 100644 --- a/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py +++ b/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py @@ -9,10 +9,11 @@ from django.db import transaction from collections import defaultdict from io import StringIO -from datetime import timedelta, date +from datetime import timedelta from postgresqleu.mailqueue.util import send_simple_mail +from postgresqleu.util.time import today_global from postgresqleu.confreg.util import expire_additional_options from postgresqleu.confreg.models import ConferenceRegistration @@ -31,7 +32,7 @@ class Command(BaseCommand): # that have additional options with autocancel set return Conference.objects.filter(active=True, conferenceadditionaloption__invoice_autocancel_hours__isnull=False, - enddate__gt=date.today() + timedelta(days=1), + enddate__gt=today_global() + timedelta(days=1), ).exists() @transaction.atomic diff --git a/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py b/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py index 9cdaa47f..19558b27 100644 --- a/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py +++ b/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py @@ -11,12 +11,13 @@ from django.conf import settings from django.utils import timezone import sys -from datetime import datetime, timedelta +from datetime import timedelta from postgresqleu.confreg.models import Conference, ConferenceSession from postgresqleu.confreg.models import ConferenceRegistration from postgresqleu.util.messaging.twitter import Twitter +from postgresqleu.util.time import today_global class Command(BaseCommand): @@ -28,8 +29,8 @@ class Command(BaseCommand): @classmethod def should_run(self): return Conference.objects.filter(twitterreminders_active=True, - startdate__lte=datetime.today() + timedelta(days=1), - enddate__gte=datetime.today() - timedelta(days=1)) \ + startdate__lte=today_global() + timedelta(days=1), + enddate__gte=today_global() - timedelta(days=1)) \ .exclude(twitter_token='') \ .exclude(twitter_secret='').exists() @@ -49,8 +50,8 @@ class Command(BaseCommand): # more plugins. has_error = False for conference in Conference.objects.filter(twitterreminders_active=True, - startdate__lte=datetime.today() + timedelta(days=1), - enddate__gte=datetime.today() - timedelta(days=1)) \ + startdate__lte=today_global() + timedelta(days=1), + enddate__gte=today_global() - timedelta(days=1)) \ .exclude(twitter_token='') \ .exclude(twitter_secret=''): tw = Twitter(conference) diff --git a/postgresqleu/confreg/models.py b/postgresqleu/confreg/models.py index 575f6ebe..d1adc967 100644 --- a/postgresqleu/confreg/models.py +++ b/postgresqleu/confreg/models.py @@ -19,6 +19,7 @@ from postgresqleu.util.validators import TwitterValidator from postgresqleu.util.validators import PictureUrlValidator from postgresqleu.util.forms import ChoiceArrayField from postgresqleu.util.fields import LowercaseEmailField, ImageBinaryField +from postgresqleu.util.time import today_conference import base64 import datetime @@ -267,10 +268,10 @@ class Conference(models.Model): # conference. Note that this will always be zero if the conference # is in the past (so we don't end up with unnecessary db queries) if self.enddate: - if self.enddate < datetime.datetime.today().date(): + if self.enddate < today_conference(): return 0 else: - if self.startdate < datetime.datetime.today().date(): + if self.startdate < tday_conference(): return 0 return self.conferencesession_set.exclude(status=F('lastnotifiedstatus')).exclude(speaker__isnull=True).count() @@ -289,7 +290,7 @@ class Conference(models.Model): @property def needs_data_purge(self): - return self.enddate < datetime.date.today() and not self.personal_data_purged + return self.enddate < today_conference() and not self.personal_data_purged def clean(self): cc = super(Conference, self).clean() diff --git a/postgresqleu/confreg/util.py b/postgresqleu/confreg/util.py index 93a2e2dd..5cb6fd40 100644 --- a/postgresqleu/confreg/util.py +++ b/postgresqleu/confreg/util.py @@ -13,6 +13,7 @@ import re from postgresqleu.mailqueue.util import send_simple_mail from postgresqleu.util.middleware import RedirectException +from postgresqleu.util.time import today_conference from postgresqleu.confreg.jinjafunc import JINJA_TEMPLATE_ROOT, render_jinja_conference_template from postgresqleu.confreg.jinjapdf import render_jinja_ticket @@ -83,7 +84,7 @@ def invoicerows_for_registration(reg, update_used_vouchers): # Nonexistant voucher code means discount code was used try: d = DiscountCode.objects.get(code=reg.vouchercode, conference=reg.conference) - if d.validuntil and d.validuntil < date.today(): + if d.validuntil and d.validuntil < today_conference(): raise InvoicerowsException("Discount code is no longer valid") elif d.maxuses > 0 and d.registrations.count() >= d.maxuses: raise InvoicerowsException("Discount code does not have enough remaining instances") diff --git a/postgresqleu/confreg/views.py b/postgresqleu/confreg/views.py index 2e44ad66..87c3fcbd 100644 --- a/postgresqleu/confreg/views.py +++ b/postgresqleu/confreg/views.py @@ -58,6 +58,7 @@ from .backendforms import ResendWelcomeMailForm from postgresqleu.util.request import get_int_or_error from postgresqleu.util.decorators import superuser_required from postgresqleu.util.random import generate_random_token +from postgresqleu.util.time import today_conference from postgresqleu.invoices.models import Invoice, InvoicePaymentMethod, InvoiceRow from postgresqleu.invoices.util import InvoiceWrapper from postgresqleu.confwiki.models import Wikipage @@ -307,7 +308,7 @@ def register(request, confname, whatfor=None): # Render the dashboard. return _registration_dashboard(request, conference, reg, has_other_multiregs, redir_root) else: - if datetime.now().date() < conference.startdate: + if today_conference() < conference.startdate: return render_conference_response(request, conference, 'reg', 'confreg/not_yet_open.html') else: return render_conference_response(request, conference, 'reg', 'confreg/closed.html') @@ -420,7 +421,7 @@ def multireg(request, confname, regid=None): is_active = conference.active or conference.testers.filter(pk=request.user.id).exists() if not is_active: # Registration not open. - if datetime.now().date() < conference.startdate: + if today_conference() < conference.startdate: return render_conference_response(request, conference, 'reg', 'confreg/not_yet_open.html') else: return render_conference_response(request, conference, 'reg', 'confreg/closed.html') @@ -585,7 +586,7 @@ def multireg_newinvoice(request, confname): is_active = conference.active or conference.testers.filter(pk=request.user.id).exists() if not is_active: # Registration not open. - if datetime.now().date() < conference.startdate: + if today_conference() < conference.startdate: return render_conference_response(request, conference, 'reg', 'confreg/not_yet_open.html') else: return render_conference_response(request, conference, 'reg', 'confreg/closed.html') @@ -617,7 +618,7 @@ def multireg_newinvoice(request, confname): errors.append('{0} has no registration type specified'.format(r.email)) elif not r.regtype.active: errors.append('{0} uses registration type {1} which is not active'.format(r.email, r.regtype)) - elif r.regtype.activeuntil and r.regtype.activeuntil < date.today(): + elif r.regtype.activeuntil and r.regtype.activeuntil < today_conference(): errors.append('{0} uses registration type {1} which is not active'.format(r.email, r.regtype)) else: try: @@ -702,7 +703,7 @@ def multireg_bulkview(request, confname, bulkid): is_active = conference.active or conference.testers.filter(pk=request.user.id).exists() if not is_active: # Registration not open. - if datetime.now().date() < conference.startdate: + if today_conference() < conference.startdate: return render_conference_response(request, conference, 'reg', 'confreg/not_yet_open.html') else: return render_conference_response(request, conference, 'reg', 'confreg/closed.html') @@ -822,7 +823,7 @@ def reg_add_options(request, confname): if a and reg.regtype not in a: # New regtype is required. Figure out if there is an upsellable # one available. - upsellable = o.requires_regtype.filter(Q(upsell_target=True, active=True, specialtype__isnull=True) & (Q(activeuntil__isnull=True) | Q(activeuntil__lt=datetime.today().date()))) + upsellable = o.requires_regtype.filter(Q(upsell_target=True, active=True, specialtype__isnull=True) & (Q(activeuntil__isnull=True) | Q(activeuntil__lt=today_conference()))) num = len(upsellable) if num == 0: messages.warning(request, "Option {0} requires a registration type that's not available.".format(o.name)) @@ -2954,9 +2955,9 @@ def admin_dashboard(request): current = [] upcoming = [] for c in conferences: - if abs((date.today() - c.startdate).days) < 14 or abs((date.today() - c.enddate).days) < 14: + if abs((today_conference() - c.startdate).days) < 14 or abs((today_conference() - c.enddate).days) < 14: current.insert(0, c) - elif c.startdate > date.today(): + elif c.startdate > today_conference(): upcoming.insert(0, c) return render(request, 'confreg/admin_dashboard.html', { @@ -3289,7 +3290,7 @@ def _admin_registration_cancel(request, conference, redirurl, regs): if conference.vat_registrations: this_to_refund_vat += (regtotalvat[rid] * pattern.percent / Decimal(100) - pattern.fees * conference.vat_registrations.vatpercent / Decimal(100)).quantize(Decimal('0.01')) - today = date.today() + today = today_conference() if (pattern.fromdate is None or pattern.fromdate <= today) and \ (pattern.todate is None or pattern.todate >= today): suggest = "***" diff --git a/postgresqleu/confsponsor/benefitclasses/attendeelist.py b/postgresqleu/confsponsor/benefitclasses/attendeelist.py index d7b696b4..3c32e09d 100644 --- a/postgresqleu/confsponsor/benefitclasses/attendeelist.py +++ b/postgresqleu/confsponsor/benefitclasses/attendeelist.py @@ -2,7 +2,6 @@ from django import forms from django.core.exceptions import ValidationError from postgresqleu.confsponsor.backendforms import BackendSponsorshipLevelBenefitForm -from datetime import datetime import base64 import io as StringIO import csv @@ -10,6 +9,7 @@ import csv from .base import BaseBenefit, BaseBenefitForm from postgresqleu.confreg.models import ConferenceRegistration +from postgresqleu.util.time import today_conference class AttendeeListForm(BaseBenefitForm): @@ -45,7 +45,7 @@ class AttendeeList(BaseBenefit): if claimedbenefit.declined: return "" if claimedbenefit.confirmed: - if self.level.conference.enddate < datetime.today().date(): + if self.level.conference.enddate < today_conference(): data = StringIO.StringIO() c = csv.writer(data, delimiter=';') for r in ConferenceRegistration.objects.filter(conference=self.level.conference, diff --git a/postgresqleu/confsponsor/forms.py b/postgresqleu/confsponsor/forms.py index c2b138af..cc981d32 100644 --- a/postgresqleu/confsponsor/forms.py +++ b/postgresqleu/confsponsor/forms.py @@ -16,8 +16,9 @@ from postgresqleu.util.validators import BeforeValidator, AfterValidator, Twitte from postgresqleu.util.validators import Http200Validator from postgresqleu.util.widgets import Bootstrap4CheckboxSelectMultiple, EmailTextWidget from postgresqleu.util.widgets import Bootstrap4HtmlDateTimeInput +from postgresqleu.util.time import today_conference -from datetime import date, timedelta +from datetime import timedelta from decimal import Decimal @@ -140,7 +141,7 @@ class PurchaseVouchersForm(forms.Form): def __init__(self, conference, *args, **kwargs): self.conference = conference super(PurchaseVouchersForm, self).__init__(*args, **kwargs) - activeQ = Q(activeuntil__isnull=True) | Q(activeuntil__gt=date.today()) + activeQ = Q(activeuntil__isnull=True) | Q(activeuntil__gte=today_conference()) if self.data and self.data.get('regtype', None) and self.data.get('num', None) and _int_with_default(self.data['num'], 0) > 0: RegistrationType.objects.get(pk=self.data['regtype']) self.fields['confirm'].help_text = 'Check this box to confirm that you will pay the generated invoice' @@ -175,7 +176,7 @@ class PurchaseDiscountForm(forms.Form): self.fields['requiredoptions'].queryset = ConferenceAdditionalOption.objects.filter(conference=conference, public=True) self.fields['expires'].initial = conference.startdate - timedelta(days=2) self.fields['expires'].validators.append(BeforeValidator(conference.startdate - timedelta(days=1))) - self.fields['expires'].validators.append(AfterValidator(date.today() - timedelta(days=1))) + self.fields['expires'].validators.append(AfterValidator(today_conference() - timedelta(days=1))) if not showconfirm: del self.fields['confirm'] diff --git a/postgresqleu/confsponsor/invoicehandler.py b/postgresqleu/confsponsor/invoicehandler.py index 00ce3ff6..de730147 100644 --- a/postgresqleu/confsponsor/invoicehandler.py +++ b/postgresqleu/confsponsor/invoicehandler.py @@ -1,12 +1,13 @@ from django.utils import timezone from django.conf import settings -from datetime import datetime, timedelta, date +from datetime import timedelta import base64 import os from postgresqleu.mailqueue.util import send_simple_mail from postgresqleu.invoices.util import InvoiceManager +from postgresqleu.util.time import today_conference from .models import Sponsor, PurchasedVoucher from postgresqleu.confreg.models import PrepaidBatch, PrepaidVoucher @@ -141,10 +142,10 @@ def create_sponsor_invoice(user, sponsor): invoicerows = [ ['%s %s sponsorship' % (conference, level), 1, level.levelcost, vatlevel], ] - if conference.startdate < date.today() + timedelta(days=5): + if conference.startdate < today_conference() + timedelta(days=5): # If conference happens in the next 5 days, invoice is due immediately - duedate = date.today() - elif conference.startdate < date.today() + timedelta(days=30): + duedate = today_conferece() + elif conference.startdate < today_conference() + timedelta(days=30): # Less than 30 days before the conference, set the due date to # 5 days before the conference duedate = conference.startdate - timedelta(days=5) @@ -274,8 +275,8 @@ def create_voucher_invoice(conference, invoiceaddr, user, rt, num): user.first_name + ' ' + user.last_name, invoiceaddr, 'Prepaid vouchers for %s' % conference.conferencename, - datetime.now(), - date.today(), + timezone.now(), + today_conference(), invoicerows, processor=processor, accounting_account=settings.ACCOUNTING_CONFREG_ACCOUNT, diff --git a/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py b/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py index 35213280..4c956783 100644 --- a/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py +++ b/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py @@ -3,10 +3,11 @@ # from django.core.management.base import BaseCommand +from django.utils import timezone from django.db import transaction from django.conf import settings -from datetime import date, datetime, timedelta, time +from datetime import timedelta from django.db.models import Q, F, Count @@ -15,6 +16,7 @@ from postgresqleu.confreg.util import send_conference_mail from postgresqleu.confsponsor.models import Sponsor from postgresqleu.mailqueue.util import send_simple_mail from postgresqleu.invoices.util import InvoiceManager, InvoiceWrapper +from postgresqleu.util.time import today_global class Command(BaseCommand): @@ -32,7 +34,7 @@ class Command(BaseCommand): def handle(self, *args, **options): # We're always going to process all conferences, since most will not have any # open discount codes. - filt = Q(sponsor__isnull=False, is_invoiced=False) & (Q(validuntil__lt=date.today()) | Q(num_uses__gte=F('maxuses'))) + filt = Q(sponsor__isnull=False, is_invoiced=False) & (Q(validuntil__lte=today_global()) | Q(num_uses__gte=F('maxuses'))) codes = DiscountCode.objects.annotate(num_uses=Count('registrations')).filter(filt) for code in codes: # Either the code has expired, or it is fully used by now. Time to generate the invoice. We'll also @@ -84,8 +86,8 @@ class Command(BaseCommand): "{0} {1}".format(code.sponsor_rep.first_name, code.sponsor_rep.last_name), '%s\n%s' % (code.sponsor.name, code.sponsor.invoiceaddr), '{0} discount code {1}'.format(code.conference, code.code), - datetime.now(), - date.today() + timedelta(days=1), + timezone.now(), + today_global() + timedelta(days=1), invoicerows, accounting_account=settings.ACCOUNTING_CONFREG_ACCOUNT, accounting_object=code.conference.accounting_object, @@ -122,7 +124,7 @@ class Command(BaseCommand): 'sponsor': code.sponsor, 'invoice': code.invoice, 'curr': settings.CURRENCY_ABBREV, - 'expired_time': code.validuntil < date.today(), + 'expired_time': code.validuntil < today_global(), }, sender=code.conference.sponsoraddr, receivername='{0} {1}'.format(manager.first_name, manager.last_name) diff --git a/postgresqleu/confsponsor/views.py b/postgresqleu/confsponsor/views.py index ca5f4dde..1a15cf29 100644 --- a/postgresqleu/confsponsor/views.py +++ b/postgresqleu/confsponsor/views.py @@ -9,7 +9,7 @@ from django.contrib import messages from django.contrib.auth.models import User from django.utils import timezone -from datetime import datetime, timedelta +from datetime import timedelta import io import random from collections import OrderedDict @@ -25,6 +25,7 @@ from postgresqleu.mailqueue.util import send_simple_mail from postgresqleu.util.storage import InlineEncodedStorage from postgresqleu.util.decorators import superuser_required from postgresqleu.util.request import get_int_or_error +from postgresqleu.util.time import today_global from postgresqleu.invoices.util import InvoiceWrapper, InvoiceManager from .models import Sponsor, SponsorshipLevel, SponsorshipBenefit @@ -45,9 +46,9 @@ from .vatutil import validate_eu_vat_number @login_required def sponsor_dashboard(request): # We define "past sponsors" as those older than a month - because we have to pick something. - currentsponsors = Sponsor.objects.filter(managers=request.user, conference__enddate__gte=datetime.today() - timedelta(days=31)).order_by('conference__startdate') - pastsponsors = Sponsor.objects.filter(managers=request.user, conference__enddate__lt=datetime.today() - timedelta(days=31)).order_by('conference__startdate') - conferences = Conference.objects.filter(callforsponsorsopen=True, startdate__gt=datetime.today()).order_by('startdate') + currentsponsors = Sponsor.objects.filter(managers=request.user, conference__enddate__gte=today_global() - timedelta(days=31)).order_by('conference__startdate') + pastsponsors = Sponsor.objects.filter(managers=request.user, conference__enddate__lt=today_global() - timedelta(days=31)).order_by('conference__startdate') + conferences = Conference.objects.filter(callforsponsorsopen=True, startdate__gt=today_blobal()).order_by('startdate') return render(request, 'confsponsor/dashboard.html', { "currentsponsors": currentsponsors, diff --git a/postgresqleu/elections/views.py b/postgresqleu/elections/views.py index 08f7bd6d..e424abb2 100644 --- a/postgresqleu/elections/views.py +++ b/postgresqleu/elections/views.py @@ -3,16 +3,17 @@ from django.http import HttpResponseRedirect, Http404 from django.contrib.auth.decorators import login_required from django.db import connection +from postgresqleu.utils.time import today_global from .models import Election, Member, Candidate, Vote from .forms import VoteForm -from datetime import date, timedelta +from datetime import timedelta def home(request): elections = Election.objects.filter(isopen=True).order_by('startdate') - open_elections = [e for e in elections if e.startdate <= date.today() and e.enddate >= date.today()] - past_elections = [e for e in elections if e.startdate < date.today() and e.enddate < date.today()] - upcoming_elections = [e for e in elections if e.startdate > date.today()] + open_elections = [e for e in elections if e.startdate <= today_global() and e.enddate >= today_global()] + past_elections = [e for e in elections if e.startdate < today_global() and e.enddate < today_global()] + upcoming_elections = [e for e in elections if e.startdate > today_global()] return render(request, 'elections/home.html', { 'open': open_elections, @@ -26,10 +27,10 @@ def election(request, electionid): if not election.isopen: raise Http404("This election is not open (yet)") - if election.startdate > date.today(): + if election.startdate > today_global(): raise Http404("This election has not started yet") - if election.enddate < date.today(): + if election.enddate < today_global(): # Election is closed, consider publishing the results if not election.resultspublic: # If user is an admin, show anyway, otherwise throw an error @@ -67,7 +68,7 @@ def election(request, electionid): return render(request, 'elections/mustbemember.html', {}) # Make sure that the membership hasn't expired - if member.paiduntil < date.today(): + if member.paiduntil < today_global(): return render(request, 'elections/mustbemember.html', {}) # Verify that the user has been a member for at least 28 days. @@ -110,7 +111,7 @@ def ownvotes(request, electionid): if not election.isopen: raise Http404("This election is not open (yet)") - if election.enddate >= date.today(): + if election.enddate >= today_global(): raise Http404("This election has not ended yet") member = get_object_or_404(Member, user=request.user) diff --git a/postgresqleu/invoices/views.py b/postgresqleu/invoices/views.py index d81a00f1..4a05275d 100644 --- a/postgresqleu/invoices/views.py +++ b/postgresqleu/invoices/views.py @@ -10,12 +10,13 @@ from django.conf import settings import base64 import io -from datetime import datetime, timedelta +from datetime import timedelta from decimal import Decimal from postgresqleu.util.auth import authenticate_backend_group from postgresqleu.util.pagination import simple_pagination from postgresqleu.util.request import get_int_or_error +from postgresqleu.util.time import today_global from .models import Invoice, InvoiceRow, InvoiceHistory, InvoicePaymentMethod, VatRate from .models import InvoiceRefund from .forms import InvoiceForm, InvoiceRowForm, RefundForm @@ -116,8 +117,8 @@ def oneinvoice(request, invoicenum): # since they're all based on the same model and form. if invoicenum == 'new': invoice = Invoice( - invoicedate=datetime.today(), - duedate=datetime.today() + timedelta(days=30), + invoicedate=today_global(), + duedate=today_global() + timedelta(days=30), ) else: invoice = get_object_or_404(Invoice, pk=invoicenum) diff --git a/postgresqleu/membership/invoicehandler.py b/postgresqleu/membership/invoicehandler.py index 192139e3..cc0c9cd6 100644 --- a/postgresqleu/membership/invoicehandler.py +++ b/postgresqleu/membership/invoicehandler.py @@ -1,8 +1,10 @@ from django.conf import settings +from django.utils import timezone +from postgresqleu.util.time import today_global from .models import Member, MemberLog, get_config -from datetime import datetime, timedelta, date +from datetime import timedelta class InvoiceProcessor(object): @@ -28,21 +30,21 @@ class InvoiceProcessor(object): # Extend the membership. If already paid to a date in the future, # extend from that date. Otherwise, from today. - if member.paiduntil and member.paiduntil > date.today(): + if member.paiduntil and member.paiduntil > today_global(): member.paiduntil = member.paiduntil + timedelta(days=cfg.membership_years * 365) else: - member.paiduntil = date.today() + timedelta(days=cfg.membership_years * 365) + member.paiduntil = today_global() + timedelta(days=cfg.membership_years * 365) member.expiry_warning_sent = None # If the member isn't already a member, set todays date as the # starting date. if not member.membersince: - member.membersince = date.today() + member.membersince = today_global() member.save() # Create a log record too, and save it - MemberLog(member=member, timestamp=datetime.now(), message="Payment for %s years received, membership extended to %s" % (cfg.membership_years, member.paiduntil)).save() + MemberLog(member=member, timestamp=timezone.now(), message="Payment for %s years received, membership extended to %s" % (cfg.membership_years, member.paiduntil)).save() # Process an invoice being canceled. This means we need to unlink # it from the membership. diff --git a/postgresqleu/membership/models.py b/postgresqleu/membership/models.py index 3f53c3d6..cd352f52 100644 --- a/postgresqleu/membership/models.py +++ b/postgresqleu/membership/models.py @@ -5,11 +5,12 @@ from django.conf import settings from django.utils import timezone from postgresqleu.util.fields import LowercaseEmailField +from postgresqleu.util.time import today_global from postgresqleu.countries.models import Country from postgresqleu.invoices.models import Invoice, InvoicePaymentMethod from postgresqleu.membership.util import country_validator_choices -from datetime import date, datetime, timedelta +from datetime import timedelta class MembershipConfiguration(models.Model): @@ -59,7 +60,7 @@ class Member(models.Model): @property def expiressoon(self): if self.paiduntil: - if self.paiduntil < date.today() + timedelta(60): + if self.paiduntil < today_global() + timedelta(days=60): return True else: return False diff --git a/postgresqleu/membership/views.py b/postgresqleu/membership/views.py index 5fef422b..811d9bb5 100644 --- a/postgresqleu/membership/views.py +++ b/postgresqleu/membership/views.py @@ -12,11 +12,12 @@ from .forms import MemberForm, ProxyVoterForm from postgresqleu.util.decorators import superuser_required from postgresqleu.util.random import generate_random_token +from postgresqleu.util.time import today_global from postgresqleu.invoices.util import InvoiceManager, InvoicePresentationWrapper from postgresqleu.invoices.models import InvoiceProcessor from postgresqleu.mailqueue.util import send_simple_mail -from datetime import date, datetime, timedelta +from datetime import timedelta import json import base64 import os @@ -31,7 +32,7 @@ def home(request): # We have a batch job that expires members, but do it here as well to make sure # the web is up to date with information if necessary. - if member.paiduntil and member.paiduntil < date.today(): + if member.paiduntil and member.paiduntil < today_global(): MemberLog(member=member, timestamp=timezone.now(), message="Membership expired").save() @@ -135,7 +136,7 @@ def meetings(request): } for m in meetings] return render(request, 'membership/meetings.html', { - 'active': member.paiduntil and member.paiduntil >= datetime.today().date(), + 'active': member.paiduntil and member.paiduntil >= today_global(), 'member': member, 'meetings': meetinginfo, }) @@ -143,7 +144,7 @@ def meetings(request): @transaction.atomic def _meeting(request, member, meeting, isproxy): - if not (member.paiduntil and member.paiduntil >= datetime.today().date()): + if not (member.paiduntil and member.paiduntil >= today_global()): return HttpResponse("Your membership is not active") if not meeting.allmembers: @@ -197,7 +198,7 @@ def meeting_proxy(request, meetingid): meeting = get_object_or_404(Meeting, pk=meetingid) member = get_object_or_404(Member, user=request.user) - if not (member.paiduntil and member.paiduntil >= datetime.today().date()): + if not (member.paiduntil and member.paiduntil >= today_global()): return HttpResponse("Your membership is not active") if not meeting.allmembers: diff --git a/postgresqleu/transferwise/api.py b/postgresqleu/transferwise/api.py index 571c31b2..cc7512f0 100644 --- a/postgresqleu/transferwise/api.py +++ b/postgresqleu/transferwise/api.py @@ -8,6 +8,7 @@ import json import re import uuid +from postgresqleu.util.time import today_global from .models import TransferwiseRefund @@ -82,7 +83,7 @@ class TransferwiseApi(object): def get_transactions(self, startdate=None, enddate=None): if not enddate: - enddate = (datetime.today() + timedelta(days=1)).date() + enddate = today_global() + timedelta(days=1) if not startdate: startdate = enddate - timedelta(days=60) diff --git a/postgresqleu/util/time.py b/postgresqleu/util/time.py new file mode 100644 index 00000000..76567187 --- /dev/null +++ b/postgresqleu/util/time.py @@ -0,0 +1,9 @@ +from django.utils import timezone + + +def today_conference(): + return timezone.now().date() + + +def today_global(): + return timezone.now().date() diff --git a/postgresqleu/views.py b/postgresqleu/views.py index 317cb1d7..5c806d71 100644 --- a/postgresqleu/views.py +++ b/postgresqleu/views.py @@ -11,6 +11,7 @@ from postgresqleu.invoices.models import PendingBankTransaction, BankFileUpload, from postgresqleu.invoices.models import InvoiceRefund from postgresqleu.util.db import exec_to_dict, conditional_exec_to_scalar +from postgresqleu.util.time import today_global import datetime import markdown @@ -18,7 +19,7 @@ import markdown # Handle the frontpage def index(request): - events = Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate') + events = Conference.objects.filter(promoactive=True, enddate__gte=today_global()).order_by('startdate') series = ConferenceSeries.objects.filter(visible=True).extra( where=["EXISTS (SELECT 1 FROM confreg_conference c WHERE c.series_id=confreg_conferenceseries.id AND c.promoactive)"] ) @@ -58,8 +59,8 @@ ORDER BY priosort DESC, datetime DESC LIMIT 5""") # Handle the events frontpage def eventsindex(request): - events = list(Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate')) - past = Conference.objects.filter(promoactive=True, enddate__lt=datetime.datetime.today()).order_by('-startdate')[:5] + events = list(Conference.objects.filter(promoactive=True, enddate__gte=today_global()).order_by('startdate')) + past = Conference.objects.filter(promoactive=True, enddate__lt=today_global()).order_by('-startdate')[:5] series = ConferenceSeries.objects.filter(visible=True).extra( where=["EXISTS (SELECT 1 FROM confreg_conference c WHERE c.series_id=confreg_conferenceseries.id AND c.promoactive)"] ) @@ -76,8 +77,8 @@ def eventsindex(request): # Handle past events list def pastevents(request): - events = list(Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate')) - past = Conference.objects.filter(promoactive=True, enddate__lt=datetime.datetime.today()).order_by('-startdate') + events = list(Conference.objects.filter(promoactive=True, enddate__gte=today_global()).order_by('startdate')) + past = Conference.objects.filter(promoactive=True, enddate__lt=today_global()).order_by('-startdate') series = ConferenceSeries.objects.filter(visible=True).extra( where=["EXISTS (SELECT 1 FROM confreg_conference c WHERE c.series_id=confreg_conferenceseries.id AND c.promoactive)"] ) @@ -96,15 +97,15 @@ def eventseries(request, id): return render(request, 'events/series.html', { 'series': series, - 'upcoming': [e for e in events if e.enddate >= datetime.datetime.today().date()], - 'past': [e for e in events if e.enddate < datetime.datetime.today().date()], + 'upcoming': [e for e in events if e.enddate >= today_global()], + 'past': [e for e in events if e.enddate < today_global()], }) # Handle a users list of previous events @login_required def attendee_events(request): - events = list(Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate')) + events = list(Conference.objects.filter(promoactive=True, enddate__gte=today_global()).order_by('startdate')) series = ConferenceSeries.objects.filter(visible=True).extra( where=["EXISTS (SELECT 1 FROM confreg_conference c WHERE c.series_id=confreg_conferenceseries.id AND c.promoactive)"] ) |
