As of today, Ingenico platform 4.125 has non-uniform handling of the
PARAMPLUS parameters that can be passed as part of transaction metadata.
This parameter is documented as being parsed[1] as a series of
parameter-value pairs, to be passed as extra parameters to the feedback
transaction. Based on this, it seems that the PARAMPLUS value should not
be urlencoded globally, but each field value should be urlencoded, as
the Ingenico side will have to be able to parse and re-emit these
individual parameters.
In one case we were missing this urlencoding step, so this commit fixes
it.
Without this, the querydirect.asp API would return invalid XML data when
we retrieve the status of a transaction that used a PARAMPLUS value with
an '=' sign!
For example with PARAMPLUS passed as
return_url=/payment/confirm?tx_id=123
the value returned by querydirect.asp would contain the following:
(note the invalid extra quote character in the `return_url` param)
```
<?xml version="1.0"?>
<ncresponse
(...)
ED="1234"
return_url="/payment/confirm?tx_id="123"
SCORING=""
SCO_CATEGORY="G">
</ncresponse>
```
Url-encoding the value of the return_url in PARAMPLUS fixes this
nonsensical result.
However, the Ingenico API then fails to decode the parameter value when
passing it to the feedback URL, such as the ACCEPTURL we depend on.
As a workaround, since we only pass a single parameter inside
PARAMPLUS, we'll url-unquote it afterwards.
[1]
https://payment-services.ingenico.com/int/en/ogone/support/guides/integration%20guides/e-commerce#feedbackparameters_variablefeedbackparameters
117 lines
4.8 KiB
Python
117 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
import logging
|
|
import pprint
|
|
import werkzeug
|
|
from werkzeug.urls import url_unquote_plus
|
|
|
|
from odoo import http
|
|
from odoo.http import request
|
|
from odoo.addons.payment.models.payment_acquirer import ValidationError
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class OgoneController(http.Controller):
|
|
_accept_url = '/payment/ogone/test/accept'
|
|
_decline_url = '/payment/ogone/test/decline'
|
|
_exception_url = '/payment/ogone/test/exception'
|
|
_cancel_url = '/payment/ogone/test/cancel'
|
|
|
|
@http.route([
|
|
'/payment/ogone/accept', '/payment/ogone/test/accept',
|
|
'/payment/ogone/decline', '/payment/ogone/test/decline',
|
|
'/payment/ogone/exception', '/payment/ogone/test/exception',
|
|
'/payment/ogone/cancel', '/payment/ogone/test/cancel',
|
|
], type='http', auth='none')
|
|
def ogone_form_feedback(self, **post):
|
|
""" Ogone contacts using GET, at least for accept """
|
|
_logger.info('Ogone: entering form_feedback with post data %s', pprint.pformat(post)) # debug
|
|
request.env['payment.transaction'].sudo().form_feedback(post, 'ogone')
|
|
return werkzeug.utils.redirect(url_unquote_plus(post.pop('return_url', '/')))
|
|
|
|
@http.route(['/payment/ogone/s2s/create_json'], type='json', auth='public', csrf=False)
|
|
def ogone_s2s_create_json(self, **kwargs):
|
|
if not kwargs.get('partner_id'):
|
|
kwargs = dict(kwargs, partner_id=request.env.user.partner_id.id)
|
|
new_id = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs)
|
|
return new_id.id
|
|
|
|
@http.route(['/payment/ogone/s2s/create_json_3ds'], type='json', auth='public', csrf=False)
|
|
def ogone_s2s_create_json_3ds(self, verify_validity=False, **kwargs):
|
|
if not kwargs.get('partner_id'):
|
|
kwargs = dict(kwargs, partner_id=request.env.user.partner_id.id)
|
|
token = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs)
|
|
|
|
if not token:
|
|
res = {
|
|
'result': False,
|
|
}
|
|
return res
|
|
|
|
res = {
|
|
'result': True,
|
|
'id': token.id,
|
|
'short_name': token.short_name,
|
|
'3d_secure': False,
|
|
'verified': False,
|
|
}
|
|
|
|
if verify_validity != False:
|
|
baseurl = request.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
|
params = {
|
|
'accept_url': baseurl + '/payment/ogone/validate/accept',
|
|
'decline_url': baseurl + '/payment/ogone/validate/decline',
|
|
'exception_url': baseurl + '/payment/ogone/validate/exception',
|
|
'return_url': kwargs.get('return_url', baseurl)
|
|
}
|
|
tx = token.validate(**params)
|
|
res['verified'] = token.verified
|
|
|
|
if tx and tx.html_3ds:
|
|
res['3d_secure'] = tx.html_3ds
|
|
|
|
return res
|
|
|
|
@http.route(['/payment/ogone/s2s/create'], type='http', auth='public', methods=["POST"], csrf=False)
|
|
def ogone_s2s_create(self, **post):
|
|
error = ''
|
|
acq = request.env['payment.acquirer'].browse(int(post.get('acquirer_id')))
|
|
try:
|
|
token = acq.s2s_process(post)
|
|
except Exception as e:
|
|
# synthax error: 'CHECK ERROR: |Not a valid date\n\n50001111: None'
|
|
token = False
|
|
error = str(e).splitlines()[0].split('|')[-1] or ''
|
|
|
|
if token and post.get('verify_validity'):
|
|
baseurl = request.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
|
params = {
|
|
'accept_url': baseurl + '/payment/ogone/validate/accept',
|
|
'decline_url': baseurl + '/payment/ogone/validate/decline',
|
|
'exception_url': baseurl + '/payment/ogone/validate/exception',
|
|
'return_url': post.get('return_url', baseurl)
|
|
}
|
|
tx = token.validate(**params)
|
|
if tx and tx.html_3ds:
|
|
return tx.html_3ds
|
|
return werkzeug.utils.redirect(post.get('return_url', '/') + (error and '#error=%s' % werkzeug.url_quote(error) or ''))
|
|
|
|
@http.route([
|
|
'/payment/ogone/validate/accept',
|
|
'/payment/ogone/validate/decline',
|
|
'/payment/ogone/validate/exception',
|
|
], type='http', auth='none')
|
|
def ogone_validation_form_feedback(self, **post):
|
|
""" Feedback from 3d secure for a bank card validation """
|
|
request.env['payment.transaction'].sudo().form_feedback(post, 'ogone')
|
|
return werkzeug.utils.redirect(werkzeug.url_unquote(post.pop('return_url', '/')))
|
|
|
|
@http.route(['/payment/ogone/s2s/feedback'], auth='none', csrf=False)
|
|
def feedback(self, **kwargs):
|
|
try:
|
|
tx = request.env['payment.transaction'].sudo()._ogone_form_get_tx_from_data(kwargs)
|
|
tx._ogone_s2s_validate()
|
|
except ValidationError:
|
|
return 'ko'
|
|
return 'ok'
|