diff --git a/src/pretix/plugins/paypal2/payment.py b/src/pretix/plugins/paypal2/payment.py index 07fda5c45e..d56e31ea0d 100644 --- a/src/pretix/plugins/paypal2/payment.py +++ b/src/pretix/plugins/paypal2/payment.py @@ -31,6 +31,7 @@ from django import forms from django.conf import settings from django.contrib import messages from django.core.cache import cache +from django.db import transaction from django.http import HttpRequest from django.template.loader import get_template from django.templatetags.static import static @@ -55,6 +56,7 @@ from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota from pretix.base.payment import BasePaymentProvider, PaymentException from pretix.base.services.mail import SendMailException from pretix.base.settings import SettingsSandbox +from pretix.helpers import OF_SELF from pretix.helpers.urls import build_absolute_uri as build_global_uri from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse from pretix.plugins.paypal2.client.core.environment import ( @@ -621,7 +623,13 @@ class PaypalMethod(BasePaymentProvider): } return template.render(ctx) + @transaction.atomic def execute_payment(self, request: HttpRequest, payment: OrderPayment): + payment = OrderPayment.objects.select_for_update(of=OF_SELF).get(pk=payment.pk) + if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED: + logger.warning('payment is already confirmed; possible return-view/webhook race-condition') + return + try: if request.session.get('payment_paypal_oid', '') == '': raise PaymentException(_('We were unable to process your payment. See below for details on how to ' diff --git a/src/pretix/plugins/paypal2/views.py b/src/pretix/plugins/paypal2/views.py index 92f8e4e9ae..f87ca4f2b8 100644 --- a/src/pretix/plugins/paypal2/views.py +++ b/src/pretix/plugins/paypal2/views.py @@ -507,7 +507,10 @@ def webhook(request, *args, **kwargs): pass elif sale['status'] == 'APPROVED': request.session['payment_paypal_oid'] = payment.info_data['id'] - payment.payment_provider.execute_payment(request, payment) + try: + payment.payment_provider.execute_payment(request, payment) + except PaymentException as e: + logger.exception('PayPal2 - Could not capture/execute_payment from Webhook: {}'.format(str(e))) return HttpResponse(status=200)