From ddca887bcdef03acf34c3ba148bc0363f3d35fc6 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Mon, 26 Dec 2022 19:53:38 +0100 Subject: [PATCH] 11.0 - account_ebics - backport of 12.0 code to enable configuration of request types on FDL --- account_ebics/README.rst | 6 +- account_ebics/__manifest__.py | 4 +- account_ebics/data/ebics_file_format.xml | 190 +++++++++++------- .../models/account_bank_statement.py | 4 +- account_ebics/models/ebics_config.py | 4 +- account_ebics/models/ebics_file.py | 37 +++- account_ebics/models/ebics_file_format.py | 81 +++----- .../models/fintech_ebics_register.py | 4 +- .../wizard/account_bank_statement_import.py | 4 +- .../wizard/ebics_change_passphrase.py | 4 +- account_ebics/wizard/ebics_xfer.py | 59 +++--- 11 files changed, 209 insertions(+), 188 deletions(-) diff --git a/account_ebics/README.rst b/account_ebics/README.rst index 05a20c9..625aea7 100644 --- a/account_ebics/README.rst +++ b/account_ebics/README.rst @@ -1,6 +1,6 @@ -.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png - :target: https://www.gnu.org/licenses/agpl - :alt: License: AGPL-3 +.. image:: https://img.shields.io/badge/license-LGPL--3-blue.png + :target: https://www.gnu.org/licenses/lpgl + :alt: License: LGPL-3 ====================== EBICS banking protocol diff --git a/account_ebics/__manifest__.py b/account_ebics/__manifest__.py index 7a41c0f..ef5dcf7 100644 --- a/account_ebics/__manifest__.py +++ b/account_ebics/__manifest__.py @@ -1,10 +1,10 @@ # Copyright 2009-2022 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). { 'name': 'EBICS banking protocol', 'version': '11.0.1.8.0', - 'license': 'AGPL-3', + 'license': 'LGPL-3', 'author': 'Noviat', 'category': 'Accounting & Finance', 'depends': ['account'], diff --git a/account_ebics/data/ebics_file_format.xml b/account_ebics/data/ebics_file_format.xml index 079a8f8..da1766f 100644 --- a/account_ebics/data/ebics_file_format.xml +++ b/account_ebics/data/ebics_file_format.xml @@ -2,6 +2,8 @@ + + camt.052 down @@ -11,109 +13,141 @@ c52.xml - - - camt.053.001.02.stm + + camt.052 + down + Z52 + camt.052 + bank to customer account report in format camt.052 + c52.xml + + + + camt.053 down C53 - Bank Statement in Format camt.053 + camt.053 + Bank to customer statement report in format camt.053 c53.xml + + camt.053 + down + Z53 + camt.053 + Bank to customer statement report in format camt.053 + c53.xml + + camt.054 down C54 camt.054 Bank to customer debit credit notification in format camt.054 - c54.xml + c52.xml - - - pain.001.001.03.sct - up - CCT - Payment Order in Format pain.001.001.03 - xml - - - - pain.008.001.02.sdd - up - CDD - Sepa Core Direct Debit Order in Format pain.008.001.02 - xml - - - - pain.008.001.02.sbb - up - CDB - Sepa Direct Debit (B2B) Order in Format pain.008.001.02 - xml - - - - - pain.001 - up - XE2 - Payment Order in Format pain.001.001.03 - xml - - - - - pain.008 - up - XE3 - Direct Debit Order in Format pain.008.001.02 - xml - - - - camt.054.001.02.rdd + + camt.054 down - FDL - Bank Statement in Format camt.054 - c54.xml + Z54 + camt.054 + Bank to customer debit credit notification in format camt.054 + c52.xml - - + camt.xxx.cfonb120.stm down FDL - Bank Statement in Format cfonb120 + cfonb120 + Bank to customer statement report in format cfonb120 cfonb120.dat - - + + pain.002 + down + CDZ + Payment status report for direct debit in format pain.002 + psr.xml + + + + pain.002 + down + Z01 + pain.002 + Payment status report for direct debit in format pain.002 + psr.xml + + + + + + pain.001.001.03 + up + CCT + Payment Order in format pain.001.001.03 + cct.xml + + + + pain.001.001.03 + up + XE2 + Payment Order in format pain.001.001.03 + cct.xml + + + + pain.008.001.02.sdd + up + CDD + Sepa Core Direct Debit Order in format pain.008.001.02 + sdd.xml + + + + pain.008.001.02.sdd + up + CDD + Sepa Core Direct Debit Order in format pain.008.001.02 + sdd.xml + + + + pain.008.001.02.sdd + up + XE3 + Sepa Core Direct Debit Order in format pain.008.001.02 + sdd.xml + + + + pain.008.001.02.sbb + up + CDB + Sepa Direct Debit (B2B) Order in format pain.008.001.02 + sbb.xml + + + + pain.008.001.02.sbb + up + XE4 + Sepa Direct Debit (B2B) Order in format pain.008.001.02 + sbb.xml + + + pain.001.001.02.sct up FUL - Payment Order in Format pain.001.001.02 - xml + Payment Order in format pain.001.001.02 + cct.xml diff --git a/account_ebics/models/account_bank_statement.py b/account_ebics/models/account_bank_statement.py index db65fcd..cf3b2df 100644 --- a/account_ebics/models/account_bank_statement.py +++ b/account_ebics/models/account_bank_statement.py @@ -1,5 +1,5 @@ -# Copyright 2009-2018 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# Copyright 2009-2022 Noviat. +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). from odoo import fields, models diff --git a/account_ebics/models/ebics_config.py b/account_ebics/models/ebics_config.py index 711ea84..643af03 100644 --- a/account_ebics/models/ebics_config.py +++ b/account_ebics/models/ebics_config.py @@ -1,5 +1,5 @@ -# Copyright 2009-2019 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# Copyright 2009-2022 Noviat. +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). """ import logging diff --git a/account_ebics/models/ebics_file.py b/account_ebics/models/ebics_file.py index 8f1e3b6..545622e 100644 --- a/account_ebics/models/ebics_file.py +++ b/account_ebics/models/ebics_file.py @@ -1,5 +1,5 @@ # Copyright 2009-2022 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). import logging @@ -74,12 +74,11 @@ class EbicsFile(models.Model): raise UserError(_( "You can only remove EBICS files in state 'Draft'.")) # execute format specific actions - ff = ebics_file.format_id.name + ff = ebics_file.format_id.download_process_method if ff in ff_methods: if ff_methods[ff].get('unlink'): ff_methods[ff]['unlink'](ebics_file) - elif ff[:7] == 'camt.05' and ff_methods[ff[:8]].get('unlink'): - ff_methods[ff[:8]]['unlink'](self) + # remove bank statements ebics_file.bank_statement_ids.unlink() return super(EbicsFile, self).unlink() @@ -96,16 +95,12 @@ class EbicsFile(models.Model): self.ensure_one() self.note_process = '' ff_methods = self._file_format_methods() - ff = self.format_id.name + ff = self.format_id.download_process_method if ff in ff_methods: if ff_methods[ff].get('process'): res = ff_methods[ff]['process'](self) self.state = 'done' return res - elif ff[:7] == 'camt.05' and ff_methods[ff[:8]].get('process'): - res = ff_methods[ff[:8]]['process'](self) - self.state = 'done' - return res else: return self._process_undefined_format() @@ -130,18 +125,21 @@ class EbicsFile(models.Model): for extra file formats. """ res = { - 'camt.xxx.cfonb120.stm': + 'cfonb120': {'process': self._process_cfonb120, 'unlink': self._unlink_cfonb120}, 'camt.052': {'process': self._process_camt052, 'unlink': self._unlink_camt052}, - 'camt.053.001.02.stm': + 'camt.053': {'process': self._process_camt053, 'unlink': self._unlink_camt053}, 'camt.054': {'process': self._process_camt054, 'unlink': self._unlink_camt054}, + 'pain.002': + {'process': self._process_pain002, + 'unlink': self._unlink_pain002}, } return res @@ -294,6 +292,23 @@ class EbicsFile(models.Model): """ pass + @staticmethod + def _process_pain002(self): + """ + Placeholder for processing pain.002 files. + TODO: + add import logic based upon OCA 'account_payment_return_import' + """ + pass + + @staticmethod + def _unlink_pain002(self): + """ + Placeholder for pain.002 specific actions before removing the + EBICS data file. + """ + raise NotImplementedError + def _process_undefined_format(self): raise UserError(_( "The current version of the 'account_ebics' module " diff --git a/account_ebics/models/ebics_file_format.py b/account_ebics/models/ebics_file_format.py index 24e1420..50bc9ff 100644 --- a/account_ebics/models/ebics_file_format.py +++ b/account_ebics/models/ebics_file_format.py @@ -1,5 +1,5 @@ # Copyright 2009-2022 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). from odoo import api, fields, models @@ -7,21 +7,35 @@ from odoo import api, fields, models class EbicsFileFormat(models.Model): _name = 'ebics.file.format' _description = 'EBICS File Formats' - _order = 'type,name' + _order = 'type,name,order_type' - name = fields.Selection( - selection=lambda self: self._selection_name(), - string='Request Type', required=True) + name = fields.Char( + string='Request Type', + required=True, + help="E.g. camt.xxx.cfonb120.stm, pain.001.001.03.sct.\n" + "Specify camt.052, camt.053, camt.054 for camt " + "Order Types such as C53, Z53, C54, Z54.\n" + "This name has to match the 'Request Type' in your " + "EBICS contract for Order Type 'FDL' or 'FUL'.\n") type = fields.Selection( selection=[('down', 'Download'), ('up', 'Upload')], required=True) - order_type = fields.Selection( - selection=lambda self: self._selection_order_type(), + order_type = fields.Char( string='Order Type', - help="For most banks is France you should use the " + required=True, + help="E.g. C53 (check your EBICS contract).\n" + "For most banks in France you should use the " "format neutral Order Types 'FUL' for upload " "and 'FDL' for download.") + download_process_method = fields.Selection( + selection='_selection_download_process_method', + help="Enable processing within Odoo of the downloaded file " + "via the 'Process' button." + "E.g. specify camt.053 to import a camt.053 file and create " + "a bank statement.") + # TODO: + # move signature_class parameter so that it can be set per EBICS config signature_class = fields.Selection( selection=[('E', 'Single signature'), ('T', 'Transport signature')], @@ -30,52 +44,19 @@ class EbicsFileFormat(models.Model): "ERP system when using class 'E' to prevent unauthorised " "users to make supplier payments." "\nLeave this field empty to use the default " - "defined for your bank connection.") + "defined for your EBICS Configuration.") description = fields.Char() suffix = fields.Char( required=True, help="Specify the filename suffix for this File Format." - "\nE.g. camt.053.xml") + "\nE.g. c53.xml") @api.model - def _selection_order_type(self): - up = self._supported_upload_order_types() - down = self._supported_download_order_types() - selection = [(x, x) for x in up + down] - return selection + def _selection_download_process_method(self): + methods = self.env['ebics.file']._file_format_methods().keys() + return [(x, x) for x in methods] - def _supported_upload_order_types(self): - return ['FUL', 'CCT', 'CDD', 'CDB', 'XE2', 'XE3'] - - def _supported_download_order_types(self): - return ['FDL', 'C52', 'C53', 'C54'] - - @api.model - def _selection_name(self): - """ - List of supported EBICS Request Types. - Extend this method via a custom module when testing - a new Request Type and make a PR for the - account_ebics module when this new Request Type - is working correctly. - This PR should include at least updates to - - 'data/ebics_file_format.xml' - - 'models/ebics_file_format.py' - An overview of the EBICS Request Types can be found in - the doc folder of this module (EBICS_Annex2). - """ - request_types = [ - 'camt.053.001.02.stm', - 'pain.001.001.03.sct', - 'pain.008.001.02.sdd', - 'pain.008.001.02.sbb', - 'camt.xxx.cfonb120.stm', - 'pain.001.001.02.sct', - 'camt.052', - 'camt.053', - 'camt.054', - 'pain.001', - 'pain.008', - ] - selection = [(x, x) for x in request_types] - return selection + @api.onchange('type') + def _onchange_type(self): + if self.type == 'up': + self.download_process_method = False diff --git a/account_ebics/models/fintech_ebics_register.py b/account_ebics/models/fintech_ebics_register.py index 3d5e80f..7e83744 100644 --- a/account_ebics/models/fintech_ebics_register.py +++ b/account_ebics/models/fintech_ebics_register.py @@ -1,5 +1,5 @@ -# Copyright 2009-2019 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# Copyright 2009-2022 Noviat. +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). import logging from sys import exc_info diff --git a/account_ebics/wizard/account_bank_statement_import.py b/account_ebics/wizard/account_bank_statement_import.py index 22aae30..f85b2ce 100644 --- a/account_ebics/wizard/account_bank_statement_import.py +++ b/account_ebics/wizard/account_bank_statement_import.py @@ -1,5 +1,5 @@ -# Copyright 2009-2019 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# Copyright 2009-2022 Noviat. +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). import logging diff --git a/account_ebics/wizard/ebics_change_passphrase.py b/account_ebics/wizard/ebics_change_passphrase.py index 5e5282c..bca24f9 100644 --- a/account_ebics/wizard/ebics_change_passphrase.py +++ b/account_ebics/wizard/ebics_change_passphrase.py @@ -1,5 +1,5 @@ -# Copyright 2009-2019 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# Copyright 2009-2022 Noviat. +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). import logging diff --git a/account_ebics/wizard/ebics_xfer.py b/account_ebics/wizard/ebics_xfer.py index bd2bcb0..bc6e12f 100644 --- a/account_ebics/wizard/ebics_xfer.py +++ b/account_ebics/wizard/ebics_xfer.py @@ -1,5 +1,5 @@ # Copyright 2009-2022 Noviat. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl). """ import logging @@ -64,10 +64,10 @@ class EbicsXfer(models.TransientModel): string='EBICS File Format', help="Select EBICS File Format to upload/download." "\nLeave blank to download all available files.") - order_type = fields.Selection( - selection=lambda self: self._selection_order_type(), + order_type = fields.Char( + related='format_id.order_type', string='Order Type', - help="For most banks is France you should use the " + help="For most banks in France you should use the " "format neutral Order Types 'FUL' for upload " "and 'FDL' for download.") test_mode = fields.Boolean( @@ -89,10 +89,6 @@ class EbicsXfer(models.TransientModel): else: return cfg_mod - @api.model - def _selection_order_type(self): - return self.env['ebics.file.format']._selection_order_type() - @api.onchange('ebics_config_id') def _onchange_ebics_config_id(self): domain = {} @@ -156,25 +152,28 @@ class EbicsXfer(models.TransientModel): self.note = '' client = self._setup_client() if client: - download_formats = self.format_id \ + download_formats = ( + self.format_id or self.ebics_config_id.ebics_file_format_ids.filtered( - lambda r: r.type == 'down') + lambda r: r.type == 'down' + ) + ) ebics_files = self.env['ebics.file'] for df in download_formats: - success = False - order_type = df.order_type or 'FDL' - params = {} - if order_type == 'FDL': - params['filetype'] = df.name - if order_type in ['FDL', 'C52', 'C53', 'C54']: - params.update({ - 'start': self.date_from or None, - 'end': self.date_to or None, - }) - kwargs = {k: v for k, v in params.items() if v} try: - method = getattr(client, order_type) - data = method(**kwargs) + success = False + if df.order_type == 'FDL': + data = client.FDL( + df.name, self.date_from or None, self.date_to or None + ) + else: + params = None + if self.date_from and self.date_to: + params = {'DateRange': { + 'Start': self.date_from or None, + 'End': self.date_to or None, + }} + data = client.download(df.order_type, params=params) ebics_files += self._handle_download_data(data, df) success = True except EbicsFunctionalError: @@ -259,9 +258,7 @@ class EbicsXfer(models.TransientModel): ef_format = self.format_id OrderID = False try: - order_type = ef_format.order_type or 'FUL' - method = hasattr(client, order_type) \ - and getattr(client, order_type) + order_type = self.order_type if order_type == 'FUL': kwargs = {} # bank = self.ebics_config_id.bank_id.bank v8.0 @@ -270,15 +267,9 @@ class EbicsXfer(models.TransientModel): kwargs['country'] = bank.country.code if self.test_mode: kwargs['TEST'] = 'TRUE' - OrderID = method(ef_format.name, upload_data, **kwargs) - elif order_type in ['CCT', 'CDD', 'CDB']: - OrderID = method(upload_data) - elif order_type in ['XE2', 'XE3']: - OrderID = client.upload(order_type, upload_data) + OrderID = client.FUL(ef_format.name, upload_data, **kwargs) else: - # TODO: investigate if it makes sense to support - # a generic upload for a non-predefined order_type - pass + OrderID = client.upload(order_type, upload_data) if OrderID: self.note += '\n' self.note += _(