diff --git a/addons/payment_acquirer_ogone/models/ogone.py b/addons/payment_acquirer_ogone/models/ogone.py index 7f501ec2e4f..fd3c3f55ee4 100644 --- a/addons/payment_acquirer_ogone/models/ogone.py +++ b/addons/payment_acquirer_ogone/models/ogone.py @@ -161,41 +161,16 @@ class PaymentTxOgone(osv.Model): 'ogone_feedback_model': fields.char(), 'ogone_feedback_eval': fields.char(), 'ogone_complus': fields.char('Complus'), + 'ogone_payid': fields.char() } # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- - def _ogone_form_get_tx_from_shasign_out(self, cr, uid, data, context=None): - reference, pay_id, shasign = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN') - if not reference or not pay_id or not shasign: - error_msg = 'Ogone: received data with missing reference (%s) or pay_id (%s) or shashign (%s)' % (reference, pay_id, shasign) - _logger.error(error_msg) - raise ValidationError(error_msg) - - # find tx -> @TDENOTE use paytid ? - tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) - if not tx_ids or len(tx_ids) > 1: - error_msg = 'Ogone: received data for reference' % (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']._ogone_generate_shasign(tx.acquirer_id, 'out', data) - if shasign_check.upper() != shasign.upper(): - error_msg = 'Ogone: invalid shasign, received %s, computed %s, for data %s' % (shasign, shasign_check, data) - _logger.error(error_msg) - raise ValidationError(error_msg) - - return tx - def ogone_form_generate_values(self, cr, uid, id, tx_custom_values=None, context=None): + """ Ogone-specific value generation for rendering a transaction-based + form button. """ tx = self.browse(cr, uid, id, context=context) tx_data = { @@ -217,16 +192,51 @@ class PaymentTxOgone(osv.Model): context=context ) + def _ogone_form_get_tx_from_shasign_out(self, cr, uid, data, context=None): + """ Given a data dict coming from ogone, verify it and find the related + transaction record. """ + reference, pay_id, shasign = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN') + if not reference or not pay_id or not shasign: + error_msg = 'Ogone: received data with missing reference (%s) or pay_id (%s) or shashign (%s)' % (reference, pay_id, shasign) + _logger.error(error_msg) + raise ValidationError(error_msg) + + # find tx -> @TDENOTE use paytid ? + tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) + if not tx_ids or len(tx_ids) > 1: + error_msg = 'Ogone: 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']._ogone_generate_shasign(tx.acquirer_id, 'out', data) + if shasign_check.upper() != shasign.upper(): + error_msg = 'Ogone: invalid shasign, received %s, computed %s, for data %s' % (shasign, shasign_check, data) + _logger.error(error_msg) + raise ValidationError(error_msg) + + return tx + def ogone_form_feedback(self, cr, uid, data, context=None): - print '-- ogone: ogone_form_feedback' tx = self._ogone_form_get_tx_from_shasign_out(cr, uid, data, context) if not tx: raise ValidationError('Ogone: feedback: tx not found') + if tx.state == 'done': + _logger.warning('Ogone: trying to validate an already validated tx (ref %s' % tx.reference) + return False status = int(data.get('STATUS', '0')) - print '\togone: statuts %s' % status if status in [5, 9]: - tx.write({'state': 'done'}) + tx.write({ + 'state': 'done', + 'date_validate': data['TRXDATE'], + 'ogone_payid': data['PAYID'], + }) return True else: error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % { @@ -324,6 +334,9 @@ class PaymentTxOgone(osv.Model): tx_data['SHASIGN'] = shasign return tx_data + def ogone_s2s_feedback(self, cr, uid, data, context=None): + pass + def ogone_s2s_execute(self, cr, uid, id, values, context=None): tx = self.browse(cr, uid, id, context=context) @@ -400,4 +413,4 @@ class PaymentTxOgone(osv.Model): if not tx_done and tries == 0: raise Exception('Cannot get transaction status...') - return (tx_status, orderid, payid) + return tx_status diff --git a/addons/payment_acquirer_ogone/static/src/img/icon_code.png b/addons/payment_acquirer_ogone/static/src/img/icon_code.png deleted file mode 100644 index 49bbab035b1..00000000000 Binary files a/addons/payment_acquirer_ogone/static/src/img/icon_code.png and /dev/null differ diff --git a/addons/payment_acquirer_ogone/static/src/img/icon_credit_card.png b/addons/payment_acquirer_ogone/static/src/img/icon_credit_card.png deleted file mode 100644 index 91c266d207b..00000000000 Binary files a/addons/payment_acquirer_ogone/static/src/img/icon_credit_card.png and /dev/null differ diff --git a/addons/payment_acquirer_ogone/tests/test_ogone.py b/addons/payment_acquirer_ogone/tests/test_ogone.py index f847d5d91f4..f7e85dccb97 100644 --- a/addons/payment_acquirer_ogone/tests/test_ogone.py +++ b/addons/payment_acquirer_ogone/tests/test_ogone.py @@ -1,60 +1,50 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Business Applications -# Copyright (c) 2012-TODAY OpenERP S.A. -# -# 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 . -# -############################################################################## +from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError from openerp.addons.payment_acquirer.tests.common import PaymentAcquirerCommon from openerp.addons.payment_acquirer_ogone.controllers.main import OgoneController -# from openerp.osv.orm import except_orm +from openerp.tools import mute_logger from lxml import objectify # import requests +import time import urlparse -class BasicPayment(PaymentAcquirerCommon): +class OgonePayment(PaymentAcquirerCommon): - def test_20_ogone_form(self): + def setUp(self): + super(OgonePayment, self).setUp() cr, uid = self.cr, self.uid - context = {} - base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - # ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [ogone_id], None, None)[ogone_id]['ogone_standard_order_url'] - model, ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'ogone_acquirer_button') + self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') + model, self.ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'ogone_acquirer_button') # create a new ogone account - ogone_id = self.payment_acquirer.create( + self.ogone_id = self.payment_acquirer.create( cr, uid, { 'name': 'ogone', 'env': 'test', - 'view_template_id': ogone_view_id, + 'view_template_id': self.ogone_view_id, 'ogone_pspid': 'pinky', 'ogone_userid': 'OOAPI', 'ogone_password': 'R!ci/6Nu8a', 'ogone_shakey_in': 'tINY4Yv14789gUix1130', 'ogone_shakey_out': 'tINYj885Tfvd4P471464', - }, context=context - ) - # verify acquirer data - ogone = self.payment_acquirer.browse(cr, uid, ogone_id, context) + }) + self.ogone_url = self.payment_acquirer._get_ogone_urls(cr, uid, [self.ogone_id], None, None)[self.ogone_id]['ogone_standard_order_url'] + + def test_00_ogone_acquirer(self): + ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None) self.assertEqual(ogone.env, 'test', 'test without test env') + def test_10_ogone_form_render(self): + cr, uid, context = self.cr, self.uid, {} + + # ---------------------------------------- + # Test: button direct rendering + shasign + # ---------------------------------------- + form_values = { 'PSPID': 'pinky', 'ORDERID': 'test_ref0', @@ -69,19 +59,20 @@ class BasicPayment(PaymentAcquirerCommon): 'OWNERTOWN': 'Sin City', 'OWNERTELNO': '0032 12 34 56 78', 'SHASIGN': '815f67b8ff70d234ffcf437c13a9fa7f807044cc', - 'ACCEPTURL': '%s' % urlparse.urljoin(base_url, OgoneController._accept_url), - 'DECLINEURL': '%s' % urlparse.urljoin(base_url, OgoneController._decline_url), - 'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneController._exception_url), - 'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneController._cancel_url), + 'ACCEPTURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._accept_url), + 'DECLINEURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._decline_url), + 'EXCEPTIONURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._exception_url), + 'CANCELURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._cancel_url), } # render the button res = self.payment_acquirer.render( - cr, uid, ogone_id, + cr, uid, self.ogone_id, 'test_ref0', 0.01, self.currency_euro, partner_id=None, partner_values=self.buyer_values, context=context) + # check form result tree = objectify.fromstring(res) self.assertEqual(tree.get('action'), 'https://secure.ogone.com/ncol/test/orderstandard.asp', 'ogone: wrong form POST url') @@ -93,13 +84,16 @@ class BasicPayment(PaymentAcquirerCommon): form_values[form_input.get('name')], 'ogone: wrong value for form: received %s instead of %s' % (form_input.get('value'), form_values[form_input.get('name')]) ) - # resp = requests.post(tree.get('action'), data=form_values) + + # ---------------------------------------- + # Test2: button using tx + validation + # ---------------------------------------- # create a new draft tx tx_id = self.payment_transaction.create( cr, uid, { 'amount': 0.01, - 'acquirer_id': ogone_id, + 'acquirer_id': self.ogone_id, 'currency_id': self.currency_euro_id, 'reference': 'test_ref0', 'partner_id': self.buyer_id, @@ -107,12 +101,13 @@ class BasicPayment(PaymentAcquirerCommon): ) # render the button res = self.payment_acquirer.render( - cr, uid, ogone_id, - 'test_ref0', 0.01, self.currency_euro, + cr, uid, self.ogone_id, + 'should_be_erased', 0.01, self.currency_euro, tx_id=tx_id, partner_id=None, partner_values=self.buyer_values, context=context) + # check form result tree = objectify.fromstring(res) self.assertEqual(tree.get('action'), 'https://secure.ogone.com/ncol/test/orderstandard.asp', 'ogone: wrong form POST url') @@ -125,33 +120,78 @@ class BasicPayment(PaymentAcquirerCommon): 'ogone: 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')]) ) - def test_21_ogone_s2s(self): - cr, uid = self.cr, self.uid - context = {} + @mute_logger('openerp.addons.payment_acquirer_ogone.models.ogone', 'ValidationError') + def test_20_ogone_form_management(self): + cr, uid, context = self.cr, self.uid, {} - model, ogone_view_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment_acquirer_ogone', 'ogone_acquirer_button') + # typical data posted by ogone after client has successfully paid + ogone_post_data = { + 'orderID': u'test_ref_2', + 'STATUS': u'9', + 'CARDNO': u'XXXXXXXXXXXX0002', + 'PAYID': u'25381582', + 'CN': u'Norbert Buyer', + 'NCERROR': u'0', + 'TRXDATE': u'11/15/13', + 'IP': u'85.201.233.72', + 'BRAND': u'VISA', + 'ACCEPTANCE': u'test123', + 'currency': u'EUR', + 'amount': u'1.95', + 'SHASIGN': u'7B7B0ED9CBC4A85543A9073374589033A62A05A5', + 'ED': u'0315', + 'PM': u'CreditCard' + } - # create a new ogone account - ogone_id = self.payment_acquirer.create( + # should raise error about unknown tx + with self.assertRaises(ValidationError): + self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + + # create tx + tx_id = self.payment_transaction.create( cr, uid, { - 'name': 'ogone', - 'env': 'test', - 'view_template_id': ogone_view_id, - 'ogone_pspid': 'pinky', - 'ogone_userid': 'OOAPI', - 'ogone_password': 'R!ci/6Nu8a', - 'ogone_shakey_in': 'tINY4Yv14789gUix1130', - 'ogone_shakey_out': 'tINYj885Tfvd4P471464', + 'amount': 1.95, + 'acquirer_id': self.ogone_id, + 'currency_id': self.currency_euro_id, + 'reference': 'test_ref_2', + 'partner_name': 'Norbert Buyer', }, context=context ) + # validate it + self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + # check state + tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) + self.assertEqual(tx.state, 'done', 'ogone: validation did not put tx into done state') + self.assertEqual(tx.ogone_payid, ogone_post_data.get('PAYID'), 'ogone: validation did not update tx payid') + + # reset tx + tx.write({'state': 'draft', 'date_validate': False, 'ogone_payid': False}) + + # now ogone post is ok: try to modify the SHASIGN + ogone_post_data['SHASIGN'] = 'a4c16bae286317b82edb49188d3399249a784691' + with self.assertRaises(ValidationError): + self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + + # simulate an error + ogone_post_data['STATUS'] = 2 + ogone_post_data['SHASIGN'] = 'a4c16bae286317b82edb49188d3399249a784691' + self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + # check state + tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) + self.assertEqual(tx.state, 'error', 'ogone: erroneous validation did not put tx into error state') + + def test_30_ogone_s2s(self): + test_ref = 'test_ref_%.15f' % time.time() + print test_ref + cr, uid, context = self.cr, self.uid, {} # create a new draft tx tx_id = self.payment_transaction.create( cr, uid, { 'amount': 0.01, - 'acquirer_id': ogone_id, + 'acquirer_id': self.ogone_id, 'currency_id': self.currency_euro_id, - 'reference': 'test_ogone_0', + 'reference': test_ref, 'partner_id': self.buyer_id, 'type': 'server2server', }, context=context @@ -162,11 +202,12 @@ class BasicPayment(PaymentAcquirerCommon): 'expiry_date_mm': '01', 'expiry_date_yy': '2015', 'holder_name': 'Norbert Poilu', - 'number': '4000000000000002', + 'number': '4000000000000006', 'brand': 'VISA', }, context=context) print res + print '--------------------' res = self.payment_transaction.ogone_s2s_execute(cr, uid, tx_id, {}, context=context) print res