diff --git a/account_bank_statement_import_qif/README.rst b/account_bank_statement_import_qif/README.rst index 66411e6..5707836 100644 --- a/account_bank_statement_import_qif/README.rst +++ b/account_bank_statement_import_qif/README.rst @@ -1,35 +1,48 @@ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License: AGPL-3 + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 -Module to import QIF bank statements. -===================================== +========================== +Import QIF bank statements +========================== -This module allows you to import the machine readable QIF Files in Odoo: they are parsed and stored in human readable format in +This module allows you to import the machine readable QIF Files in Odoo: they +are parsed and stored in human readable format in Accounting \ Bank and Cash \ Bank Statements. Important Note ---------------- -Because of the QIF format limitation, we cannot ensure the same transactions aren't imported several times or handle multicurrency. -Whenever possible, you should use a more appropriate file format like OFX. +-------------- +Because of the QIF format limitation, we cannot ensure the same transactions +aren't imported several times or handle multicurrency. Whenever possible, you +should use a more appropriate file format like OFX. -The module has been initiated by a backport of the new framework developed -by Odoo for V9 at its early stage. It's no more kept in sync with the V9 since -it has reach a stage where maintaining a pure backport of 9.0 in 8.0 is not -feasible anymore +The module was initiated as a backport of the new framework developed +by Odoo for V9 at its early stage. As Odoo has relicensed this module as +private inside its Odoo enterprise layer, now this one is maintained from the +original AGPL code. -Known issues / Roadmap -====================== +Usage +===== -* None +To use this module, you need to: + +#. Go to *Accounting* dashboard. +#. Click on *Import statement* from any of the bank journals. +#. Select a QIF file. +#. Press *Import*. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/174/9.0 Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. +Bugs are tracked on +`GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed feedback -`here `_. - +If you spotted it first, help us smashing it by providing a detailed and +welcomed feedback. Credits ======= @@ -41,6 +54,7 @@ Contributors * Alexis de Lattre * Laurent Mignon * Ronald Portier +* Pedro M. Baeza Maintainer ---------- @@ -55,4 +69,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit http://odoo-community.org. +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_bank_statement_import_qif/__init__.py b/account_bank_statement_import_qif/__init__.py index 3bf4df8..0796ed1 100644 --- a/account_bank_statement_import_qif/__init__.py +++ b/account_bank_statement_import_qif/__init__.py @@ -1,2 +1,4 @@ # -*- coding: utf-8 -*- -from . import account_bank_statement_import_qif +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import wizards diff --git a/account_bank_statement_import_qif/__openerp__.py b/account_bank_statement_import_qif/__openerp__.py index 4c54418..1e2eb75 100644 --- a/account_bank_statement_import_qif/__openerp__.py +++ b/account_bank_statement_import_qif/__openerp__.py @@ -1,16 +1,24 @@ # -*- coding: utf-8 -*- +# Copyright 2015 Odoo S. A. +# Copyright 2015 Laurent Mignon +# Copyright 2015 Ronald Portier +# Copyright 2016 Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Import QIF Bank Statement', - 'category': 'Banking addons', - 'version': '8.0.1.0.0', + 'name': 'Import QIF Bank Statements', + 'category': 'Accounting', + 'version': '9.0.1.0.0', 'author': 'OpenERP SA,' + 'Tecnativa,' 'Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/bank-statement-import', - 'images': [], 'depends': [ - 'account_bank_statement_import' + 'account_bank_statement_import', ], - 'auto_install': False, - 'installable': False, + 'data': [ + 'wizards/account_bank_statement_import_qif_view.xml', + ], + 'installable': True, + 'license': 'AGPL-3', } diff --git a/account_bank_statement_import_qif/i18n/account_bank_statement_import_qif.pot b/account_bank_statement_import_qif/i18n/account_bank_statement_import_qif.pot deleted file mode 100644 index 65c2bf0..0000000 --- a/account_bank_statement_import_qif/i18n/account_bank_statement_import_qif.pot +++ /dev/null @@ -1,49 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * account_bank_statement_import_qif -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 8.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-08 12:01+0000\n" -"PO-Revision-Date: 2015-06-08 12:01+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: account_bank_statement_import_qif -#: help:account.bank.statement.import,journal_id:0 -msgid "Accounting journal related to the bank statement you're importing. It has be be manually chosen for statement formats which doesn't allow automatic journal detection (QIF for example)." -msgstr "" - -#. module: account_bank_statement_import_qif -#: code:addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py:54 -#, python-format -msgid "Could not decipher the QIF file." -msgstr "" - -#. module: account_bank_statement_import_qif -#: field:account.bank.statement.import,hide_journal_field:0 -msgid "Hide the journal field in the view" -msgstr "" - -#. module: account_bank_statement_import_qif -#: model:ir.model,name:account_bank_statement_import_qif.model_account_bank_statement_import -msgid "Import Bank Statement" -msgstr "" - -#. module: account_bank_statement_import_qif -#: field:account.bank.statement.import,journal_id:0 -msgid "Journal" -msgstr "" - -#. module: account_bank_statement_import_qif -#: code:addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py:98 -#, python-format -msgid "This file is either not a bank statement or is not correctly formed." -msgstr "" - diff --git a/account_bank_statement_import_qif/i18n/es.po b/account_bank_statement_import_qif/i18n/es.po index 3872d17..769d74d 100644 --- a/account_bank_statement_import_qif/i18n/es.po +++ b/account_bank_statement_import_qif/i18n/es.po @@ -21,7 +21,7 @@ msgstr "" #: code:addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py:39 #, python-format msgid "Could not decipher the QIF file." -msgstr "" +msgstr "No se puede descifrar el archivo QIF." #. module: account_bank_statement_import_qif #: model:ir.model,name:account_bank_statement_import_qif.model_account_bank_statement_import @@ -32,4 +32,4 @@ msgstr "Importar extracto bancario" #: code:addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py:83 #, python-format msgid "This file is either not a bank statement or is not correctly formed." -msgstr "" +msgstr "Este archivo no es un extracto bancario o no está correctamente formado." diff --git a/account_bank_statement_import_qif/tests/test_import_bank_statement.py b/account_bank_statement_import_qif/tests/test_import_bank_statement.py index 5c13125..af0e1cf 100644 --- a/account_bank_statement_import_qif/tests/test_import_bank_statement.py +++ b/account_bank_statement_import_qif/tests/test_import_bank_statement.py @@ -1,4 +1,9 @@ # -*- coding: utf-8 -*- +# Copyright 2015 Odoo S. A. +# Copyright 2015 Laurent Mignon +# Copyright 2015 Ronald Portier +# Copyright 2016 Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from openerp.tests.common import TransactionCase from openerp.modules.module import get_module_resource @@ -13,17 +18,32 @@ class TestQifFile(TransactionCase): super(TestQifFile, self).setUp() self.statement_import_model = self.env['account.bank.statement.import'] self.statement_line_model = self.env['account.bank.statement.line'] + self.journal = self.env['account.journal'].create({ + 'name': 'Test bank journal', + 'code': 'TEST', + 'type': 'bank', + }) + self.partner = self.env['res.partner'].create({ + # Different case for trying insensitive case search + 'name': 'EPIC Technologies', + }) def test_qif_file_import(self): - from openerp.tools import float_compare qif_file_path = get_module_resource( - 'account_bank_statement_import_qif', - 'test_qif_file', 'test_qif.qif') + 'account_bank_statement_import_qif', 'tests', 'test_qif.qif', + ) qif_file = open(qif_file_path, 'rb').read().encode('base64') - bank_statement_improt = self.statement_import_model.with_context( - journal_id=self.ref('account.bank_journal')).create( - dict(data_file=qif_file)) - bank_statement_improt.import_file() - bank_statement = self.statement_line_model.search( - [('name', '=', 'YOUR LOCAL SUPERMARKET')], limit=1)[0].statement_id - assert float_compare(bank_statement.balance_end_real, -1896.09, 2) == 0 + wizard = self.statement_import_model.with_context( + journal_id=self.journal.id + ).create( + dict(data_file=qif_file) + ) + wizard.import_file() + statement = self.statement_line_model.search( + [('name', '=', 'YOUR LOCAL SUPERMARKET')], limit=1, + )[0].statement_id + self.assertAlmostEqual(statement.balance_end_real, -1896.09, 2) + line = self.statement_line_model.search( + [('name', '=', 'Epic Technologies')], limit=1, + ) + self.assertEqual(line.partner_id, self.partner) diff --git a/account_bank_statement_import_qif/test_qif_file/test_qif.qif b/account_bank_statement_import_qif/tests/test_qif.qif similarity index 100% rename from account_bank_statement_import_qif/test_qif_file/test_qif.qif rename to account_bank_statement_import_qif/tests/test_qif.qif diff --git a/account_bank_statement_import_qif/wizards/__init__.py b/account_bank_statement_import_qif/wizards/__init__.py new file mode 100644 index 0000000..f82d76e --- /dev/null +++ b/account_bank_statement_import_qif/wizards/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import account_bank_statement_import_qif diff --git a/account_bank_statement_import_qif/account_bank_statement_import_qif.py b/account_bank_statement_import_qif/wizards/account_bank_statement_import_qif.py similarity index 59% rename from account_bank_statement_import_qif/account_bank_statement_import_qif.py rename to account_bank_statement_import_qif/wizards/account_bank_statement_import_qif.py index 0b9061e..1016bac 100644 --- a/account_bank_statement_import_qif/account_bank_statement_import_qif.py +++ b/account_bank_statement_import_qif/wizards/account_bank_statement_import_qif.py @@ -1,20 +1,21 @@ # -*- coding: utf-8 -*- +# Copyright 2015 Odoo S. A. +# Copyright 2015 Laurent Mignon +# Copyright 2015 Ronald Portier +# Copyright 2016 Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import dateutil.parser import StringIO from openerp.tools.translate import _ from openerp import api, models -from openerp.exceptions import Warning +from openerp.exceptions import UserError class AccountBankStatementImport(models.TransientModel): _inherit = "account.bank.statement.import" - @api.model - def _get_hide_journal_field(self): - return self.env.context.get('journal_id') and True - @api.model def _check_qif(self, data_file): return data_file.strip().startswith('!Type:') @@ -24,7 +25,6 @@ class AccountBankStatementImport(models.TransientModel): if not self._check_qif(data_file): return super(AccountBankStatementImport, self)._parse_file( data_file) - try: file_data = "" for line in StringIO.StringIO(data_file).readlines(): @@ -36,7 +36,7 @@ class AccountBankStatementImport(models.TransientModel): header = data_list[0].strip() header = header.split(":")[1] except: - raise Warning(_('Could not decipher the QIF file.')) + raise UserError(_('Could not decipher the QIF file.')) transactions = [] vals_line = {} total = 0 @@ -55,19 +55,10 @@ class AccountBankStatementImport(models.TransientModel): elif line[0] == 'N': # Check number vals_line['ref'] = line[1:] elif line[0] == 'P': # Payee - vals_line['name'] = ('name' in vals_line and - line[1:] + ': ' + vals_line['name'] or - line[1:]) - # Since QIF doesn't provide account numbers, we'll have to - # find res.partner and res.partner.bank here - # (normal behavious is to provide 'account_number', which - # the generic module uses to find partner/bank) - banks = self.env['res.partner.bank'].search( - [('owner_name', '=', line[1:])], limit=1) - if banks: - bank_account = banks[0] - vals_line['bank_account_id'] = bank_account.id - vals_line['partner_id'] = bank_account.partner_id.id + vals_line['name'] = ( + 'name' in vals_line and + line[1:] + ': ' + vals_line['name'] or line[1:] + ) elif line[0] == 'M': # Memo vals_line['name'] = ('name' in vals_line and vals_line['name'] + ': ' + line[1:] or @@ -80,11 +71,28 @@ class AccountBankStatementImport(models.TransientModel): else: pass else: - raise Warning(_('This file is either not a bank statement or is ' - 'not correctly formed.')) - + raise UserError(_('This file is either not a bank statement or is ' + 'not correctly formed.')) vals_bank_statement.update({ 'balance_end_real': total, 'transactions': transactions }) return None, None, [vals_bank_statement] + + def _complete_stmts_vals(self, stmt_vals, journal_id, account_number): + """Match partner_id if hasn't been deducted yet.""" + res = super(AccountBankStatementImport, self)._complete_stmts_vals( + stmt_vals, journal_id, account_number, + ) + # Since QIF doesn't provide account numbers (normal behaviour is to + # provide 'account_number', which the generic module uses to find + # the partner), we have to find res.partner through the name + partner_obj = self.env['res.partner'] + for statement in res: + for line_vals in statement['transactions']: + if not line_vals.get('partner_id') and line_vals.get('name'): + partner = partner_obj.search( + [('name', 'ilike', line_vals['name'])], limit=1, + ) + line_vals['partner_id'] = partner.id + return res diff --git a/account_bank_statement_import_qif/wizards/account_bank_statement_import_qif_view.xml b/account_bank_statement_import_qif/wizards/account_bank_statement_import_qif_view.xml new file mode 100644 index 0000000..d6ab5b7 --- /dev/null +++ b/account_bank_statement_import_qif/wizards/account_bank_statement_import_qif_view.xml @@ -0,0 +1,14 @@ + + + + + account.bank.statement.import + + + +
  • Quicken Interchange Format (.qif)
  • +
    +
    +
    + +