Fix #303 -- valid until date for payment providers (#334)

* Fix 303

* fix #303

* minor refactoring

* improving timezone aware

* added documentation
This commit is contained in:
Christopher Dambamuromo
2016-11-27 15:09:26 +00:00
committed by Raphael Michel
parent db6fb51fc6
commit 4a2e3e3e16
2 changed files with 54 additions and 5 deletions

View File

@@ -1,13 +1,16 @@
from collections import OrderedDict
from datetime import date
from decimal import Decimal
from typing import Any, Dict
import pytz
from django import forms
from django.contrib import messages
from django.dispatch import receiver
from django.forms import Form
from django.http import HttpRequest
from django.template.loader import get_template
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from pretix.base.decimal import round_decimal
@@ -86,7 +89,7 @@ class BasePaymentProvider:
settings keys and the values should be corresponding Django form fields.
The default implementation returns the appropriate fields for the ``_enabled``,
``_fee_abs`` and ``_fee_percent`` settings mentioned above.
``_fee_abs``, ``_fee_percent`` and ``_availability_date`` settings mentioned above.
We suggest that you return an ``OrderedDict`` object instead of a dictionary
and make use of the default implementation. Your implementation could look
@@ -126,6 +129,13 @@ class BasePaymentProvider:
help_text=_('Percentage'),
required=False
)),
('_availability_date',
forms.DateField(
label=_('Available until'),
help_text=_('Users will not be able to choose this payment provider after the given date.'),
required=False,
widget=forms.DateInput(attrs={'class': 'datepickerfield'})
)),
('_fee_reverse_calc',
forms.BooleanField(
label=_('Calculate the fee from the total value including the fee.'),
@@ -190,6 +200,14 @@ class BasePaymentProvider:
form.fields = self.payment_form_fields
return form
def _is_still_available(self, now_dt=None):
now_dt = now_dt or now()
tz = pytz.timezone(self.event.settings.timezone)
availability_date = self.settings.get('_availability_date', as_type=date)
if availability_date:
return availability_date >= now_dt.astimezone(tz).date()
return True
def is_allowed(self, request: HttpRequest) -> bool:
"""
You can use this method to disable this payment provider for certain groups
@@ -197,9 +215,9 @@ class BasePaymentProvider:
user will not be able to select this payment method. This will only be called
during checkout, not on retrying.
The default implementation always returns ``True``.
The default implementation checks for the _availability_date setting to be either unset or in the future.
"""
return True
return self._is_still_available()
def payment_form_render(self, request: HttpRequest) -> str:
"""
@@ -335,11 +353,11 @@ class BasePaymentProvider:
Will be called to check whether it is allowed to change the payment method of
an order to this one.
The default implementation always returns ``True``.
The default implementation checks for the _availability_date setting to be either unset or in the future.
:param order: The order object
"""
return True
return self._is_still_available()
def order_can_retry(self, order: Order) -> bool:
"""

View File

@@ -1,6 +1,8 @@
import datetime
from decimal import Decimal
import pytest
import pytz
from django.utils.timezone import now
from tests.testdummy.payment import DummyPaymentProvider
@@ -50,3 +52,32 @@ def test_payment_fee_reverse_percent_and_abs_default(event):
prov.settings.set('_fee_abs', Decimal('0.30'))
prov.settings.set('_fee_percent', Decimal('2.90'))
assert prov.calculate_fee(Decimal('100.00')) == Decimal('3.30')
@pytest.mark.django_db
def test_availability_date_available(event):
prov = DummyPaymentProvider(event)
prov.settings.set('_availability_date', datetime.date.today() + datetime.timedelta(days=1))
result = prov._is_still_available()
assert result
@pytest.mark.django_db
def test_availability_date_not_available(event):
prov = DummyPaymentProvider(event)
prov.settings.set('_availability_date', datetime.date.today() - datetime.timedelta(days=1))
result = prov._is_still_available()
assert not result
@pytest.mark.django_db
def test_availability_date_timezones(event):
event.settings.set('timezone', 'US/Pacific')
prov = DummyPaymentProvider(event)
prov.settings.set('_availability_date', '2016-12-01')
tz = pytz.timezone('US/Pacific')
utc = pytz.timezone('UTC')
assert prov._is_still_available(tz.localize(datetime.datetime(2016, 11, 30, 23, 0, 0)).astimezone(utc))
assert prov._is_still_available(tz.localize(datetime.datetime(2016, 12, 1, 23, 59, 0)).astimezone(utc))
assert not prov._is_still_available(tz.localize(datetime.datetime(2016, 12, 2, 0, 0, 1)).astimezone(utc))