Browse Source

[ENH] Improve determination of start and end balance for camt.

pull/153/head
Ronald Portier 8 years ago
parent
commit
49a7b8408b
  1. 98
      account_bank_statement_import_camt/models/parser.py

98
account_bank_statement_import_camt/models/parser.py

@ -2,8 +2,9 @@
"""Class to parse camt files.""" """Class to parse camt files."""
############################################################################## ##############################################################################
# #
# Copyright (C) 2013-2015 Therp BV <http://therp.nl>
# Copyright (C) 2013-2018 Therp BV <http://therp.nl>
# Copyright 2017 Open Net Sàrl # Copyright 2017 Open Net Sàrl
# (C) 2015 1200wd.com
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published # it under the terms of the GNU Affero General Public License as published
@ -19,14 +20,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################## ##############################################################################
import logging
import re import re
from copy import copy from copy import copy
from datetime import datetime from datetime import datetime
from lxml import etree from lxml import etree
from openerp import _ from openerp import _
from openerp.addons.account_bank_statement_import.parserlib import ( from openerp.addons.account_bank_statement_import.parserlib import (
BankStatement) BankStatement)
@ -195,38 +195,53 @@ class CamtParser(models.AbstractModel):
transaction['data'] = etree.tostring(data) transaction['data'] = etree.tostring(data)
yield transaction yield transaction
def get_balance_amounts(self, ns, node):
"""Return opening and closing balance.
Depending on kind of balance and statement, the balance might be in a
different kind of node:
OPBD = OpeningBalance
PRCD = PreviousClosingBalance
ITBD = InterimBalance (first ITBD is start-, second is end-balance)
CLBD = ClosingBalance
def get_balance_type_node(self, node, balance_type):
"""
:param node: BkToCstmrStmt/Stmt/Bal node
:param balance type: one of 'OPBD', 'PRCD', 'ITBD', 'CLBD'
""" """
start_balance_node = None
end_balance_node = None
for node_name in ['OPBD', 'PRCD', 'CLBD', 'ITBD']:
code_expr = ( code_expr = (
'./ns:Bal/ns:Tp/ns:CdOrPrtry/ns:Cd[text()="%s"]/../../..' % './ns:Bal/ns:Tp/ns:CdOrPrtry/ns:Cd[text()="%s"]/../../..' %
node_name
balance_type
) )
balance_node = node.xpath(code_expr, namespaces={'ns': ns})
if balance_node:
if node_name in ['OPBD', 'PRCD']:
start_balance_node = balance_node[0]
elif node_name == 'CLBD':
end_balance_node = balance_node[0]
else:
if not start_balance_node:
start_balance_node = balance_node[0]
if not end_balance_node:
end_balance_node = balance_node[-1]
return (
self.parse_amount(ns, start_balance_node),
self.parse_amount(ns, end_balance_node)
return self.xpath(node, code_expr)
def get_start_balance(self, node):
"""
Find the (only) balance node with code OpeningBalance, or
the only one with code 'PreviousClosingBalance'
or the first balance node with code InterimBalance in
the case of preceeding pagination.
:param node: BkToCstmrStmt/Stmt/Bal node
"""
balance = 0
nodes = (
self.get_balance_type_node(node, 'OPBD') or
self.get_balance_type_node(node, 'PRCD') or
self.get_balance_type_node(node, 'ITBD')
) )
if nodes:
balance = self.parse_amount(nodes[0])
return balance
def get_end_balance(self, node):
"""
Find the (only) balance node with code ClosingBalance, or
the second (and last) balance node with code InterimBalance in
the case of continued pagination.
:param node: BkToCstmrStmt/Stmt/Bal node
"""
balance = 0
nodes = (
self.get_balance_type_node(node, 'CLAV') or
self.get_balance_type_node(node, 'CLBD') or
self.get_balance_type_node(node, 'ITBD')
)
if nodes:
balance = self.parse_amount(nodes[-1])
return balance
def parse_statement(self, ns, node): def parse_statement(self, ns, node):
"""Parse a single Stmt node.""" """Parse a single Stmt node."""
@ -241,14 +256,14 @@ class CamtParser(models.AbstractModel):
ns, node, './ns:Id', statement, 'statement_id') ns, node, './ns:Id', statement, 'statement_id')
self.add_value_from_node( self.add_value_from_node(
ns, node, './ns:Acct/ns:Ccy', statement, 'local_currency') ns, node, './ns:Acct/ns:Ccy', statement, 'local_currency')
(statement.start_balance, statement.end_balance) = (
self.get_balance_amounts(ns, node))
entry_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns})
transactions = []
for entry_node in entry_nodes:
statement.start_balance = self.get_start_balance(node)
statement.end_balance = self.get_end_balance(node)
transaction_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns})
total_amount = 0
for entry_node in transaction_nodes:
transaction = statement.create_transaction() transaction = statement.create_transaction()
transactions.extend(self.parse_entry(ns, entry_node, transaction))
statement['transactions'] = transactions
total_amount += transaction['transferred_amount']
self.parse_transaction(ns, entry_node, transaction)
if statement['transactions']: if statement['transactions']:
execution_date = statement['transactions'][0].execution_date[:10] execution_date = statement['transactions'][0].execution_date[:10]
statement.date = datetime.strptime(execution_date, "%Y-%m-%d") statement.date = datetime.strptime(execution_date, "%Y-%m-%d")
@ -256,6 +271,15 @@ class CamtParser(models.AbstractModel):
if execution_date not in statement.statement_id: if execution_date not in statement.statement_id:
statement.statement_id = "%s-%s" % ( statement.statement_id = "%s-%s" % (
execution_date, statement.statement_id) execution_date, statement.statement_id)
if statement.start_balance == 0 and statement.end_balance != 0:
statement.start_balance = statement.end_balance - total_amount
_logger.debug(
_("Start balance %s calculated from end balance %s and"
" Total amount %s."),
statement.start_balance,
statement.end_balance,
total_amount
)
return statement return statement
def check_version(self, ns, root): def check_version(self, ns, root):

Loading…
Cancel
Save