Pedro M. Baeza
8 years ago
committed by
GitHub
12 changed files with 170 additions and 152 deletions
-
2.travis.yml
-
28account_bank_statement_import_ofx/README.rst
-
5account_bank_statement_import_ofx/__init__.py
-
21account_bank_statement_import_ofx/__manifest__.py
-
78account_bank_statement_import_ofx/account_bank_statement_import_ofx.py
-
27account_bank_statement_import_ofx/demo/demo_data.xml
-
4account_bank_statement_import_ofx/tests/__init__.py
-
41account_bank_statement_import_ofx/tests/test_import_bank_statement.py
-
0account_bank_statement_import_ofx/tests/test_ofx_file/test_ofx.ofx
-
12account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml
-
2account_bank_statement_import_ofx/wizard/__init__.py
-
94account_bank_statement_import_ofx/wizard/account_bank_statement_import.py
@ -1,3 +1,2 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
|
|||
from . import account_bank_statement_import_ofx |
|||
# -*- coding: utf-8 -*- |
|||
from . import wizard |
@ -1,20 +1,23 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
# -*- coding: utf-8 -*- |
|||
{ |
|||
'name': 'Import OFX Bank Statement', |
|||
'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)', |
|||
'website': 'https://github.com/OCA/bank-statement-import', |
|||
'website': 'https://odoo-community.org/', |
|||
'depends': [ |
|||
'account_bank_statement_import' |
|||
'account_bank_statement_import', |
|||
], |
|||
'demo': [ |
|||
'demo/demo_data.xml', |
|||
'data': [ |
|||
'views/view_account_bank_statement_import.xml', |
|||
], |
|||
'external_dependencies': { |
|||
'python': ['ofxparse'], |
|||
}, |
|||
'auto_install': False, |
|||
'installable': False, |
|||
'installable': True, |
|||
} |
@ -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] |
@ -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> |
@ -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 |
@ -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> |
@ -0,0 +1,2 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from . import account_bank_statement_import |
@ -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] |
Write
Preview
Loading…
Cancel
Save
Reference in new issue