From 2807c3ffd78006ce66ac873738b95c58bc973761 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 18 Nov 2022 10:27:25 +0100 Subject: [PATCH] add support for ebics 3.0 --- account_ebics/README.rst | 1 - account_ebics/data/ebics_file_format.xml | 41 ++++++++++++ account_ebics/models/ebics_config.py | 6 +- account_ebics/models/ebics_file_format.py | 63 ++++++++++++++++++- account_ebics/models/ebics_userid.py | 22 ++++--- account_ebics/views/ebics_config_views.xml | 2 +- .../views/ebics_file_format_views.xml | 39 +++++++++++- account_ebics/wizards/ebics_xfer.py | 20 ++++-- 8 files changed, 173 insertions(+), 21 deletions(-) diff --git a/account_ebics/README.rst b/account_ebics/README.rst index 73aa9cb..2649075 100644 --- a/account_ebics/README.rst +++ b/account_ebics/README.rst @@ -194,5 +194,4 @@ You can also find this information in the doc folder of this module (file EBICS_ Known Issues / Roadmap ====================== -- add support for EBICS 3.0 - add support to import externally generated keys & certificates (currently only 3SKey signature certificate) diff --git a/account_ebics/data/ebics_file_format.xml b/account_ebics/data/ebics_file_format.xml index e1baaad..05bad93 100644 --- a/account_ebics/data/ebics_file_format.xml +++ b/account_ebics/data/ebics_file_format.xml @@ -4,6 +4,7 @@ + 2 camt.052 down C52 @@ -13,6 +14,7 @@ + 2 camt.052 down Z52 @@ -22,6 +24,7 @@ + 2 camt.053 down C53 @@ -33,6 +36,7 @@ + 2 camt.053 down Z53 @@ -44,6 +48,7 @@ + 2 camt.054 down C54 @@ -55,6 +60,7 @@ + 2 camt.054 down Z54 @@ -66,6 +72,7 @@ + 2 camt.xxx.cfonb120.stm down FDL @@ -77,6 +84,7 @@ + 2 pain.002 down CDZ @@ -87,6 +95,7 @@ + 2 pain.002 down Z01 @@ -97,9 +106,23 @@ psr.xml + + 3 + down + BTD + cfonb120 + Bank to customer statement report in format cfonb120 + cfonb120.dat + EOP + cfonb120 + + + 2 pain.xxx.cfonb160.dco up FUL @@ -108,6 +131,7 @@ + 2 pain.001.001.03 up CCT @@ -116,6 +140,7 @@ + 2 pain.001.001.03 up XE2 @@ -124,6 +149,7 @@ + 2 pain.008.001.02.sdd up CDD @@ -134,6 +160,7 @@ + 2 pain.008.001.02.sdd up XE3 @@ -144,6 +171,7 @@ + 2 pain.008.001.02.sbb up CDB @@ -154,6 +182,7 @@ + 2 pain.008.001.02.sbb up XE4 @@ -164,6 +193,7 @@ + 2 pain.001.001.02.sct up FUL @@ -171,4 +201,15 @@ xml + + 3 + up + BTU + SEPA credit transfer + txt + SCT + pain.001 + GLB + + diff --git a/account_ebics/models/ebics_config.py b/account_ebics/models/ebics_config.py index 537358d..b25b668 100644 --- a/account_ebics/models/ebics_config.py +++ b/account_ebics/models/ebics_config.py @@ -51,7 +51,11 @@ class EbicsConfig(models.Model): help="Contact your bank to get the EBICS URL.", ) ebics_version = fields.Selection( - selection=[("H003", "H003 (2.4)"), ("H004", "H004 (2.5)")], + selection=[ + ("H003", "H003 (2.4)"), + ("H004", "H004 (2.5)"), + ("H005", "H005 (3.0)"), + ], string="EBICS protocol version", readonly=True, states={"draft": [("readonly", False)]}, diff --git a/account_ebics/models/ebics_file_format.py b/account_ebics/models/ebics_file_format.py index ffeb0f0..d2ab636 100644 --- a/account_ebics/models/ebics_file_format.py +++ b/account_ebics/models/ebics_file_format.py @@ -9,9 +9,17 @@ class EbicsFileFormat(models.Model): _description = "EBICS File Formats" _order = "type,name,order_type" + ebics_version = fields.Selection( + selection=[ + ("2", "2"), + ("3", "3"), + ], + string="EBICS protocol version", + required=True, + default="2", + ) 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" @@ -23,7 +31,8 @@ class EbicsFileFormat(models.Model): ) order_type = fields.Char( required=True, - help="E.g. C53 (check your EBICS contract).\n" + help="EBICS 3.0: BTD (download) or BTU (upload).\n" + "EBICS 2.0: E.g. C53 (check your EBICS contract). " "For most banks in France you should use the " "format neutral Order Types 'FUL' for upload " "and 'FDL' for download.", @@ -48,7 +57,48 @@ class EbicsFileFormat(models.Model): description = fields.Char() suffix = fields.Char( required=True, - help="Specify the filename suffix for this File Format." "\nE.g. c53.xml", + help="Specify the filename suffix for this File Format.\nE.g. c53.xml", + ) + # EBICS 3.0 BTF + btf_service = fields.Char( + string="BTF Service", + help="BTF Service Name)\n" + "The service code name consisting of 3 alphanumeric characters " + "[A-Z0-9] (e.g. SCT, SDD, STM, EOP)", + ) + btf_message = fields.Char( + string="BTF Message Name", + help="BTF Message Name\n" + "The message name consisting of up to 10 alphanumeric characters " + "[a-z0-9.] (eg. pain.001, pain.008, camt.053)", + ) + btf_scope = fields.Char( + string="BTF Scope", + help="Scope of service.\n" + "Either an ISO-3166 ALPHA 2 country code or an issuer code " + "of 3 alphanumeric characters [A-Z0-9].", + ) + btf_option = fields.Char( + string="BTF Option", + help="The service option code consisting of 3-10 alphanumeric " + "characters [A-Z0-9] (eg. COR, B2B)", + ) + btf_container = fields.Char( + string="BTF Container", + help="Type of container consisting of 3 characters [A-Z] (eg. XML, ZIP).", + ) + btf_version = fields.Char( + string="BTF Version", + help="Message version consisting of 2 numeric characters [0-9] (eg. 03).", + ) + btf_variant = fields.Char( + string="BTF Variant", + help="Message variant consisting of 3 numeric characters [0-9] (eg. 001).", + ) + btf_format = fields.Char( + string="BTF Format", + help="Message format consisting of 1-4 alphanumeric characters [A-Z0-9] " + "(eg. XML, JSON, PDF).", ) @api.model @@ -60,3 +110,10 @@ class EbicsFileFormat(models.Model): def _onchange_type(self): if self.type == "up": self.download_process_method = False + + def name_get(self): + res = [] + for rec in self: + name = rec.ebics_version == "2" and rec.name or rec.btf_message + res.append((rec.id, name)) + return res diff --git a/account_ebics/models/ebics_userid.py b/account_ebics/models/ebics_userid.py index 3c27bd0..7df3026 100644 --- a/account_ebics/models/ebics_userid.py +++ b/account_ebics/models/ebics_userid.py @@ -14,8 +14,8 @@ from odoo.exceptions import UserError _logger = logging.getLogger(__name__) # logging.basicConfig( -# level=logging.DEBUG, -# format='[%(asctime)s] %(levelname)s - %(name)s: %(message)s') +# level=logging.DEBUG, +# format='[%(asctime)s] %(levelname)s - %(name)s: %(message)s') try: import fintech @@ -173,7 +173,9 @@ class EbicsUserID(models.Model): for rec in self: keys_dir = rec.ebics_config_id.ebics_keys rec.ebics_keys_fn = ( - rec.name and keys_dir and (keys_dir + "/" + rec.name + "_keys") + rec.name + and keys_dir + and (keys_dir + "/" + rec.name.replace(" ", "_") + "_keys") ) @api.depends("ebics_keys_fn") @@ -254,7 +256,7 @@ class EbicsUserID(models.Model): # enable import of all type of certicates: A00x, X002, E002 if self.swift_3skey: kwargs = { - self.ebics_config_id.ebics_key_version: base64.decodestring( + self.ebics_config_id.ebics_key_version: base64.decodebytes( self.swift_3skey_certificate ), } @@ -300,7 +302,7 @@ class EbicsUserID(models.Model): ) try: supported_versions = client.HEV() - if ebics_version not in supported_versions: + if supported_versions and ebics_version not in supported_versions: err_msg = _("EBICS version mismatch.") + "\n" err_msg += _("Versions supported by your bank:") for k in supported_versions: @@ -321,9 +323,11 @@ class EbicsUserID(models.Model): tb, ) raise UserError( - _("urlopen error:\n url '%(url)s' - %(val)s"), - url=self.ebics_config_id.ebics_url, - val=str(value), + _( + "urlopen error:\n url '%(url)s' - %(val)s", + url=self.ebics_config_id.ebics_url, + val=str(value), + ) ) from err except EbicsFunctionalError as err: e = exc_info() @@ -441,7 +445,7 @@ class EbicsUserID(models.Model): ) self.write( { - "ebics_public_bank_keys": base64.encodestring(public_bank_keys), + "ebics_public_bank_keys": base64.encodebytes(public_bank_keys), "ebics_public_bank_keys_fn": fn, "state": "to_verify", } diff --git a/account_ebics/views/ebics_config_views.xml b/account_ebics/views/ebics_config_views.xml index d7b9aec..b15b21e 100644 --- a/account_ebics/views/ebics_config_views.xml +++ b/account_ebics/views/ebics_config_views.xml @@ -66,7 +66,7 @@ diff --git a/account_ebics/views/ebics_file_format_views.xml b/account_ebics/views/ebics_file_format_views.xml index 1402ac2..e677d3c 100644 --- a/account_ebics/views/ebics_file_format_views.xml +++ b/account_ebics/views/ebics_file_format_views.xml @@ -6,6 +6,7 @@ ebics.file.format + @@ -22,6 +23,7 @@
+ - + + + + + + + + + diff --git a/account_ebics/wizards/ebics_xfer.py b/account_ebics/wizards/ebics_xfer.py index 73abbb4..6552b85 100644 --- a/account_ebics/wizards/ebics_xfer.py +++ b/account_ebics/wizards/ebics_xfer.py @@ -22,6 +22,7 @@ _logger = logging.getLogger(__name__) try: import fintech from fintech.ebics import ( + BusinessTransactionFormat, EbicsBank, EbicsClient, EbicsFunctionalError, @@ -81,9 +82,6 @@ class EbicsXfer(models.TransientModel): order_type = fields.Char( related="format_id.order_type", string="Order Type", - 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( help="Select this option to test if the syntax of " @@ -202,7 +200,19 @@ class EbicsXfer(models.TransientModel): for df in download_formats: try: success = False - if df.order_type == "FDL": + if df.order_type == "BTD": + btf = BusinessTransactionFormat( + df.btf_service, + df.btf_message, + scope=df.btf_scope or None, + option=df.btf_option or None, + container=df.btf_container or None, + version=df.btf_version or None, + variant=df.btf_variant or None, + format=df.btf_format or None, + ) + data = client.BTD(btf, start=date_from, end=date_to) + elif df.order_type == "FDL": data = client.FDL(df.name, date_from, date_to) else: params = None @@ -323,7 +333,7 @@ class EbicsXfer(models.TransientModel): self.note = "" client = self._setup_client() if client: - upload_data = base64.decodestring(self.upload_data) + upload_data = base64.decodebytes(self.upload_data) ef_format = self.format_id OrderID = False try: