Fix bug that lead to wrong payment amount when switching payment method to PayPal later

This commit is contained in:
Raphael Michel
2017-05-10 19:12:55 +02:00
parent 90d14c004f
commit 127086a50e
3 changed files with 29 additions and 12 deletions

View File

@@ -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 '<div class="alert alert-warning">%s</div>' % _('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.

View File

@@ -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

View File

@@ -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()