Skip to content

Commit

Permalink
Cleaning up code. Webhook was probably even not working
Browse files Browse the repository at this point in the history
  • Loading branch information
Delawen committed Oct 19, 2020
1 parent fe0d366 commit 57fb216
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 134 deletions.
7 changes: 0 additions & 7 deletions pretix_mercadopago/models.py

This file was deleted.

6 changes: 3 additions & 3 deletions pretix_mercadopago/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pretix.multidomain import event_url

from .views import (
oauth_disconnect, redirect_view, success, webhook,
oauth_disconnect, redirect_view, success,
)

event_patterns = [
Expand All @@ -14,7 +14,7 @@

url(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/return/', success, name='return'),

event_url(r'^webhook/$', webhook, name='webhook', require_live=False),
event_url(r'^webhook/$', success, name='webhook', require_live=False),
])),
]

Expand All @@ -24,5 +24,5 @@
views.admin_view, name='backend'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/mercadopago/disconnect/',
oauth_disconnect, name='oauth.disconnect'),
url(r'^_mercadopago/webhook/$', webhook, name='webhook'),
url(r'^_mercadopago/webhook/$', success, name='webhook'),
]
145 changes: 21 additions & 124 deletions pretix_mercadopago/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django_scopes import scopes_disabled

from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota
from pretix.base.payment import PaymentException
from pretix.control.permissions import event_permission_required
from pretix.multidomain.urlreverse import eventreverse
from pretix_mercadopago.models import ReferencedMercadoPagoObject
from pretix_mercadopago.payment import Mercadopago

logger = logging.getLogger('pretix.plugins.meli')
Expand Down Expand Up @@ -46,10 +44,8 @@ def redirect_view(request, *args, **kwargs):
return r

# Return url for MercadoPago when payment is pending or success


@csrf_exempt
def success(request, *args, **kwargs):
orderid = request.GET.get('external_reference')
collection_id = request.GET.get('collection_id')
status = request.GET.get('collection_status')

Expand All @@ -60,14 +56,12 @@ def success(request, *args, **kwargs):
paymentInfo = mp.get_payment(collection_id)

payment = None
orderid = None
if paymentInfo["status"] == 200:
if orderid == paymentInfo['response']['external_reference']:
payment = OrderPayment.objects.get(pk=orderid)
else:
messages.error(request, _('Invalid attempt to pay order ' + orderid))

orderid = paymentInfo['response']['external_reference']
payment = OrderPayment.objects.get(pk=orderid)
else:
messages.error(request, str(e))
messages.error(request, _('Invalid attempt update payment details of ' + collection_id))
return None

# Documentation for payment object:
Expand All @@ -79,18 +73,29 @@ def success(request, *args, **kwargs):
# Something fishy detected
if status != mpstatus:
messages.error(request, _('Invalid attempt to pay order ' + orderid))
elif mpstatus == 'approved':

# Update with what MercadoPago has
if mpstatus == 'approved':
payment.order.status = Order.STATUS_PAID
payment.state = 'confirmed'
try:
payment.confirm()
except Quota.QuotaExceededException:
messages.error(request, _('Quota exceeded with order ' + orderid))
elif (mpstatus == 'pending') or (mpstatus == 'authorized') or (mpstatus == 'in_process') or (mpstatus == 'in_mediation'):
payment.order.status = Order.STATUS_PENDING
payment.state = 'pending'
elif (mpstatus == 'cancelled'):
payment.order.status = Order.STATUS_CANCELED
payment.state = 'canceled'
payment.fail(info={
'error': True,
'message': _('Payment Cancelled'),
})
elif (mpstatus == 'rejected'):
payment.order.status = Order.STATUS_CANCELED
payment.state = 'failed'
payment.fail(info={
'error': True,
'message': _('Payment Rejected'),
})
elif (mpstatus == 'refunded') or (mpstatus == 'charged_back'):
payment.order.status = Order.STATUS_CANCELED
payment.state = 'refunded'
Expand All @@ -99,124 +104,16 @@ def success(request, *args, **kwargs):
payment.order.save()
payment.save()

if payment:
return redirect(eventreverse(request.event, 'presale:event.order', kwargs={
'order': payment.order.code,
'secret': payment.order.secret
}) + ('?paid=yes' if payment.order.status == Order.STATUS_PAID else ''))
else:
messages.error(request, _('Invalid attempt update payment details of ' + collection_id))
urlkwargs['step'] = 'confirm'
return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs=urlkwargs))


