|
@ -3,6 +3,7 @@ |
|
|
############################################################################## |
|
|
############################################################################## |
|
|
# |
|
|
# |
|
|
# Copyright (C) 2013-2015 Therp BV <http://therp.nl> |
|
|
# Copyright (C) 2013-2015 Therp BV <http://therp.nl> |
|
|
|
|
|
# Copyright 2017 Open Net Sàrl |
|
|
# |
|
|
# |
|
|
# 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 |
|
@ -18,11 +19,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 re |
|
|
import re |
|
|
from datetime import datetime |
|
|
from datetime import datetime |
|
|
from lxml import etree |
|
|
from lxml import etree |
|
|
from openerp.addons.account_bank_statement_import.parserlib import ( |
|
|
from openerp.addons.account_bank_statement_import.parserlib import ( |
|
|
BankStatement) |
|
|
BankStatement) |
|
|
|
|
|
from copy import copy |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CamtParser(object): |
|
|
class CamtParser(object): |
|
@ -62,7 +65,7 @@ class CamtParser(object): |
|
|
break |
|
|
break |
|
|
|
|
|
|
|
|
def parse_transaction_details(self, ns, node, transaction): |
|
|
def parse_transaction_details(self, ns, node, transaction): |
|
|
"""Parse transaction details (message, party, account...).""" |
|
|
|
|
|
|
|
|
"""Parse TxDtls node.""" |
|
|
# message |
|
|
# message |
|
|
self.add_value_from_node( |
|
|
self.add_value_from_node( |
|
|
ns, node, [ |
|
|
ns, node, [ |
|
@ -78,6 +81,9 @@ class CamtParser(object): |
|
|
], |
|
|
], |
|
|
transaction, 'eref' |
|
|
transaction, 'eref' |
|
|
) |
|
|
) |
|
|
|
|
|
amount = self.parse_amount(ns, node) |
|
|
|
|
|
if amount != 0.0: |
|
|
|
|
|
transaction['amount'] = amount |
|
|
# remote party values |
|
|
# remote party values |
|
|
party_type = 'Dbtr' |
|
|
party_type = 'Dbtr' |
|
|
party_type_node = node.xpath( |
|
|
party_type_node = node.xpath( |
|
@ -119,33 +125,48 @@ class CamtParser(object): |
|
|
'remote_account' |
|
|
'remote_account' |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
def parse_transaction(self, ns, node, transaction): |
|
|
|
|
|
"""Parse transaction (entry) node.""" |
|
|
|
|
|
|
|
|
def parse_entry(self, ns, node, transaction): |
|
|
|
|
|
"""Parse an Ntry node and yield transactions.""" |
|
|
self.add_value_from_node( |
|
|
self.add_value_from_node( |
|
|
ns, node, './ns:BkTxCd/ns:Prtry/ns:Cd', transaction, |
|
|
ns, node, './ns:BkTxCd/ns:Prtry/ns:Cd', transaction, |
|
|
'transfer_type' |
|
|
'transfer_type' |
|
|
) |
|
|
) |
|
|
|
|
|
self.add_value_from_node( |
|
|
|
|
|
ns, node, './ns:BookgDt/ns:Dt', transaction, 'date') |
|
|
self.add_value_from_node( |
|
|
self.add_value_from_node( |
|
|
ns, node, './ns:BookgDt/ns:Dt', transaction, 'execution_date') |
|
|
ns, node, './ns:BookgDt/ns:Dt', transaction, 'execution_date') |
|
|
self.add_value_from_node( |
|
|
self.add_value_from_node( |
|
|
ns, node, './ns:ValDt/ns:Dt', transaction, 'value_date') |
|
|
ns, node, './ns:ValDt/ns:Dt', transaction, 'value_date') |
|
|
transaction.transferred_amount = self.parse_amount(ns, node) |
|
|
|
|
|
details_node = node.xpath( |
|
|
|
|
|
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns}) |
|
|
|
|
|
if details_node: |
|
|
|
|
|
self.parse_transaction_details(ns, details_node[0], transaction) |
|
|
|
|
|
if not transaction.message: |
|
|
|
|
|
|
|
|
amount = self.parse_amount(ns, node) |
|
|
|
|
|
if amount != 0.0: |
|
|
|
|
|
transaction['amount'] = amount |
|
|
self.add_value_from_node( |
|
|
self.add_value_from_node( |
|
|
ns, node, './ns:AddtlNtryInf', transaction, 'message') |
|
|
|
|
|
if not transaction.eref: |
|
|
|
|
|
|
|
|
ns, node, './ns:AddtlNtryInf', transaction, 'name') |
|
|
self.add_value_from_node( |
|
|
self.add_value_from_node( |
|
|
ns, node, [ |
|
|
ns, node, [ |
|
|
|
|
|
'./ns:NtryDtls/ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref', |
|
|
'./ns:NtryDtls/ns:Btch/ns:PmtInfId', |
|
|
'./ns:NtryDtls/ns:Btch/ns:PmtInfId', |
|
|
], |
|
|
], |
|
|
transaction, 'eref' |
|
|
|
|
|
|
|
|
transaction, 'ref' |
|
|
) |
|
|
) |
|
|
transaction.data = etree.tostring(node) |
|
|
|
|
|
return transaction |
|
|
|
|
|
|
|
|
details_nodes = node.xpath( |
|
|
|
|
|
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns}) |
|
|
|
|
|
if len(details_nodes) == 0: |
|
|
|
|
|
yield transaction |
|
|
|
|
|
return |
|
|
|
|
|
transaction_base = transaction |
|
|
|
|
|
for i, dnode in enumerate(details_nodes): |
|
|
|
|
|
transaction = copy(transaction_base) |
|
|
|
|
|
self.parse_transaction_details(ns, dnode, transaction) |
|
|
|
|
|
# transactions['data'] should be a synthetic xml snippet which |
|
|
|
|
|
# contains only the TxDtls that's relevant. |
|
|
|
|
|
data = copy(node) |
|
|
|
|
|
for j, dnode in enumerate(data.xpath( |
|
|
|
|
|
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns})): |
|
|
|
|
|
if j != i: |
|
|
|
|
|
dnode.getparent().remove(dnode) |
|
|
|
|
|
transaction['data'] = etree.tostring(data) |
|
|
|
|
|
yield transaction |
|
|
|
|
|
|
|
|
def get_balance_amounts(self, ns, node): |
|
|
def get_balance_amounts(self, ns, node): |
|
|
"""Return opening and closing balance. |
|
|
"""Return opening and closing balance. |
|
@ -195,10 +216,12 @@ class CamtParser(object): |
|
|
ns, node, './ns:Acct/ns:Ccy', statement, 'local_currency') |
|
|
ns, node, './ns:Acct/ns:Ccy', statement, 'local_currency') |
|
|
(statement.start_balance, statement.end_balance) = ( |
|
|
(statement.start_balance, statement.end_balance) = ( |
|
|
self.get_balance_amounts(ns, node)) |
|
|
self.get_balance_amounts(ns, node)) |
|
|
transaction_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns}) |
|
|
|
|
|
for entry_node in transaction_nodes: |
|
|
|
|
|
|
|
|
entry_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns}) |
|
|
|
|
|
transactions = [] |
|
|
|
|
|
for entry_node in entry_nodes: |
|
|
transaction = statement.create_transaction() |
|
|
transaction = statement.create_transaction() |
|
|
self.parse_transaction(ns, entry_node, transaction) |
|
|
|
|
|
|
|
|
transactions.extend(self.parse_entry(ns, entry_node, transaction)) |
|
|
|
|
|
statement['transactions'] = transactions |
|
|
if statement['transactions']: |
|
|
if statement['transactions']: |
|
|
execution_date = statement['transactions'][0].execution_date |
|
|
execution_date = statement['transactions'][0].execution_date |
|
|
statement.date = datetime.strptime(execution_date, "%Y-%m-%d") |
|
|
statement.date = datetime.strptime(execution_date, "%Y-%m-%d") |
|
|