Browse Source

Merge pull request #80 from akretion/10-mig-ofx

[10.0] port OFX module
pull/89/head
Pedro M. Baeza 8 years ago
committed by GitHub
parent
commit
271c52cf16
  1. 2
      .travis.yml
  2. 28
      account_bank_statement_import_ofx/README.rst
  3. 5
      account_bank_statement_import_ofx/__init__.py
  4. 21
      account_bank_statement_import_ofx/__manifest__.py
  5. 78
      account_bank_statement_import_ofx/account_bank_statement_import_ofx.py
  6. 27
      account_bank_statement_import_ofx/demo/demo_data.xml
  7. 4
      account_bank_statement_import_ofx/tests/__init__.py
  8. 41
      account_bank_statement_import_ofx/tests/test_import_bank_statement.py
  9. 0
      account_bank_statement_import_ofx/tests/test_ofx_file/test_ofx.ofx
  10. 12
      account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml
  11. 2
      account_bank_statement_import_ofx/wizard/__init__.py
  12. 94
      account_bank_statement_import_ofx/wizard/account_bank_statement_import.py

2
.travis.yml

@ -30,7 +30,7 @@ virtualenv:
install: install:
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools - git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH} - export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- pip install ofxparse
- pip install git+https://github.com/jseutter/ofxparse.git
- travis_install_nightly - travis_install_nightly
# example: dependency # example: dependency
# - git clone https://github.com/OCA/webkit-tools -b ${VERSION} $HOME/webkit-tools # - git clone https://github.com/OCA/webkit-tools -b ${VERSION} $HOME/webkit-tools

28
account_bank_statement_import_ofx/README.rst