@csrf_exempt
@require_POST
@scopes_disabled()
def webhook(request, *args, **kwargs):
event_body = request.body.decode('utf-8').strip()
event_json = json.loads(event_body)

# We do not check the signature, we just use it as a trigger to look the charge up.
if event_json['resource_type'] not in ('sale', 'refund'):
return HttpResponse("Not interested in this resource type", status=200)

if event_json['resource_type'] == 'sale':
saleid = event_json['resource']['id']
else:
saleid = event_json['resource']['sale_id']

try:
refs = [saleid]
if event_json['resource'].get('parent_payment'):
refs.append(event_json['resource'].get('parent_payment'))

rso = ReferencedMercadoPagoObject.objects.select_related('order', 'order__event').get(
reference__in=refs
)
event = rso.order.event
except ReferencedMercadoPagoObject.DoesNotExist:
rso = None
if hasattr(request, 'event'):
event = request.event
else:
return HttpResponse("Unable to detect event", status=200)

prov = MercadoPago(event)
prov.init_api()

try:
sale = prov.get_preference(saleid)
except:
logger.exception('MercadoPago error on webhook. Event data: %s' % str(event_json))
return HttpResponse('Sale not found', status=500)

if rso and rso.payment:
payment = rso.payment
else:
payments = OrderPayment.objects.filter(order__event=event, provider='mercadopago',
info__icontains=sale['id'])
payment = None
# for p in payments:
# payment_info = p.info_data
# for res in payment_info['transactions'][0]['related_resources']:
# for k, v in res.items():
# if k == 'sale' and v['id'] == sale['id']:
# payment = p
# break

if not payment:
return HttpResponse('Payment not found', status=200)

payment.order.log_action('pretix.plugins.mercadopago.event', data=event_json)

if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED and sale['state'] in ('partially_refunded', 'refunded'):
if event_json['resource_type'] == 'refund':
try:
refund = paypalrestsdk.Refund.find(event_json['resource']['id'])
except:
logger.exception('MercadoPago error on webhook. Event data: %s' % str(event_json))
return HttpResponse('Refund not found', status=500)

known_refunds = {r.info_data.get('id'): r for r in payment.refunds.all()}
if refund['id'] not in known_refunds:
payment.create_external_refund(
amount=abs(Decimal(refund['amount']['total'])),
info=json.dumps(refund.to_dict() if not isinstance(refund, dict) else refund)
)
elif known_refunds.get(refund['id']).state in (
OrderRefund.REFUND_STATE_CREATED, OrderRefund.REFUND_STATE_TRANSIT) and refund['state'] == 'completed':
known_refunds.get(refund['id']).done()

if 'total_refunded_amount' in refund:
known_sum = payment.refunds.filter(
state__in=(OrderRefund.REFUND_STATE_DONE, OrderRefund.REFUND_STATE_TRANSIT,
OrderRefund.REFUND_STATE_CREATED, OrderRefund.REFUND_SOURCE_EXTERNAL)
).aggregate(s=Sum('amount'))['s'] or Decimal('0.00')
total_refunded_amount = Decimal(refund['total_refunded_amount']['value'])
if known_sum < total_refunded_amount:
payment.create_external_refund(
amount=total_refunded_amount - known_sum
)
elif sale['state'] == 'refunded':
known_sum = payment.refunds.filter(
state__in=(OrderRefund.REFUND_STATE_DONE, OrderRefund.REFUND_STATE_TRANSIT,
OrderRefund.REFUND_STATE_CREATED, OrderRefund.REFUND_SOURCE_EXTERNAL)
).aggregate(s=Sum('amount'))['s'] or Decimal('0.00')

if known_sum < payment.amount:
payment.create_external_refund(
amount=payment.amount - known_sum
)
elif payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED,
OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED) and sale['state'] == 'completed':
try:
payment.confirm()
except Quota.QuotaExceededException:
pass

return HttpResponse(status=200)


@event_permission_required('can_change_event_settings')
@require_POST
def oauth_disconnect(request, **kwargs):
Expand Down

0 comments on commit 57fb216

Please sign in to comment.