diff --git a/account_ebics/README.rst b/account_ebics/README.rst index ec60692..f054250 100644 --- a/account_ebics/README.rst +++ b/account_ebics/README.rst @@ -27,8 +27,6 @@ and fintech 7.2.7 or higher for EBICS 3.0. SWIFT 3SKey support requires fintech 6.4 or higher. - - | We also recommend to consider the installation of the following modules: @@ -71,9 +69,17 @@ We also recommend to consider the installation of the following modules: - account_ebics_payment_order - Recommended if you are using the OCA account_payment_order module. + Required if you are using the OCA account_payment_order module. - Cf. https://github.com/Noviat/account_ebics and https://github.com/OCA/bank-payment + Cf. https://github.com/OCA/bank-payment + +| + +- account_ebics_oca_statement_import + + Required if you are using the OCA Bank Statement import modules. + + https://github.com/OCA/bank-statement-import | @@ -93,27 +99,6 @@ We also recommend to consider the installation of the following modules: | -- account_statement_import_helper - - Required if you are processing bank statements with local bank account numbers (e.g. french CFONB files) - and using import parsers based upon the OCA account_statement_import module. - - The import helper will match the local bank account number with the IBAN number specified on the Odoo Financial journal. - - Cf. https://github.com/Noviat/noviat-apps - -| - -- account_bank_statement_import_helper - - Required if you are processing bank statements with local bank account numbers - and using import parsers based upon the Odoo Enterprise account_bank_statement_import module. - - The import helper will match the local bank account number with the IBAN number specified on the Odoo Financial journal. - - Cf. https://github.com/Noviat/noviat-apps - -| Fintech license --------------- @@ -130,13 +115,6 @@ The name of the licensee. The keycode of the licensed version. -- fintech_register_users - -The licensed EBICS user ids. It must be a string or a list of user ids. - -You should NOT specify this parameter if your license is subsciption -based (with monthly recurring billing). - | | Example: | @@ -146,7 +124,6 @@ based (with monthly recurring billing). ; fintech fintech_register_name = MyCompany fintech_register_keycode = AB1CD-E2FG-3H-IJ4K-5L - fintech_register_users = USER1, USER2 | diff --git a/account_ebics/__manifest__.py b/account_ebics/__manifest__.py index 9b32d3f..0e15ad3 100644 --- a/account_ebics/__manifest__.py +++ b/account_ebics/__manifest__.py @@ -3,7 +3,7 @@ { "name": "EBICS banking protocol", - "version": "16.0.1.3.1", + "version": "16.0.1.4.0", "license": "LGPL-3", "author": "Noviat", "website": "https://www.noviat.com", diff --git a/account_ebics/models/account_bank_statement.py b/account_ebics/models/account_bank_statement.py index 64616e1..89c5eaf 100644 --- a/account_ebics/models/account_bank_statement.py +++ b/account_ebics/models/account_bank_statement.py @@ -8,3 +8,4 @@ class AccountBankStatement(models.Model): _inherit = "account.bank.statement" ebics_file_id = fields.Many2one(comodel_name="ebics.file", string="EBICS Data File") + import_format = fields.Char(readonly=True) diff --git a/account_ebics/models/ebics_config.py b/account_ebics/models/ebics_config.py index d84eb25..a7b6fe5 100644 --- a/account_ebics/models/ebics_config.py +++ b/account_ebics/models/ebics_config.py @@ -91,14 +91,6 @@ class EbicsConfig(models.Model): "between customer and financial institution. " "The human user also can authorise orders.", ) - ebics_files = fields.Char( - string="EBICS Files Root", - required=True, - readonly=True, - states={"draft": [("readonly", False)]}, - default=lambda self: self._default_ebics_files(), - help="Root Directory for EBICS File Transfer Folders.", - ) # We store the EBICS keys in a separate directory in the file system. # This directory requires special protection to reduce fraude. ebics_keys = fields.Char( @@ -253,14 +245,3 @@ class EbicsConfig(models.Model): ) % dirname ) - - def _check_ebics_files(self): - dirname = self.ebics_files or "" - if not os.path.exists(dirname): - raise UserError( - _( - "EBICS Files Root Directory %s is not available." - "\nPlease contact your system administrator." - ) - % dirname - ) diff --git a/account_ebics/models/ebics_file.py b/account_ebics/models/ebics_file.py index 63f4353..7ef3514 100644 --- a/account_ebics/models/ebics_file.py +++ b/account_ebics/models/ebics_file.py @@ -11,12 +11,13 @@ from lxml import etree from odoo import _, fields, models from odoo.exceptions import UserError -from odoo.tools.safe_eval import safe_eval from odoo.addons.base.models.res_bank import sanitize_account_number _logger = logging.getLogger(__name__) +DUP_CHECK_FORMATS = ["cfonb120", "camt053"] + class EbicsFile(models.Model): _name = "ebics.file" @@ -177,31 +178,95 @@ class EbicsFile(models.Model): return False return True - def _process_download_result(self, res): + def _lookup_journal(self, res, acc_number, currency_code): + currency = self.env["res.currency"].search( + [("name", "=ilike", currency_code)], limit=1 + ) + journal = self.env["account.journal"] + if not currency: + message = _("Currency %(cc)s not found.", cc=currency_code) + res["notifications"].append({"type": "error", "message": message}) + return (currency, journal) + + journals = self.env["account.journal"].search( + [ + ("type", "=", "bank"), + ( + "bank_account_id.sanitized_acc_number", + "ilike", + acc_number, + ), + ] + ) + if not journals: + message = _( + "No financial journal found for Account Number %(nbr)s, " + "Currency %(cc)s", + nbr=acc_number, + cc=currency_code, + ) + res["notifications"].append({"type": "error", "message": message}) + return (currency, journal) + + for jrnl in journals: + journal_currency = jrnl.currency_id or jrnl.company_id.currency_id + if journal_currency != currency: + continue + else: + journal = jrnl + break + + if not journal: + message = _( + "No financial journal found for Account Number %(nbr)s, " + "Currency %(cc)s", + nbr=acc_number, + cc=currency_code, + ) + res["notifications"].append({"type": "error", "message": message}) + return (currency, journal) + + def _process_download_result(self, res, file_format=None): + """ + We perform a duplicate statement check after the creation of the bank + statements since we rely on Odoo Enterprise or OCA modules for the + bank statement creation. + From a development standpoint (code creation/maintenance) a check after + creation is the easiest way. + """ statement_ids = res["statement_ids"] notifications = res["notifications"] statements = self.env["account.bank.statement"].sudo().browse(statement_ids) - st_cnt = len(statement_ids) + if statements: + statements.write({"import_format": file_format}) + statements = self._statement_duplicate_check(res, statements) + st_cnt = len(statements) warning_cnt = error_cnt = 0 if notifications: + errors = [] + warnings = [] for notif in notifications: if notif["type"] == "error": error_cnt += 1 + parts = [notif[k] for k in notif if k in ("message", "details")] + errors.append("\n".join(parts)) elif notif["type"] == "warning": warning_cnt += 1 - parts = [notif[k] for k in notif if k in ("message", "details")] - self.note_process += "\n".join(parts) - self.note_process += "\n\n" - self.note_process += "\n" + parts = [notif[k] for k in notif if k in ("message", "details")] + warnings.append("\n".join(parts)) + + self.note_process += _("Process file %(fn)s results:", fn=self.name) if error_cnt: - self.note_process += ( - _("Number of errors detected during import: %s") % error_cnt - ) - self.note_process += "\n" + self.note_process += "\n\n" + _("Errors") + ":\n" + self.note_process += "\n".join(errors) + self.note_process += "\n\n" + self.note_process += _("Number of errors: %(nr)s", nr=error_cnt) if warning_cnt: - self.note_process += ( - _("Number of warnings detected during import: %s") % warning_cnt - ) + self.note_process += "\n\n" + _("Warnings") + ":\n" + self.note_process += "\n".join(warnings) + self.note_process += "\n\n" + self.note_process += _("Number of warnings: %(nr)s", nr=warning_cnt) + self.note_process += "\n" if st_cnt: self.note_process += "\n\n" self.note_process += _( @@ -211,16 +276,17 @@ class EbicsFile(models.Model): ) self.note_process += "\n" for statement in statements: - self.note_process += ("\n%s, %s (%s)") % ( - statement.date, - statement.name, - statement.company_id.name, + self.note_process += "\n" + _( + "Statement %(st)s dated %(date)s (Company: %(cpy)s)", + st=statement.name, + date=statement.date, + cpy=statement.company_id.name, ) - if statement_ids: - self.sudo().bank_statement_ids = [(4, x) for x in statement_ids] + if statements: + self.sudo().bank_statement_ids = [(4, x) for x in statements.ids] company_ids = self.sudo().bank_statement_ids.mapped("company_id").ids self.company_ids = [(6, 0, company_ids)] - ctx = dict(self.env.context, statement_ids=statement_ids) + ctx = dict(self.env.context, statement_ids=statements.ids) module = __name__.split("addons.")[1].split(".")[0] result_view = self.env.ref("%s.ebics_file_view_form_result" % module) return { @@ -235,104 +301,47 @@ class EbicsFile(models.Model): "type": "ir.actions.act_window", } - def _process_cfonb120(self): + def _statement_duplicate_check(self, res, statements): """ - Disable this code while waiting on OCA cfonb release for 16.0 + This check is required for import modules that do not + set the 'unique_import_id' on the statement lines. + E.g. OCA camt import """ - # pylint: disable=W0101 - raise NotImplementedError + to_unlink = self.env["account.bank.statement"] + for statement in statements.filtered( + lambda r: r.import_format in DUP_CHECK_FORMATS + ): + dup = self.env["account.bank.statement"].search_count( + [ + ("id", "!=", statement.id), + ("name", "=", statement.name), + ("company_id", "=", statement.company_id.id), + ("date", "=", statement.date), + ("import_format", "=", statement.import_format), + ] + ) + if dup: + message = _( + "Statement %(st_name)s dated %(date)s has already been imported.", + st_name=statement.name, + date=statement.date, + ) + res["notifications"].append({"type": "warning", "message": message}) + to_unlink += statement + res["statement_ids"] = [ + x for x in res["statement_ids"] if x not in to_unlink.ids + ] + statements -= to_unlink + to_unlink.unlink() + return statements + def _process_cfonb120(self): import_module = "account_statement_import_fr_cfonb" self._check_import_module(import_module) - wiz_model = "account.statement.import" - data_file = base64.b64decode(self.data) - lines = data_file.split(b"\n") - wiz_vals_list = [] - st_lines = b"" - transactions = False - for line in lines: - rec_type = line[0:2] - acc_number = line[21:32] - st_lines += line + b"\n" - if rec_type == b"04": - transactions = True - if rec_type == b"07": - if transactions: - fn = "_".join([acc_number.decode(), self.name]) - wiz_vals_list.append( - { - "statement_filename": fn, - "statement_file": base64.b64encode(st_lines), - } - ) - st_lines = b"" - transactions = False - result_action = self.env["ir.actions.act_window"]._for_xml_id( - "account.action_bank_statement_tree" - ) - result_action["context"] = safe_eval(result_action["context"]) - statement_ids = [] - notifications = [] - for i, wiz_vals in enumerate(wiz_vals_list, start=1): - result = { - "statement_ids": [], - "notifications": [], - } - statement_filename = wiz_vals["statement_filename"] - wiz = ( - self.env[wiz_model] - .with_context(active_model="ebics.file") - .create(wiz_vals) - ) - try: - with self.env.cr.savepoint(): - file_data = base64.b64decode(wiz_vals["statement_file"]) - msg_hdr = _( - "{} : Import failed for statement number %(index)s, filename %(fn)s:\n", - index=i, - fn=statement_filename, - ) - wiz.import_single_file(file_data, result) - if not result["statement_ids"]: - message = msg_hdr.format(_("Warning")) - message += _( - "You have already imported this file, or this file " - "only contains already imported transactions." - ) - notifications += [ - { - "type": "warning", - "message": message, - } - ] - else: - statement_ids.extend(result["statement_ids"]) - notifications.extend(result["notifications"]) - - except UserError as e: - message = msg_hdr.format(_("Error")) - message += "".join(e.args) - notifications += [ - { - "type": "error", - "message": message, - } - ] - - except Exception: - tb = "".join(format_exception(*exc_info())) - message = msg_hdr.format(_("Error")) - message += tb - notifications += [ - { - "type": "error", - "message": message, - } - ] - - result_action["context"]["notifications"] = notifications - result_action["domain"] = [("id", "in", statement_ids)] - return self._process_result_action(result_action) + res = {"statement_ids": [], "notifications": []} + st_datas = self._split_cfonb(res) + self._process_bank_statement_oca(res, st_datas) + return self._process_download_result(res, file_format="cfonb120") def _unlink_cfonb120(self): """ @@ -340,10 +349,45 @@ class EbicsFile(models.Model): EBICS data file and its related bank statements. """ + def _split_cfonb(self, res): + """ + Split CFONB file received via EBICS per statement. + Statements without transactions are removed. + """ + datas = [] + file_data = base64.b64decode(self.data) + lines = file_data.split(b"\n") + st_lines = b"" + transactions = False + for line in lines: + rec_type = line[0:2] + currency_code = line[16:19].decode() + acc_number = line[21:32].decode() + st_lines += line + b"\n" + if rec_type == b"04": + transactions = True + if rec_type == b"07": + if transactions: + currency, journal = self._lookup_journal( + res, acc_number, currency_code + ) + if currency and journal: + datas.append( + { + "acc_number": acc_number, + "journal_id": journal.id, + "company_id": journal.company_id.id, + "data": base64.b64encode(st_lines), + } + ) + st_lines = b"" + transactions = False + return datas + def _process_camt052(self): import_module = "account_statement_import_camt" self._check_import_module(import_module) - return self._process_camt053(self) + return self._process_camt053(file_format="camt052") def _unlink_camt052(self): """ @@ -354,7 +398,7 @@ class EbicsFile(models.Model): def _process_camt054(self): import_module = "account_statement_import_camt" self._check_import_module(import_module) - return self._process_camt053(self) + return self._process_camt053(file_format="camt054") def _unlink_camt054(self): """ @@ -362,7 +406,7 @@ class EbicsFile(models.Model): EBICS data file and its related bank statements. """ - def _process_camt053(self): + def _process_camt053(self, file_format=None): """ The Odoo standard statement import is based on manual selection of a financial journal before importing the electronic statement file. @@ -394,28 +438,26 @@ class EbicsFile(models.Model): res = {"statement_ids": [], "notifications": []} st_datas = self._split_camt(res) if author == "oca": - self._process_camt053_oca(res, st_datas) + self._process_bank_statement_oca(res, st_datas) else: - self._process_camt053_oe(res, st_datas) - return self._process_download_result(res) + self._process_bank_statement_oe(res, st_datas) + file_format = file_format or "camt053" + return self._process_download_result(res, file_format=file_format) - def _process_camt053_oca(self, res, st_datas): - msg_hdr = _("{} : Import failed for file %(fn)s:\n", fn=self.name) + def _process_bank_statement_oca(self, res, st_datas): for st_data in st_datas: try: with self.env.cr.savepoint(): - self._create_statement_camt053_oca(res, st_data) + self._create_bank_statement_oca(res, st_data) except UserError as e: - message = msg_hdr.format(_("Error")) - message += "".join(e.args) - res["notifications"].append({"type": "error", "message": message}) + res["notifications"].append( + {"type": "error", "message": "".join(e.args)} + ) except Exception: tb = "".join(format_exception(*exc_info())) - message = msg_hdr.format(_("Error")) - message += tb - res["notifications"].append({"type": "error", "message": message}) + res["notifications"].append({"type": "error", "message": tb}) - def _create_statement_camt053_oca(self, res, st_data): + def _create_bank_statement_oca(self, res, st_data): wiz = ( self.env["account.statement.import"] .with_company(st_data["company_id"]) @@ -424,27 +466,28 @@ class EbicsFile(models.Model): ) wiz.import_single_file(base64.b64decode(st_data["data"]), res) - def _process_camt053_oe(self, res, st_datas): + def _process_bank_statement_oe(self, res, st_datas): """ We execute a cr.commit() after every statement import since we get a 'savepoint does not exist' error when using 'with self.env.cr.savepoint()'. """ - msg_hdr = _("{} : Import failed for file %(fn)s:\n", fn=self.name) for st_data in st_datas: try: - self._create_statement_camt053_oe(res, st_data) + self._create_bank_statement_oe(res, st_data) self.env.cr.commit() # pylint: disable=E8102 except UserError as e: - message = msg_hdr.format(_("Error")) - message += "".join(e.args) - res["notifications"].append({"type": "error", "message": message}) + msg = "".join(e.args) + msg += "\n" + msg += _( + "Statement for Account Number %(nr)s has not been processed.", + nr=st_data["acc_number"], + ) + res["notifications"].append({"type": "error", "message": msg}) except Exception: tb = "".join(format_exception(*exc_info())) - message = msg_hdr.format(_("Error")) - message += tb - res["notifications"].append({"type": "error", "message": message}) + res["notifications"].append({"type": "error", "message": tb}) - def _create_statement_camt053_oe(self, res, st_data): + def _create_bank_statement_oe(self, res, st_data): attachment = ( self.env["ir.attachment"] .with_company(st_data["company_id"]) @@ -486,20 +529,14 @@ class EbicsFile(models.Model): Statements without transactions are removed. """ datas = [] - msg_hdr = _("{} : Import failed for file %(fn)s:\n", fn=self.name) file_data = base64.b64decode(self.data) root = etree.fromstring(file_data, parser=etree.XMLParser(recover=True)) if root is None: - message = msg_hdr.format(_("Error")) - message += _("Invalid XML file.") + message = _("Invalid XML file.") res["notifications"].append({"type": "error", "message": message}) ns = {k or "ns": v for k, v in root.nsmap.items()} - for i, stmt in enumerate(root[0].findall("ns:Stmt", ns), start=1): - msg_hdr = _( - "{} : Import failed for statement number %(index)s, filename %(fn)s:\n", - index=i, - fn=self.name, - ) + stmts = root[0].findall("ns:Stmt", ns) + for i, stmt in enumerate(stmts): acc_number = sanitize_account_number( stmt.xpath( "ns:Acct/ns:Id/ns:IBAN/text() | ns:Acct/ns:Id/ns:Othr/ns:Id/text()", @@ -507,72 +544,34 @@ class EbicsFile(models.Model): )[0] ) if not acc_number: - message = msg_hdr.format(_("Error")) - message += _("No bank account number found.") + message = _("No bank account number found.") res["notifications"].append({"type": "error", "message": message}) continue currency_code = stmt.xpath( "ns:Acct/ns:Ccy/text() | ns:Bal/ns:Amt/@Ccy", namespaces=ns )[0] - currency = self.env["res.currency"].search( - [("name", "=ilike", currency_code)], limit=1 - ) - if not currency: - message = msg_hdr.format(_("Error")) - message += _("Currency %(cc)s not found.", cc=currency_code) - res["notifications"].append({"type": "error", "message": message}) - continue - journal = self.env["account.journal"].search( - [ - ("type", "=", "bank"), - ( - "bank_account_id.sanitized_acc_number", - "ilike", - acc_number, - ), - ] - ) - if not journal: - message = msg_hdr.format(_("Error")) - message += _( - "No financial journal found for Account Number %(nbr)s, " - "Currency %(cc)s", - nbr=acc_number, - cc=currency_code, - ) - res["notifications"].append({"type": "error", "message": message}) - continue - - journal_currency = journal.currency_id or journal.company_id.currency_id - if journal_currency != currency: - message = msg_hdr.format(_("Error")) - message += _( - "No financial journal found for Account Number %(nbr)s, " - "Currency %(cc)s", - nbr=acc_number, - cc=currency_code, - ) - res["notifications"].append({"type": "error", "message": message}) - continue root_new = deepcopy(root) entries = False - for j, el in enumerate(root_new[0].findall("ns:Stmt", ns), start=1): + for j, el in enumerate(root_new[0].findall("ns:Stmt", ns)): if j != i: el.getparent().remove(el) else: entries = el.findall("ns:Ntry", ns) if not entries: continue - - datas.append( - { - "acc_number": acc_number, - "journal_id": journal.id, - "company_id": journal.company_id.id, - "data": base64.b64encode(etree.tostring(root_new)), - } - ) + else: + currency, journal = self._lookup_journal(res, acc_number, currency_code) + if not (currency and journal): + continue + datas.append( + { + "acc_number": acc_number, + "journal_id": journal.id, + "company_id": journal.company_id.id, + "data": base64.b64encode(etree.tostring(root_new)), + } + ) return datas diff --git a/account_ebics/models/ebics_userid.py b/account_ebics/models/ebics_userid.py index 2e1cfb3..89a9977 100644 --- a/account_ebics/models/ebics_userid.py +++ b/account_ebics/models/ebics_userid.py @@ -129,7 +129,7 @@ class EbicsUserID(models.Model): "by means of the SWIFT 3SKey token.", ) swift_3skey_certificate = fields.Binary(string="3SKey Certficate") - swift_3skey_certificate_fn = fields.Char(string="EBICS certificate name") + swift_3skey_certificate_fn = fields.Char(string="3SKey Certificate Filename") # X.509 Distinguished Name attributes used to # create self-signed X.509 certificates ebics_key_x509 = fields.Boolean( @@ -255,7 +255,6 @@ class EbicsUserID(models.Model): Create new keys and certificates for this user """ self.ensure_one() - self.ebics_config_id._check_ebics_files() if self.state != "draft": raise UserError( _("Set state to 'draft' before Bank Key (re)initialisation.") @@ -442,7 +441,6 @@ class EbicsUserID(models.Model): must be downloaded and checked for consistency. """ self.ensure_one() - self.ebics_config_id._check_ebics_files() if self.state != "get_bank_keys": raise UserError(_("Set state to 'Get Keys from Bank'.")) try: diff --git a/account_ebics/static/description/index.html b/account_ebics/static/description/index.html index b6b1ad1..dc19440 100644 --- a/account_ebics/static/description/index.html +++ b/account_ebics/static/description/index.html @@ -429,8 +429,17 @@ which allows to see all statements downloaded via the ir.cron automated EBICS do +
+