@ -1,20 +1,15 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3 :alt: License: AGPL-3
=========================
Import OFX Bank Statement Import OFX Bank Statement
========================= =========================
This module allows you to import the machine readable OFX Files in Odoo: they are parsed and stored in human readable format in
Accounting \ Bank and Cash \ Bank Statements.
This module adds support for the import of bank statements in `OFX format <https://en.wikipedia.org/wiki/Open_Financial_Exchange>`_.
Bank Statements may be generated containing a subset of the OFX information (only those transaction lines that are required for the Bank Statements may be generated containing a subset of the OFX information (only those transaction lines that are required for the
creation of the Financial Accounting records). creation of the Financial Accounting records).
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
Installation Installation
============ ============
@ -22,6 +17,13 @@ The module requires one additional python lib:
* `ofxparse <http://pypi.python.org/pypi/ofxparse>`_ * `ofxparse <http://pypi.python.org/pypi/ofxparse>`_
Usage
=====
.. 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/10.0
Known issues / Roadmap Known issues / Roadmap
====================== ======================
@ -30,11 +32,10 @@ Known issues / Roadmap
Bug Tracker 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**>`_.
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.
Credits Credits
======= =======
@ -46,6 +47,7 @@ Contributors
* Alexis de Lattre <alexis@via.ecp.fr> * Alexis de Lattre <alexis@via.ecp.fr>
* Laurent Mignon <laurent.mignon@acsone.eu> * Laurent Mignon <laurent.mignon@acsone.eu>
* Ronald Portier <rportier@therp.nl> * Ronald Portier <rportier@therp.nl>
* Sylvain LE GAL <https://twitter.com/legalsylvain>
Maintainer Maintainer
---------- ----------
@ -60,4 +62,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. 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.

5
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 wizard

21
account_bank_statement_import_ofx/__manifest__.py

@ -1,20 +1,23 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
{ {
'name': 'Import OFX Bank Statement', 'name': 'Import OFX Bank Statement',
'category': 'Banking addons', 'category': 'Banking addons',
'version': '8.0.1.0.0',
'author': 'OpenERP SA,'
'version': '10.0.1.0.0',
'license': 'AGPL-3',
'author': 'Odoo SA,'
'Akretion,'
'La Louve,'
'GRAP,'
'Odoo Community Association (OCA)', 'Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/bank-statement-import',
'website': 'https://odoo-community.org/',
'depends': [ 'depends': [
'account_bank_statement_import'
'account_bank_statement_import',
], ],
'demo': [
'demo/demo_data.xml',
'data': [
'views/view_account_bank_statement_import.xml',
], ],
'external_dependencies': { 'external_dependencies': {
'python': ['ofxparse'], 'python': ['ofxparse'],
}, },
'auto_install': False,
'installable': False,
'installable': True,
} }

78
account_bank_statement_import_ofx/account_bank_statement_import_ofx.py

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
import logging
import StringIO
from openerp import api, models
from openerp.tools.translate import _
from openerp.exceptions import Warning
_logger = logging.getLogger(__name__)
try:
from ofxparse import OfxParser as ofxparser
except ImportError:
_logger.warn("ofxparse not found, OFX parsing disabled.")
ofxparser = None
class AccountBankStatementImport(models.TransientModel):
_inherit = 'account.bank.statement.import'
@api.model
def _check_ofx(self, data_file):
if ofxparser is None:
return False
try:
ofx = ofxparser.parse(StringIO.StringIO(data_file))
except:
return False
return ofx
@api.model
def _parse_file(self, data_file):
ofx = self._check_ofx(data_file)
if not ofx:
return super(AccountBankStatementImport, self)._parse_file(
data_file)
transactions = []
total_amt = 0.00
try:
for transaction in ofx.account.statement.transactions:
# Since ofxparse 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)
bank_account_id = partner_id = False
banks = self.env['res.partner.bank'].search(
[('owner_name', '=', transaction.payee)], limit=1)
if banks:
bank_account = banks[0]
bank_account_id = bank_account.id
partner_id = bank_account.partner_id.id
vals_line = {
'date': transaction.date,
'name': transaction.payee + (
transaction.memo and ': ' + transaction.memo or ''),
'ref': transaction.id,
'amount': transaction.amount,
'unique_import_id': transaction.id,
'bank_account_id': bank_account_id,
'partner_id': partner_id,
}
total_amt += float(transaction.amount)
transactions.append(vals_line)
except Exception, e:
raise Warning(_("The following problem occurred during import. "
"The file might not be valid.\n\n %s" % e.message))
vals_bank_statement = {
'name': ofx.account.routing_number,
'transactions': transactions,
'balance_start': ofx.account.statement.balance,
'balance_end_real':
float(ofx.account.statement.balance) + total_amt,
}
return ofx.account.statement.currency, ofx.account.number, [
vals_bank_statement]

27
account_bank_statement_import_ofx/demo/demo_data.xml

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="ofx_bank_journal" model="account.journal">
<field name="name">Bank Journal - (test ofx)</field>
<field name="code">TBNKOFX</field>
<field name="type">bank</field>
<field name="sequence_id" ref="account.sequence_bank_journal"/>
<field name="default_debit_account_id" ref="account.usd_bnk"/>
<field name="default_credit_account_id" ref="account.usd_bnk"/>
<field name="user_id" ref="base.user_root"/>
<field name="currency" ref="base.USD"/>
</record>
<record id="ofx_company_bank" model="res.partner.bank">
<field name="owner_name">Your Company</field>
<field name="acc_number">123456</field>
<field name="partner_id" ref="base.partner_root"></field>
<field name="company_id" ref="base.main_company"></field>
<field name="journal_id" ref="ofx_bank_journal"></field>
<field name="state">bank</field>
<field name="bank" ref="base.res_bank_1"/>
</record>
</data>
</openerp>

4
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 from . import test_import_bank_statement

41
account_bank_statement_import_ofx/tests/test_import_bank_statement.py

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from openerp.tests.common import TransactionCase
from openerp.modules.module import get_module_resource
from odoo.tests.common import TransactionCase
from odoo.modules.module import get_module_resource
class TestOfxFile(TransactionCase): class TestOfxFile(TransactionCase):
@ -10,26 +10,39 @@ class TestOfxFile(TransactionCase):
def setUp(self): def setUp(self):
super(TestOfxFile, self).setUp() super(TestOfxFile, self).setUp()
self.statement_import_model = self.env['account.bank.statement.import']
self.bank_statement_model = self.env['account.bank.statement']
self.absi_model = self.env['account.bank.statement.import']
self.abs_model = self.env['account.bank.statement']
self.absl_model = self.env['account.bank.statement.line']
cur = self.env.ref('base.USD')
self.env.ref('base.main_company').currency_id = cur.id
bank = self.env['res.partner.bank'].create({
'acc_number': '123456',
'partner_id': self.env.ref('base.main_partner').id,
'company_id': self.env.ref('base.main_company').id,
'bank_id': self.env.ref('base.res_bank_1').id,
})
self.env['account.journal'].create({
'name': 'Bank Journal TEST OFX',
'code': 'BNK12',
'type': 'bank',
'bank_account_id': bank.id,
})
def test_ofx_file_import(self): def test_ofx_file_import(self):
ofx_file_path = get_module_resource( ofx_file_path = get_module_resource(
'account_bank_statement_import_ofx', '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') ofx_file = open(ofx_file_path, 'rb').read().encode('base64')
bank_statement = self.statement_import_model.create(
bank_statement = self.absi_model.create(
dict(data_file=ofx_file)) dict(data_file=ofx_file))
bank_statement.import_file() bank_statement.import_file()
bank_st_record = self.bank_statement_model.search(
[('name', '=', '000000123')])[0]
bank_st_record = self.abs_model.search(
[('name', 'like', '123456')])[0]
self.assertEquals(bank_st_record.balance_start, 2156.56) self.assertEquals(bank_st_record.balance_start, 2156.56)
self.assertEquals(bank_st_record.balance_end_real, 1796.56) self.assertEquals(bank_st_record.balance_end_real, 1796.56)
line = bank_st_record.line_ids[0]
self.assertEquals(line.name, 'Agrolait')
line = self.absl_model.search([
('name', '=', 'Agrolait'),
('statement_id', '=', bank_st_record.id)])[0]
self.assertEquals(line.ref, '219378') self.assertEquals(line.ref, '219378')
self.assertEquals(line.partner_id.id, self.ref('base.res_partner_2'))
self.assertEquals(
line.bank_account_id.id,
self.ref('account_bank_statement_import.ofx_partner_bank_1'))
self.assertEquals(line.date, '2013-08-24')

0
account_bank_statement_import_ofx/test_ofx_file/test_ofx.ofx → account_bank_statement_import_ofx/tests/test_ofx_file/test_ofx.ofx

12
account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_account_bank_statement_import_form" model="ir.ui.view">
<field name="model">account.bank.statement.import</field>
<field name="inherit_id" ref="account_bank_statement_import.account_bank_statement_import_view"/>
<field name="arch" type="xml">
<xpath expr="//ul[@id='statement_format']" position="inside">
<li>Open Financial Exchange (.OFX Money)</li>
</xpath>
</field>
</record>
</odoo>

2
account_bank_statement_import_ofx/wizard/__init__.py

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import account_bank_statement_import

94
account_bank_statement_import_ofx/wizard/account_bank_statement_import.py

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
import logging
import StringIO
from odoo import api, models, fields, _
from odoo.exceptions import UserError
from odoo.tools import float_is_zero
_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'
@api.model
def _check_ofx(self, data_file):
if not OfxParser:
return False
try:
ofx = OfxParser.parse(StringIO.StringIO(data_file))
except Exception as e:
_logger.debug(e)
return False
return ofx
@api.model
def _prepare_ofx_transaction_line(self, transaction):
# since odoo 9, the account module defines a constraint
# on account.bank.statement.line: 'amount' must be != 0
# But some banks have some transactions with amount=0
# for bank charges that are offered, which blocks the import
precision = self.env['decimal.precision'].precision_get('Account')
if float_is_zero(
float(transaction.amount), precision_digits=precision):
return False
# 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.
vals = {
'date': transaction.date,
'name': transaction.payee + (
transaction.memo and ': ' + transaction.memo or ''),
'ref': transaction.id,
'amount': float(transaction.amount),
'unique_import_id': transaction.id,
}
return vals
@api.model
def _parse_file(self, data_file):
ofx = self._check_ofx(data_file)
if not ofx:
return super(AccountBankStatementImport, self)._parse_file(
data_file)
transactions = []
total_amt = 0.00
start_date = end_date = False
try:
for transaction in ofx.account.statement.transactions:
vals = self._prepare_ofx_transaction_line(transaction)
if vals:
transactions.append(vals)
total_amt += vals['amount']
tdate = fields.Date.to_string(vals['date'])
if not start_date or tdate < start_date:
start_date = tdate
if not end_date or tdate > end_date:
end_date = tdate
except Exception, e:
raise UserError(_(
"The following problem occurred during import. "
"The file might not be valid.\n\n %s") % e.message)
vals_bank_statement = {
'name': _('Account %s %s > %s') % (
ofx.account.number, start_date, end_date),
'transactions': transactions,
'balance_start': ofx.account.statement.balance,
'balance_end_real':
float(ofx.account.statement.balance) + total_amt,
}
return ofx.account.statement.currency, ofx.account.number, [
vals_bank_statement]
Loading…
Cancel
Save