From c4aed04a187b77ac264db72a4a6d01eb5c61dfcf Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Tue, 20 Dec 2022 14:53:43 +0100 Subject: [PATCH] PPv2: Fix incomplete validation of capture status --- src/pretix/plugins/paypal2/payment.py | 2 +- src/pretix/plugins/paypal2/views.py | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/pretix/plugins/paypal2/payment.py b/src/pretix/plugins/paypal2/payment.py index 030c405c7e..c1351b8757 100644 --- a/src/pretix/plugins/paypal2/payment.py +++ b/src/pretix/plugins/paypal2/payment.py @@ -698,7 +698,7 @@ class PaypalMethod(BasePaymentProvider): except ReferencedPayPalObject.MultipleObjectsReturned: pass - if capture.status == 'PENDING': + if capture.status != 'COMPLETED': messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as ' 'soon as the payment completed.')) payment.info = json.dumps(pp_captured_order.dict()) diff --git a/src/pretix/plugins/paypal2/views.py b/src/pretix/plugins/paypal2/views.py index 26bad8b091..54a6f333fd 100644 --- a/src/pretix/plugins/paypal2/views.py +++ b/src/pretix/plugins/paypal2/views.py @@ -426,7 +426,10 @@ def webhook(request, *args, **kwargs): if not payment: return HttpResponse('Payment not found', status=200) - payment.order.log_action('pretix.plugins.paypal.event', data=event_json) + payment.order.log_action('pretix.plugins.paypal.event', data={ + 'event': event_json, + 'sale': sale, + }) if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED and sale['status'] in ('PARTIALLY_REFUNDED', 'REFUNDED', 'COMPLETED'): if event_json['resource_type'] == 'refund': @@ -470,10 +473,24 @@ def webhook(request, *args, **kwargs): elif payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED) \ and sale['status'] == 'COMPLETED': - try: - payment.confirm() - except Quota.QuotaExceededException: - pass + capture_completed = True + for purchaseunit in sale['purchase_units']: + for capture in purchaseunit['payments']['captures']: + try: + ReferencedPayPalObject.objects.get_or_create(order=payment.order, payment=payment, + reference=capture['id']) + except ReferencedPayPalObject.MultipleObjectsReturned: + pass + + if capture['status'] not in ('COMPLETED', 'REFUNDED', 'PARTIALLY_REFUNDED'): + capture_completed = False + if capture_completed: + try: + payment.info = json.dumps(sale) + payment.save(update_fields=['info']) + payment.confirm() + except Quota.QuotaExceededException: + pass return HttpResponse(status=200)