91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import logging
|
|
|
|
import psycopg2
|
|
|
|
from odoo import http
|
|
from odoo.http import request
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class PaymentPostProcessing(http.Controller):
|
|
|
|
"""
|
|
This controller is responsible for the monitoring and finalization of the post-processing of
|
|
transactions.
|
|
|
|
It exposes the route `/payment/status`: All payment flows must go through this route at some
|
|
point to allow the user checking on the transactions' status, and to trigger the finalization of
|
|
their post-processing.
|
|
"""
|
|
|
|
MONITORED_TX_ID_KEY = '__payment_monitored_tx_id__'
|
|
|
|
@http.route('/payment/status', type='http', auth='public', website=True, sitemap=False)
|
|
def display_status(self, **kwargs):
|
|
""" Fetch the transaction and display it on the payment status page.
|
|
|
|
:param dict kwargs: Optional data. This parameter is not used here
|
|
:return: The rendered status page
|
|
:rtype: str
|
|
"""
|
|
monitored_tx = self._get_monitored_transaction()
|
|
# The session might have expired, or the transaction never existed.
|
|
values = {'tx': monitored_tx} if monitored_tx else {'payment_not_found': True}
|
|
return request.render('payment.payment_status', values)
|
|
|
|
@http.route('/payment/status/poll', type='json', auth='public')
|
|
def poll_status(self, **_kwargs):
|
|
""" Fetch the transaction and trigger its post-processing.
|
|
|
|
:return: The post-processing values of the transaction.
|
|
:rtype: dict
|
|
"""
|
|
# We only poll the payment status if a payment was found, so the transaction should exist.
|
|
monitored_tx = self._get_monitored_transaction()
|
|
|
|
# Post-process the transaction before redirecting the user to the landing route and its
|
|
# document.
|
|
if not monitored_tx.is_post_processed:
|
|
try:
|
|
monitored_tx._post_process()
|
|
except (
|
|
psycopg2.OperationalError, psycopg2.IntegrityError
|
|
): # The database cursor could not be committed.
|
|
request.env.cr.rollback() # Rollback and try later.
|
|
raise Exception('retry')
|
|
except Exception as e:
|
|
request.env.cr.rollback()
|
|
_logger.exception(
|
|
"Encountered an error while post-processing transaction with id %s:\n%s",
|
|
monitored_tx.id, e
|
|
)
|
|
raise
|
|
|
|
return {
|
|
'provider_code': monitored_tx.provider_code,
|
|
'state': monitored_tx.state,
|
|
'landing_route': monitored_tx.landing_route,
|
|
}
|
|
|
|
@classmethod
|
|
def monitor_transaction(cls, transaction):
|
|
""" Make the provided transaction id monitored.
|
|
|
|
:param payment.transaction transaction: The transaction to monitor.
|
|
:return: None
|
|
"""
|
|
request.session[cls.MONITORED_TX_ID_KEY] = transaction.id
|
|
|
|
def _get_monitored_transaction(self):
|
|
""" Retrieve the user's last transaction from the session (the transaction being monitored).
|
|
|
|
:return: the user's last transaction
|
|
:rtype: payment.transaction
|
|
"""
|
|
return request.env['payment.transaction'].sudo().browse(
|
|
request.session.get(self.MONITORED_TX_ID_KEY)
|
|
).exists()
|