diff --git a/account_bank_statement_import_qif/README.rst b/account_bank_statement_import_qif/README.rst new file mode 100644 index 0000000..66411e6 --- /dev/null +++ b/account_bank_statement_import_qif/README.rst @@ -0,0 +1,58 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License: AGPL-3 + +Module to 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 +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. + +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 + +Known issues / Roadmap +====================== + +* None + +Bug Tracker +=========== + +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 `_. + + +Credits +======= + +Contributors +------------ + +* Odoo SA +* Alexis de Lattre +* Laurent Mignon +* Ronald Portier + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +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. diff --git a/account_bank_statement_import_qif/__init__.py b/account_bank_statement_import_qif/__init__.py index 7ff3caa..3bf4df8 100644 --- a/account_bank_statement_import_qif/__init__.py +++ b/account_bank_statement_import_qif/__init__.py @@ -1,3 +1,2 @@ # -*- coding: utf-8 -*- from . import account_bank_statement_import_qif - diff --git a/account_bank_statement_import_qif/__openerp__.py b/account_bank_statement_import_qif/__openerp__.py index 21b9684..d550b1b 100644 --- a/account_bank_statement_import_qif/__openerp__.py +++ b/account_bank_statement_import_qif/__openerp__.py @@ -1,28 +1,16 @@ # -*- coding: utf-8 -*- -# noqa: This is a backport from Odoo. OCA has no control over style here. -# flake8: noqa { 'name': 'Import QIF Bank Statement', - 'category' : 'Accounting & Finance', + 'category': 'Accounting & Finance', 'version': '1.0', - 'author': 'OpenERP SA', - 'description': ''' -Module to 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 -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. -''', + 'author': 'OpenERP SA,' + 'Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/bank-statement-import', 'images': [], - 'depends': ['account_bank_statement_import'], - 'demo': [], - 'data': ['account_bank_statement_import_qif_view.xml'], + 'depends': [ + 'account_bank_statement_import' + ], 'auto_install': False, 'installable': True, } diff --git a/account_bank_statement_import_qif/account_bank_statement_import_qif.py b/account_bank_statement_import_qif/account_bank_statement_import_qif.py index 38f6a5c..2683e77 100644 --- a/account_bank_statement_import_qif/account_bank_statement_import_qif.py +++ b/account_bank_statement_import_qif/account_bank_statement_import_qif.py @@ -1,46 +1,44 @@ # -*- coding: utf-8 -*- -# noqa: This is a backport from Odoo. OCA has no control over style here. -# flake8: noqa import dateutil.parser import StringIO from openerp.tools.translate import _ -from openerp.osv import osv, fields +from openerp import api, models from openerp.exceptions import Warning -class account_bank_statement_import(osv.TransientModel): - _inherit = "account.bank.statement.import" - - _columns = { - 'journal_id': fields.many2one('account.journal', string='Journal', help='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).'), - 'hide_journal_field': fields.boolean('Hide the journal field in the view'), - } - def _get_hide_journal_field(self, cr, uid, context=None): - return context and 'journal_id' in context or False +class AccountBankStatementImport(models.TransientModel): + _inherit = "account.bank.statement.import" - _defaults = { - 'hide_journal_field': _get_hide_journal_field, - } + @api.model + def _get_hide_journal_field(self): + return self.env.context.get('journal_id') and True - def _get_journal(self, cr, uid, currency_id, bank_account_id, account_number, context=None): - """ As .QIF format does not allow us to detect the journal, we need to let the user choose it. - We set it in context before to call super so it's the same as calling the widget from a journal """ - if context is None: - context = {} - if context.get('active_id'): - record = self.browse(cr, uid, context.get('active_id'), context=context) + @api.model + def _get_journal(self, currency_id, bank_account_id, account_number): + """ As .QIF format does not allow us to detect the journal, we need to + let the user choose it. + We set it in context before to call super so it's the same as + calling the widget from a journal """ + record = self + active_id = self.env.context.get('active_id') + if active_id: + record = self.browse(active_id) if record.journal_id: - context['journal_id'] = record.journal_id.id - return super(account_bank_statement_import, self)._get_journal(cr, uid, currency_id, bank_account_id, account_number, context=context) + record = record.with_context(journal_id=record.journal_id.id) + return super(AccountBankStatementImport, record)._get_journal( + currency_id, bank_account_id, account_number) - def _check_qif(self, cr, uid, data_file, context=None): + @api.model + def _check_qif(self, data_file): return data_file.strip().startswith('!Type:') - def _parse_file(self, cr, uid, data_file, context=None): - if not self._check_qif(cr, uid, data_file, context=context): - return super(account_bank_statement_import, self)._parse_file(cr, uid, data_file, context=context) + @api.model + def _parse_file(self, data_file): + if not self._check_qif(data_file): + return super(AccountBankStatementImport, self)._parse_file( + data_file) try: file_data = "" @@ -64,22 +62,31 @@ class account_bank_statement_import(osv.TransientModel): if not line: continue if line[0] == 'D': # date of transaction - vals_line['date'] = dateutil.parser.parse(line[1:], fuzzy=True).date() + vals_line['date'] = dateutil.parser.parse( + line[1:], fuzzy=True).date() elif line[0] == 'T': # Total amount total += float(line[1:].replace(',', '')) vals_line['amount'] = float(line[1:].replace(',', '')) 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) - ids = self.pool.get('res.partner.bank').search(cr, uid, [('owner_name', '=', line[1:])], context=context) - if ids: - vals_line['bank_account_id'] = bank_account_id = ids[0] - vals_line['partner_id'] = self.pool.get('res.partner.bank').browse(cr, uid, bank_account_id, context=context).partner_id.id + 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 elif line[0] == 'M': # Memo - vals_line['name'] = 'name' in vals_line and vals_line['name'] + ': ' + line[1:] or line[1:] + vals_line['name'] = ('name' in vals_line and + vals_line['name'] + ': ' + line[1:] or + line[1:]) elif line[0] == '^': # end of item transactions.append(vals_line) vals_line = {} @@ -88,11 +95,11 @@ class account_bank_statement_import(osv.TransientModel): else: pass else: - raise Warning(_('This file is either not a bank statement or is not correctly formed.')) - + raise Warning(_('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] - diff --git a/account_bank_statement_import_qif/account_bank_statement_import_qif_view.xml b/account_bank_statement_import_qif/account_bank_statement_import_qif_view.xml deleted file mode 100644 index 3b3a342..0000000 --- a/account_bank_statement_import_qif/account_bank_statement_import_qif_view.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - Import Bank Statements Inherited - account.bank.statement.import - - - - - - - - - - - - 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 new file mode 100644 index 0000000..65c2bf0 --- /dev/null +++ b/account_bank_statement_import_qif/i18n/account_bank_statement_import_qif.pot @@ -0,0 +1,49 @@ +# 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/tests/__init__.py b/account_bank_statement_import_qif/tests/__init__.py index 902f7b0..9ce25a7 100644 --- a/account_bank_statement_import_qif/tests/__init__.py +++ b/account_bank_statement_import_qif/tests/__init__.py @@ -1,4 +1,2 @@ # -*- coding: utf-8 -*- -# noqa: This is a backport from Odoo. OCA has no control over style here. -# flake8: noqa from . import test_import_bank_statement 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 8d87650..5c13125 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,32 +1,29 @@ # -*- coding: utf-8 -*- -# noqa: This is a backport from Odoo. OCA has no control over style here. -# flake8: noqa + from openerp.tests.common import TransactionCase from openerp.modules.module import get_module_resource + class TestQifFile(TransactionCase): - """Tests for import bank statement qif file format (account.bank.statement.import) + """Tests for import bank statement qif file format + (account.bank.statement.import) """ def setUp(self): super(TestQifFile, self).setUp() - self.statement_import_model = self.registry('account.bank.statement.import') - self.bank_statement_model = self.registry('account.bank.statement') - self.bank_statement_line_model = self.registry('account.bank.statement.line') + self.statement_import_model = self.env['account.bank.statement.import'] + self.statement_line_model = self.env['account.bank.statement.line'] def test_qif_file_import(self): from openerp.tools import float_compare - cr, uid = self.cr, self.uid - qif_file_path = get_module_resource('account_bank_statement_import_qif', 'test_qif_file', 'test_qif.qif') + qif_file_path = get_module_resource( + 'account_bank_statement_import_qif', + 'test_qif_file', 'test_qif.qif') qif_file = open(qif_file_path, 'rb').read().encode('base64') - bank_statement_id = self.statement_import_model.create(cr, uid, dict( - data_file=qif_file, - )) - context = { - 'journal_id': self.registry('ir.model.data').get_object_reference(cr, uid, 'account', 'bank_journal')[1] - } - self.statement_import_model.import_file(cr, uid, [bank_statement_id], context=context) - line_id = self.bank_statement_line_model.search(cr, uid, [('name', '=', 'YOUR LOCAL SUPERMARKET')])[0] - statement_id = self.bank_statement_line_model.browse(cr, uid, line_id).statement_id.id - bank_st_record = self.bank_statement_model.browse(cr, uid, statement_id) - assert float_compare(bank_st_record.balance_end_real, -1896.09, 2) == 0 + 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