From 61810d00c1fde0a2cf2946f5bc3699b310ea0d71 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Fri, 3 Jun 2016 16:04:20 +0200 Subject: [PATCH] [REF] OCA convention; [ADD] patch ofx parser to make this module work with some european bank like credit cooperatif; [IMP] wizard view to display OFX implementation; --- account_bank_statement_import_ofx/README.rst | 21 +++++++++- account_bank_statement_import_ofx/__init__.py | 5 +-- .../__manifest__.py | 15 +++++-- .../demo/demo_data.xml | 42 +++++++++---------- .../models/__init__.py | 2 + .../account_bank_statement_import.py} | 21 ++++------ .../models/ofx.py | 40 ++++++++++++++++++ .../tests/__init__.py | 4 +- .../tests/test_import_bank_statement.py | 2 +- .../{ => tests}/test_ofx_file/test_ofx.ofx | 0 .../view_account_bank_statement_import.xml | 12 ++++++ 11 files changed, 116 insertions(+), 48 deletions(-) create mode 100644 account_bank_statement_import_ofx/models/__init__.py rename account_bank_statement_import_ofx/{account_bank_statement_import_ofx.py => models/account_bank_statement_import.py} (84%) create mode 100644 account_bank_statement_import_ofx/models/ofx.py rename account_bank_statement_import_ofx/{ => tests}/test_ofx_file/test_ofx.ofx (100%) create mode 100644 account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml diff --git a/account_bank_statement_import_ofx/README.rst b/account_bank_statement_import_ofx/README.rst index 6fb1260..cc06cc1 100644 --- a/account_bank_statement_import_ofx/README.rst +++ b/account_bank_statement_import_ofx/README.rst @@ -1,6 +1,7 @@ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg :alt: License: AGPL-3 +========================= Import OFX Bank Statement ========================= @@ -22,6 +23,21 @@ The module requires one additional python lib: * `ofxparse `_ +Technical Note +============== + +this module is based on ofxparse python lib and overload some of its functions. + +* For the time being the default ofxparse lib available with + 'pip install ofxparse' do not manage correctly european amount that are + written with ',' and not with '.'. (For exemple, The Credit Cooperatif + French Bank provides OFX 1.0 with amounts written with coma) + +April, 27 2016: this problem has been fixed here: +https://github.com/jseutter/ofxparse/commit/283f89c3246ed3fedccc3ef5c96078b7d5b94579 +but it is not available in the pip lib for the time being. + + Known issues / Roadmap ====================== @@ -40,12 +56,13 @@ Credits ======= Contributors ------------- +------------ -* Odoo SA +* Odoo SA * Alexis de Lattre * Laurent Mignon * Ronald Portier +* Sylvain LE GAL Maintainer ---------- diff --git a/account_bank_statement_import_ofx/__init__.py b/account_bank_statement_import_ofx/__init__.py index fb5e0c3..a0fdc10 100644 --- a/account_bank_statement_import_ofx/__init__.py +++ b/account_bank_statement_import_ofx/__init__.py @@ -1,3 +1,2 @@ -# -*- encoding: utf-8 -*- - -from . import account_bank_statement_import_ofx +# -*- coding: utf-8 -*- +from . import models diff --git a/account_bank_statement_import_ofx/__manifest__.py b/account_bank_statement_import_ofx/__manifest__.py index 329859e..7e02544 100644 --- a/account_bank_statement_import_ofx/__manifest__.py +++ b/account_bank_statement_import_ofx/__manifest__.py @@ -1,13 +1,20 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- { 'name': 'Import OFX Bank Statement', 'category': 'Banking addons', - 'version': '8.0.1.0.0', + 'version': '9.0.0.0.0', + 'license': 'AGPL-3', 'author': 'OpenERP SA,' + 'La Louve,' + 'GRAP,' 'Odoo Community Association (OCA)', - 'website': 'https://github.com/OCA/bank-statement-import', + 'website': 'https://odoo-community.org/', 'depends': [ - 'account_bank_statement_import' + 'l10n_generic_coa', + 'account_bank_statement_import', + ], + 'data': [ + 'views/view_account_bank_statement_import.xml', ], 'demo': [ 'demo/demo_data.xml', diff --git a/account_bank_statement_import_ofx/demo/demo_data.xml b/account_bank_statement_import_ofx/demo/demo_data.xml index 8387f27..3a7a352 100644 --- a/account_bank_statement_import_ofx/demo/demo_data.xml +++ b/account_bank_statement_import_ofx/demo/demo_data.xml @@ -1,27 +1,23 @@ - - + - - Bank Journal - (test ofx) - TBNKOFX - bank - - - - - - + + Bank Journal - (test ofx) + OFX/%(range_year)s/ + no_gap + 4 + 1 + - - Your Company - 123456 - - - - bank - - - - + + Bank Journal - (test ofx) + 123456 + TBNKOFX + bank + + + + + + diff --git a/account_bank_statement_import_ofx/models/__init__.py b/account_bank_statement_import_ofx/models/__init__.py new file mode 100644 index 0000000..5dfe830 --- /dev/null +++ b/account_bank_statement_import_ofx/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import account_bank_statement_import diff --git a/account_bank_statement_import_ofx/account_bank_statement_import_ofx.py b/account_bank_statement_import_ofx/models/account_bank_statement_import.py similarity index 84% rename from account_bank_statement_import_ofx/account_bank_statement_import_ofx.py rename to account_bank_statement_import_ofx/models/account_bank_statement_import.py index 0a82d5f..c05ee73 100644 --- a/account_bank_statement_import_ofx/account_bank_statement_import_ofx.py +++ b/account_bank_statement_import_ofx/models/account_bank_statement_import.py @@ -5,15 +5,11 @@ import StringIO from openerp import api, models from openerp.tools.translate import _ -from openerp.exceptions import Warning +from openerp.exceptions import Warning as UserError -_logger = logging.getLogger(__name__) +from .ofx import OfxParser, OfxParser_ok -try: - from ofxparse import OfxParser as ofxparser -except ImportError: - _logger.warn("ofxparse not found, OFX parsing disabled.") - ofxparser = None +_logger = logging.getLogger(__name__) class AccountBankStatementImport(models.TransientModel): @@ -21,11 +17,12 @@ class AccountBankStatementImport(models.TransientModel): @api.model def _check_ofx(self, data_file): - if ofxparser is None: + if not OfxParser_ok: return False try: - ofx = ofxparser.parse(StringIO.StringIO(data_file)) - except: + ofx = OfxParser.parse(StringIO.StringIO(data_file)) + except Exception as e: + _logger.debug(e) return False return ofx @@ -64,7 +61,7 @@ class AccountBankStatementImport(models.TransientModel): total_amt += float(transaction.amount) transactions.append(vals_line) except Exception, e: - raise Warning(_("The following problem occurred during import. " + raise UserError(_("The following problem occurred during import. " "The file might not be valid.\n\n %s" % e.message)) vals_bank_statement = { @@ -72,7 +69,7 @@ class AccountBankStatementImport(models.TransientModel): 'transactions': transactions, 'balance_start': ofx.account.statement.balance, 'balance_end_real': - float(ofx.account.statement.balance) + total_amt, + float(ofx.account.statement.balance) + total_amt, } return ofx.account.statement.currency, ofx.account.number, [ vals_bank_statement] diff --git a/account_bank_statement_import_ofx/models/ofx.py b/account_bank_statement_import_ofx/models/ofx.py new file mode 100644 index 0000000..d746938 --- /dev/null +++ b/account_bank_statement_import_ofx/models/ofx.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +import logging + +_logger = logging.getLogger(__name__) + +try: + from ofxparse import OfxParser as OfxParserOriginal + OfxParser_ok = True +except ImportError: + _logger.warn("ofxparse not found, OFX parsing disabled.") + OfxParserOriginal = object + OfxParser_ok = False + + +class OfxParser(OfxParserOriginal): + """ Custom changes in the OFX Parser. + """ + + @classmethod + def _tagToDecimal(self, tag): + tag.string = tag.string.replace(',', '.') + + @classmethod + def parseStatement(cls_, stmt_ofx): + """Amount with ',' replaced by '.' in the following tags : + //LEDGERBAL/BALAMT + """ + ledgerbal_tag = stmt_ofx.find('ledgerbal') + if hasattr(ledgerbal_tag, "contents"): + cls_._tagToDecimal(ledgerbal_tag.find('balamt')) + return super(OfxParser, cls_).parseStatement(stmt_ofx) + + @classmethod + def parseTransaction(cls_, txn_ofx): + """Amount with ',' replaced by '.' in the following tags : + //TRNAMT + """ + cls_._tagToDecimal(txn_ofx.find('trnamt')) + return super(OfxParser, cls_).parseTransaction(txn_ofx) diff --git a/account_bank_statement_import_ofx/tests/__init__.py b/account_bank_statement_import_ofx/tests/__init__.py index 15a0140..9ce25a7 100644 --- a/account_bank_statement_import_ofx/tests/__init__.py +++ b/account_bank_statement_import_ofx/tests/__init__.py @@ -1,4 +1,2 @@ -# -*- encoding: utf-8 -*- -# noqa: This is a backport from Odoo. OCA has no control over style here. -# flake8: noqa +# -*- coding: utf-8 -*- from . import test_import_bank_statement diff --git a/account_bank_statement_import_ofx/tests/test_import_bank_statement.py b/account_bank_statement_import_ofx/tests/test_import_bank_statement.py index b35afa1..0efe690 100644 --- a/account_bank_statement_import_ofx/tests/test_import_bank_statement.py +++ b/account_bank_statement_import_ofx/tests/test_import_bank_statement.py @@ -16,7 +16,7 @@ class TestOfxFile(TransactionCase): def test_ofx_file_import(self): ofx_file_path = get_module_resource( 'account_bank_statement_import_ofx', - 'test_ofx_file', 'test_ofx.ofx') + 'tests/test_ofx_file/', 'test_ofx.ofx') ofx_file = open(ofx_file_path, 'rb').read().encode('base64') bank_statement = self.statement_import_model.create( dict(data_file=ofx_file)) diff --git a/account_bank_statement_import_ofx/test_ofx_file/test_ofx.ofx b/account_bank_statement_import_ofx/tests/test_ofx_file/test_ofx.ofx similarity index 100% rename from account_bank_statement_import_ofx/test_ofx_file/test_ofx.ofx rename to account_bank_statement_import_ofx/tests/test_ofx_file/test_ofx.ofx diff --git a/account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml b/account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml new file mode 100644 index 0000000..3f0892f --- /dev/null +++ b/account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml @@ -0,0 +1,12 @@ + + + + account.bank.statement.import + + + +
  • Open Financial Exchange (.OFX Money)
  • +
    +
    +
    +