forked from CGM_Public/pretix_original
PayPal: Improve handling of exceptions form paypalrestsdk
This commit is contained in:
@@ -5,6 +5,7 @@ from collections import OrderedDict
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import paypalrestsdk
|
import paypalrestsdk
|
||||||
|
import paypalrestsdk.exceptions
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
@@ -196,68 +197,72 @@ class Paypal(BasePaymentProvider):
|
|||||||
if request.resolver_match and 'cart_namespace' in request.resolver_match.kwargs:
|
if request.resolver_match and 'cart_namespace' in request.resolver_match.kwargs:
|
||||||
kwargs['cart_namespace'] = request.resolver_match.kwargs['cart_namespace']
|
kwargs['cart_namespace'] = request.resolver_match.kwargs['cart_namespace']
|
||||||
|
|
||||||
if request.event.settings.payment_paypal_connect_user_id:
|
try:
|
||||||
try:
|
if request.event.settings.payment_paypal_connect_user_id:
|
||||||
tokeninfo = Tokeninfo.create_with_refresh_token(request.event.settings.payment_paypal_connect_refresh_token)
|
try:
|
||||||
except BadRequest as ex:
|
tokeninfo = Tokeninfo.create_with_refresh_token(request.event.settings.payment_paypal_connect_refresh_token)
|
||||||
ex = json.loads(ex.content)
|
except BadRequest as ex:
|
||||||
messages.error(request, '{}: {} ({})'.format(
|
ex = json.loads(ex.content)
|
||||||
_('We had trouble communicating with PayPal'),
|
messages.error(request, '{}: {} ({})'.format(
|
||||||
ex['error_description'],
|
_('We had trouble communicating with PayPal'),
|
||||||
ex['correlation_id'])
|
ex['error_description'],
|
||||||
)
|
ex['correlation_id'])
|
||||||
return
|
)
|
||||||
|
return
|
||||||
|
|
||||||
# Even if the token has been refreshed, calling userinfo() can fail. In this case we just don't
|
# Even if the token has been refreshed, calling userinfo() can fail. In this case we just don't
|
||||||
# get the userinfo again and use the payment_paypal_connect_user_id that we already have on file
|
# get the userinfo again and use the payment_paypal_connect_user_id that we already have on file
|
||||||
try:
|
try:
|
||||||
userinfo = tokeninfo.userinfo()
|
userinfo = tokeninfo.userinfo()
|
||||||
request.event.settings.payment_paypal_connect_user_id = userinfo.email
|
request.event.settings.payment_paypal_connect_user_id = userinfo.email
|
||||||
except UnauthorizedAccess:
|
except UnauthorizedAccess:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
payee = {
|
payee = {
|
||||||
"email": request.event.settings.payment_paypal_connect_user_id,
|
"email": request.event.settings.payment_paypal_connect_user_id,
|
||||||
# If PayPal ever offers a good way to get the MerchantID via the Identifity API,
|
# If PayPal ever offers a good way to get the MerchantID via the Identifity API,
|
||||||
# we should use it instead of the merchant's eMail-address
|
# we should use it instead of the merchant's eMail-address
|
||||||
# "merchant_id": request.event.settings.payment_paypal_connect_user_id,
|
# "merchant_id": request.event.settings.payment_paypal_connect_user_id,
|
||||||
}
|
|
||||||
else:
|
|
||||||
payee = {}
|
|
||||||
|
|
||||||
payment = paypalrestsdk.Payment({
|
|
||||||
'header': {'PayPal-Partner-Attribution-Id': 'ramiioSoftwareentwicklung_SP'},
|
|
||||||
'intent': 'sale',
|
|
||||||
'payer': {
|
|
||||||
"payment_method": "paypal",
|
|
||||||
},
|
|
||||||
"redirect_urls": {
|
|
||||||
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return', kwargs=kwargs),
|
|
||||||
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort', kwargs=kwargs),
|
|
||||||
},
|
|
||||||
"transactions": [
|
|
||||||
{
|
|
||||||
"item_list": {
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": __('Order for %s') % str(request.event),
|
|
||||||
"quantity": 1,
|
|
||||||
"price": self.format_price(cart['total']),
|
|
||||||
"currency": request.event.currency
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"amount": {
|
|
||||||
"currency": request.event.currency,
|
|
||||||
"total": self.format_price(cart['total'])
|
|
||||||
},
|
|
||||||
"description": __('Event tickets for {event}').format(event=request.event.name),
|
|
||||||
"payee": payee
|
|
||||||
}
|
}
|
||||||
]
|
else:
|
||||||
})
|
payee = {}
|
||||||
request.session['payment_paypal_payment'] = None
|
|
||||||
return self._create_payment(request, payment)
|
payment = paypalrestsdk.Payment({
|
||||||
|
'header': {'PayPal-Partner-Attribution-Id': 'ramiioSoftwareentwicklung_SP'},
|
||||||
|
'intent': 'sale',
|
||||||
|
'payer': {
|
||||||
|
"payment_method": "paypal",
|
||||||
|
},
|
||||||
|
"redirect_urls": {
|
||||||
|
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return', kwargs=kwargs),
|
||||||
|
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort', kwargs=kwargs),
|
||||||
|
},
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"item_list": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": __('Order for %s') % str(request.event),
|
||||||
|
"quantity": 1,
|
||||||
|
"price": self.format_price(cart['total']),
|
||||||
|
"currency": request.event.currency
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"currency": request.event.currency,
|
||||||
|
"total": self.format_price(cart['total'])
|
||||||
|
},
|
||||||
|
"description": __('Event tickets for {event}').format(event=request.event.name),
|
||||||
|
"payee": payee
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
request.session['payment_paypal_payment'] = None
|
||||||
|
return self._create_payment(request, payment)
|
||||||
|
except paypalrestsdk.exceptions.ConnectionError as e:
|
||||||
|
messages.error(request, _('We had trouble communicating with PayPal'))
|
||||||
|
logger.exception('Error on creating payment: ' + str(e))
|
||||||
|
|
||||||
def format_price(self, value):
|
def format_price(self, value):
|
||||||
return str(round_decimal(value, self.event.currency, {
|
return str(round_decimal(value, self.event.currency, {
|
||||||
@@ -292,29 +297,25 @@ class Paypal(BasePaymentProvider):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _create_payment(self, request, payment):
|
def _create_payment(self, request, payment):
|
||||||
try:
|
if payment.create():
|
||||||
if payment.create():
|
if payment.state not in ('created', 'approved', 'pending'):
|
||||||
if payment.state not in ('created', 'approved', 'pending'):
|
|
||||||
messages.error(request, _('We had trouble communicating with PayPal'))
|
|
||||||
logger.error('Invalid payment state: ' + str(payment))
|
|
||||||
return
|
|
||||||
request.session['payment_paypal_id'] = payment.id
|
|
||||||
for link in payment.links:
|
|
||||||
if link.method == "REDIRECT" and link.rel == "approval_url":
|
|
||||||
if request.session.get('iframe_session', False):
|
|
||||||
signer = signing.Signer(salt='safe-redirect')
|
|
||||||
return (
|
|
||||||
build_absolute_uri(request.event, 'plugins:paypal:redirect') + '?url=' +
|
|
||||||
urllib.parse.quote(signer.sign(link.href))
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return str(link.href)
|
|
||||||
else:
|
|
||||||
messages.error(request, _('We had trouble communicating with PayPal'))
|
messages.error(request, _('We had trouble communicating with PayPal'))
|
||||||
logger.error('Error on creating payment: ' + str(payment.error))
|
logger.error('Invalid payment state: ' + str(payment))
|
||||||
except Exception as e:
|
return
|
||||||
|
request.session['payment_paypal_id'] = payment.id
|
||||||
|
for link in payment.links:
|
||||||
|
if link.method == "REDIRECT" and link.rel == "approval_url":
|
||||||
|
if request.session.get('iframe_session', False):
|
||||||
|
signer = signing.Signer(salt='safe-redirect')
|
||||||
|
return (
|
||||||
|
build_absolute_uri(request.event, 'plugins:paypal:redirect') + '?url=' +
|
||||||
|
urllib.parse.quote(signer.sign(link.href))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return str(link.href)
|
||||||
|
else:
|
||||||
messages.error(request, _('We had trouble communicating with PayPal'))
|
messages.error(request, _('We had trouble communicating with PayPal'))
|
||||||
logger.exception('Error on creating payment: ' + str(e))
|
logger.error('Error on creating payment: ' + str(payment.error))
|
||||||
|
|
||||||
def checkout_confirm_render(self, request) -> str:
|
def checkout_confirm_render(self, request) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -375,7 +376,7 @@ class Paypal(BasePaymentProvider):
|
|||||||
])
|
])
|
||||||
try:
|
try:
|
||||||
payment.execute({"payer_id": request.session.get('payment_paypal_payer')})
|
payment.execute({"payer_id": request.session.get('payment_paypal_payer')})
|
||||||
except Exception as e:
|
except paypalrestsdk.exceptions.ConnectionError as e:
|
||||||
messages.error(request, _('We had trouble communicating with PayPal'))
|
messages.error(request, _('We had trouble communicating with PayPal'))
|
||||||
logger.exception('Error on creating payment: ' + str(e))
|
logger.exception('Error on creating payment: ' + str(e))
|
||||||
|
|
||||||
@@ -511,72 +512,76 @@ class Paypal(BasePaymentProvider):
|
|||||||
def payment_prepare(self, request, payment_obj):
|
def payment_prepare(self, request, payment_obj):
|
||||||
self.init_api()
|
self.init_api()
|
||||||
|
|
||||||
if request.event.settings.payment_paypal_connect_user_id:
|
try:
|
||||||
try:
|
if request.event.settings.payment_paypal_connect_user_id:
|
||||||
tokeninfo = Tokeninfo.create_with_refresh_token(request.event.settings.payment_paypal_connect_refresh_token)
|
try:
|
||||||
except BadRequest as ex:
|
tokeninfo = Tokeninfo.create_with_refresh_token(request.event.settings.payment_paypal_connect_refresh_token)
|
||||||
ex = json.loads(ex.content)
|
except BadRequest as ex:
|
||||||
messages.error(request, '{}: {} ({})'.format(
|
ex = json.loads(ex.content)
|
||||||
_('We had trouble communicating with PayPal'),
|
messages.error(request, '{}: {} ({})'.format(
|
||||||
ex['error_description'],
|
_('We had trouble communicating with PayPal'),
|
||||||
ex['correlation_id'])
|
ex['error_description'],
|
||||||
)
|
ex['correlation_id'])
|
||||||
return
|
)
|
||||||
|
return
|
||||||
|
|
||||||
# Even if the token has been refreshed, calling userinfo() can fail. In this case we just don't
|
# Even if the token has been refreshed, calling userinfo() can fail. In this case we just don't
|
||||||
# get the userinfo again and use the payment_paypal_connect_user_id that we already have on file
|
# get the userinfo again and use the payment_paypal_connect_user_id that we already have on file
|
||||||
try:
|
try:
|
||||||
userinfo = tokeninfo.userinfo()
|
userinfo = tokeninfo.userinfo()
|
||||||
request.event.settings.payment_paypal_connect_user_id = userinfo.email
|
request.event.settings.payment_paypal_connect_user_id = userinfo.email
|
||||||
except UnauthorizedAccess:
|
except UnauthorizedAccess:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
payee = {
|
payee = {
|
||||||
"email": request.event.settings.payment_paypal_connect_user_id,
|
"email": request.event.settings.payment_paypal_connect_user_id,
|
||||||
# If PayPal ever offers a good way to get the MerchantID via the Identifity API,
|
# If PayPal ever offers a good way to get the MerchantID via the Identifity API,
|
||||||
# we should use it instead of the merchant's eMail-address
|
# we should use it instead of the merchant's eMail-address
|
||||||
# "merchant_id": request.event.settings.payment_paypal_connect_user_id,
|
# "merchant_id": request.event.settings.payment_paypal_connect_user_id,
|
||||||
}
|
|
||||||
else:
|
|
||||||
payee = {}
|
|
||||||
|
|
||||||
payment = paypalrestsdk.Payment({
|
|
||||||
'header': {'PayPal-Partner-Attribution-Id': 'ramiioSoftwareentwicklung_SP'},
|
|
||||||
'intent': 'sale',
|
|
||||||
'payer': {
|
|
||||||
"payment_method": "paypal",
|
|
||||||
},
|
|
||||||
"redirect_urls": {
|
|
||||||
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return'),
|
|
||||||
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort'),
|
|
||||||
},
|
|
||||||
"transactions": [
|
|
||||||
{
|
|
||||||
"item_list": {
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": __('Order {slug}-{code}').format(slug=self.event.slug.upper(),
|
|
||||||
code=payment_obj.order.code),
|
|
||||||
"quantity": 1,
|
|
||||||
"price": self.format_price(payment_obj.amount),
|
|
||||||
"currency": payment_obj.order.event.currency
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"amount": {
|
|
||||||
"currency": request.event.currency,
|
|
||||||
"total": self.format_price(payment_obj.amount)
|
|
||||||
},
|
|
||||||
"description": __('Order {order} for {event}').format(
|
|
||||||
event=request.event.name,
|
|
||||||
order=payment_obj.order.code
|
|
||||||
),
|
|
||||||
"payee": payee
|
|
||||||
}
|
}
|
||||||
]
|
else:
|
||||||
})
|
payee = {}
|
||||||
request.session['payment_paypal_payment'] = payment_obj.pk
|
|
||||||
return self._create_payment(request, payment)
|
payment = paypalrestsdk.Payment({
|
||||||
|
'header': {'PayPal-Partner-Attribution-Id': 'ramiioSoftwareentwicklung_SP'},
|
||||||
|
'intent': 'sale',
|
||||||
|
'payer': {
|
||||||
|
"payment_method": "paypal",
|
||||||
|
},
|
||||||
|
"redirect_urls": {
|
||||||
|
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return'),
|
||||||
|
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort'),
|
||||||
|
},
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"item_list": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": __('Order {slug}-{code}').format(slug=self.event.slug.upper(),
|
||||||
|
code=payment_obj.order.code),
|
||||||
|
"quantity": 1,
|
||||||
|
"price": self.format_price(payment_obj.amount),
|
||||||
|
"currency": payment_obj.order.event.currency
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"currency": request.event.currency,
|
||||||
|
"total": self.format_price(payment_obj.amount)
|
||||||
|
},
|
||||||
|
"description": __('Order {order} for {event}').format(
|
||||||
|
event=request.event.name,
|
||||||
|
order=payment_obj.order.code
|
||||||
|
),
|
||||||
|
"payee": payee
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
request.session['payment_paypal_payment'] = payment_obj.pk
|
||||||
|
return self._create_payment(request, payment)
|
||||||
|
except paypalrestsdk.exceptions.ConnectionError as e:
|
||||||
|
messages.error(request, _('We had trouble communicating with PayPal'))
|
||||||
|
logger.exception('Error on creating payment: ' + str(e))
|
||||||
|
|
||||||
def shred_payment_info(self, obj):
|
def shred_payment_info(self, obj):
|
||||||
if obj.info:
|
if obj.info:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import logging
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import paypalrestsdk
|
import paypalrestsdk
|
||||||
|
import paypalrestsdk.exceptions
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
@@ -55,7 +56,7 @@ def oauth_return(request, *args, **kwargs):
|
|||||||
try:
|
try:
|
||||||
tokeninfo = Tokeninfo.create(request.GET.get('code'))
|
tokeninfo = Tokeninfo.create(request.GET.get('code'))
|
||||||
userinfo = Tokeninfo.create_with_refresh_token(tokeninfo['refresh_token']).userinfo()
|
userinfo = Tokeninfo.create_with_refresh_token(tokeninfo['refresh_token']).userinfo()
|
||||||
except:
|
except paypalrestsdk.exceptions.ConnectionError:
|
||||||
logger.exception('Failed to obtain OAuth token')
|
logger.exception('Failed to obtain OAuth token')
|
||||||
messages.error(request, _('An error occurred during connecting with PayPal, please try again.'))
|
messages.error(request, _('An error occurred during connecting with PayPal, please try again.'))
|
||||||
else:
|
else:
|
||||||
@@ -170,7 +171,7 @@ def webhook(request, *args, **kwargs):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
sale = paypalrestsdk.Sale.find(saleid)
|
sale = paypalrestsdk.Sale.find(saleid)
|
||||||
except:
|
except paypalrestsdk.exceptions.ConnectionError:
|
||||||
logger.exception('PayPal error on webhook. Event data: %s' % str(event_json))
|
logger.exception('PayPal error on webhook. Event data: %s' % str(event_json))
|
||||||
return HttpResponse('Sale not found', status=500)
|
return HttpResponse('Sale not found', status=500)
|
||||||
|
|
||||||
@@ -197,7 +198,7 @@ def webhook(request, *args, **kwargs):
|
|||||||
if event_json['resource_type'] == 'refund':
|
if event_json['resource_type'] == 'refund':
|
||||||
try:
|
try:
|
||||||
refund = paypalrestsdk.Refund.find(event_json['resource']['id'])
|
refund = paypalrestsdk.Refund.find(event_json['resource']['id'])
|
||||||
except:
|
except paypalrestsdk.exceptions.ConnectionError:
|
||||||
logger.exception('PayPal error on webhook. Event data: %s' % str(event_json))
|
logger.exception('PayPal error on webhook. Event data: %s' % str(event_json))
|
||||||
return HttpResponse('Refund not found', status=500)
|
return HttpResponse('Refund not found', status=500)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user