From 7bc559acabc3e95b9a42789697bba1acdaf08de9 Mon Sep 17 00:00:00 2001
From: Raphael Michel
Date: Sat, 23 Dec 2023 11:29:20 +0100
Subject: [PATCH] PayPal: Add communication messages on known issue
---
src/pretix/plugins/paypal2/payment.py | 69 ++++++++++++++++---
.../paypal2/checkout_payment_form.html | 15 +++-
.../pretixplugins/paypal2/pending.html | 13 +++-
3 files changed, 83 insertions(+), 14 deletions(-)
diff --git a/src/pretix/plugins/paypal2/payment.py b/src/pretix/plugins/paypal2/payment.py
index 1911e8509..446283753 100644
--- a/src/pretix/plugins/paypal2/payment.py
+++ b/src/pretix/plugins/paypal2/payment.py
@@ -24,11 +24,13 @@ import json
import logging
import urllib.parse
from collections import OrderedDict
+from datetime import timedelta
from decimal import Decimal
from django import forms
from django.conf import settings
from django.contrib import messages
+from django.core.cache import cache
from django.http import HttpRequest
from django.template.loader import get_template
from django.templatetags.static import static
@@ -38,6 +40,7 @@ from django.utils.safestring import mark_safe
from django.utils.timezone import now
from django.utils.translation import gettext as __, gettext_lazy as _
from django_countries import countries
+from django_scopes import scopes_disabled
from i18nfield.strings import LazyI18nString
from paypalcheckoutsdk.orders import (
OrdersCaptureRequest, OrdersCreateRequest, OrdersGetRequest,
@@ -424,12 +427,25 @@ class PaypalMethod(BasePaymentProvider):
kwargs[key] = request.resolver_match.kwargs[key]
return kwargs
+ @scopes_disabled()
+ def count_known_failures():
+ return OrderPayment.objects.filter(
+ provider="paypal", info__contains="RESOURCE_NOT_FOUND", created__gt=now() - timedelta(hours=2)
+ ).count()
+
+ known_issue_failures = cache.get_or_set(
+ 'paypal2_known_issue_failures',
+ count_known_failures(),
+ 600
+ )
+
template = get_template('pretixplugins/paypal2/checkout_payment_form.html')
ctx = {
'request': request,
'event': self.event,
'settings': self.settings,
'method': self.method,
+ 'known_issue': known_issue_failures > 1,
'xhr': eventreverse(self.event, 'plugins:paypal2:xhr', kwargs=build_kwargs())
}
return template.render(ctx)
@@ -445,7 +461,12 @@ class PaypalMethod(BasePaymentProvider):
req = OrdersGetRequest(paypal_order_id)
response = self.client.execute(req)
except IOError as e:
- messages.warning(request, _('We had trouble communicating with PayPal'))
+ if "RESOURCE_NOT_FOUND" in str(e):
+ messages.warning(request, _('Your payment has failed due to a known issue within PayPal. Please try '
+ 'again, there is a high chance of the payment succeeding on a second '
+ 'or third attempt. You can also try other payment methods, if available.'))
+ else:
+ messages.warning(request, _('We had trouble communicating with PayPal'))
logger.exception('PayPal OrdersGetRequest({}): {}'.format(paypal_order_id, str(e)))
return False
else:
@@ -566,7 +587,12 @@ class PaypalMethod(BasePaymentProvider):
})
response = self.client.execute(paymentreq)
except IOError as e:
- messages.error(request, _('We had trouble communicating with PayPal'))
+ if "RESOURCE_NOT_FOUND" in str(e):
+ messages.error(request, _('Your payment has failed due to a known issue within PayPal. Please try '
+ 'again, there is a high chance of the payment succeeding on a second '
+ 'or third attempt. You can also try other payment methods, if available.'))
+ else:
+ messages.error(request, _('We had trouble communicating with PayPal'))
logger.exception('PayPal OrdersCreateRequest: {}'.format(str(e)))
else:
if response.result.status not in ('CREATED', 'PAYER_ACTION_REQUIRED'):
@@ -615,6 +641,10 @@ class PaypalMethod(BasePaymentProvider):
"order_id": paypal_oid,
}
})
+ if "RESOURCE_NOT_FOUND" in str(e):
+ raise PaymentException(_('Your payment has failed due to a known issue within PayPal. Please try '
+ 'again, there is a high chance of the payment succeeding on a second '
+ 'or third attempt. You can also try other payment methods, if available.'))
raise PaymentException(_('We had trouble communicating with PayPal'))
else:
pp_captured_order = response.result
@@ -673,7 +703,13 @@ class PaypalMethod(BasePaymentProvider):
])
self.client.execute(patchreq)
except IOError as e:
- messages.error(request, _('We had trouble communicating with PayPal'))
+ if "RESOURCE_NOT_FOUND" in str(e):
+ messages.error(request,
+ _('Your payment has failed due to a known issue within PayPal. Please try '
+ 'again, there is a high chance of the payment succeeding on a second '
+ 'or third attempt. You can also try other payment methods, if available.'))
+ else:
+ messages.error(request, _('We had trouble communicating with PayPal'))
payment.fail(info={
"error": {
"name": "IOError",
@@ -712,9 +748,14 @@ class PaypalMethod(BasePaymentProvider):
except IOError as e:
payment.fail(info={**pp_captured_order.dict(), "error": {"message": str(e)}}, log_data={"error": str(e)})
logger.exception('PayPal OrdersCaptureRequest({}): {}'.format(pp_captured_order.id, str(e)))
- raise PaymentException(
- _('We were unable to process your payment. See below for details on how to proceed.')
- )
+ if "RESOURCE_NOT_FOUND" in str(e):
+ raise PaymentException(
+ _('Your payment has failed due to a known issue within PayPal. Please try '
+ 'again, there is a high chance of the payment succeeding on a second '
+ 'or third attempt. You can also try other payment methods, if available.')
+ )
+ else:
+ raise PaymentException(_('We were unable to process your payment. See below for details on how to proceed.'))
else:
pp_captured_order = response.result
@@ -769,9 +810,13 @@ class PaypalMethod(BasePaymentProvider):
retry = False
except (KeyError, IndexError):
pass
+
+ error = payment.info_data.get("error", {})
+ is_known_issue = error.get("name") == "RESOURCE_NOT_FOUND" or "RESOURCE_NOT_FOUND" in error.get("message")
+
template = get_template('pretixplugins/paypal2/pending.html')
ctx = {'request': request, 'event': self.event, 'settings': self.settings,
- 'retry': retry, 'order': payment.order}
+ 'retry': retry, 'order': payment.order, 'is_known_issue': is_known_issue}
return template.render(ctx)
def matching_id(self, payment: OrderPayment):
@@ -932,7 +977,15 @@ class PaypalMethod(BasePaymentProvider):
req = OrdersGetRequest(paypal_order_id)
response = self.client.execute(req)
except IOError as e:
- messages.warning(request, _('We had trouble communicating with PayPal'))
+ if "RESOURCE_NOT_FOUND" in str(e):
+ messages.warning(
+ request,
+ _('Your payment has failed due to a known issue within PayPal. Please try '
+ 'again, there is a high chance of the payment succeeding on a second '
+ 'or third attempt. You can also try other payment methods, if available.')
+ )
+ else:
+ messages.warning(request, _('We had trouble communicating with PayPal'))
logger.exception('PayPal OrdersGetRequest({}): {}'.format(paypal_order_id, str(e)))
return False
else:
diff --git a/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/checkout_payment_form.html b/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/checkout_payment_form.html
index 51c666b7c..827497492 100644
--- a/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/checkout_payment_form.html
+++ b/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/checkout_payment_form.html
@@ -13,6 +13,15 @@
{% endif %}
-
-
-
\ No newline at end of file
+{% if known_issue %}
+
+ {% blocktrans trimmed %}
+ There is currently a known issue with PayPal that causes some payments to fail. If your payment fails,
+ please just try again. You can also try with a different payment method, if you prefer.
+ {% endblocktrans %}
+
+{% endif %}
+
+
+
+
\ No newline at end of file
diff --git a/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/pending.html b/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/pending.html
index 7ea6214ea..640bbd4bc 100644
--- a/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/pending.html
+++ b/src/pretix/plugins/paypal2/templates/pretixplugins/paypal2/pending.html
@@ -1,9 +1,16 @@
{% load i18n %}
{% if retry %}
-
{% blocktrans trimmed %}
- Our attempt to execute your Payment via PayPal has failed. Please try again or contact us.
- {% endblocktrans %}
+ {% if is_known_issue %}
+
{% blocktrans trimmed %}
+ Your payment has failed due to a known issue within PayPal. Please try again, there is a high chance of the
+ payment succeeding on a second or third attempt. You can also try other payment methods, if available.
+ {% endblocktrans %}
+ {% else %}
+
{% blocktrans trimmed %}
+ Our attempt to execute your payment via PayPal has failed. Please try again or contact us.
+ {% endblocktrans %}
+ {% endif %}
{% else %}
{% blocktrans trimmed %}
We're waiting for an answer from PayPal regarding your payment. Please contact us, if this