[REF] payment_buckaroo: migrate Buckaroo to the new payment API

See the merge commit for more details.

task-2333032
This commit is contained in:
Barad Mahendrasinh
2021-03-30 09:25:51 +02:00
committed by Antoine Vandevenne (anv)
parent 660dc0ebaf
commit 356c93a42d
14 changed files with 344 additions and 401 deletions
+6 -5
View File
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
from . import controllers
from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers
from odoo.addons.payment import reset_payment_provider
from . import models
from odoo.addons.payment import reset_payment_acquirer
from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook
def uninstall_hook(cr, registry):
reset_payment_provider(cr, registry, 'buckaroo')
reset_payment_acquirer(cr, registry, 'buckaroo')
+3 -4
View File
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Buckaroo Payment Acquirer',
'version': '2.0',
'category': 'Accounting/Payment Acquirers',
'sequence': 355,
'summary': 'Payment Acquirer: Buckaroo Implementation',
'version': '1.0',
'description': """Buckaroo Payment Acquirer""",
'depends': ['payment'],
'data': [
@@ -13,8 +13,7 @@
'views/payment_buckaroo_templates.xml',
'data/payment_acquirer_data.xml',
],
'installable': True,
'application': True,
'post_init_hook': 'create_missing_journal_for_acquirers',
'post_init_hook': 'create_missing_journals',
'uninstall_hook': 'uninstall_hook',
}
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import main
+11 -17
View File
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
import pprint
import werkzeug
from odoo import http
@@ -12,20 +13,13 @@ _logger = logging.getLogger(__name__)
class BuckarooController(http.Controller):
_return_url = '/payment/buckaroo/return'
_cancel_url = '/payment/buckaroo/cancel'
_exception_url = '/payment/buckaroo/error'
_reject_url = '/payment/buckaroo/reject'
@http.route([
'/payment/buckaroo/return',
'/payment/buckaroo/cancel',
'/payment/buckaroo/error',
'/payment/buckaroo/reject',
], type='http', auth='public', csrf=False)
def buckaroo_return(self, **post):
""" Buckaroo."""
_logger.info('Buckaroo: entering form_feedback with post data %s', pprint.pformat(post)) # debug
request.env['payment.transaction'].sudo().form_feedback(post, 'buckaroo')
post = {key.upper(): value for key, value in post.items()}
return_url = post.get('ADD_RETURNDATA') or '/'
return werkzeug.utils.redirect('/payment/process')
@http.route(_return_url, type='http', auth='public', methods=['POST'], csrf=False)
def buckaroo_return_from_redirect(self, **data):
""" Process the data returned by Buckaroo after redirection.
:param dict data: The feedback data
"""
_logger.info("received notification data:\n%s", pprint.pformat(data))
request.env['payment.transaction'].sudo()._handle_feedback_data('buckaroo', data)
return werkzeug.utils.redirect('/payment/status')
@@ -1,14 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<odoo noupdate="1">
<record id="payment.payment_acquirer_buckaroo" model="payment.acquirer">
<field name="name">Buckaroo</field>
<field name="image_128" type="base64" file="payment_buckaroo/static/src/img/buckaroo_icon.png"/>
<field name="provider">buckaroo</field>
<field name="company_id" ref="base.main_company"/>
<field name="view_template_id" ref="buckaroo_form"/>
</record>
<record id="payment.payment_acquirer_buckaroo" model="payment.acquirer">
<field name="provider">buckaroo</field>
<field name="redirect_form_view_id" ref="redirect_form"/>
<field name="support_authorization">False</field>
<field name="support_fees_computation">False</field>
<field name="support_tokenization">False</field>
</record>
</data>
</odoo>
+3 -2
View File
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import payment
from . import payment_acquirer
from . import payment_transaction
-192
View File
@@ -1,192 +0,0 @@
# coding: utf-8
from hashlib import sha1
import logging
from werkzeug import urls
from odoo import api, fields, models, _
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment_buckaroo.controllers.main import BuckarooController
from odoo.tools.float_utils import float_compare
_logger = logging.getLogger(__name__)
def normalize_keys_upper(data):
"""Set all keys of a dictionnary to uppercase
Buckaroo parameters names are case insensitive
convert everything to upper case to be able to easily detected the presence
of a parameter by checking the uppercase key only
"""
return {key.upper(): val for key, val in data.items()}
class AcquirerBuckaroo(models.Model):
_inherit = 'payment.acquirer'
provider = fields.Selection(selection_add=[
('buckaroo', 'Buckaroo')
], ondelete={'buckaroo': 'set default'})
brq_websitekey = fields.Char('WebsiteKey', required_if_provider='buckaroo', groups='base.group_user')
brq_secretkey = fields.Char('SecretKey', required_if_provider='buckaroo', groups='base.group_user')
def _get_buckaroo_urls(self, environment):
""" Buckaroo URLs
"""
if environment == 'prod':
return {
'buckaroo_form_url': 'https://checkout.buckaroo.nl/html/',
}
else:
return {
'buckaroo_form_url': 'https://testcheckout.buckaroo.nl/html/',
}
def _buckaroo_generate_digital_sign(self, inout, values):
""" Generate the shasign for incoming or outgoing communications.
:param browse acquirer: the payment.acquirer browse record. It should
have a shakey in shaky out
:param string inout: 'in' (odoo contacting buckaroo) or 'out' (buckaroo
contacting odoo).
:param dict values: transaction values
:return string: shasign
"""
assert inout in ('in', 'out')
assert self.provider == 'buckaroo'
keys = "add_returndata Brq_amount Brq_culture Brq_currency Brq_invoicenumber Brq_return Brq_returncancel Brq_returnerror Brq_returnreject brq_test Brq_websitekey".split()
def get_value(key):
if values.get(key):
return values[key]
return ''
values = dict(values or {})
if inout == 'out':
for key in list(values):
# case insensitive keys
if key.upper() == 'BRQ_SIGNATURE':
del values[key]
break
items = sorted(values.items(), key=lambda pair: pair[0].lower())
sign = ''.join('%s=%s' % (k, urls.url_unquote_plus(v)) for k, v in items)
else:
sign = ''.join('%s=%s' % (k, get_value(k)) for k in keys)
# Add the pre-shared secret key at the end of the signature
sign = sign + self.brq_secretkey
shasign = sha1(sign.encode('utf-8')).hexdigest()
return shasign
def buckaroo_form_generate_values(self, values):
base_url = self.get_base_url()
buckaroo_tx_values = dict(values)
buckaroo_tx_values.update({
'Brq_websitekey': self.brq_websitekey,
'Brq_amount': values['amount'],
'Brq_currency': values['currency'] and values['currency'].name or '',
'Brq_invoicenumber': values['reference'],
'brq_test': True if self.state == 'test' else False,
'Brq_return': urls.url_join(base_url, BuckarooController._return_url),
'Brq_returncancel': urls.url_join(base_url, BuckarooController._cancel_url),
'Brq_returnerror': urls.url_join(base_url, BuckarooController._exception_url),
'Brq_returnreject': urls.url_join(base_url, BuckarooController._reject_url),
'Brq_culture': (values.get('partner_lang') or 'en_US').replace('_', '-'),
'add_returndata': buckaroo_tx_values.pop('return_url', '') or '',
})
buckaroo_tx_values['Brq_signature'] = self._buckaroo_generate_digital_sign('in', buckaroo_tx_values)
return buckaroo_tx_values
def buckaroo_get_form_action_url(self):
self.ensure_one()
environment = 'prod' if self.state == 'enabled' else 'test'
return self._get_buckaroo_urls(environment)['buckaroo_form_url']
class TxBuckaroo(models.Model):
_inherit = 'payment.transaction'
# buckaroo status
_buckaroo_valid_tx_status = [190]
_buckaroo_pending_tx_status = [790, 791, 792, 793]
_buckaroo_cancel_tx_status = [890, 891]
_buckaroo_error_tx_status = [490, 491, 492]
_buckaroo_reject_tx_status = [690]
# --------------------------------------------------
# FORM RELATED METHODS
# --------------------------------------------------
@api.model
def _buckaroo_form_get_tx_from_data(self, data):
""" Given a data dict coming from buckaroo, verify it and find the related
transaction record. """
origin_data = dict(data)
data = normalize_keys_upper(data)
reference, pay_id, shasign = data.get('BRQ_INVOICENUMBER'), data.get('BRQ_PAYMENT'), data.get('BRQ_SIGNATURE')
if not reference or not pay_id or not shasign:
error_msg = _('Buckaroo: received data with missing reference (%s) or pay_id (%s) or shasign (%s)') % (reference, pay_id, shasign)
_logger.info(error_msg)
raise ValidationError(error_msg)
tx = self.search([('reference', '=', reference)])
if not tx or len(tx) > 1:
error_msg = _('Buckaroo: received data for reference %s') % (reference)
if not tx:
error_msg += _('; no order found')
else:
error_msg += _('; multiple order found')
_logger.info(error_msg)
raise ValidationError(error_msg)
# verify shasign
shasign_check = tx.acquirer_id._buckaroo_generate_digital_sign('out', origin_data)
if shasign_check.upper() != shasign.upper():
error_msg = _('Buckaroo: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data)
_logger.info(error_msg)
raise ValidationError(error_msg)
return tx
def _buckaroo_form_get_invalid_parameters(self, data):
invalid_parameters = []
data = normalize_keys_upper(data)
if self.acquirer_reference and data.get('BRQ_TRANSACTIONS') != self.acquirer_reference:
invalid_parameters.append(('Transaction Id', data.get('BRQ_TRANSACTIONS'), self.acquirer_reference))
# check what is buyed
if float_compare(float(data.get('BRQ_AMOUNT', '0.0')), self.amount, 2) != 0:
invalid_parameters.append(('Amount', data.get('BRQ_AMOUNT'), '%.2f' % self.amount))
if data.get('BRQ_CURRENCY') != self.currency_id.name:
invalid_parameters.append(('Currency', data.get('BRQ_CURRENCY'), self.currency_id.name))
return invalid_parameters
def _buckaroo_form_validate(self, data):
data = normalize_keys_upper(data)
status_code = int(data.get('BRQ_STATUSCODE', '0'))
if status_code in self._buckaroo_valid_tx_status:
self.write({'acquirer_reference': data.get('BRQ_TRANSACTIONS')})
self._set_transaction_done()
return True
elif status_code in self._buckaroo_pending_tx_status:
self.write({'acquirer_reference': data.get('BRQ_TRANSACTIONS')})
self._set_transaction_pending()
return True
elif status_code in self._buckaroo_cancel_tx_status:
self.write({'acquirer_reference': data.get('BRQ_TRANSACTIONS')})
self._set_transaction_cancel()
return True
else:
error = 'Buckaroo: feedback error'
_logger.info(error)
self.write({
'state_message': error,
'acquirer_reference': data.get('BRQ_TRANSACTIONS'),
})
self._set_transaction_cancel()
return False
@@ -0,0 +1,65 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from hashlib import sha1
from werkzeug import urls
from odoo import fields, models
class PaymentAcquirer(models.Model):
_inherit = 'payment.acquirer'
provider = fields.Selection(
selection_add=[('buckaroo', "Buckaroo")], ondelete={'buckaroo': 'set default'})
buckaroo_website_key = fields.Char(
string="Website Key", help="The key solely used to identify the website with Buckaroo",
required_if_provider='buckaroo')
buckaroo_secret_key = fields.Char(
string="Buckaroo Secret Key", required_if_provider='buckaroo', groups='base.group_system')
def _buckaroo_get_api_url(self):
""" Return the API URL according to the state.
Note: self.ensure_one()
:return: The API URL
:rtype: str
"""
self.ensure_one()
if self.state == 'enabled':
return 'https://checkout.buckaroo.nl/html/'
else:
return 'https://testcheckout.buckaroo.nl/html/'
def _buckaroo_generate_digital_sign(self, values, incoming=True):
""" Generate the shasign for incoming or outgoing communications.
:param dict values: The values used to generate the signature
:param bool incoming: Whether the signature must be generate for an incoming (Buckaroo to
Odoo) or outgoing (Odoo to Buckaroo) communication.
:return: The shasign
:rtype: str
"""
if incoming:
# Remove the signature from the values used to check the signature
for key in values.keys():
if key.upper() == 'BRQ_SIGNATURE': # Keys are case-insensitive
del values[key]
break
# Incoming communication values must be URL-decoded before checking the signature
items = [(k, urls.url_unquote_plus(v)) for k, v in values.items()]
else:
# Only use items whose key starts with 'add_', 'brq_', or 'cust_' (case insensitive)
items = [
(k, v) for k, v in values.items()
if any(k.upper().startswith(key_prefix) for key_prefix in ('ADD_', 'BRQ_', 'CUST_'))
]
# Sort parameters by upper-cased key name
sorted_items = sorted(items, key=lambda pair: pair[0].upper())
# Build the signing string by concatenating all parameters
sign_string = ''.join(f'{k}={v or ""}' for k, v in sorted_items)
# Append the pre-shared secret key to the signing string
sign_string += self.buckaroo_secret_key
# Calculate the SHA-1 hash over the signing string
return sha1(sign_string.encode('utf-8')).hexdigest()
@@ -0,0 +1,144 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from werkzeug import urls
from odoo import _, api, models
from odoo.exceptions import ValidationError
from odoo.addons.payment_buckaroo.controllers.main import BuckarooController
_logger = logging.getLogger(__name__)
def _normalize_dataset(data):
""" Set all keys of a dictionary to uppercase.
As Buckaroo parameters names are case insensitive, we can convert everything to upper case to
easily detected the presence of a parameter by checking the uppercase key only.
:param dict data: The dictionary whose keys must be set to uppercase
:return: A copy of the original data with all keys set to uppercase
:rtype: dict
"""
return {key.upper(): val for key, val in data.items()}
class PaymentTransaction(models.Model):
_inherit = 'payment.transaction'
# Buckaroo status codes
_pending_tx_status = [790, 791, 792, 793]
_valid_tx_status = [190]
_cancel_tx_status = [890, 891]
def _get_specific_rendering_values(self, processing_values):
""" Override of payment to return Buckaroo-specific rendering values.
Note: self.ensure_one() from `_get_processing_values`
:param dict processing_values: The generic and specific processing values of the transaction
:return: The dict of acquirer-specific processing values
:rtype: dict
"""
res = super()._get_specific_rendering_values(processing_values)
if self.provider != 'buckaroo':
return res
return_url = urls.url_join(self.acquirer_id._get_base_url(), BuckarooController._return_url)
rendering_values = {
'api_url': self.acquirer_id._buckaroo_get_api_url(),
'Brq_websitekey': self.acquirer_id.buckaroo_website_key,
'Brq_amount': self.amount,
'Brq_currency': self.currency_id.name,
'Brq_invoicenumber': self.reference,
# Include all 4 URL keys despite they share the same value as they are part of the sig.
'Brq_return': return_url,
'Brq_returncancel': return_url,
'Brq_returnerror': return_url,
'Brq_returnreject': return_url,
}
if self.partner_lang:
rendering_values['Brq_culture'] = self.partner_lang.replace('_', '-')
rendering_values['Brq_signature'] = self.acquirer_id._buckaroo_generate_digital_sign(
rendering_values, incoming=False
)
return rendering_values
@api.model
def _get_tx_from_feedback_data(self, provider, data):
""" Override of payment to find the transaction based on Buckaroo data.
:param str provider: The provider of the acquirer that handled the transaction
:param dict data: The feedback data sent by the provider
:return: The transaction if found
:rtype: recordset of `payment.transaction`
:raise: ValidationError if inconsistent data were received
:raise: ValidationError if the data match no transaction
:raise: ValidationError if the signature can not be verified
"""
tx = super()._get_tx_from_feedback_data(provider, data)
if provider != 'buckaroo':
return tx
normalized_data = _normalize_dataset(data)
reference = normalized_data.get('BRQ_INVOICENUMBER')
shasign = normalized_data.get('BRQ_SIGNATURE')
if not reference or not shasign:
raise ValidationError(
"Buckaroo: " + _(
"Received data with missing reference (%(ref)s) or shasign (%(sign))",
ref=reference, sign=shasign
)
)
tx = self.search([('reference', '=', reference), ('provider', '=', 'buckaroo')])
if not tx:
raise ValidationError(
"Buckaroo: " + _("No transaction found matching reference %s.", reference)
)
# Verify signature
shasign_check = tx.acquirer_id._buckaroo_generate_digital_sign(data, incoming=True)
if shasign_check != shasign:
raise ValidationError(
"Buckaroo: " + _(
"Invalid shasign: received %(sign)s, computed %(check)s",
sign=shasign, check=shasign_check
)
)
return tx
def _process_feedback_data(self, data):
""" Override of payment to process the transaction based on Buckaroo data.
Note: self.ensure_one()
:param dict data: The feedback data sent by the provider
:return: None
:raise: ValidationError if inconsistent data were received
"""
super()._process_feedback_data(data)
if self.provider != 'buckaroo':
return
normalized_data = _normalize_dataset(data)
transaction_keys = normalized_data.get('BRQ_TRANSACTIONS')
if not transaction_keys:
raise ValidationError("Buckaroo: " + _("Received data with missing transaction keys"))
# BRQ_TRANSACTIONS can hold multiple, comma-separated, tx keys. In practice, it holds only
# one reference. So we split for semantic correctness and keep the first transaction key.
self.acquirer_reference = transaction_keys.split(',')[0]
status_code = int(normalized_data.get('BRQ_STATUSCODE') or 0)
if status_code in self._pending_tx_status:
self._set_pending()
elif status_code in self._valid_tx_status:
self._set_done()
elif status_code in self._cancel_tx_status:
self._set_canceled()
else:
_logger.warning("Buckaroo: received unknown status code: %s", status_code)
self._set_error("Buckaroo: " + _("Unknown status code: %s", status_code))
+2 -1
View File
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import common
from . import test_buckaroo
+19
View File
@@ -0,0 +1,19 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.payment.tests.common import PaymentCommon
class BuckarooCommon(PaymentCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.buckaroo = cls._prepare_acquirer('buckaroo', update_values={
'buckaroo_website_key': 'dummy',
'buckaroo_secret_key': 'dummy',
})
# Override defaults
cls.acquirer = cls.buckaroo
cls.currency = cls.currency_euro
+52 -130
View File
@@ -1,120 +1,51 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from lxml import objectify
from werkzeug import urls
import odoo
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment.tests.common import PaymentAcquirerCommon
from odoo.addons.payment_buckaroo.controllers.main import BuckarooController
from odoo.exceptions import ValidationError
from odoo.tests import tagged
from odoo.tools import mute_logger
from .common import BuckarooCommon
from ..controllers.main import BuckarooController
@odoo.tests.tagged('post_install', '-at_install', 'external', '-standard')
class BuckarooCommon(PaymentAcquirerCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
# get the buckaroo account
cls.buckaroo = cls.env.ref('payment.payment_acquirer_buckaroo')
cls.buckaroo.write({
'brq_websitekey': 'dummy',
'brq_secretkey': 'dummy',
'state': 'test',
})
@tagged('post_install', '-at_install')
class BuckarooTest(BuckarooCommon):
@odoo.tests.tagged('post_install', '-at_install', 'external', '-standard')
class BuckarooForm(BuckarooCommon):
def test_10_Buckaroo_form_render(self):
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
# be sure not to do stupid things
self.assertEqual(self.buckaroo.state, 'test', 'test without test environment')
# ----------------------------------------
# Test: button direct rendering
# ----------------------------------------
form_values = {
'add_returndata': '/payment/process',
'Brq_websitekey': self.buckaroo.brq_websitekey,
'Brq_amount': '2240.0',
'Brq_currency': 'EUR',
'Brq_invoicenumber': 'SO004',
'Brq_signature': 'f09bb79451a7ddef3178462ea52b07e55d34e99e', # update me
'brq_test': 'True',
'Brq_return': urls.url_join(base_url, BuckarooController._return_url),
'Brq_returncancel': urls.url_join(base_url, BuckarooController._cancel_url),
'Brq_returnerror': urls.url_join(base_url, BuckarooController._exception_url),
'Brq_returnreject': urls.url_join(base_url, BuckarooController._reject_url),
def test_redirect_form_values(self):
return_url = self._build_url(BuckarooController._return_url)
expected_values = {
'Brq_websitekey': self.buckaroo.buckaroo_website_key,
'Brq_amount': str(self.amount),
'Brq_currency': self.currency.name,
'Brq_invoicenumber': self.reference,
'Brq_signature': '04c26578116990496770687a8bf225200e0f56e6',
'Brq_return': return_url,
'Brq_returncancel': return_url,
'Brq_returnerror': return_url,
'Brq_returnreject': return_url,
'Brq_culture': 'en-US',
}
# render the button
res = self.buckaroo.render(
'SO004', 2240.0, self.currency_euro.id,
partner_id=None,
values=self.buyer_values)
# check form result
tree = objectify.fromstring(res)
data_set = tree.xpath("//input[@name='data_set']")
self.assertEqual(len(data_set), 1, 'paypal: Found %d "data_set" input instead of 1' % len(data_set))
self.assertEqual(data_set[0].get('data-action-url'), 'https://testcheckout.buckaroo.nl/html/', 'Buckaroo: wrong form POST url')
for form_input in tree.input:
if form_input.get('name') in ['submit', 'data_set']:
continue
self.assertEqual(
form_input.get('value'),
form_values[form_input.get('name')],
'Buckaroo: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
)
tx_sudo = self.create_transaction(flow='redirect')
with mute_logger('odoo.addons.payment.models.payment_transaction'):
processing_values = tx_sudo._get_processing_values()
form_info = self._extract_values_from_html_form(processing_values['redirect_form_html'])
# ----------------------------------------
# Test2: button using tx + validation
# ----------------------------------------
self.assertEqual(form_info['action'], "https://testcheckout.buckaroo.nl/html/")
self.assertDictEqual(expected_values, form_info['inputs'],
"Buckaroo: invalid inputs specified in the redirect form.")
# create a new draft tx
tx = self.env['payment.transaction'].create({
'amount': 2240.0,
'acquirer_id': self.buckaroo.id,
'currency_id': self.currency_euro.id,
'reference': 'SO004',
'partner_id': self.buyer_id,
})
# render the button
res = self.buckaroo.render(
'should_be_erased', 2240.0, self.currency_euro,
partner_id=None,
values=self.buyer_values)
# check form result
tree = objectify.fromstring(res)
data_set = tree.xpath("//input[@name='data_set']")
self.assertEqual(len(data_set), 1, 'paypal: Found %d "data_set" input instead of 1' % len(data_set))
self.assertEqual(data_set[0].get('data-action-url'), 'https://testcheckout.buckaroo.nl/html/', 'Buckaroo: wrong form POST url')
for form_input in tree.input:
if form_input.get('name') in ['submit', 'data_set']:
continue
self.assertEqual(
form_input.get('value'),
form_values[form_input.get('name')],
'Buckaroo: wrong value for form input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')])
)
@mute_logger('odoo.addons.payment_buckaroo.models.payment', 'ValidationError')
def test_20_buckaroo_form_management(self):
# be sure not to do stupid thing
self.assertEqual(self.buckaroo.state, 'test', 'test without test environment')
def test_feedback_processing(self):
self.amount = 2240.0
self.reference = 'SO004'
# typical data posted by buckaroo after client has successfully paid
buckaroo_post_data = {
'BRQ_RETURNDATA': u'',
'BRQ_AMOUNT': u'2240.00',
'BRQ_CURRENCY': u'EUR',
'BRQ_AMOUNT': str(self.amount),
'BRQ_CURRENCY': self.currency.name,
'BRQ_CUSTOMER_NAME': u'Jan de Tester',
'BRQ_INVOICENUMBER': u'SO004',
'BRQ_INVOICENUMBER': self.reference,
'brq_payment': u'573311D081B04069BD6336001611DBD4',
'BRQ_PAYMENT_METHOD': u'paypal',
'BRQ_SERVICE_PAYPAL_PAYERCOUNTRY': u'NL',
@@ -123,52 +54,43 @@ class BuckarooForm(BuckarooCommon):
'BRQ_SERVICE_PAYPAL_PAYERLASTNAME': u'Tester',
'BRQ_SERVICE_PAYPAL_PAYERMIDDLENAME': u'de',
'BRQ_SERVICE_PAYPAL_PAYERSTATUS': u'verified',
'Brq_signature': u'9e75e51cbcb6fbc798b40d1787cc5b7c36557d56',
'Brq_signature': u'e439f3af06b9752197631715628d6a198a25900f',
'BRQ_STATUSCODE': u'190',
'BRQ_STATUSCODE_DETAIL': u'S001',
'BRQ_STATUSMESSAGE': u'Transaction successfully processed',
'BRQ_TEST': u'true',
'BRQ_TIMESTAMP': u'2014-05-08 12:41:21',
'BRQ_TRANSACTIONS': u'D6106678E1D54EEB8093F5B3AC42EA7B',
'BRQ_WEBSITEKEY': u'5xTGyGyPyl',
}
# should raise error about unknown tx
with self.assertRaises(ValidationError):
self.env['payment.transaction'].form_feedback(buckaroo_post_data, 'buckaroo')
with self.assertRaises(ValidationError): # unknown transaction
self.env['payment.transaction']._handle_feedback_data('buckaroo', buckaroo_post_data)
tx = self.env['payment.transaction'].create({
'amount': 2240.0,
'acquirer_id': self.buckaroo.id,
'currency_id': self.currency_euro.id,
'reference': 'SO004',
'partner_name': 'Norbert Buyer',
'partner_country_id': self.country_france.id})
tx = self.create_transaction(flow='redirect')
# validate it
tx.form_feedback(buckaroo_post_data, 'buckaroo')
# check state
tx._handle_feedback_data('buckaroo', buckaroo_post_data)
self.assertEqual(tx.state, 'done', 'Buckaroo: validation did not put tx into done state')
self.assertEqual(tx.acquirer_reference, buckaroo_post_data.get('BRQ_TRANSACTIONS'), 'Buckaroo: validation did not update tx payid')
self.assertEqual(tx.acquirer_reference, buckaroo_post_data.get('BRQ_TRANSACTIONS'),
'Buckaroo: validation did not update tx payid')
# reset tx
tx = self.env['payment.transaction'].create({
'amount': 2240.0,
'acquirer_id': self.buckaroo.id,
'currency_id': self.currency_euro.id,
'reference': 'SO004-2',
'partner_name': 'Norbert Buyer',
'partner_country_id': self.country_france.id})
# New reference for new tx
self.reference = 'SO004-2'
tx = self.create_transaction(flow='redirect')
buckaroo_post_data['BRQ_INVOICENUMBER'] = 'SO004-2'
buckaroo_post_data['BRQ_INVOICENUMBER'] = self.reference
# now buckaroo post is ok: try to modify the SHASIGN
buckaroo_post_data['Brq_signature'] = '54d928810e343acf5fb0c3ee75fd747ff159ef7a'
with self.assertRaises(ValidationError):
tx.form_feedback(buckaroo_post_data, 'buckaroo')
self.env['payment.transaction']._handle_feedback_data('buckaroo', buckaroo_post_data)
# simulate an error
buckaroo_post_data['BRQ_STATUSCODE'] = '2'
buckaroo_post_data['Brq_signature'] = '9138e2bf09a708a4eb485ce7777e5406898b689d'
tx.form_feedback(buckaroo_post_data, 'buckaroo')
buckaroo_post_data['Brq_signature'] = 'b8e54e26b2b5a5e697b8ed5085329ea712fd48b2'
# check state
self.assertEqual(tx.state, 'cancel', 'Buckaroo: erroneous validation did not put tx into error state')
# Avoid warning log bc of unknown status code
with mute_logger('odoo.addons.payment_buckaroo.models.payment_transaction'):
self.env['payment.transaction']._handle_feedback_data('buckaroo', buckaroo_post_data)
self.assertEqual(tx.state, 'error',
'Buckaroo: unexpected status code should put tx in error state')
@@ -1,27 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<template id="buckaroo_form">
<div>
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
<input type="hidden" name="Brq_websitekey" t-att-value="Brq_websitekey"/>
<input type="hidden" name="Brq_amount" t-att-value="Brq_amount"/>
<input type="hidden" name="Brq_currency" t-att-value="Brq_currency"/>
<input type="hidden" name="Brq_invoicenumber" t-att-value="Brq_invoicenumber"/>
<input type="hidden" name="Brq_signature" t-att-value="Brq_signature"/>
<input type="hidden" name="brq_test" t-att-value="brq_test"/>
<input type="hidden" name="Brq_culture" t-att-value="Brq_culture"/>
<!-- URLs -->
<input t-if="Brq_return" type="hidden" name='Brq_return'
t-att-value="Brq_return"/>
<input t-if="Brq_returncancel" type="hidden" name='Brq_returncancel'
t-att-value="Brq_returncancel"/>
<input t-if="Brq_returnerror" type="hidden" name='Brq_returnerror'
t-att-value="Brq_returnerror"/>
<input t-if="Brq_returnreject" type="hidden" name='Brq_returnreject'
t-att-value="Brq_returnreject"/>
<input type="hidden" name='add_returndata' t-att-value="add_returndata"/>
</div>
</template>
</data>
<template id="redirect_form">
<form t-att-action="api_url" method="post">
<input type="hidden" name="Brq_websitekey" t-att-value="Brq_websitekey"/>
<input type="hidden" name="Brq_amount" t-att-value="Brq_amount"/>
<input type="hidden" name="Brq_currency" t-att-value="Brq_currency"/>
<input type="hidden" name="Brq_invoicenumber" t-att-value="Brq_invoicenumber"/>
<input type="hidden" name="Brq_signature" t-att-value="Brq_signature"/>
<input t-if="Brq_culture" type="hidden" name="Brq_culture" t-att-value="Brq_culture"/>
<!-- URLs -->
<input type="hidden" name="Brq_return" t-att-value="Brq_return"/>
<input type="hidden" name="Brq_returncancel" t-att-value="Brq_returncancel"/>
<input type="hidden" name="Brq_returnerror" t-att-value="Brq_returnerror"/>
<input type="hidden" name="Brq_returnreject" t-att-value="Brq_returnreject"/>
</form>
</template>
</odoo>
+13 -15
View File
@@ -1,20 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="acquirer_form_buckaroo" model="ir.ui.view">
<field name="name">acquirer.form.buckaroo</field>
<field name="model">payment.acquirer</field>
<field name="inherit_id" ref="payment.acquirer_form"/>
<field name="arch" type="xml">
<xpath expr='//group[@name="acquirer"]' position='inside'>
<group attrs="{'invisible': [('provider', '!=', 'buckaroo')]}">
<field name="brq_websitekey" attrs="{'required':[ ('provider', '=', 'buckaroo'), ('state', '!=', 'disabled')]}"/>
<field name="brq_secretkey" attrs="{'required':[ ('provider', '=', 'buckaroo'), ('state', '!=', 'disabled')]}"/>
</group>
</xpath>
</field>
</record>
<record id="payment_acquirer_form" model="ir.ui.view">
<field name="name">Buckaroo Acquirer Form</field>
<field name="model">payment.acquirer</field>
<field name="inherit_id" ref="payment.payment_acquirer_form"/>
<field name="arch" type="xml">
<xpath expr='//group[@name="acquirer"]' position='inside'>
<group attrs="{'invisible': [('provider', '!=', 'buckaroo')]}">
<field name="buckaroo_website_key" attrs="{'required':[ ('provider', '=', 'buckaroo'), ('state', '!=', 'disabled')]}"/>
<field name="buckaroo_secret_key" string="Secret Key" attrs="{'required':[ ('provider', '=', 'buckaroo'), ('state', '!=', 'disabled')]}"/>
</group>
</xpath>
</field>
</record>
</data>
</odoo>