diff options
| author | Thibault Delavallée <tde@openerp.com> | 2014-01-22 18:57:02 +0100 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2014-01-22 18:57:02 +0100 |
| commit | 0b69bad9968ce2650f6dffd7df703cd33e7f38af (patch) | |
| tree | 947ae3933f8b4f382bf090031d1ea15e53e88155 /addons/payment_adyen/models | |
| parent | f70e54255641f4d3d61777501b20b0f8c7a1fb77 (diff) | |
[RENAME] payment_acquirer_* -> payment_ *
bzr revid: tde@openerp.com-20140122175702-1h1e51z4njt4s70w
Diffstat (limited to 'addons/payment_adyen/models')
| -rw-r--r-- | addons/payment_adyen/models/__init__.py | 3 | ||||
| -rw-r--r-- | addons/payment_adyen/models/adyen.py | 180 |
2 files changed, 183 insertions, 0 deletions
diff --git a/addons/payment_adyen/models/__init__.py b/addons/payment_adyen/models/__init__.py new file mode 100644 index 00000000000..fdc540ef04d --- /dev/null +++ b/addons/payment_adyen/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import adyen diff --git a/addons/payment_adyen/models/adyen.py b/addons/payment_adyen/models/adyen.py new file mode 100644 index 00000000000..80103f50dae --- /dev/null +++ b/addons/payment_adyen/models/adyen.py @@ -0,0 +1,180 @@ +# -*- 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.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 + +_logger = logging.getLogger(__name__) + + +class AcquirerAdyen(osv.Model): + _inherit = 'payment.acquirer' + + def _get_adyen_urls(self, cr, uid, env, context=None): + """ Adyen URLs + + - yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple + """ + if env == 'prod': + return { + 'adyen_form_url': 'https://prod.adyen.com/hpp/pay.shtml', + } + else: + return { + 'adyen_form_url': 'https://test.adyen.com/hpp/pay.shtml', + } + + _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(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, partner_values, tx_values, context=None): + 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) + + adyen_tx_values = dict(tx_values) + adyen_tx_values.update({ + 'merchantReference': tx_values['reference'], + 'paymentAmount': '%d' % int(float_round(tx_values['amount'], 2) * 100), + 'currencyCode': tx_values['currency'] and tx_values['currency'].name or '', + 'shipBeforeDate': tmp_date, + 'skinCode': acquirer.adyen_skin_code, + 'merchantAccount': acquirer.adyen_merchant_account, + 'shopperLocale': partner_values['lang'], + 'sessionValidity': tmp_date, + 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), + }) + if adyen_tx_values.get('return_url'): + adyen_tx_values['merchantReturnData'] = json.dumps({'return_url': '%s' % adyen_tx_values.pop('return_url')}) + adyen_tx_values['merchantSig'] = self._adyen_generate_merchant_sig(acquirer, 'in', adyen_tx_values) + return partner_values, adyen_tx_values + + def adyen_get_form_action_url(self, cr, uid, id, context=None): + acquirer = self.browse(cr, uid, id, context=context) + return self._get_adyen_urls(cr, uid, acquirer.env, context=context)['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_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): + 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)) + # seller + if data.get('skinCode') != tx.acquirer_id.adyen_skin_code: + invalid_parameters.append(('skinCode', data.get('skinCode'), tx.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, 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 |
