From 37c3ed60f690285e4e9c363bf816c54c586319e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Dec 2013 16:02:18 +0100 Subject: [PATCH 1/3] [IMP] [WIP] website_sale: beginning of cleaning acquirer choice (should be small icon + pay now button) bzr revid: tde@openerp.com-20131202150218-i403w7ulnm3b7b1n --- addons/website_sale/views/website_sale.xml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/addons/website_sale/views/website_sale.xml b/addons/website_sale/views/website_sale.xml index 13af89ea937..32d43f2dafa 100644 --- a/addons/website_sale/views/website_sale.xml +++ b/addons/website_sale/views/website_sale.xml @@ -879,17 +879,20 @@
-

Payment method:

-
+

Choose your payment method

+
+ + +
+
- -
From 19ea5b9674a725e60a9703c6f8df3c49b48eedf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Dec 2013 16:03:42 +0100 Subject: [PATCH 2/3] [ADD] payment_acquirer_adyen: Adyen payment acquirer Added support of adyen, only form-based. Please refer to adyen.com for more details about the acquirer. This is a classic implementation of a form-based acquirer with its controller, and alread integrated in the ecommerce. Tests will be improved. bzr revid: tde@openerp.com-20131202150342-191ipeoeru0jssah --- addons/payment_acquirer_adyen/__init__.py | 23 ++ addons/payment_acquirer_adyen/__openerp__.py | 17 ++ .../controllers/__init__.py | 3 + .../controllers/main.py | 31 +++ addons/payment_acquirer_adyen/data/adyen.xml | 15 ++ .../payment_acquirer_adyen/doc/changelog.rst | 9 + addons/payment_acquirer_adyen/doc/index.rst | 14 ++ .../payment_acquirer_adyen/models/__init__.py | 3 + addons/payment_acquirer_adyen/models/adyen.py | 198 ++++++++++++++++ .../static/description/icon.png | Bin 0 -> 11578 bytes .../static/src/img/logo.jpg | Bin 0 -> 4095 bytes .../payment_acquirer_adyen/tests/__init__.py | 7 + .../tests/test_adyen.py | 220 ++++++++++++++++++ addons/payment_acquirer_adyen/views/adyen.xml | 30 +++ .../views/payment_acquirer.xml | 35 +++ 15 files changed, 605 insertions(+) create mode 100644 addons/payment_acquirer_adyen/__init__.py create mode 100644 addons/payment_acquirer_adyen/__openerp__.py create mode 100644 addons/payment_acquirer_adyen/controllers/__init__.py create mode 100644 addons/payment_acquirer_adyen/controllers/main.py create mode 100644 addons/payment_acquirer_adyen/data/adyen.xml create mode 100644 addons/payment_acquirer_adyen/doc/changelog.rst create mode 100644 addons/payment_acquirer_adyen/doc/index.rst create mode 100644 addons/payment_acquirer_adyen/models/__init__.py create mode 100644 addons/payment_acquirer_adyen/models/adyen.py create mode 100644 addons/payment_acquirer_adyen/static/description/icon.png create mode 100644 addons/payment_acquirer_adyen/static/src/img/logo.jpg create mode 100644 addons/payment_acquirer_adyen/tests/__init__.py create mode 100644 addons/payment_acquirer_adyen/tests/test_adyen.py create mode 100644 addons/payment_acquirer_adyen/views/adyen.xml create mode 100644 addons/payment_acquirer_adyen/views/payment_acquirer.xml diff --git a/addons/payment_acquirer_adyen/__init__.py b/addons/payment_acquirer_adyen/__init__.py new file mode 100644 index 00000000000..dde6f25c728 --- /dev/null +++ b/addons/payment_acquirer_adyen/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013-Today OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import models +import controllers diff --git a/addons/payment_acquirer_adyen/__openerp__.py b/addons/payment_acquirer_adyen/__openerp__.py new file mode 100644 index 00000000000..e2344c88406 --- /dev/null +++ b/addons/payment_acquirer_adyen/__openerp__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +{ + 'name': 'Adyen Payment Acquirer', + 'category': 'Hidden', + 'summary': 'Payment Acquirer: Adyen Implementation', + 'version': '1.0', + 'description': """Adyen Payment Acquirer""", + 'author': 'OpenERP SA', + 'depends': ['payment_acquirer'], + 'data': [ + 'views/adyen.xml', + 'views/payment_acquirer.xml', + 'data/adyen.xml', + ], + 'installable': True, +} diff --git a/addons/payment_acquirer_adyen/controllers/__init__.py b/addons/payment_acquirer_adyen/controllers/__init__.py new file mode 100644 index 00000000000..bbd183e955b --- /dev/null +++ b/addons/payment_acquirer_adyen/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import main diff --git a/addons/payment_acquirer_adyen/controllers/main.py b/addons/payment_acquirer_adyen/controllers/main.py new file mode 100644 index 00000000000..2ea9fb00c51 --- /dev/null +++ b/addons/payment_acquirer_adyen/controllers/main.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from openerp.addons.web import http +from openerp.addons.web.http import request +from openerp.addons.website.models import website + +try: + import simplejson as json +except ImportError: + import json +import logging +import pprint + +_logger = logging.getLogger(__name__) + + +class AdyenController(http.Controller): + _return_url = '/payment/adyen/return/' + + @website.route([ + '/payment/adyen/return/', + ], type='http', auth='public') + def adyen_return(self, **post): + """ Paypal IPN. """ + _logger.info('Beginning Adyen form_feedback with post data %s', pprint.pformat(post)) # debug + request.registry['payment.transaction'].form_feedback(request.cr, request.uid, post, 'adyen', context=request.context) + return_url = post.pop('return_url', '') + if not return_url: + custom = json.loads(post.pop('merchantReturnData', '{}')) + return_url = custom.pop('return_url', '/') + return request.redirect(return_url) diff --git a/addons/payment_acquirer_adyen/data/adyen.xml b/addons/payment_acquirer_adyen/data/adyen.xml new file mode 100644 index 00000000000..ec5cb3c7373 --- /dev/null +++ b/addons/payment_acquirer_adyen/data/adyen.xml @@ -0,0 +1,15 @@ + + + + + + adyen + + test + OpenERPCOM + cbqYWvVL + cbqYWvVL + + + + diff --git a/addons/payment_acquirer_adyen/doc/changelog.rst b/addons/payment_acquirer_adyen/doc/changelog.rst new file mode 100644 index 00000000000..d0c24af384d --- /dev/null +++ b/addons/payment_acquirer_adyen/doc/changelog.rst @@ -0,0 +1,9 @@ +.. _changelog: + +Changelog +========= + +`trunk (saas-3)` +---------------- + +- Module creation \ No newline at end of file diff --git a/addons/payment_acquirer_adyen/doc/index.rst b/addons/payment_acquirer_adyen/doc/index.rst new file mode 100644 index 00000000000..85028ed0d3e --- /dev/null +++ b/addons/payment_acquirer_adyen/doc/index.rst @@ -0,0 +1,14 @@ +Payment module documentation +============================ + +Payment documentation topics +'''''''''''''''''''''''''''' + + +Changelog +''''''''' + +.. toctree:: + :maxdepth: 1 + + changelog.rst diff --git a/addons/payment_acquirer_adyen/models/__init__.py b/addons/payment_acquirer_adyen/models/__init__.py new file mode 100644 index 00000000000..fdc540ef04d --- /dev/null +++ b/addons/payment_acquirer_adyen/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import adyen diff --git a/addons/payment_acquirer_adyen/models/adyen.py b/addons/payment_acquirer_adyen/models/adyen.py new file mode 100644 index 00000000000..54c5cdfeb9f --- /dev/null +++ b/addons/payment_acquirer_adyen/models/adyen.py @@ -0,0 +1,198 @@ +# -*- coding: utf-'8' "-*-" + +import base64 +try: + import simplejson as json +except ImportError: + import json +from hashlib import sha1 +import hmac +import logging +import urlparse + +from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError +from openerp.addons.payment_acquirer_adyen.controllers.main import AdyenController +from openerp.osv import osv, fields +from openerp.tools import float_round + +_logger = logging.getLogger(__name__) + + +class AcquirerAdyen(osv.Model): + _inherit = 'payment.acquirer' + + def _get_adyen_urls(self, cr, uid, ids, name, args, context=None): + """ Adyen URLs + + - yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple + """ + res = {} + for acquirer in self.browse(cr, uid, ids, context=context): + qualif = acquirer.env + res[acquirer.id] = { + 'adyen_form_url': 'https://%s.adyen.com/hpp/pay.shtml' % qualif, + } + return res + + _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'), + 'adyen_form_url': fields.function( + _get_adyen_urls, multi='_get_adyen_urls', + type='char', string='Transaction URL', required_if_provider='adyen'), + } + + def _adyen_generate_merchant_sig(self, acquirer, 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' (openerp contacting ogone) or 'out' (adyen + contacting openerp). 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.name == 'adyen' + + if inout == 'in': + keys = "paymentAmount currencyCode shipBeforeDate merchantReference skinCode merchantAccount sessionValidity shopperEmail shopperReference recurringContract allowedMethods blockedMethods shopperStatement merchantReturnData billingAddressType deliveryAddressType offset".split() + else: + keys = "authResult pspReference merchantReference skinCode paymentMethod shopperLocale merchantReturnData".split() + + def get_value(key): + if values.get(key): + return values[key] + return '' + + sign = ''.join('%s' % get_value(k) for k in keys).encode('ascii') + key = acquirer.adyen_skin_hmac_key.encode('ascii') + return base64.b64encode(hmac.new(key, sign, sha1).digest()) + + def adyen_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None): + if partner_values is None: + partner_values = {} + base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') + acquirer = self.browse(cr, uid, id, context=context) + # tmp + import datetime + from dateutil import relativedelta + tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1) + + partner = None + if partner_id: + partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) + tx_values = { + 'merchantReference': reference, + 'paymentAmount': '%d' % int(float_round(amount, 2) * 100), + 'currencyCode': currency and currency.name or 'EUR', + 'shipBeforeDate': tmp_date, + 'skinCode': acquirer.adyen_skin_code, + 'merchantAccount': acquirer.adyen_merchant_account, + 'shopperLocale': partner and partner.lang or partner_values.get('lang', 'en_US'), + 'sessionValidity': tmp_date, + 'merchantSig': 'oij', + 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), + } + if tx_custom_values and tx_custom_values.get('return_url'): + tx_values['merchantReturnData'] = json.dumps({'return_url': '%s' % tx_custom_values.pop('return_url')}) + if tx_custom_values: + tx_values.update(tx_custom_values) + tx_values['merchantSig'] = self._adyen_generate_merchant_sig(acquirer, 'in', tx_values) + return tx_values + + def adyen_get_form_action_url(self, cr, uid, id, context=None): + acquirer = self.browse(cr, uid, id, context=context) + return acquirer.adyen_form_url + + +class TxAdyen(osv.Model): + _inherit = 'payment.transaction' + + _columns = { + 'adyen_psp_reference': fields.char('Adyen PSP Reference'), + } + + # -------------------------------------------------- + # FORM RELATED METHODS + # -------------------------------------------------- + + def adyen_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None): + tx = self.browse(cr, uid, id, context=context) + + tx_data = { + 'shopperLocale': tx.partner_lang, + } + if tx_custom_values: + tx_data.update(tx_custom_values) + return self.pool['payment.acquirer'].paypal_form_generate_values( + cr, uid, tx.acquirer_id.id, + tx.reference, tx.amount, tx.currency_id, + tx_custom_values=tx_data, + context=context + ) + + def _adyen_form_get_tx_from_data(self, cr, uid, data, context=None): + 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) + _logger.error(error_msg) + 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: + error_msg = 'Adyen: received data for reference %s' % (reference) + if not tx_ids: + error_msg += '; no order found' + else: + error_msg += '; multiple order found' + _logger.error(error_msg) + raise ValidationError(error_msg) + tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) + + # verify shasign + shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig(tx.acquirer_id, '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) + # raise ValidationError(error_msg) + + return tx + + def _adyen_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): + # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details + invalid_parameters = [] + if data.get('skinCode') != tx.acquirer_id.adyen_skin_code: + invalid_parameters.append(('skinCode', data.get('skinCode'), tx.acquirer_id.adyen_skin_code)) + if not data.get('authResult'): + invalid_parameters.append(('authResult', data.get('authResult'), 'something')) + return invalid_parameters + + def _adyen_form_validate(self, cr, uid, tx, data, context=None): + status = data.get('authResult', 'PENDING') + if status == 'AUTHORISED': + tx.write({ + 'state': 'done', + 'adyen_psp_reference': data.get('pspReference'), + # 'date_validate': data.get('payment_date', fields.datetime.now()), + # 'paypal_txn_type': data.get('express_checkout') + }) + return True + elif status == 'PENDING': + tx.write({ + 'state': 'pending', + 'adyen_psp_reference': data.get('pspReference'), + }) + return True + else: + error = 'Paypal: feedback error' + _logger.info(error) + tx.write({ + 'state': 'error', + 'state_message': error + }) + return False diff --git a/addons/payment_acquirer_adyen/static/description/icon.png b/addons/payment_acquirer_adyen/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ccbc55b8c5dc88dcd11a9aefb3c90979ba8b7775 GIT binary patch literal 11578 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 literal 0 HcmV?d00001 diff --git a/addons/payment_acquirer_adyen/tests/__init__.py b/addons/payment_acquirer_adyen/tests/__init__.py new file mode 100644 index 00000000000..b201c351ca7 --- /dev/null +++ b/addons/payment_acquirer_adyen/tests/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +from . import test_adyen + +checks = [ + test_adyen, +] diff --git a/addons/payment_acquirer_adyen/tests/test_adyen.py b/addons/payment_acquirer_adyen/tests/test_adyen.py new file mode 100644 index 00000000000..0b190bef431 --- /dev/null +++ b/addons/payment_acquirer_adyen/tests/test_adyen.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- + +from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError +from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon +from openerp.addons.payment_acquirer_adyen.controllers.main import AdyenController +from openerp.osv.orm import except_orm +from openerp.tools import mute_logger + +from lxml import objectify +import urlparse + + +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') + model, self.paypal_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_adyen', 'adyen_acquirer_button') + + # create a new ogone account + self.adyen_id = self.payment_acquirer.create( + cr, uid, { + 'name': 'adyen', + 'env': 'test', + 'view_template_id': self.paypal_view_id, + 'adyen_merchant_account': 'OpenERP', + 'adyen_skin_code': 'cbqYWvVL', + 'adyen_skin_hmac_key': 'cbqYWvVL', + }) + + # some CC (always use expiration date 06 / 2016, cvc 737, cid 7373 (amex)) + self.amex = (('370000000000002', '7373')) + self.dinersclub = (('36006666333344', '737')) + self.discover = (('6011601160116611', '737'), ('644564456445644', '737')) + self.jcb = (('3530111333300000', '737')) + self.mastercard = (('5555444433331111', '737'), ('5555555555554444', '737')) + self.visa = (('4111 1111 1111 1111', '737'), ('4444333322221111', '737')) + self.mcdebit = (('5500000000000004', '737')) + self.visadebit = (('4400000000000008', '737')) + self.maestro = (('6731012345678906', '737')) + self.laser = (('630495060000000000', '737')) + self.hipercard = (('6062828888666688', '737')) + self.dsmastercard = (('521234567890 1234', '737', 'user', 'password')) + self.dsvisa = (('4212345678901237', '737', 'user', 'password')) + self.mistercash = (('6703444444444449', None, 'user', 'password')) + + +class AdyenServer2Server(AdyenCommon): + + def test_00_tx_management(self): + cr, uid, context = self.cr, self.uid, {} + + # res = self.payment_acquirer._paypal_s2s_get_access_token(cr, uid, [self.paypal_id], context=context) + # self.assertTrue(res[self.paypal_id] is not False, 'paypal: did not generate access token') + + # tx_id = self.payment_transaction.s2s_create( + # cr, uid, { + # 'amount': 0.01, + # 'acquirer_id': self.paypal_id, + # 'currency_id': self.currency_euro_id, + # 'reference': 'test_reference', + # 'partner_id': self.buyer_id, + # }, { + # 'number': self.visa[0][0], + # 'cvc': self.visa[0][1], + # 'brand': 'visa', + # 'expiry_mm': 9, + # 'expiry_yy': 2015, + # }, context=context + # ) + + # tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) + # self.assertTrue(tx.paypal_txn_id is not False, 'paypal: txn_id should have been set after s2s request') + + # self.payment_transaction.write(cr, uid, tx_id, {'paypal_txn_id': False}, context=context) + + +class AdyenForm(AdyenCommon): + + def test_10_adyen_form_render(self): + cr, uid, context = self.cr, self.uid, {} + + # ---------------------------------------- + # Test: button direct rendering + # ---------------------------------------- + + form_values = { + 'cmd': '_xclick', + 'business': 'tde+paypal-facilitator@openerp.com', + 'item_name': 'test_ref0', + 'item_number': 'test_ref0', + 'first_name': 'Buyer', + 'last_name': 'Norbert', + 'amount': '0.01', + 'currency_code': 'EUR', + 'address1': 'Huge Street 2/543', + 'city': 'Sin City', + 'zip': '1000', + 'country': 'Belgium', + 'email': 'norbert.buyer@example.com', + 'return': '%s' % urlparse.urljoin(self.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, + partner_id=None, + partner_values=self.buyer_values, + context=context) + print res + + # check form result + tree = objectify.fromstring(res) + self.assertEqual(tree.get('action'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url') + for form_input in tree.input: + if form_input.get('name') in ['submit']: + continue + self.assertEqual( + form_input.get('value'), + form_values[form_input.get('name')], + 'paypal: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')]) + ) + + @mute_logger('openerp.addons.payment_acquirer_paypal.models.paypal', 'ValidationError') + def test_20_paypal_form_management(self): + cr, uid, context = self.cr, self.uid, {} + + # typical data posted by paypal after client has successfully paid + paypal_post_data = { + 'protection_eligibility': u'Ineligible', + 'last_name': u'Poilu', + 'txn_id': u'08D73520KX778924N', + 'receiver_email': u'tde+paypal-facilitator@openerp.com', + 'payment_status': u'Pending', + 'payment_gross': u'', + 'tax': u'0.00', + 'residence_country': u'FR', + 'address_state': u'Alsace', + 'payer_status': u'verified', + 'txn_type': u'web_accept', + 'address_street': u'Av. de la Pelouse, 87648672 Mayet', + 'handling_amount': u'0.00', + 'payment_date': u'03:21:19 Nov 18, 2013 PST', + 'first_name': u'Norbert', + 'item_name': u'test_ref_2', + 'address_country': u'France', + 'charset': u'windows-1252', + 'custom': u'', + 'notify_version': u'3.7', + 'address_name': u'Norbert Poilu', + 'pending_reason': u'multi_currency', + 'item_number': u'test_ref_2', + 'receiver_id': u'DEG7Z7MYGT6QA', + 'transaction_subject': u'', + 'business': u'tde+paypal-facilitator@openerp.com', + 'test_ipn': u'1', + 'payer_id': u'VTDKRZQSAHYPS', + 'verify_sign': u'An5ns1Kso7MWUdW4ErQKJJJ4qi4-AVoiUf-3478q3vrSmqh08IouiYpM', + 'address_zip': u'75002', + 'address_country_code': u'FR', + 'address_city': u'Paris', + 'address_status': u'unconfirmed', + 'mc_currency': u'EUR', + 'shipping': u'0.00', + 'payer_email': u'tde+buyer@openerp.com', + 'payment_type': u'instant', + 'mc_gross': u'1.95', + 'ipn_track_id': u'866df2ccd444b', + 'quantity': u'1' + } + + # should raise error about unknown tx + with self.assertRaises(ValidationError): + self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) + + # create tx + tx_id = self.payment_transaction.create( + cr, uid, { + 'amount': 1.95, + 'acquirer_id': self.paypal_id, + 'currency_id': self.currency_euro_id, + 'reference': 'test_ref_2', + 'partner_name': 'Norbert Buyer', + }, context=context + ) + # validate it + self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) + # check + tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) + self.assertEqual(tx.state, 'pending', 'paypal: wrong state after receiving a valid pending notification') + self.assertEqual(tx.state_message, 'multi_currency', 'paypal: wrong state message after receiving a valid pending notification') + self.assertEqual(tx.paypal_txn_id, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification') + self.assertFalse(tx.date_validate, 'paypal: validation date should not be updated whenr receiving pending notification') + + # update tx + self.payment_transaction.write(cr, uid, [tx_id], { + 'state': 'draft', + 'paypal_txn_id': False, + }, context=context) + # update notification from paypal + paypal_post_data['payment_status'] = 'Completed' + # validate it + self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) + # check + tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) + self.assertEqual(tx.state, 'done', 'paypal: wrong state after receiving a valid pending notification') + self.assertEqual(tx.paypal_txn_id, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification') + self.assertEqual(tx.date_validate, '2013-11-18 03:21:19', 'paypal: wrong validation date') + +# {'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_acquirer_adyen/views/adyen.xml b/addons/payment_acquirer_adyen/views/adyen.xml new file mode 100644 index 00000000000..aeaa5260b11 --- /dev/null +++ b/addons/payment_acquirer_adyen/views/adyen.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/addons/payment_acquirer_adyen/views/payment_acquirer.xml b/addons/payment_acquirer_adyen/views/payment_acquirer.xml new file mode 100644 index 00000000000..9b75828f315 --- /dev/null +++ b/addons/payment_acquirer_adyen/views/payment_acquirer.xml @@ -0,0 +1,35 @@ + + + + + + acquirer.form.adyen + payment.acquirer + + + + + + + + + + + + acquirer.transaction.form.adyen + payment.transaction + + + + + + + + + + + + + + From f47c5d367f73f5791b838e46dc169f41706d915d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 2 Dec 2013 16:29:58 +0100 Subject: [PATCH 3/3] [CLEAN] payment_acquirer_adyen: cleaned tests: removed code pasted from paypal, updated tests. Tests should be added, but will be done in a few days. bzr revid: tde@openerp.com-20131202152958-em5tq1x20y2rlo9q --- .../tests/test_adyen.py | 135 ++---------------- 1 file changed, 10 insertions(+), 125 deletions(-) diff --git a/addons/payment_acquirer_adyen/tests/test_adyen.py b/addons/payment_acquirer_adyen/tests/test_adyen.py index 0b190bef431..4fe53b6f2ca 100644 --- a/addons/payment_acquirer_adyen/tests/test_adyen.py +++ b/addons/payment_acquirer_adyen/tests/test_adyen.py @@ -25,7 +25,7 @@ class AdyenCommon(PaymentAcquirerCommon): 'name': 'adyen', 'env': 'test', 'view_template_id': self.paypal_view_id, - 'adyen_merchant_account': 'OpenERP', + 'adyen_merchant_account': 'OpenERPCOM', 'adyen_skin_code': 'cbqYWvVL', 'adyen_skin_hmac_key': 'cbqYWvVL', }) @@ -52,30 +52,6 @@ class AdyenServer2Server(AdyenCommon): def test_00_tx_management(self): cr, uid, context = self.cr, self.uid, {} - # res = self.payment_acquirer._paypal_s2s_get_access_token(cr, uid, [self.paypal_id], context=context) - # self.assertTrue(res[self.paypal_id] is not False, 'paypal: did not generate access token') - - # tx_id = self.payment_transaction.s2s_create( - # cr, uid, { - # 'amount': 0.01, - # 'acquirer_id': self.paypal_id, - # 'currency_id': self.currency_euro_id, - # 'reference': 'test_reference', - # 'partner_id': self.buyer_id, - # }, { - # 'number': self.visa[0][0], - # 'cvc': self.visa[0][1], - # 'brand': 'visa', - # 'expiry_mm': 9, - # 'expiry_yy': 2015, - # }, context=context - # ) - - # tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) - # self.assertTrue(tx.paypal_txn_id is not False, 'paypal: txn_id should have been set after s2s request') - - # self.payment_transaction.write(cr, uid, tx_id, {'paypal_txn_id': False}, context=context) - class AdyenForm(AdyenCommon): @@ -87,20 +63,12 @@ class AdyenForm(AdyenCommon): # ---------------------------------------- form_values = { - 'cmd': '_xclick', - 'business': 'tde+paypal-facilitator@openerp.com', - 'item_name': 'test_ref0', - 'item_number': 'test_ref0', - 'first_name': 'Buyer', - 'last_name': 'Norbert', - 'amount': '0.01', - 'currency_code': 'EUR', - 'address1': 'Huge Street 2/543', - 'city': 'Sin City', - 'zip': '1000', - 'country': 'Belgium', - 'email': 'norbert.buyer@example.com', - 'return': '%s' % urlparse.urljoin(self.base_url, AdyenController._return_url), + 'merchantAccount': 'OpenERPCOM', + 'merchantReference': 'test_ref0', + 'skinCode': 'cbqYWvVL', + 'paymentAmount': '1', + 'currencyCode': 'EUR', + 'resURL': '%s' % urlparse.urljoin(self.base_url, AdyenController._return_url), } # render the button @@ -110,106 +78,23 @@ class AdyenForm(AdyenCommon): partner_id=None, partner_values=self.buyer_values, context=context) - print res # check form result tree = objectify.fromstring(res) - self.assertEqual(tree.get('action'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url') + self.assertEqual(tree.get('action'), 'https://test.adyen.com/hpp/pay.shtml', 'adyen: wrong form POST url') for form_input in tree.input: - if form_input.get('name') in ['submit']: + if form_input.get('name') in ['submit', 'shipBeforeDate', 'sessionValidity', 'shopperLocale', 'merchantSig']: continue self.assertEqual( form_input.get('value'), form_values[form_input.get('name')], - 'paypal: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')]) + 'adyen: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')]) ) @mute_logger('openerp.addons.payment_acquirer_paypal.models.paypal', 'ValidationError') def test_20_paypal_form_management(self): cr, uid, context = self.cr, self.uid, {} - # typical data posted by paypal after client has successfully paid - paypal_post_data = { - 'protection_eligibility': u'Ineligible', - 'last_name': u'Poilu', - 'txn_id': u'08D73520KX778924N', - 'receiver_email': u'tde+paypal-facilitator@openerp.com', - 'payment_status': u'Pending', - 'payment_gross': u'', - 'tax': u'0.00', - 'residence_country': u'FR', - 'address_state': u'Alsace', - 'payer_status': u'verified', - 'txn_type': u'web_accept', - 'address_street': u'Av. de la Pelouse, 87648672 Mayet', - 'handling_amount': u'0.00', - 'payment_date': u'03:21:19 Nov 18, 2013 PST', - 'first_name': u'Norbert', - 'item_name': u'test_ref_2', - 'address_country': u'France', - 'charset': u'windows-1252', - 'custom': u'', - 'notify_version': u'3.7', - 'address_name': u'Norbert Poilu', - 'pending_reason': u'multi_currency', - 'item_number': u'test_ref_2', - 'receiver_id': u'DEG7Z7MYGT6QA', - 'transaction_subject': u'', - 'business': u'tde+paypal-facilitator@openerp.com', - 'test_ipn': u'1', - 'payer_id': u'VTDKRZQSAHYPS', - 'verify_sign': u'An5ns1Kso7MWUdW4ErQKJJJ4qi4-AVoiUf-3478q3vrSmqh08IouiYpM', - 'address_zip': u'75002', - 'address_country_code': u'FR', - 'address_city': u'Paris', - 'address_status': u'unconfirmed', - 'mc_currency': u'EUR', - 'shipping': u'0.00', - 'payer_email': u'tde+buyer@openerp.com', - 'payment_type': u'instant', - 'mc_gross': u'1.95', - 'ipn_track_id': u'866df2ccd444b', - 'quantity': u'1' - } - - # should raise error about unknown tx - with self.assertRaises(ValidationError): - self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) - - # create tx - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 1.95, - 'acquirer_id': self.paypal_id, - 'currency_id': self.currency_euro_id, - 'reference': 'test_ref_2', - 'partner_name': 'Norbert Buyer', - }, context=context - ) - # validate it - self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) - # check - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) - self.assertEqual(tx.state, 'pending', 'paypal: wrong state after receiving a valid pending notification') - self.assertEqual(tx.state_message, 'multi_currency', 'paypal: wrong state message after receiving a valid pending notification') - self.assertEqual(tx.paypal_txn_id, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification') - self.assertFalse(tx.date_validate, 'paypal: validation date should not be updated whenr receiving pending notification') - - # update tx - self.payment_transaction.write(cr, uid, [tx_id], { - 'state': 'draft', - 'paypal_txn_id': False, - }, context=context) - # update notification from paypal - paypal_post_data['payment_status'] = 'Completed' - # validate it - self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) - # check - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) - self.assertEqual(tx.state, 'done', 'paypal: wrong state after receiving a valid pending notification') - self.assertEqual(tx.paypal_txn_id, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification') - self.assertEqual(tx.date_validate, '2013-11-18 03:21:19', 'paypal: wrong validation date') - # {'authResult': u'AUTHORISED', # 'merchantReference': u'SO014', # 'merchantReturnData': u'return_url=/shop/payment/validate',