diff --git a/addons/payment_adyen_paybylink/controllers/main.py b/addons/payment_adyen_paybylink/controllers/main.py index 63ea206d506ee..3ad41a46bcab8 100644 --- a/addons/payment_adyen_paybylink/controllers/main.py +++ b/addons/payment_adyen_paybylink/controllers/main.py @@ -37,24 +37,30 @@ def adyen_notification(self, **post): ) try: # Check the integrity of the notification - tx_sudo = request.env['payment.transaction'].sudo().\ - _adyen_form_get_tx_from_data(post) - self._verify_notification_signature(post, tx_sudo) - - # Check whether the event of the notification succeeded and - # reshape the notification data for parsing event_code = post['eventCode'] - if event_code in ('AUTHORISATION', 'REFUND') and post['success'] == 'true': - post['authResult'] = 'AUTHORISED' + if event_code == 'REPORT_AVAILABLE' and post['success'] == 'true': + # 'merchantReference': '' + # 'psp_reference': 'settlement_detail_report_batch_554.xlsx' + journal = request.env['account.journal'].sudo()._adyen_get_journal_from_data(post) + journal.download_report(post) + else: + tx_sudo = request.env['payment.transaction'].sudo(). \ + _adyen_form_get_tx_from_data(post) + self._verify_notification_signature(post, tx_sudo) - # Handle the notification data - request.env['payment.transaction'].sudo().form_feedback( - post, 'adyen') + # Check whether the event of the notification succeeded and + # reshape the notification data for parsing + if event_code in ('AUTHORISATION', 'REFUND') and post['success'] == 'true': + post['authResult'] = 'AUTHORISED' - # Handle fraud cases - elif (event_code == 'NOTIFICATION_OF_CHARGEBACK' and - post['success'] == 'true'): - tx_sudo.process_fraud_case(post) + # Handle the notification data + request.env['payment.transaction'].sudo().form_feedback( + post, 'adyen') + + # Handle fraud cases + elif (event_code == 'NOTIFICATION_OF_CHARGEBACK' and + post['success'] == 'true'): + tx_sudo.process_fraud_case(post) # Acknowledge the notification to avoid getting spammed except ValidationError: @@ -107,6 +113,7 @@ def _compute_signature(payload, hmac_key): :return: The computed signature :rtype: str """ + def _flatten_dict(_value, _path_base='', _separator='.'): """ Recursively generate a flat representation of a dict. diff --git a/addons/payment_adyen_paybylink/models/__init__.py b/addons/payment_adyen_paybylink/models/__init__.py index 8e04237423ad2..94f5179eb28e8 100644 --- a/addons/payment_adyen_paybylink/models/__init__.py +++ b/addons/payment_adyen_paybylink/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_journal from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_adyen_paybylink/models/account_journal.py b/addons/payment_adyen_paybylink/models/account_journal.py new file mode 100644 index 0000000000000..7acb8bf9de896 --- /dev/null +++ b/addons/payment_adyen_paybylink/models/account_journal.py @@ -0,0 +1,67 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import logging +import subprocess + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError, UserError + +_logger = logging.getLogger(__name__) + + +def runcmd(cmd, verbose=False, *args, **kwargs): + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + shell=True + ) + std_out, std_err = process.communicate() + if verbose: + _logger.info(std_out.strip(), std_err) + pass + + +class AccountJournal(models.Model): + _inherit = 'account.journal' + + @api.model + def _adyen_get_journal_from_data(self, data): + merchant_account = data.get('merchantAccountCode') + if not merchant_account: + error_msg = _('Missing merchantAccountCode in REPORT_AVAILABLE notification from Adyen.') + _logger.info(error_msg) + raise ValidationError(error_msg) + journal = self.env['account.journal'].search([("adyen_merchant_account", "=", merchant_account)]) + if len(journal) != 1: + error_msg = _(f'Expected 1 journal for Adyen Merchant Account: {merchant_account}. Found {len(journal)}') + _logger.info(error_msg) + raise ValidationError(error_msg) + return journal + + @api.model + def download_report(self, post): + """ Download bank statement report from Adyen to the server + """ + adyen_user = self.acquirer_id.adyen_report_user + adyen_pass = self.acquirer_id.adyen_report_password + if not adyen_user or not adyen_pass: + raise UserError( + f'User or password missing for acquirer {self.name} ' + f'related to journal {self.acquirer_id.name}' + ) + path = '/tmp/adyen/' + cmd = "mkdir -p {path} && wget -P {path} --http-user='{user}@Company.VANMOOF' " \ + "--http-password='{pwd}' --no-check-certificate {url}".format( + path=path, user=adyen_user, pwd=adyen_pass, url=post["reason"]) + try: + _logger.debug('Downloading {url} to {path}{file}'.format( + file=post['pspReference'], url=post["reason"], path=path)) + runcmd(cmd, verbose=True) + return path + post['pspReference'] + except Exception as e: + message = f"Download Failed for Ayden Report notification {post} \n " \ + f"with the exception: {e.args[0]}." + _logger.error(message) + raise UserError(message) diff --git a/addons/payment_adyen_paybylink/models/payment_acquirer.py b/addons/payment_adyen_paybylink/models/payment_acquirer.py index c2e7df960429a..62e702b8f86cd 100644 --- a/addons/payment_adyen_paybylink/models/payment_acquirer.py +++ b/addons/payment_adyen_paybylink/models/payment_acquirer.py @@ -3,15 +3,15 @@ import logging import re import requests +import subprocess from werkzeug import urls from odoo import _, api, fields, models -from odoo.exceptions import ValidationError +from odoo.exceptions import ValidationError, UserError from odoo.addons.payment_adyen_paybylink.const import API_ENDPOINT_VERSIONS - _logger = logging.getLogger(__name__) @@ -40,6 +40,8 @@ class PaymentAcquirer(models.Model): # the 'NOT NULL' constraint on those fields. adyen_skin_code = fields.Char(default="Do not use this field") adyen_skin_hmac_key = fields.Char(default="Do not use this field") + adyen_report_user = fields.Char(string="Report User") + adyen_report_password = fields.Char(string="Reporting Password") @api.model_create_multi def create(self, values_list): diff --git a/addons/payment_adyen_paybylink/views/payment_views.xml b/addons/payment_adyen_paybylink/views/payment_views.xml index c88f4b4afe717..a1572ef693f96 100644 --- a/addons/payment_adyen_paybylink/views/payment_views.xml +++ b/addons/payment_adyen_paybylink/views/payment_views.xml @@ -19,6 +19,16 @@ + + + + + + + + +