1 # -*- coding: utf-'8' "-*-"
5 import simplejson as json
8 from hashlib import sha1
13 from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
14 from openerp.addons.payment_acquirer_adyen.controllers.main import AdyenController
15 from openerp.osv import osv, fields
16 from openerp.tools import float_round
18 _logger = logging.getLogger(__name__)
21 class AcquirerAdyen(osv.Model):
22 _inherit = 'payment.acquirer'
24 def _get_adyen_urls(self, cr, uid, env, context=None):
27 - yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple
31 'adyen_form_url': 'https://prod.adyen.com/hpp/pay.shtml',
35 'adyen_form_url': 'https://test.adyen.com/hpp/pay.shtml',
39 'adyen_merchant_account': fields.char('Merchant Account', required_if_provider='adyen'),
40 'adyen_skin_code': fields.char('Skin Code', required_if_provider='adyen'),
41 'adyen_skin_hmac_key': fields.char('Skin HMAC Key', required_if_provider='adyen'),
44 def _adyen_generate_merchant_sig(self, acquirer, inout, values):
45 """ Generate the shasign for incoming or outgoing communications.
47 :param browse acquirer: the payment.acquirer browse record. It should
48 have a shakey in shaky out
49 :param string inout: 'in' (openerp contacting ogone) or 'out' (adyen
50 contacting openerp). In this last case only some
51 fields should be contained (see e-Commerce basic)
52 :param dict values: transaction values
54 :return string: shasign
56 assert inout in ('in', 'out')
57 assert acquirer.name == 'adyen'
60 keys = "paymentAmount currencyCode shipBeforeDate merchantReference skinCode merchantAccount sessionValidity shopperEmail shopperReference recurringContract allowedMethods blockedMethods shopperStatement merchantReturnData billingAddressType deliveryAddressType offset".split()
62 keys = "authResult pspReference merchantReference skinCode paymentMethod shopperLocale merchantReturnData".split()
69 sign = ''.join('%s' % get_value(k) for k in keys).encode('ascii')
70 key = acquirer.adyen_skin_hmac_key.encode('ascii')
71 return base64.b64encode(hmac.new(key, sign, sha1).digest())
73 def adyen_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None):
74 base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
75 acquirer = self.browse(cr, uid, id, context=context)
78 from dateutil import relativedelta
79 tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1)
81 adyen_tx_values = dict(tx_values)
82 adyen_tx_values.update({
83 'merchantReference': tx_values['reference'],
84 'paymentAmount': '%d' % int(float_round(tx_values['amount'], 2) * 100),
85 'currencyCode': tx_values['currency'] and tx_values['currency'].name or '',
86 'shipBeforeDate': tmp_date,
87 'skinCode': acquirer.adyen_skin_code,
88 'merchantAccount': acquirer.adyen_merchant_account,
89 'shopperLocale': partner_values['lang'],
90 'sessionValidity': tmp_date,
91 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url),
93 if adyen_tx_values.get('return_url'):
94 adyen_tx_values['merchantReturnData'] = json.dumps({'return_url': '%s' % adyen_tx_values.pop('return_url')})
95 adyen_tx_values['merchantSig'] = self._adyen_generate_merchant_sig(acquirer, 'in', adyen_tx_values)
96 return partner_values, adyen_tx_values
98 def adyen_get_form_action_url(self, cr, uid, id, context=None):
99 acquirer = self.browse(cr, uid, id, context=context)
100 return self._get_adyen_urls(cr, uid, acquirer.env, context=context)['adyen_form_url']
103 class TxAdyen(osv.Model):
104 _inherit = 'payment.transaction'
107 'adyen_psp_reference': fields.char('Adyen PSP Reference'),
110 # --------------------------------------------------
111 # FORM RELATED METHODS
112 # --------------------------------------------------
114 def _adyen_form_get_tx_from_data(self, cr, uid, data, context=None):
115 reference, pspReference = data.get('merchantReference'), data.get('pspReference')
116 if not reference or not pspReference:
117 error_msg = 'Adyen: received data with missing reference (%s) or missing pspReference (%s)' % (reference, pspReference)
118 _logger.error(error_msg)
119 raise ValidationError(error_msg)
121 # find tx -> @TDENOTE use pspReference ?
122 tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context)
123 if not tx_ids or len(tx_ids) > 1:
124 error_msg = 'Adyen: received data for reference %s' % (reference)
126 error_msg += '; no order found'
128 error_msg += '; multiple order found'
129 _logger.error(error_msg)
130 raise ValidationError(error_msg)
131 tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context)
134 shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig(tx.acquirer_id, 'out', data)
135 if shasign_check != data.get('merchantSig'):
136 error_msg = 'Adyen: invalid merchantSig, received %s, computed %s' % (data.get('merchantSig'), shasign_check)
137 _logger.warning(error_msg)
138 # raise ValidationError(error_msg)
142 def _adyen_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
143 invalid_parameters = []
145 # reference at acquirer: pspReference
146 if tx.acquirer_reference and data.get('pspReference') != tx.acquirer_reference:
147 invalid_parameters.append(('pspReference', data.get('pspReference'), tx.acquirer_reference))
149 if data.get('skinCode') != tx.acquirer_id.adyen_skin_code:
150 invalid_parameters.append(('skinCode', data.get('skinCode'), tx.acquirer_id.adyen_skin_code))
152 if not data.get('authResult'):
153 invalid_parameters.append(('authResult', data.get('authResult'), 'something'))
155 return invalid_parameters
157 def _adyen_form_validate(self, cr, uid, tx, data, context=None):
158 status = data.get('authResult', 'PENDING')
159 if status == 'AUTHORISED':
162 'adyen_psp_reference': data.get('pspReference'),
163 # 'date_validate': data.get('payment_date', fields.datetime.now()),
164 # 'paypal_txn_type': data.get('express_checkout')
167 elif status == 'PENDING':
170 'adyen_psp_reference': data.get('pspReference'),
174 error = 'Paypal: feedback error'
178 'state_message': error