mirror of
https://github.com/lucaspalomodevelop/indico-plugins.git
synced 2026-03-12 23:27:22 +00:00
120 lines
5.3 KiB
Python
120 lines
5.3 KiB
Python
# This file is part of the Indico plugins.
|
|
# Copyright (C) 2002 - 2022 CERN
|
|
#
|
|
# The Indico plugins are free software; you can redistribute
|
|
# them and/or modify them under the terms of the MIT License;
|
|
# see the LICENSE file for more details.
|
|
|
|
from itertools import chain
|
|
|
|
import requests
|
|
from flask import flash, redirect, request
|
|
from flask_pluginengine import current_plugin
|
|
from werkzeug.exceptions import BadRequest
|
|
|
|
from indico.modules.events.payment.models.transactions import TransactionAction
|
|
from indico.modules.events.payment.notifications import notify_amount_inconsistency
|
|
from indico.modules.events.payment.util import register_transaction
|
|
from indico.modules.events.registration.models.registrations import Registration
|
|
from indico.web.flask.util import url_for
|
|
from indico.web.rh import RH
|
|
|
|
from indico_payment_paypal import _
|
|
|
|
|
|
IPN_VERIFY_EXTRA_PARAMS = (('cmd', '_notify-validate'),)
|
|
|
|
|
|
paypal_transaction_action_mapping = {'Completed': TransactionAction.complete,
|
|
'Denied': TransactionAction.reject,
|
|
'Pending': TransactionAction.pending}
|
|
|
|
|
|
class RHPaypalIPN(RH):
|
|
"""Process the notification sent by the PayPal"""
|
|
|
|
CSRF_ENABLED = False
|
|
|
|
def _process_args(self):
|
|
self.token = request.args['token']
|
|
self.registration = Registration.query.filter_by(uuid=self.token).first()
|
|
if not self.registration:
|
|
raise BadRequest
|
|
|
|
def _process(self):
|
|
self._verify_business()
|
|
verify_params = list(chain(IPN_VERIFY_EXTRA_PARAMS, request.form.items()))
|
|
result = requests.post(current_plugin.settings.get('url'), data=verify_params).text
|
|
if result != 'VERIFIED':
|
|
current_plugin.logger.warning("Paypal IPN string %s did not validate (%s)", verify_params, result)
|
|
return
|
|
if self._is_transaction_duplicated():
|
|
current_plugin.logger.info("Payment not recorded because transaction was duplicated\nData received: %s",
|
|
request.form)
|
|
return
|
|
payment_status = request.form.get('payment_status')
|
|
if payment_status == 'Failed':
|
|
current_plugin.logger.info("Payment failed (status: %s)\nData received: %s", payment_status, request.form)
|
|
return
|
|
if payment_status == 'Refunded' or float(request.form.get('mc_gross')) <= 0:
|
|
current_plugin.logger.warning("Payment refunded (status: %s)\nData received: %s",
|
|
payment_status, request.form)
|
|
return
|
|
if payment_status not in paypal_transaction_action_mapping:
|
|
current_plugin.logger.warning("Payment status '%s' not recognized\nData received: %s",
|
|
payment_status, request.form)
|
|
return
|
|
self._verify_amount()
|
|
register_transaction(registration=self.registration,
|
|
amount=float(request.form['mc_gross']),
|
|
currency=request.form['mc_currency'],
|
|
action=paypal_transaction_action_mapping[payment_status],
|
|
provider='paypal',
|
|
data=request.form)
|
|
|
|
def _verify_business(self):
|
|
expected = current_plugin.event_settings.get(self.registration.registration_form.event, 'business').lower()
|
|
candidates = {request.form.get('business', '').lower(),
|
|
request.form.get('receiver_id', '').lower(),
|
|
request.form.get('receiver_email', '').lower()}
|
|
if expected in candidates:
|
|
return True
|
|
current_plugin.logger.warning("Unexpected business: %s not in %r (request data: %r)", expected, candidates,
|
|
request.form)
|
|
return False
|
|
|
|
def _verify_amount(self):
|
|
expected_amount = self.registration.price
|
|
expected_currency = self.registration.currency
|
|
amount = float(request.form['mc_gross'])
|
|
currency = request.form['mc_currency']
|
|
if expected_amount == amount and expected_currency == currency:
|
|
return True
|
|
current_plugin.logger.warning("Payment doesn't match event's fee: %s %s != %s %s",
|
|
amount, currency, expected_amount, expected_currency)
|
|
notify_amount_inconsistency(self.registration, amount, currency)
|
|
return False
|
|
|
|
def _is_transaction_duplicated(self):
|
|
transaction = self.registration.transaction
|
|
if not transaction or transaction.provider != 'paypal':
|
|
return False
|
|
return (transaction.data['payment_status'] == request.form.get('payment_status') and
|
|
transaction.data['txn_id'] == request.form.get('txn_id'))
|
|
|
|
|
|
class RHPaypalSuccess(RHPaypalIPN):
|
|
"""Confirmation message after successful payment"""
|
|
|
|
def _process(self):
|
|
flash(_('Your payment request has been processed.'), 'success')
|
|
return redirect(url_for('event_registration.display_regform', self.registration.locator.registrant))
|
|
|
|
|
|
class RHPaypalCancel(RHPaypalIPN):
|
|
"""Cancellation message"""
|
|
|
|
def _process(self):
|
|
flash(_('You cancelled the payment process.'), 'info')
|
|
return redirect(url_for('event_registration.display_regform', self.registration.locator.registrant))
|