diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/payment_buckaroo/models/payment.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/payment_buckaroo/models/payment.py')
| -rw-r--r-- | addons/payment_buckaroo/models/payment.py | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/addons/payment_buckaroo/models/payment.py b/addons/payment_buckaroo/models/payment.py new file mode 100644 index 00000000..8689cf5f --- /dev/null +++ b/addons/payment_buckaroo/models/payment.py @@ -0,0 +1,192 @@ +# coding: utf-8 +from hashlib import sha1 +import logging + +from werkzeug import urls + +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_buckaroo.controllers.main import BuckarooController + +from odoo.tools.float_utils import float_compare + +_logger = logging.getLogger(__name__) + + +def normalize_keys_upper(data): + """Set all keys of a dictionnary to uppercase + + Buckaroo parameters names are case insensitive + convert everything to upper case to be able to easily detected the presence + of a parameter by checking the uppercase key only + """ + return {key.upper(): val for key, val in data.items()} + + +class AcquirerBuckaroo(models.Model): + _inherit = 'payment.acquirer' + + provider = fields.Selection(selection_add=[ + ('buckaroo', 'Buckaroo') + ], ondelete={'buckaroo': 'set default'}) + brq_websitekey = fields.Char('WebsiteKey', required_if_provider='buckaroo', groups='base.group_user') + brq_secretkey = fields.Char('SecretKey', required_if_provider='buckaroo', groups='base.group_user') + + def _get_buckaroo_urls(self, environment): + """ 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 _buckaroo_generate_digital_sign(self, 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' (odoo contacting buckaroo) or 'out' (buckaroo + contacting odoo). + :param dict values: transaction values + + :return string: shasign + """ + assert inout in ('in', 'out') + assert self.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 '' + + values = dict(values or {}) + + if inout == 'out': + for key in list(values): + # case insensitive keys + if key.upper() == 'BRQ_SIGNATURE': + del values[key] + break + + items = sorted(values.items(), key=lambda pair: pair[0].lower()) + sign = ''.join('%s=%s' % (k, urls.url_unquote_plus(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 + self.brq_secretkey + shasign = sha1(sign.encode('utf-8')).hexdigest() + return shasign + + def buckaroo_form_generate_values(self, values): + base_url = self.get_base_url() + buckaroo_tx_values = dict(values) + buckaroo_tx_values.update({ + 'Brq_websitekey': self.brq_websitekey, + 'Brq_amount': values['amount'], + 'Brq_currency': values['currency'] and values['currency'].name or '', + 'Brq_invoicenumber': values['reference'], + 'brq_test': True if self.state == 'test' else False, + 'Brq_return': urls.url_join(base_url, BuckarooController._return_url), + 'Brq_returncancel': urls.url_join(base_url, BuckarooController._cancel_url), + 'Brq_returnerror': urls.url_join(base_url, BuckarooController._exception_url), + 'Brq_returnreject': urls.url_join(base_url, BuckarooController._reject_url), + 'Brq_culture': (values.get('partner_lang') or 'en_US').replace('_', '-'), + 'add_returndata': buckaroo_tx_values.pop('return_url', '') or '', + }) + buckaroo_tx_values['Brq_signature'] = self._buckaroo_generate_digital_sign('in', buckaroo_tx_values) + return buckaroo_tx_values + + def buckaroo_get_form_action_url(self): + self.ensure_one() + environment = 'prod' if self.state == 'enabled' else 'test' + return self._get_buckaroo_urls(environment)['buckaroo_form_url'] + + +class TxBuckaroo(models.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] + + # -------------------------------------------------- + # FORM RELATED METHODS + # -------------------------------------------------- + + @api.model + def _buckaroo_form_get_tx_from_data(self, data): + """ Given a data dict coming from buckaroo, verify it and find the related + transaction record. """ + origin_data = dict(data) + data = normalize_keys_upper(data) + 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 shasign (%s)') % (reference, pay_id, shasign) + _logger.info(error_msg) + raise ValidationError(error_msg) + + tx = self.search([('reference', '=', reference)]) + if not tx or len(tx) > 1: + error_msg = _('Buckaroo: received data for reference %s') % (reference) + if not tx: + error_msg += _('; no order found') + else: + error_msg += _('; multiple order found') + _logger.info(error_msg) + raise ValidationError(error_msg) + + # verify shasign + shasign_check = tx.acquirer_id._buckaroo_generate_digital_sign('out', origin_data) + if shasign_check.upper() != shasign.upper(): + error_msg = _('Buckaroo: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data) + _logger.info(error_msg) + raise ValidationError(error_msg) + + return tx + + def _buckaroo_form_get_invalid_parameters(self, data): + invalid_parameters = [] + data = normalize_keys_upper(data) + if self.acquirer_reference and data.get('BRQ_TRANSACTIONS') != self.acquirer_reference: + invalid_parameters.append(('Transaction Id', data.get('BRQ_TRANSACTIONS'), self.acquirer_reference)) + # check what is buyed + if float_compare(float(data.get('BRQ_AMOUNT', '0.0')), self.amount, 2) != 0: + invalid_parameters.append(('Amount', data.get('BRQ_AMOUNT'), '%.2f' % self.amount)) + if data.get('BRQ_CURRENCY') != self.currency_id.name: + invalid_parameters.append(('Currency', data.get('BRQ_CURRENCY'), self.currency_id.name)) + + return invalid_parameters + + def _buckaroo_form_validate(self, data): + data = normalize_keys_upper(data) + status_code = int(data.get('BRQ_STATUSCODE', '0')) + if status_code in self._buckaroo_valid_tx_status: + self.write({'acquirer_reference': data.get('BRQ_TRANSACTIONS')}) + self._set_transaction_done() + return True + elif status_code in self._buckaroo_pending_tx_status: + self.write({'acquirer_reference': data.get('BRQ_TRANSACTIONS')}) + self._set_transaction_pending() + return True + elif status_code in self._buckaroo_cancel_tx_status: + self.write({'acquirer_reference': data.get('BRQ_TRANSACTIONS')}) + self._set_transaction_cancel() + return True + else: + error = 'Buckaroo: feedback error' + _logger.info(error) + self.write({ + 'state_message': error, + 'acquirer_reference': data.get('BRQ_TRANSACTIONS'), + }) + self._set_transaction_cancel() + return False |
