From d698313f1d711b93c07fb7085147200a26ee7097 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 23 Dec 2016 13:29:41 +0100 Subject: [PATCH] Do not allow initiating stripe/paypal payments after the last payment date --- src/pretix/base/models/event.py | 11 ++++++++++- src/pretix/base/models/orders.py | 13 +++---------- src/pretix/base/payment.py | 6 +++++- src/pretix/plugins/paypal/payment.py | 2 +- src/pretix/plugins/stripe/payment.py | 2 +- src/pretix/presale/views/order.py | 17 +++++++++++++++++ 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py index 592548847..122df60e1 100644 --- a/src/pretix/base/models/event.py +++ b/src/pretix/base/models/event.py @@ -1,4 +1,5 @@ import uuid +from datetime import date, datetime, time import pytz from django.conf import settings @@ -8,7 +9,7 @@ from django.core.validators import RegexValidator from django.db import models from django.template.defaultfilters import date as _date from django.utils.functional import cached_property -from django.utils.timezone import now +from django.utils.timezone import make_aware, now from django.utils.translation import ugettext_lazy as _ from pretix.base.email import CustomSMTPBackend @@ -208,6 +209,14 @@ class Event(LoggedModel): else: return get_connection(fail_silently=False) + @property + def payment_term_last(self): + tz = pytz.timezone(self.settings.timezone) + return make_aware(datetime.combine( + self.settings.get('payment_term_last', as_type=date), + time(hour=23, minute=59, second=59) + ), tz) + class EventPermission(models.Model): """ diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index bcbf5d209..c27ede80a 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -1,17 +1,16 @@ import copy import string -from datetime import date, datetime, time +from datetime import datetime from decimal import Decimal from typing import List, Union -import pytz from django.conf import settings from django.db import models from django.db.models import F from django.db.models.signals import post_delete from django.dispatch import receiver from django.utils.crypto import get_random_string -from django.utils.timezone import make_aware, now +from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from ..decimal import round_decimal @@ -273,13 +272,7 @@ class Order(LoggedModel): } if self.event.settings.get('payment_term_last'): - tz = pytz.timezone(self.event.settings.timezone) - last_date = make_aware(datetime.combine( - self.event.settings.get('payment_term_last', as_type=date), - time(hour=23, minute=59, second=59) - ), tz) - - if now() > last_date: + if now() > self.event.payment_term_last: return error_messages['late'] if self.status == self.STATUS_PENDING: return True diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index c214b9aed..c2e302c69 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -365,8 +365,12 @@ class BasePaymentProvider: whether the user should be presented with an option to retry the payment. The default implementation always returns False. + If you want to enable retrials for your payment method, the best is to just return + ``self._is_still_available()`` from this method to disable it as soon as the method + gets disabled or the methods end date is reached. + The retry workflow is also used if a user switches to this payment method for an existing - order! Therefore, they can only switch to your p + order! :param order: The order object """ diff --git a/src/pretix/plugins/paypal/payment.py b/src/pretix/plugins/paypal/payment.py index c165d6195..1d328badf 100644 --- a/src/pretix/plugins/paypal/payment.py +++ b/src/pretix/plugins/paypal/payment.py @@ -257,7 +257,7 @@ class Paypal(BasePaymentProvider): order.save() def order_can_retry(self, order): - return True + return self._is_still_available() def order_prepare(self, request, order): self.init_api() diff --git a/src/pretix/plugins/stripe/payment.py b/src/pretix/plugins/stripe/payment.py index 9795479f1..bf1de5ef9 100644 --- a/src/pretix/plugins/stripe/payment.py +++ b/src/pretix/plugins/stripe/payment.py @@ -86,7 +86,7 @@ class Stripe(BasePaymentProvider): return template.render(ctx) def order_can_retry(self, order): - return True + return self._is_still_available() def payment_perform(self, request, order) -> str: self._init_api() diff --git a/src/pretix/presale/views/order.py b/src/pretix/presale/views/order.py index df3195c0f..e0d711ec9 100644 --- a/src/pretix/presale/views/order.py +++ b/src/pretix/presale/views/order.py @@ -139,6 +139,11 @@ class OrderPaymentStart(EventViewMixin, OrderDetailMixin, TemplateView): or not self.payment_provider.is_enabled): messages.error(request, _('The payment for this order cannot be continued.')) return redirect(self.get_order_url()) + + if self.request.event.settings.get('payment_term_last'): + if now() > self.request.event.payment_term_last: + messages.error(request, _('The payment is too late to be accepted.')) + return redirect(self.get_order_url()) return super().dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): @@ -225,6 +230,12 @@ class OrderPaymentComplete(EventViewMixin, OrderDetailMixin, View): not self.payment_provider.is_enabled): messages.error(request, _('The payment information you entered was incomplete.')) return redirect(self.get_payment_url()) + + if self.request.event.settings.get('payment_term_last'): + if now() > self.request.event.payment_term_last: + messages.error(request, _('The payment is too late to be accepted.')) + return redirect(self.get_order_url()) + return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): @@ -251,6 +262,12 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView): if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED): messages.error(request, _('The payment method for this order cannot be changed.')) return redirect(self.get_order_url()) + + if self.request.event.settings.get('payment_term_last'): + if now() > self.request.event.payment_term_last: + messages.error(request, _('The payment is too late to be accepted.')) + return redirect(self.get_order_url()) + return super().dispatch(request, *args, **kwargs) def get_payment_url(self):