Browse Source

[IMP] account_bank_statement_qif: use new API + i18n + move journal_id to main

pull/129/head
Laurent Mignon (ACSONE) 10 years ago
committed by Pedro M. Baeza
parent
commit
c1d42e474b
  1. 58
      account_bank_statement_import_qif/README.rst
  2. 1
      account_bank_statement_import_qif/__init__.py
  3. 26
      account_bank_statement_import_qif/__openerp__.py
  4. 87
      account_bank_statement_import_qif/account_bank_statement_import_qif.py
  5. 24
      account_bank_statement_import_qif/account_bank_statement_import_qif_view.xml
  6. 49
      account_bank_statement_import_qif/i18n/account_bank_statement_import_qif.pot
  7. 2
      account_bank_statement_import_qif/tests/__init__.py
  8. 35
      account_bank_statement_import_qif/tests/test_import_bank_statement.py

58
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 <https://github.com/OCA/bank-statement-import/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 <https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_ofx%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Odoo SA
* Alexis de Lattre <alexis@via.ecp.fr>
* Laurent Mignon <laurent.mignon@acsone.eu>
* Ronald Portier <rportier@therp.nl>
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.

1
account_bank_statement_import_qif/__init__.py

@ -1,3 +1,2 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import account_bank_statement_import_qif from . import account_bank_statement_import_qif

26
account_bank_statement_import_qif/__openerp__.py

@ -1,28 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# noqa: This is a backport from Odoo. OCA has no control over style here.
# flake8: noqa
{ {
'name': 'Import QIF Bank Statement', 'name': 'Import QIF Bank Statement',
'category' : 'Accounting & Finance',
'category': 'Accounting & Finance',
'version': '1.0', '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': [], 'images': [],
'depends': ['account_bank_statement_import'],
'demo': [],
'data': ['account_bank_statement_import_qif_view.xml'],
'depends': [
'account_bank_statement_import'
],
'auto_install': False, 'auto_install': False,
'installable': True, 'installable': True,
} }

87
account_bank_statement_import_qif/account_bank_statement_import_qif.py

@ -1,46 +1,44 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# noqa: This is a backport from Odoo. OCA has no control over style here.
# flake8: noqa
import dateutil.parser import dateutil.parser
import StringIO import StringIO
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp.osv import osv, fields
from openerp import api, models
from openerp.exceptions import Warning 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: 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:') 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: try:
file_data = "" file_data = ""
@ -64,22 +62,31 @@ class account_bank_statement_import(osv.TransientModel):
if not line: if not line:
continue continue
if line[0] == 'D': # date of transaction 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 elif line[0] == 'T': # Total amount
total += float(line[1:].replace(',', '')) total += float(line[1:].replace(',', ''))
vals_line['amount'] = float(line[1:].replace(',', '')) vals_line['amount'] = float(line[1:].replace(',', ''))
elif line[0] == 'N': # Check number elif line[0] == 'N': # Check number
vals_line['ref'] = line[1:] vals_line['ref'] = line[1:]
elif line[0] == 'P': # Payee 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 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 elif line[0] == '^': # end of item
transactions.append(vals_line) transactions.append(vals_line)
vals_line = {} vals_line = {}
@ -88,11 +95,11 @@ class account_bank_statement_import(osv.TransientModel):
else: else:
pass pass
else: 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({ vals_bank_statement.update({
'balance_end_real': total, 'balance_end_real': total,
'transactions': transactions 'transactions': transactions
}) })
return None, None, [vals_bank_statement] return None, None, [vals_bank_statement]

24
account_bank_statement_import_qif/account_bank_statement_import_qif_view.xml

@ -1,24 +0,0 @@
<?xml version="1.0" ?>
<openerp>
<data>
<record id="account_bank_statement_import_view_inherited" model="ir.ui.view">
<field name="name">Import Bank Statements Inherited</field>
<field name="model">account.bank.statement.import</field>
<field name="priority" eval="20"/>
<field name="inherit_id" ref="account_bank_statement_import.account_bank_statement_import_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='data_file']" position="after">
<field name="hide_journal_field" invisible="1"/>
<label for="journal_id"/>
<field name="journal_id"
domain="[('type', '=', 'bank')]"
attrs="{'invisible': [('hide_journal_field', '=', True)]}"
context="{'default_type':'bank'}"/>
</xpath>
</field>
</record>
</data>
</openerp>

49
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 ""

2
account_bank_statement_import_qif/tests/__init__.py

@ -1,4 +1,2 @@
# -*- coding: utf-8 -*- # -*- 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 from . import test_import_bank_statement

35
account_bank_statement_import_qif/tests/test_import_bank_statement.py

@ -1,32 +1,29 @@
# -*- coding: utf-8 -*- # -*- 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.tests.common import TransactionCase
from openerp.modules.module import get_module_resource from openerp.modules.module import get_module_resource
class TestQifFile(TransactionCase): 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): def setUp(self):
super(TestQifFile, self).setUp() 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): def test_qif_file_import(self):
from openerp.tools import float_compare 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') 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
Loading…
Cancel
Save