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_odoo_by_adyen/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/payment_odoo_by_adyen/models')
| -rw-r--r-- | addons/payment_odoo_by_adyen/models/__init__.py | 4 | ||||
| -rw-r--r-- | addons/payment_odoo_by_adyen/models/payment.py | 185 |
2 files changed, 189 insertions, 0 deletions
diff --git a/addons/payment_odoo_by_adyen/models/__init__.py b/addons/payment_odoo_by_adyen/models/__init__.py new file mode 100644 index 00000000..2ec5b9cd --- /dev/null +++ b/addons/payment_odoo_by_adyen/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import payment diff --git a/addons/payment_odoo_by_adyen/models/payment.py b/addons/payment_odoo_by_adyen/models/payment.py new file mode 100644 index 00000000..cf44d248 --- /dev/null +++ b/addons/payment_odoo_by_adyen/models/payment.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import hashlib +import hmac +import json +import logging +from werkzeug import urls + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.addons.payment_odoo_by_adyen.controllers.main import OdooByAdyenController + +_logger = logging.getLogger(__name__) + + +class AcquirerOdooByAdyen(models.Model): + _inherit = 'payment.acquirer' + + provider = fields.Selection(selection_add=[ + ('odoo_adyen', 'Odoo Payments by Adyen') + ], ondelete={'odoo_adyen': 'set default'}) + odoo_adyen_account_id = fields.Many2one('adyen.account', required_if_provider='odoo_adyen', related='company_id.adyen_account_id') + odoo_adyen_payout_id = fields.Many2one('adyen.payout', required_if_provider='odoo_adyen', string='Adyen Payout', domain="[('adyen_account_id', '=', odoo_adyen_account_id)]") + + @api.constrains('provider', 'state') + def _check_odoo_adyen_test(self): + for payment_acquirer in self: + if payment_acquirer.provider == 'odoo_adyen' and payment_acquirer.state == 'test': + raise ValidationError(_('Odoo Payments by Adyen is not available in test mode.')) + + def _get_feature_support(self): + res = super(AcquirerOdooByAdyen, self)._get_feature_support() + res['tokenize'].append('odoo_adyen') + return res + + @api.model + def _odoo_adyen_format_amount(self, amount, currency_id): + return { + 'value': int(amount * (10 ** currency_id.decimal_places)), + 'currency': currency_id.name, + } + + @api.model + def _odoo_adyen_compute_signature(self, amount, currency_id, reference): + secret = self.env['ir.config_parameter'].sudo().get_param('database.secret') + token_str = '%s%s%s' % ( + int(amount * (10 ** currency_id.decimal_places)), + currency_id.name, + reference + ) + return hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest() + + def odoo_adyen_form_generate_values(self, values): + # Don't use the value returned by `self.get_base_url` for the notification_url as + # `request.httprequest.url_root` could be forged to retrieve the signature and + # fake a payment update + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + data = { + 'adyen_uuid': self.odoo_adyen_account_id.adyen_uuid, + 'payout': self.odoo_adyen_payout_id.code, + 'amount': self._odoo_adyen_format_amount(values['amount'], values['currency']), + 'reference': values['reference'], + 'shopperLocale': values.get('partner_lang'), + 'metadata': { + 'merchant_signature': self._odoo_adyen_compute_signature(values['amount'],values['currency'],values['reference']), + 'notification_url': urls.url_join(base_url, OdooByAdyenController._notification_url), + }, + 'returnUrl': urls.url_join(self.get_base_url(), '/payment/process'), + } + + if self.save_token in ['ask', 'always']: + data.update({ + 'shopperReference': '%s_%s' % (self.odoo_adyen_account_id.adyen_uuid, values['partner_id']), + 'storePaymentMethod': True, + 'recurringProcessingModel': 'CardOnFile', + }) + + values.update({ + 'data': json.dumps(data), + }) + return values + + def odoo_adyen_get_form_action_url(self): + self.ensure_one() + proxy_url = self.env['ir.config_parameter'].sudo().get_param('adyen_platforms.proxy_url') + return urls.url_join(proxy_url, 'pay_by_link') + + def odoo_adyen_create_account(self): + return self.env['adyen.account'].action_create_redirect() + +class TxOdooByAdyen(models.Model): + _inherit = 'payment.transaction' + + def odoo_adyen_s2s_do_transaction(self, **kwargs): + self.ensure_one() + # Don't use the value returned by `self.get_base_url` for the notification_url as + # `request.httprequest.url_root` could be forged to retrieve the signature and + # fake a payment update + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + data = { + 'payout': self.acquirer_id.odoo_adyen_payout_id.code, + 'amount': self.acquirer_id._odoo_adyen_format_amount(self.amount, self.currency_id), + 'reference': self.reference, + 'paymentMethod': { + 'type': self.payment_token_id.odoo_adyen_payment_method_type, + 'storedPaymentMethodId': self.payment_token_id.acquirer_ref, + }, + 'shopperReference': '%s_%s' % (self.acquirer_id.odoo_adyen_account_id.adyen_uuid, self.partner_id.id), + 'shopperInteraction': 'ContAuth', + 'metadata': { + 'merchant_signature': self.acquirer_id._odoo_adyen_compute_signature(self.amount, self.currency_id, self.reference), + 'notification_url': urls.url_join(base_url, OdooByAdyenController._notification_url), + }, + 'returnUrl': urls.url_join(self.get_base_url(), '/payment/process'), + } + self.acquirer_id.odoo_adyen_account_id._adyen_rpc('payments', data) + + @api.model + def _odoo_adyen_form_get_tx_from_data(self, data): + reference = data.get('merchantReference') + if not reference: + error_msg = _('Odoo Payments by Adyen: received data with missing reference (%s)', reference) + _logger.info(error_msg) + raise ValidationError(error_msg) + + tx = self.env['payment.transaction'].search([('reference', '=', reference)]) + if not tx or len(tx) > 1: + error_msg = _('Odoo Payments by Adyen: 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) + + return tx + + def _odoo_adyen_form_get_invalid_parameters(self, data): + invalid_parameters = [] + + if self.acquirer_reference and data.get('pspReference') != self.acquirer_reference: + invalid_parameters.append(('pspReference', data.get('pspReference'), self.acquirer_reference)) + + return invalid_parameters + + def _odoo_adyen_form_validate(self, data): + merchant_signature = self.acquirer_id._odoo_adyen_compute_signature(self.amount, self.currency_id, self.reference) + if merchant_signature != data['additionalData']['metadata.merchant_signature']: + return False + + # Save token + if self.partner_id and not self.payment_token_id and \ + (self.type == 'form_save' or self.acquirer_id.save_token == 'always') \ + and 'recurring.shopperReference' in data['additionalData']: + res = self.acquirer_id.odoo_adyen_account_id._adyen_rpc('payment_methods', { + 'shopperReference': data['additionalData']['recurring.shopperReference'] + }) + stored_payment_methods = res['storedPaymentMethods'] + pm_id = data['additionalData']['recurring.recurringDetailReference'] + token_id = self.env['payment.token'].create({ + 'name': _("Card No XXXXXXXXXXXX%s", data['additionalData']['cardSummary']), + 'acquirer_ref': pm_id, + 'acquirer_id': self.acquirer_id.id, + 'partner_id': self.partner_id.id, + 'odoo_adyen_payment_method_type': next(pm['type'] for pm in stored_payment_methods if pm['id'] == pm_id) + }) + self.payment_token_id = token_id + + # Update status + if data['success']: + self.write({'acquirer_reference': data.get('pspReference')}) + self._set_transaction_done() + return True + else: + error = _('Odoo Payment by Adyen: feedback error') + _logger.info(error) + self.write({'state_message': error}) + self._set_transaction_cancel() + return False + +class PaymentToken(models.Model): + _inherit = 'payment.token' + + odoo_adyen_payment_method_type = fields.Char(string='PaymentMethod Type') |
