From cb2a897b0e90c5c48672a70d12f5cf289165d0c7 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 18 Nov 2020 00:37:47 +0100 Subject: [PATCH] [MIG] account_statement_import_ofx to v14 Rename module to account_statement_import_ofx Add support for multi-account OFX files --- .../wizard/__init__.py | 1 - .../wizard/account_bank_statement_import.py | 100 ------------------ .../README.rst | 0 .../__init__.py | 0 .../__manifest__.py | 8 +- .../account_bank_statement_import_ofx.pot | 0 .../i18n/de.po | 0 .../i18n/es.po | 0 .../i18n/fi.po | 0 .../i18n/fr.po | 0 .../i18n/fr_CH.po | 0 .../i18n/gl.po | 0 .../i18n/lt_LT.po | 0 .../i18n/nb_NO.po | 0 .../i18n/nl.po | 0 .../i18n/pt_BR.po | 0 .../i18n/pt_PT.po | 0 .../i18n/sl.po | 0 .../models/__init__.py | 0 .../models/account_journal.py | 3 +- .../readme/CONTRIBUTORS.rst | 0 .../readme/DESCRIPTION.rst | 2 + .../readme/INSTALL.rst | 0 .../static/description/icon.png | Bin .../tests/__init__.py | 0 .../tests/test_import_bank_statement.py | 52 ++++----- .../tests/test_ofx_file/test_ofx.ofx | 0 .../tests/test_ofx_file/test_ofx_iban.ofx | 0 .../tests/test_ofx_file/test_ofx_wrong.ofx | 0 .../views/account_statement_import.xml | 6 +- .../wizard/__init__.py | 1 + .../wizard/account_statement_import.py | 88 +++++++++++++++ 32 files changed, 127 insertions(+), 134 deletions(-) delete mode 100644 account_bank_statement_import_ofx/wizard/__init__.py delete mode 100644 account_bank_statement_import_ofx/wizard/account_bank_statement_import.py rename {account_bank_statement_import_ofx => account_statement_import_ofx}/README.rst (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/__init__.py (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/__manifest__.py (63%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/account_bank_statement_import_ofx.pot (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/de.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/es.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/fi.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/fr.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/fr_CH.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/gl.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/lt_LT.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/nb_NO.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/nl.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/pt_BR.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/pt_PT.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/i18n/sl.po (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/models/__init__.py (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/models/account_journal.py (81%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/readme/CONTRIBUTORS.rst (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/readme/DESCRIPTION.rst (73%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/readme/INSTALL.rst (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/static/description/icon.png (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/tests/__init__.py (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/tests/test_import_bank_statement.py (66%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/tests/test_ofx_file/test_ofx.ofx (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/tests/test_ofx_file/test_ofx_iban.ofx (100%) rename {account_bank_statement_import_ofx => account_statement_import_ofx}/tests/test_ofx_file/test_ofx_wrong.ofx (100%) rename account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml => account_statement_import_ofx/views/account_statement_import.xml (59%) create mode 100644 account_statement_import_ofx/wizard/__init__.py create mode 100644 account_statement_import_ofx/wizard/account_statement_import.py diff --git a/account_bank_statement_import_ofx/wizard/__init__.py b/account_bank_statement_import_ofx/wizard/__init__.py deleted file mode 100644 index 7dafcd16..00000000 --- a/account_bank_statement_import_ofx/wizard/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import account_bank_statement_import diff --git a/account_bank_statement_import_ofx/wizard/account_bank_statement_import.py b/account_bank_statement_import_ofx/wizard/account_bank_statement_import.py deleted file mode 100644 index 9618f43c..00000000 --- a/account_bank_statement_import_ofx/wizard/account_bank_statement_import.py +++ /dev/null @@ -1,100 +0,0 @@ -import io -import logging - -from odoo import _, api, models -from odoo.exceptions import UserError - -from odoo.addons.base_iban.models.res_partner_bank import ( - _map_iban_template, - validate_iban, -) - -_logger = logging.getLogger(__name__) - -try: - from ofxparse import OfxParser -except ImportError: - _logger.debug("ofxparse not found.") - OfxParser = None - - -class AccountBankStatementImport(models.TransientModel): - _inherit = "account.bank.statement.import" - - def _check_journal_bank_account(self, journal, account_number): - res = super()._check_journal_bank_account(journal, account_number) - if not res: - e_acc_num = journal.bank_account_id.sanitized_acc_number - e_acc_num = e_acc_num.replace(" ", "") - validate_iban(e_acc_num) - country_code = e_acc_num[:2].lower() - iban_template = _map_iban_template[country_code].replace(" ", "") - e_acc_num = "".join( - [c for c, t in zip(e_acc_num, iban_template) if t == "C"] - ) - res = e_acc_num == account_number - return res - - @api.model - def _check_ofx(self, data_file): - if not OfxParser: - return False - try: - ofx = OfxParser.parse(io.BytesIO(data_file)) - except Exception as e: - _logger.debug(e) - return False - return ofx - - @api.model - def _prepare_ofx_transaction_line(self, transaction): - # Since ofxparse doesn't provide account numbers, - # we cannot provide the key 'bank_account_id', - # nor the key 'account_number' - # If you read odoo10/addons/account_bank_statement_import/ - # account_bank_statement_import.py, it's the only 2 keys - # we can provide to match a partner. - name = transaction.payee - if transaction.checknum: - name += " " + transaction.checknum - if transaction.memo: - name += " : " + transaction.memo - vals = { - "date": transaction.date, - "name": name, - "ref": transaction.id, - "amount": float(transaction.amount), - "unique_import_id": transaction.id, - } - return vals - - def _parse_file(self, data_file): - ofx = self._check_ofx(data_file) - if not ofx: - return super()._parse_file(data_file) - - transactions = [] - total_amt = 0.00 - try: - for transaction in ofx.account.statement.transactions: - vals = self._prepare_ofx_transaction_line(transaction) - if vals: - transactions.append(vals) - total_amt += vals["amount"] - except Exception as e: - raise UserError( - _( - "The following problem occurred during import. " - "The file might not be valid.\n\n %s" - ) - % e.message - ) - - balance = float(ofx.account.statement.balance) - vals_bank_statement = { - "name": ofx.account.number, - "transactions": transactions, - "balance_start": balance - total_amt, - "balance_end_real": balance, - } - return ofx.account.statement.currency, ofx.account.number, [vals_bank_statement] diff --git a/account_bank_statement_import_ofx/README.rst b/account_statement_import_ofx/README.rst similarity index 100% rename from account_bank_statement_import_ofx/README.rst rename to account_statement_import_ofx/README.rst diff --git a/account_bank_statement_import_ofx/__init__.py b/account_statement_import_ofx/__init__.py similarity index 100% rename from account_bank_statement_import_ofx/__init__.py rename to account_statement_import_ofx/__init__.py diff --git a/account_bank_statement_import_ofx/__manifest__.py b/account_statement_import_ofx/__manifest__.py similarity index 63% rename from account_bank_statement_import_ofx/__manifest__.py rename to account_statement_import_ofx/__manifest__.py index 3ac95a12..5d34944f 100644 --- a/account_bank_statement_import_ofx/__manifest__.py +++ b/account_statement_import_ofx/__manifest__.py @@ -1,7 +1,7 @@ { "name": "Import OFX Bank Statement", "category": "Banking addons", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "license": "AGPL-3", "author": "Odoo SA," "Akretion," @@ -11,8 +11,8 @@ "Le Filament," "Odoo Community Association (OCA)", "website": "https://github.com/OCA/bank-statement-import", - "depends": ["account_bank_statement_import",], - "data": ["views/view_account_bank_statement_import.xml",], - "external_dependencies": {"python": ["ofxparse"],}, + "depends": ["account_statement_import"], + "data": ["views/account_statement_import.xml"], + "external_dependencies": {"python": ["ofxparse"]}, "installable": True, } diff --git a/account_bank_statement_import_ofx/i18n/account_bank_statement_import_ofx.pot b/account_statement_import_ofx/i18n/account_bank_statement_import_ofx.pot similarity index 100% rename from account_bank_statement_import_ofx/i18n/account_bank_statement_import_ofx.pot rename to account_statement_import_ofx/i18n/account_bank_statement_import_ofx.pot diff --git a/account_bank_statement_import_ofx/i18n/de.po b/account_statement_import_ofx/i18n/de.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/de.po rename to account_statement_import_ofx/i18n/de.po diff --git a/account_bank_statement_import_ofx/i18n/es.po b/account_statement_import_ofx/i18n/es.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/es.po rename to account_statement_import_ofx/i18n/es.po diff --git a/account_bank_statement_import_ofx/i18n/fi.po b/account_statement_import_ofx/i18n/fi.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/fi.po rename to account_statement_import_ofx/i18n/fi.po diff --git a/account_bank_statement_import_ofx/i18n/fr.po b/account_statement_import_ofx/i18n/fr.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/fr.po rename to account_statement_import_ofx/i18n/fr.po diff --git a/account_bank_statement_import_ofx/i18n/fr_CH.po b/account_statement_import_ofx/i18n/fr_CH.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/fr_CH.po rename to account_statement_import_ofx/i18n/fr_CH.po diff --git a/account_bank_statement_import_ofx/i18n/gl.po b/account_statement_import_ofx/i18n/gl.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/gl.po rename to account_statement_import_ofx/i18n/gl.po diff --git a/account_bank_statement_import_ofx/i18n/lt_LT.po b/account_statement_import_ofx/i18n/lt_LT.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/lt_LT.po rename to account_statement_import_ofx/i18n/lt_LT.po diff --git a/account_bank_statement_import_ofx/i18n/nb_NO.po b/account_statement_import_ofx/i18n/nb_NO.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/nb_NO.po rename to account_statement_import_ofx/i18n/nb_NO.po diff --git a/account_bank_statement_import_ofx/i18n/nl.po b/account_statement_import_ofx/i18n/nl.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/nl.po rename to account_statement_import_ofx/i18n/nl.po diff --git a/account_bank_statement_import_ofx/i18n/pt_BR.po b/account_statement_import_ofx/i18n/pt_BR.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/pt_BR.po rename to account_statement_import_ofx/i18n/pt_BR.po diff --git a/account_bank_statement_import_ofx/i18n/pt_PT.po b/account_statement_import_ofx/i18n/pt_PT.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/pt_PT.po rename to account_statement_import_ofx/i18n/pt_PT.po diff --git a/account_bank_statement_import_ofx/i18n/sl.po b/account_statement_import_ofx/i18n/sl.po similarity index 100% rename from account_bank_statement_import_ofx/i18n/sl.po rename to account_statement_import_ofx/i18n/sl.po diff --git a/account_bank_statement_import_ofx/models/__init__.py b/account_statement_import_ofx/models/__init__.py similarity index 100% rename from account_bank_statement_import_ofx/models/__init__.py rename to account_statement_import_ofx/models/__init__.py diff --git a/account_bank_statement_import_ofx/models/account_journal.py b/account_statement_import_ofx/models/account_journal.py similarity index 81% rename from account_bank_statement_import_ofx/models/account_journal.py rename to account_statement_import_ofx/models/account_journal.py index fb6c480e..efbb0b86 100644 --- a/account_bank_statement_import_ofx/models/account_journal.py +++ b/account_statement_import_ofx/models/account_journal.py @@ -5,8 +5,7 @@ class AccountJournal(models.Model): _inherit = "account.journal" def _get_bank_statements_available_import_formats(self): - """ Adds ofx to supported import formats. - """ + """Adds ofx to supported import formats.""" rslt = super()._get_bank_statements_available_import_formats() rslt.append("ofx") return rslt diff --git a/account_bank_statement_import_ofx/readme/CONTRIBUTORS.rst b/account_statement_import_ofx/readme/CONTRIBUTORS.rst similarity index 100% rename from account_bank_statement_import_ofx/readme/CONTRIBUTORS.rst rename to account_statement_import_ofx/readme/CONTRIBUTORS.rst diff --git a/account_bank_statement_import_ofx/readme/DESCRIPTION.rst b/account_statement_import_ofx/readme/DESCRIPTION.rst similarity index 73% rename from account_bank_statement_import_ofx/readme/DESCRIPTION.rst rename to account_statement_import_ofx/readme/DESCRIPTION.rst index bbc412a0..8b68e4c8 100644 --- a/account_bank_statement_import_ofx/readme/DESCRIPTION.rst +++ b/account_statement_import_ofx/readme/DESCRIPTION.rst @@ -2,3 +2,5 @@ This module adds support for the import of bank statements in `OFX format - - account.bank.statement.import + + account.statement.import diff --git a/account_statement_import_ofx/wizard/__init__.py b/account_statement_import_ofx/wizard/__init__.py new file mode 100644 index 00000000..ae69bca2 --- /dev/null +++ b/account_statement_import_ofx/wizard/__init__.py @@ -0,0 +1 @@ +from . import account_statement_import diff --git a/account_statement_import_ofx/wizard/account_statement_import.py b/account_statement_import_ofx/wizard/account_statement_import.py new file mode 100644 index 00000000..5275c098 --- /dev/null +++ b/account_statement_import_ofx/wizard/account_statement_import.py @@ -0,0 +1,88 @@ +import io +import logging + +from odoo import _, api, models +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + +try: + from ofxparse import OfxParser +except ImportError: + _logger.debug("ofxparse not found.") + OfxParser = None + + +class AccountStatementImport(models.TransientModel): + _inherit = "account.statement.import" + + @api.model + def _check_ofx(self, data_file): + if not OfxParser: + return False + try: + ofx = OfxParser.parse(io.BytesIO(data_file)) + except Exception as e: + _logger.debug(e) + return False + return ofx + + @api.model + def _prepare_ofx_transaction_line(self, transaction): + # Since ofxparse doesn't provide account numbers, + # we cannot provide the key 'bank_account_id', + # nor the key 'account_number' + # If you read odoo10/addons/account_bank_statement_import/ + # account_bank_statement_import.py, it's the only 2 keys + # we can provide to match a partner. + payment_ref = transaction.payee + if transaction.checknum: + payment_ref += " " + transaction.checknum + if transaction.memo: + payment_ref += " : " + transaction.memo + vals = { + "date": transaction.date, + "payment_ref": payment_ref, + "amount": float(transaction.amount), + "unique_import_id": transaction.id, + } + return vals + + def _parse_file(self, data_file): + ofx = self._check_ofx(data_file) + if not ofx: + return super()._parse_file(data_file) + + result = [] + try: + for account in ofx.accounts: + transactions = [] + total_amt = 0.00 + + if not account.statement.transactions: + continue + + for transaction in account.statement.transactions: + vals = self._prepare_ofx_transaction_line(transaction) + if vals: + transactions.append(vals) + total_amt += vals["amount"] + balance = float(account.statement.balance) + vals_bank_statement = { + "name": account.number, + "transactions": transactions, + "balance_start": balance - total_amt, + "balance_end_real": balance, + } + result.append( + (account.statement.currency, account.number, [vals_bank_statement]) + ) + except Exception as e: + raise UserError( + _( + "The following problem occurred during import. " + "The file might not be valid.\n\n %s" + ) + % str(e) + ) + return result