From e05f4612ebbd758088bc31fd42d4b0ed2094d4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 12:40:23 +0200 Subject: [PATCH] [MIG] payment_adyen: new API No functional change. --- addons/payment_adyen/controllers/main.py | 11 +- .../data/payment_acquirer_data.xml | 4 +- addons/payment_adyen/models/payment.py | 124 ++++++++---------- addons/payment_adyen/tests/test_adyen.py | 47 ++----- .../views/payment_adyen_templates.xml | 4 +- addons/payment_adyen/views/payment_views.xml | 4 +- 6 files changed, 74 insertions(+), 120 deletions(-) diff --git a/addons/payment_adyen/controllers/main.py b/addons/payment_adyen/controllers/main.py index de05f72d66b..b6b4331e578 100644 --- a/addons/payment_adyen/controllers/main.py +++ b/addons/payment_adyen/controllers/main.py @@ -5,8 +5,8 @@ import logging import pprint import werkzeug -from openerp import http, SUPERUSER_ID -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) @@ -20,7 +20,7 @@ class AdyenController(http.Controller): def adyen_return(self, **post): _logger.info('Beginning Adyen form_feedback with post data %s', pprint.pformat(post)) # debug if post.get('authResult') not in ['CANCELLED']: - request.registry['payment.transaction'].form_feedback(request.cr, SUPERUSER_ID, post, 'adyen', context=request.context) + request.env['payment.transaction'].sudo().form_feedback(post, 'adyen') return_url = post.pop('return_url', '') if not return_url: custom = json.loads(post.pop('merchantReturnData', '{}')) @@ -31,9 +31,8 @@ class AdyenController(http.Controller): '/payment/adyen/notification', ], type='http', auth='none', methods=['POST'], csrf=False) def adyen_notification(self, **post): - tx_id = post.get('merchantReference') and request.registry['payment.transaction'].search(request.cr, SUPERUSER_ID, [('reference', 'in', [post.get('merchantReference')])], limit=1, context=request.context) - if post.get('eventCode') in ['AUTHORISATION'] and tx_id: - tx = request.registry['payment.transaction'].browse(request.cr, SUPERUSER_ID, tx_id, context=request.context) + tx = post.get('merchantReference') and request.env['payment.transaction'].sudo().search([('reference', 'in', [post.get('merchantReference')])], limit=1) + if post.get('eventCode') in ['AUTHORISATION'] and tx: states = (post.get('merchantReference'), post.get('success'), tx.state) if (post.get('success') == 'true' and tx.state == 'done') or (post.get('success') == 'false' and tx.state in ['cancel', 'error']): _logger.info('Notification from Adyen for the reference %s: received %s, state is %s', states) diff --git a/addons/payment_adyen/data/payment_acquirer_data.xml b/addons/payment_adyen/data/payment_acquirer_data.xml index dbbc9bfd9bb..3d7ef2a1778 100644 --- a/addons/payment_adyen/data/payment_acquirer_data.xml +++ b/addons/payment_adyen/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -17,4 +17,4 @@ - + diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index c06ae797b0b..edf19953bab 100644 --- a/addons/payment_adyen/models/payment.py +++ b/addons/payment_adyen/models/payment.py @@ -9,46 +9,35 @@ import hmac import logging import urlparse -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_adyen.controllers.main import AdyenController -from openerp.osv import osv, fields -from openerp.tools import float_round -from openerp.tools.translate import _ +from odoo import api, fields, models, tools, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_adyen.controllers.main import AdyenController _logger = logging.getLogger(__name__) -class AcquirerAdyen(osv.Model): +class AcquirerAdyen(models.Model): _inherit = 'payment.acquirer' - def _get_adyen_urls(self, cr, uid, environment, context=None): - """ Adyen URLs + provider = fields.Selection(selection_add=[('adyen', 'Adyen')]) + adyen_merchant_account = fields.Char('Merchant Account', required_if_provider='adyen') + adyen_skin_code = fields.Char('Skin Code', required_if_provider='adyen') + adyen_skin_hmac_key = fields.Char('Skin HMAC Key', required_if_provider='adyen') - - yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple - """ + @api.model + def _get_adyen_urls(self, environment): + """ Adyen URLs: yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple """ return { 'adyen_form_url': 'https://%s.adyen.com/hpp/pay.shtml' % ('live' if environment == 'prod' else environment), } - def _get_providers(self, cr, uid, context=None): - providers = super(AcquirerAdyen, self)._get_providers(cr, uid, context=context) - providers.append(['adyen', 'Adyen']) - return providers - - _columns = { - 'adyen_merchant_account': fields.char('Merchant Account', required_if_provider='adyen'), - 'adyen_skin_code': fields.char('Skin Code', required_if_provider='adyen'), - 'adyen_skin_hmac_key': fields.char('Skin HMAC Key', required_if_provider='adyen'), - } - - def _adyen_generate_merchant_sig_sha256(self, acquirer, inout, values): + @api.multi + def _adyen_generate_merchant_sig_sha256(self, inout, values): """ Generate the shasign for incoming or outgoing communications., when using the SHA-256 signature. - :param browse acquirer: the payment.acquirer browse record. It should - have a shakey in shaky out - :param string inout: 'in' (openerp contacting ogone) or 'out' (adyen - contacting openerp). In this last case only some + :param string inout: 'in' (odoo contacting ogone) or 'out' (adyen + contacting odoo). In this last case only some fields should be contained (see e-Commerce basic) :param dict values: transaction values :return string: shasign @@ -62,7 +51,7 @@ class AcquirerAdyen(osv.Model): return base64.b64encode(hm.digest()) assert inout in ('in', 'out') - assert acquirer.provider == 'adyen' + assert self.provider == 'adyen' if inout == 'in': # All the fields sent to Adyen must be included in the signature. ALL the fucking @@ -83,27 +72,26 @@ class AcquirerAdyen(osv.Model): 'pspReference', 'shopperLocale', 'skinCode', ] - hmac_key = binascii.a2b_hex(acquirer.adyen_skin_hmac_key.encode('ascii')) + hmac_key = binascii.a2b_hex(self.adyen_skin_hmac_key.encode('ascii')) raw_values = {k: values.get(k.encode('ascii'), '') for k in keys if k in values} raw_values_ordered = OrderedDict(sorted(raw_values.items(), key=lambda t: t[0])) return signParams(raw_values_ordered) - def _adyen_generate_merchant_sig(self, acquirer, inout, values): + @api.multi + def _adyen_generate_merchant_sig(self, inout, values): """ Generate the shasign for incoming or outgoing communications, when using the SHA-1 signature (deprecated by Adyen). - :param browse acquirer: the payment.acquirer browse record. It should - have a shakey in shaky out - :param string inout: 'in' (openerp contacting ogone) or 'out' (adyen - contacting openerp). In this last case only some + :param string inout: 'in' (odoo contacting ogone) or 'out' (adyen + contacting odoo). In this last case only some fields should be contained (see e-Commerce basic) :param dict values: transaction values :return string: shasign """ assert inout in ('in', 'out') - assert acquirer.provider == 'adyen' + assert self.provider == 'adyen' if inout == 'in': keys = "paymentAmount currencyCode shipBeforeDate merchantReference skinCode merchantAccount sessionValidity shopperEmail shopperReference recurringContract allowedMethods blockedMethods shopperStatement merchantReturnData billingAddressType deliveryAddressType offset".split() @@ -116,66 +104,67 @@ class AcquirerAdyen(osv.Model): return '' sign = ''.join('%s' % get_value(k) for k in keys).encode('ascii') - key = acquirer.adyen_skin_hmac_key.encode('ascii') + key = self.adyen_skin_hmac_key.encode('ascii') return base64.b64encode(hmac.new(key, sign, hashlib.sha1).digest()) - def adyen_form_generate_values(self, cr, uid, ids, values, context=None): - base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def adyen_form_generate_values(self, values): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') # tmp import datetime from dateutil import relativedelta - if acquirer.provider == 'adyen' and len(acquirer.adyen_skin_hmac_key) == 64: + if self.provider == 'adyen' and len(self.adyen_skin_hmac_key) == 64: tmp_date = datetime.datetime.today() + relativedelta.relativedelta(days=1) values.update({ 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), + 'paymentAmount': '%d' % int(tools.float_round(values['amount'], 2) * 100), 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date.strftime('%Y-%m-%d'), - 'skinCode': acquirer.adyen_skin_code, - 'merchantAccount': acquirer.adyen_merchant_account, + 'skinCode': self.adyen_skin_code, + 'merchantAccount': self.adyen_merchant_account, 'shopperLocale': values.get('partner_lang', ''), 'sessionValidity': tmp_date.isoformat('T')[:19] + "Z", 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url', '') else False, 'shopperEmail': values.get('partner_email', ''), }) - values['merchantSig'] = self._adyen_generate_merchant_sig_sha256(acquirer, 'in', values) + values['merchantSig'] = self._adyen_generate_merchant_sig_sha256('in', values) else: tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1) values.update({ 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), + 'paymentAmount': '%d' % int(tools.float_round(values['amount'], 2) * 100), 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date, - 'skinCode': acquirer.adyen_skin_code, - 'merchantAccount': acquirer.adyen_merchant_account, + 'skinCode': self.adyen_skin_code, + 'merchantAccount': self.adyen_merchant_account, 'shopperLocale': values.get('partner_lang'), 'sessionValidity': tmp_date, 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url') else False, - 'merchantSig': self._adyen_generate_merchant_sig(acquirer, 'in', values), + 'merchantSig': self._adyen_generate_merchant_sig('in', values), }) return values - def adyen_get_form_action_url(self, cr, uid, ids, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - return self._get_adyen_urls(cr, uid, acquirer.environment, context=context)['adyen_form_url'] + @api.multi + def adyen_get_form_action_url(self): + return self._get_adyen_urls(self.environment)['adyen_form_url'] -class TxAdyen(osv.Model): +class TxAdyen(models.Model): _inherit = 'payment.transaction' # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- - def _adyen_form_get_tx_from_data(self, cr, uid, data, context=None): + @api.model + def _adyen_form_get_tx_from_data(self, data): reference, pspReference = data.get('merchantReference'), data.get('pspReference') if not reference or not pspReference: error_msg = _('Adyen: received data with missing reference (%s) or missing pspReference (%s)') % (reference, pspReference) @@ -183,22 +172,21 @@ class TxAdyen(osv.Model): raise ValidationError(error_msg) # find tx -> @TDENOTE use pspReference ? - tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) - if not tx_ids or len(tx_ids) > 1: + tx = self.env['payment.transaction'].search([('reference', '=', reference)]) + if not tx or len(tx) > 1: error_msg = _('Adyen: received data for reference %s') % (reference) - if not tx_ids: + if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) - tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) # verify shasign if len(tx.acquirer_id.adyen_skin_hmac_key) == 64: - shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig_sha256(tx.acquirer_id, 'out', data) + shasign_check = tx.acquirer_id._adyen_generate_merchant_sig_sha256('out', data) else: - shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig(tx.acquirer_id, 'out', data) + shasign_check = tx.acquirer_id._adyen_generate_merchant_sig('out', data) if shasign_check != data.get('merchantSig'): error_msg = _('Adyen: invalid merchantSig, received %s, computed %s') % (data.get('merchantSig'), shasign_check) _logger.warning(error_msg) @@ -206,27 +194,25 @@ class TxAdyen(osv.Model): return tx - def _adyen_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _adyen_form_get_invalid_parameters(self, data): invalid_parameters = [] # reference at acquirer: pspReference - if tx.acquirer_reference and data.get('pspReference') != tx.acquirer_reference: - invalid_parameters.append(('pspReference', data.get('pspReference'), tx.acquirer_reference)) + if self.acquirer_reference and data.get('pspReference') != self.acquirer_reference: + invalid_parameters.append(('pspReference', data.get('pspReference'), self.acquirer_reference)) # seller - if data.get('skinCode') != tx.acquirer_id.adyen_skin_code: - invalid_parameters.append(('skinCode', data.get('skinCode'), tx.acquirer_id.adyen_skin_code)) + if data.get('skinCode') != self.acquirer_id.adyen_skin_code: + invalid_parameters.append(('skinCode', data.get('skinCode'), self.acquirer_id.adyen_skin_code)) # result if not data.get('authResult'): invalid_parameters.append(('authResult', data.get('authResult'), 'something')) return invalid_parameters - def _adyen_form_validate(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _adyen_form_validate(self, data): status = data.get('authResult', 'PENDING') if status == 'AUTHORISED': - tx.write({ + self.write({ 'state': 'done', 'acquirer_reference': data.get('pspReference'), # 'date_validate': data.get('payment_date', fields.datetime.now()), @@ -234,7 +220,7 @@ class TxAdyen(osv.Model): }) return True elif status == 'PENDING': - tx.write({ + self.write({ 'state': 'pending', 'acquirer_reference': data.get('pspReference'), }) @@ -242,7 +228,7 @@ class TxAdyen(osv.Model): else: error = _('Adyen: feedback error') _logger.info(error) - tx.write({ + self.write({ 'state': 'error', 'state_message': error }) diff --git a/addons/payment_adyen/tests/test_adyen.py b/addons/payment_adyen/tests/test_adyen.py index 710bdf4e9e0..2015df6922e 100644 --- a/addons/payment_adyen/tests/test_adyen.py +++ b/addons/payment_adyen/tests/test_adyen.py @@ -3,21 +3,14 @@ from lxml import objectify import urlparse -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment.tests.common import PaymentAcquirerCommon -from openerp.addons.payment_adyen.controllers.main import AdyenController -from openerp.tools import mute_logger +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.addons.payment_adyen.controllers.main import AdyenController class AdyenCommon(PaymentAcquirerCommon): def setUp(self): super(AdyenCommon, self).setUp() - cr, uid = self.cr, self.uid - self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - - # get the adyen account - model, self.adyen_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment', 'payment_acquirer_adyen') # some CC (always use expiration date 06 / 2016, cvc 737, cid 7373 (amex)) self.amex = (('370000000000002', '7373')) @@ -36,40 +29,32 @@ class AdyenCommon(PaymentAcquirerCommon): self.mistercash = (('6703444444444449', None, 'user', 'password')) -class AdyenServer2Server(AdyenCommon): - - def test_00_tx_management(self): - cr, uid, context = self.cr, self.uid, {} - - class AdyenForm(AdyenCommon): def test_10_adyen_form_render(self): - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid things - adyen = self.payment_acquirer.browse(self.cr, self.uid, self.adyen_id, None) + adyen = self.env.ref('payment.payment_acquirer_adyen') self.assertEqual(adyen.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering # ---------------------------------------- + base_url = self.env['ir.config_parameter'].get_param('web.base.url') form_values = { 'merchantAccount': 'OpenERPCOM', 'merchantReference': 'test_ref0', 'skinCode': 'cbqYWvVL', 'paymentAmount': '1', 'currencyCode': 'EUR', - 'resURL': '%s' % urlparse.urljoin(self.base_url, AdyenController._return_url), + 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), } # render the button - res = self.payment_acquirer.render( - cr, uid, self.adyen_id, - 'test_ref0', 0.01, self.currency_euro_id, + res = adyen.render( + 'test_ref0', 0.01, self.currency_euro.id, partner_id=None, - partner_values=self.buyer_values, - context=context) + partner_values=self.buyer_values) # check form result tree = objectify.fromstring(res) @@ -82,19 +67,3 @@ class AdyenForm(AdyenCommon): form_values[form_input.get('name')], 'adyen: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')]) ) - - # @mute_logger('openerp.addons.payment_adyen.models.adyen', 'ValidationError') - # def test_20_paypal_form_management(self): - # cr, uid, context = self.cr, self.uid, {} - # # be sure not to do stupid things - # adyen = self.payment_acquirer.browse(self.cr, self.uid, self.adyen_id, None) - # self.assertEqual(adyen.env, 'test', 'test without test env') - -# {'authResult': u'AUTHORISED', -# 'merchantReference': u'SO014', -# 'merchantReturnData': u'return_url=/shop/payment/validate', -# 'merchantSig': u'GaLRO8aMHFaQX3gQ5BVP/YETzeA=', -# 'paymentMethod': u'visa', -# 'pspReference': u'8813859935907337', -# 'shopperLocale': u'en_US', -# 'skinCode': u'cbqYWvVL'} \ No newline at end of file diff --git a/addons/payment_adyen/views/payment_adyen_templates.xml b/addons/payment_adyen/views/payment_adyen_templates.xml index ff92d21dce2..4b8d178ef69 100644 --- a/addons/payment_adyen/views/payment_adyen_templates.xml +++ b/addons/payment_adyen/views/payment_adyen_templates.xml @@ -1,5 +1,5 @@ - + - + diff --git a/addons/payment_adyen/views/payment_views.xml b/addons/payment_adyen/views/payment_views.xml index fde4880a9fa..6914a28ff35 100644 --- a/addons/payment_adyen/views/payment_views.xml +++ b/addons/payment_adyen/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -19,4 +19,4 @@ - +