Browse Source
[MIG] account_bank_statement_import_ofx: Migration to 10.0
[MIG] account_bank_statement_import_ofx: Migration to 10.0
* Remove the code that matches partners, which is wrong and cannot work * Better 'name' on bank statement * Move from models directory to wizard * Remove demo data to tests * Use latest version of ofxparse from githubpull/80/head
Alexis de Lattre
8 years ago
committed by
Pedro M. Baeza
11 changed files with 139 additions and 189 deletions
-
2.travis.yml
-
37account_bank_statement_import_ofx/README.rst
-
2account_bank_statement_import_ofx/__init__.py
-
10account_bank_statement_import_ofx/__manifest__.py
-
23account_bank_statement_import_ofx/demo/demo_data.xml
-
75account_bank_statement_import_ofx/models/account_bank_statement_import.py
-
40account_bank_statement_import_ofx/models/ofx.py
-
39account_bank_statement_import_ofx/tests/test_import_bank_statement.py
-
2account_bank_statement_import_ofx/views/view_account_bank_statement_import.xml
-
0account_bank_statement_import_ofx/wizard/__init__.py
-
94account_bank_statement_import_ofx/wizard/account_bank_statement_import.py
@ -1,2 +1,2 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from . import models |
|||
from . import wizard |
@ -1,23 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<record id="ofx_sequence" model="ir.sequence"> |
|||
<field name="name">Bank Journal - (test ofx)</field> |
|||
<field name="prefix">OFX/%(range_year)s/</field> |
|||
<field name="implementation">no_gap</field> |
|||
<field name="padding">4</field> |
|||
<field name="use_date_range">1</field> |
|||
</record> |
|||
|
|||
|
|||
<record id="ofx_bank_journal" model="account.journal"> |
|||
<field name="name">Bank Journal - (test ofx)</field> |
|||
<field name="bank_acc_number">123456</field> |
|||
<field name="code">TBNKOFX</field> |
|||
<field name="type">bank</field> |
|||
<field name="sequence_id" ref="ofx_sequence"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="currency_id" ref="base.USD"/> |
|||
</record> |
|||
|
|||
</odoo> |
@ -1,75 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import logging |
|||
import StringIO |
|||
|
|||
from openerp import api, models |
|||
from openerp.tools.translate import _ |
|||
from openerp.exceptions import Warning as UserError |
|||
|
|||
from .ofx import OfxParser, OfxParser_ok |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class AccountBankStatementImport(models.TransientModel): |
|||
_inherit = 'account.bank.statement.import' |
|||
|
|||
@api.model |
|||
def _check_ofx(self, data_file): |
|||
if not OfxParser_ok: |
|||
return False |
|||
try: |
|||
ofx = OfxParser.parse(StringIO.StringIO(data_file)) |
|||
except Exception as e: |
|||
_logger.debug(e) |
|||
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( |
|||
[('bank_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 UserError(_("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,40 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import logging |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
try: |
|||
from ofxparse import OfxParser as OfxParserOriginal |
|||
OfxParser_ok = True |
|||
except ImportError: |
|||
_logger.warn("ofxparse not found, OFX parsing disabled.") |
|||
OfxParserOriginal = object |
|||
OfxParser_ok = False |
|||
|
|||
|
|||
class OfxParser(OfxParserOriginal): |
|||
""" Custom changes in the OFX Parser. |
|||
""" |
|||
|
|||
@classmethod |
|||
def _tagToDecimal(self, tag): |
|||
tag.string = tag.string.replace(',', '.') |
|||
|
|||
@classmethod |
|||
def parseStatement(cls_, stmt_ofx): |
|||
"""Amount with ',' replaced by '.' in the following tags : |
|||
//LEDGERBAL/BALAMT |
|||
""" |
|||
ledgerbal_tag = stmt_ofx.find('ledgerbal') |
|||
if hasattr(ledgerbal_tag, "contents"): |
|||
cls_._tagToDecimal(ledgerbal_tag.find('balamt')) |
|||
return super(OfxParser, cls_).parseStatement(stmt_ofx) |
|||
|
|||
@classmethod |
|||
def parseTransaction(cls_, txn_ofx): |
|||
"""Amount with ',' replaced by '.' in the following tags : |
|||
//TRNAMT |
|||
""" |
|||
cls_._tagToDecimal(txn_ofx.find('trnamt')) |
|||
return super(OfxParser, cls_).parseTransaction(txn_ofx) |
@ -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