# -*- coding: utf-'8' "-*-" from hashlib import sha1 import logging import urlparse from openerp.addons.payment.models.payment_acquirer import ValidationError from openerp.addons.payment_buckaroo.controllers.main import BuckarooController from openerp.osv import osv, fields from openerp.tools.float_utils import float_compare _logger = logging.getLogger(__name__) class AcquirerBuckaroo(osv.Model): _inherit = 'payment.acquirer' def _get_buckaroo_urls(self, cr, uid, environment, context=None): """ Buckaroo URLs """ if environment == 'prod': return { 'buckaroo_form_url': 'https://checkout.buckaroo.nl/html/', } else: return { 'buckaroo_form_url': 'https://testcheckout.buckaroo.nl/html/', } def _get_providers(self, cr, uid, context=None): providers = super(AcquirerBuckaroo, self)._get_providers(cr, uid, context=context) providers.append(['buckaroo', 'Buckaroo']) return providers _columns = { 'brq_websitekey': fields.char('WebsiteKey', required_if_provider='buckaroo'), 'brq_secretkey': fields.char('SecretKey', required_if_provider='buckaroo'), } def _buckaroo_generate_digital_sign(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 buckaroo) or 'out' (buckaroo contacting openerp). :param dict values: transaction values :return string: shasign """ assert inout in ('in', 'out') assert acquirer.provider == 'buckaroo' keys = "add_returndata Brq_amount Brq_culture Brq_currency Brq_invoicenumber Brq_return Brq_returncancel Brq_returnerror Brq_returnreject brq_test Brq_websitekey".split() def get_value(key): if values.get(key): return values[key] return '' if inout == 'out': if 'BRQ_SIGNATURE' in values: del values['BRQ_SIGNATURE'] items = sorted((k.upper(), v) for k, v in values.items()) sign = ''.join('%s=%s' % (k, v) for k, v in items) else: sign = ''.join('%s=%s' % (k,get_value(k)) for k in keys) #Add the pre-shared secret key at the end of the signature sign = sign + acquirer.brq_secretkey if isinstance(sign, str): sign = urlparse.parse_qsl(sign) shasign = sha1(sign).hexdigest() return shasign def buckaroo_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) buckaroo_tx_values = dict(tx_values) buckaroo_tx_values.update({ 'Brq_websitekey': acquirer.brq_websitekey, 'Brq_amount': tx_values['amount'], 'Brq_currency': tx_values['currency'] and tx_values['currency'].name or '', 'Brq_invoicenumber': tx_values['reference'], 'brq_test': acquirer.environment, 'Brq_return': '%s' % urlparse.urljoin(base_url, BuckarooController._return_url), 'Brq_returncancel': '%s' % urlparse.urljoin(base_url, BuckarooController._cancel_url), 'Brq_returnerror': '%s' % urlparse.urljoin(base_url, BuckarooController._exception_url), 'Brq_returnreject': '%s' % urlparse.urljoin(base_url, BuckarooController._reject_url), 'Brq_culture': partner_values.get('lang', 'en_US'), }) if buckaroo_tx_values.get('return_url'): buckaroo_tx_values['add_returndata'] = {'return_url': '%s' % buckaroo_tx_values.pop('return_url')} else: buckaroo_tx_values['add_returndata'] = '' buckaroo_tx_values['Brq_signature'] = self._buckaroo_generate_digital_sign(acquirer, 'in', buckaroo_tx_values) return partner_values, buckaroo_tx_values def buckaroo_get_form_action_url(self, cr, uid, id, context=None): acquirer = self.browse(cr, uid, id, context=context) return self._get_buckaroo_urls(cr, uid, acquirer.environment, context=context)['buckaroo_form_url'] class TxBuckaroo(osv.Model): _inherit = 'payment.transaction' # buckaroo status _buckaroo_valid_tx_status = [190] _buckaroo_pending_tx_status = [790, 791, 792, 793] _buckaroo_cancel_tx_status = [890, 891] _buckaroo_error_tx_status = [490, 491, 492] _buckaroo_reject_tx_status = [690] _columns = { 'buckaroo_txnid': fields.char('Transaction ID'), } # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- def _buckaroo_form_get_tx_from_data(self, cr, uid, data, context=None): """ Given a data dict coming from buckaroo, verify it and find the related transaction record. """ reference, pay_id, shasign = data.get('BRQ_INVOICENUMBER'), data.get('BRQ_PAYMENT'), data.get('BRQ_SIGNATURE') if not reference or not pay_id or not shasign: error_msg = 'Buckaroo: 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) tx_ids = self.search(cr, uid, [('reference', '=', reference)], context=context) if not tx_ids or len(tx_ids) > 1: error_msg = 'Buckaroo: 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']._buckaroo_generate_digital_sign(tx.acquirer_id, 'out' ,data) if shasign_check.upper() != shasign.upper(): error_msg = 'Buckaroo: invalid shasign, received %s, computed %s, for data %s' % (shasign, shasign_check, data) _logger.error(error_msg) raise ValidationError(error_msg) return tx def _buckaroo_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if tx.acquirer_reference and data.get('BRQ_TRANSACTIONS') != tx.acquirer_reference: invalid_parameters.append(('Transaction Id', data.get('BRQ_TRANSACTIONS'), tx.acquirer_reference)) # check what is buyed if float_compare(float(data.get('BRQ_AMOUNT', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('Amount', data.get('BRQ_AMOUNT'), '%.2f' % tx.amount)) if data.get('BRQ_CURRENCY') != tx.currency_id.name: invalid_parameters.append(('Currency', data.get('BRQ_CURRENCY'), tx.currency_id.name)) return invalid_parameters def _buckaroo_form_validate(self, cr, uid, tx, data, context=None): status_code = int(data.get('BRQ_STATUSCODE','0')) if status_code in self._buckaroo_valid_tx_status: tx.write({ 'state': 'done', 'buckaroo_txnid': data.get('BRQ_TRANSACTIONS'), }) return True elif status_code in self._buckaroo_pending_tx_status: tx.write({ 'state': 'pending', 'buckaroo_txnid': data.get('BRQ_TRANSACTIONS'), }) return True elif status_code in self._buckaroo_cancel_tx_status: tx.write({ 'state': 'cancel', 'buckaroo_txnid': data.get('BRQ_TRANSACTIONS'), }) return True else: error = 'Buckaroo: feedback error' _logger.info(error) tx.write({ 'state': 'error', 'state_message': error, 'buckaroo_txnid': data.get('BRQ_TRANSACTIONS'), }) return False