+
+
@@ -454,28 +463,6 @@ which allows to see all statements downloaded via the ir.cron automated EBICS do

- -
-

-
- -
-

-

Fintech license

If you have a valid Fintech.ebics license, you should add the following @@ -488,12 +475,6 @@ licensing parameters to the odoo server configuration file:

  • fintech_register_keycode
  • The keycode of the licensed version.

    - -

    The licensed EBICS user ids. It must be a string or a list of user ids.

    -

    You should NOT specify this parameter if your license is subsciption -based (with monthly recurring billing).


    Example:
    @@ -503,7 +484,6 @@ based (with monthly recurring billing).

    ; fintech fintech_register_name = MyCompany fintech_register_keycode = AB1CD-E2FG-3H-IJ4K-5L -fintech_register_users = USER1, USER2

    diff --git a/account_ebics/views/ebics_config_views.xml b/account_ebics/views/ebics_config_views.xml index f7220d9..15735fe 100644 --- a/account_ebics/views/ebics_config_views.xml +++ b/account_ebics/views/ebics_config_views.xml @@ -52,7 +52,6 @@ - diff --git a/account_ebics/wizards/ebics_admin_order.py b/account_ebics/wizards/ebics_admin_order.py index 3f28d0e..d0ffedf 100644 --- a/account_ebics/wizards/ebics_admin_order.py +++ b/account_ebics/wizards/ebics_admin_order.py @@ -27,7 +27,6 @@ class EbicsAdminOrder(models.TransientModel): def ebics_admin_order(self): self.ensure_one() - self.ebics_config_id._check_ebics_files() client = self._setup_client() if not client: self.note += ( diff --git a/account_ebics/wizards/ebics_xfer.py b/account_ebics/wizards/ebics_xfer.py index 44a5504..de50344 100644 --- a/account_ebics/wizards/ebics_xfer.py +++ b/account_ebics/wizards/ebics_xfer.py @@ -10,7 +10,6 @@ logging.basicConfig( import base64 import logging -import os from sys import exc_info from traceback import format_exception @@ -71,9 +70,9 @@ class EbicsXfer(models.TransientModel): date_from = fields.Date() date_to = fields.Date() upload_data = fields.Binary(string="File to Upload") - upload_fname = fields.Char(default="") + upload_fname = fields.Char(string="Upload Filename", default="") upload_fname_dummy = fields.Char( - related="upload_fname", string="Upload Filename", readonly=True + related="upload_fname", string="Dummy Upload Filename", readonly=True ) format_id = fields.Many2one( comodel_name="ebics.file.format", @@ -193,7 +192,6 @@ class EbicsXfer(models.TransientModel): def ebics_download(self): self.ensure_one() - self.ebics_config_id._check_ebics_files() ctx = self.env.context.copy() self.note = "" err_cnt = 0 @@ -532,43 +530,17 @@ class EbicsXfer(models.TransientModel): return ebics_files def _create_ebics_file(self, data, file_format, docname=None): - """ - Write the data as received over the EBICS connection - to a temporary file so that is is available for - analysis (e.g. in case formats are received that cannot - be handled in the current version of this module). - - TODO: add code to clean-up /tmp on a regular basis. - - After saving the data received we call the method to perform - file format specific processing. - """ - ebics_files_root = self.ebics_config_id.ebics_files - tmp_dir = os.path.normpath(ebics_files_root + "/tmp") - if not os.path.isdir(tmp_dir): - os.makedirs(tmp_dir, mode=0o700) fn_parts = [self.ebics_config_id.ebics_host, self.ebics_config_id.ebics_partner] if docname: fn_parts.append(docname) else: fn_date = self.date_to or fields.Date.today() fn_parts.append(fn_date.isoformat()) - base_fn = "_".join(fn_parts) - n = 1 - full_tmp_fn = os.path.normpath(tmp_dir + "/" + base_fn) - while os.path.exists(full_tmp_fn): - n += 1 - tmp_fn = base_fn + "_" + str(n).rjust(3, "0") - full_tmp_fn = os.path.normpath(tmp_dir + "/" + tmp_fn) - - with open(full_tmp_fn, "wb") as f: - f.write(data) - + fn = "_".join(fn_parts) ff_methods = self._file_format_methods() if file_format.name in ff_methods: data = ff_methods[file_format.name](data) - fn = base_fn suffix = file_format.suffix if suffix and not fn.endswith(suffix): fn = ".".join([fn, suffix]) diff --git a/account_ebics/wizards/ebics_xfer.xml b/account_ebics/wizards/ebics_xfer.xml index 9cb67fb..4fdcac1 100644 --- a/account_ebics/wizards/ebics_xfer.xml +++ b/account_ebics/wizards/ebics_xfer.xml @@ -82,7 +82,7 @@ - +