From 127086a50ef704e739474496996131f4dd6936b6 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 10 May 2017 19:12:55 +0200 Subject: [PATCH] Fix bug that lead to wrong payment amount when switching payment method to PayPal later --- src/pretix/base/payment.py | 16 ++++++++++------ src/pretix/plugins/paypal/views.py | 14 +++++++++++++- src/pretix/presale/views/order.py | 11 ++++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index eedd7bdc5..195f075e6 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -1,7 +1,7 @@ from collections import OrderedDict from datetime import date from decimal import Decimal -from typing import Any, Dict +from typing import Any, Dict, Union import pytz from django import forms @@ -266,7 +266,7 @@ class BasePaymentProvider: """ raise NotImplementedError() # NOQA - def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> "bool|str": + def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str]: """ Will be called after the user selects this provider as his payment method. If you provided a form to the user to enter payment data, this method should @@ -394,14 +394,14 @@ class BasePaymentProvider: """ return False - def retry_prepare(self, request: HttpRequest, order: Order) -> "bool|str": + def retry_prepare(self, request: HttpRequest, order: Order) -> Union[bool, str]: """ Deprecated, use order_prepare instead """ raise DeprecationWarning('retry_prepare is deprecated, use order_prepare instead') return self.order_prepare(request, order) - def order_prepare(self, request: HttpRequest, order: Order) -> "bool|str": + def order_prepare(self, request: HttpRequest, order: Order) -> Union[bool, str]: """ Will be called if the user retries to pay an unpaid order (after the user filled in e.g. the form returned by :py:meth:`payment_form`) or if the user changes the payment @@ -409,6 +409,10 @@ class BasePaymentProvider: It should return and report errors the same way as :py:meth:`checkout_prepare`, but receives an ``Order`` object instead of a cart object. + + Note: The ``Order`` object given to this method might be different from the version + stored in the database as it's total will already contain the payment fee for the + new payment method. """ form = self.payment_form(request) if form.is_valid(): @@ -458,7 +462,7 @@ class BasePaymentProvider: return '
%s
' % _('The money can not be automatically refunded, ' 'please transfer the money back manually.') - def order_control_refund_perform(self, request: HttpRequest, order: Order) -> "bool|str": + def order_control_refund_perform(self, request: HttpRequest, order: Order) -> Union[bool, str]: """ Will be called if the event administrator confirms the refund. @@ -523,7 +527,7 @@ class FreeOrderProvider(BasePaymentProvider): def order_control_refund_render(self, order: Order) -> str: return '' - def order_control_refund_perform(self, request: HttpRequest, order: Order) -> "bool|str": + def order_control_refund_perform(self, request: HttpRequest, order: Order) -> Union[bool, str]: """ Will be called if the event administrator confirms the refund. diff --git a/src/pretix/plugins/paypal/views.py b/src/pretix/plugins/paypal/views.py index a18583a54..3f6dc4d5d 100644 --- a/src/pretix/plugins/paypal/views.py +++ b/src/pretix/plugins/paypal/views.py @@ -57,7 +57,19 @@ def success(request, *args, **kwargs): @event_view(require_live=False) def abort(request, *args, **kwargs): messages.error(request, _('It looks like you canceled the PayPal payment')) - return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs={'step': 'payment'})) + + if request.session.get('payment_paypal_order'): + order = Order.objects.get(pk=request.session.get('payment_paypal_order')) + else: + order = None + + if order: + return redirect(eventreverse(request.event, 'presale:event.order', kwargs={ + 'order': order.code, + 'secret': order.secret + }) + ('?paid=yes' if order.status == Order.STATUS_PAID else '')) + else: + return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs={'step': 'payment'})) @csrf_exempt diff --git a/src/pretix/presale/views/order.py b/src/pretix/presale/views/order.py index 80011b30f..a3a447e9f 100644 --- a/src/pretix/presale/views/order.py +++ b/src/pretix/presale/views/order.py @@ -320,20 +320,21 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView): request.session['payment'] = p['provider'].identifier request.session['payment_change_{}'.format(self.order.pk)] = '1' + new_fee = p['provider'].calculate_fee(self._total_order_value) + self.order.payment_provider = p['provider'].identifier + self.order.payment_fee = new_fee + self.order.total = self._total_order_value + new_fee + self.order._calculate_tax() + resp = p['provider'].order_prepare(request, self.order) if resp: with transaction.atomic(): - new_fee = p['provider'].calculate_fee(self._total_order_value) self.order.log_action('pretix.event.order.payment.changed', { 'old_fee': self.order.payment_fee, 'new_fee': new_fee, 'old_provider': self.order.payment_provider, 'new_provider': p['provider'].identifier }) - self.order.payment_provider = p['provider'].identifier - self.order.payment_fee = new_fee - self.order.total = self._total_order_value + new_fee - self.order._calculate_tax() self.order.save() i = self.order.invoices.filter(is_cancellation=False).last()