mirror of
https://github.com/OCA/bank-statement-import.git
synced 2025-01-20 12:37:43 +02:00
Merge pull request #79 from hbrunn/9.0-account_bank_statement_import_camt
9.0 account bank statement import camt
This commit is contained in:
@@ -28,6 +28,7 @@ Credits
|
|||||||
Contributors
|
Contributors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
* Holger Brunn <hbrunn@therp.nl>
|
||||||
* Stefan Rijnhart <srijnhart@therp.nl>
|
* Stefan Rijnhart <srijnhart@therp.nl>
|
||||||
* Ronald Portier <rportier@therp.nl>
|
* Ronald Portier <rportier@therp.nl>
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
from . import account_bank_statement_import
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from . import models
|
||||||
|
from . import camt
|
||||||
|
|||||||
@@ -1,25 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
#
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
# Copyright (C) 2013-2015 Therp BV <http://therp.nl>
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
{
|
{
|
||||||
'name': 'CAMT Format Bank Statements Import',
|
'name': 'CAMT Format Bank Statements Import',
|
||||||
'version': '8.0.0.3.0',
|
'version': '9.0.1.0.0',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'author': 'Odoo Community Association (OCA), Therp BV',
|
'author': 'Odoo Community Association (OCA), Therp BV',
|
||||||
'website': 'https://github.com/OCA/bank-statement-import',
|
'website': 'https://github.com/OCA/bank-statement-import',
|
||||||
@@ -30,5 +14,7 @@
|
|||||||
'demo': [
|
'demo': [
|
||||||
'demo/demo_data.xml',
|
'demo/demo_data.xml',
|
||||||
],
|
],
|
||||||
'installable': False,
|
'data': [
|
||||||
|
'views/account_bank_statement_import.xml',
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""Add process_camt method to account.bank.statement.import."""
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013-2015 Therp BV <http://therp.nl>
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
import logging
|
|
||||||
from openerp import models
|
|
||||||
from .camt import CamtParser as Parser
|
|
||||||
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class AccountBankStatementImport(models.TransientModel):
|
|
||||||
"""Add process_camt method to account.bank.statement.import."""
|
|
||||||
_inherit = 'account.bank.statement.import'
|
|
||||||
|
|
||||||
def _parse_file(self, cr, uid, data_file, context=None):
|
|
||||||
"""Parse a CAMT053 XML file."""
|
|
||||||
parser = Parser()
|
|
||||||
try:
|
|
||||||
_logger.debug("Try parsing with camt.")
|
|
||||||
return parser.parse(data_file)
|
|
||||||
except ValueError:
|
|
||||||
# Not a camt file, returning super will call next candidate:
|
|
||||||
_logger.debug("Statement file was not a camt file.",
|
|
||||||
exc_info=True)
|
|
||||||
return super(AccountBankStatementImport, self)._parse_file(
|
|
||||||
cr, uid, data_file, context=context)
|
|
||||||
@@ -1,28 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Class to parse camt files."""
|
"""Class to parse camt files."""
|
||||||
##############################################################################
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
#
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
# Copyright (C) 2013-2015 Therp BV <http://therp.nl>
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from openerp.addons.account_bank_statement_import.parserlib import (
|
|
||||||
BankStatement)
|
|
||||||
|
|
||||||
|
|
||||||
class CamtParser(object):
|
class CamtParser(object):
|
||||||
@@ -58,7 +39,7 @@ class CamtParser(object):
|
|||||||
attr_value = found_node[0].text
|
attr_value = found_node[0].text
|
||||||
else:
|
else:
|
||||||
attr_value = join_str.join([x.text for x in found_node])
|
attr_value = join_str.join([x.text for x in found_node])
|
||||||
setattr(obj, attr_name, attr_value)
|
obj[attr_name] = attr_value
|
||||||
break
|
break
|
||||||
|
|
||||||
def parse_transaction_details(self, ns, node, transaction):
|
def parse_transaction_details(self, ns, node, transaction):
|
||||||
@@ -67,16 +48,21 @@ class CamtParser(object):
|
|||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, node, [
|
ns, node, [
|
||||||
'./ns:RmtInf/ns:Ustrd',
|
'./ns:RmtInf/ns:Ustrd',
|
||||||
'./ns:AddtlTxInf',
|
|
||||||
'./ns:AddtlNtryInf',
|
'./ns:AddtlNtryInf',
|
||||||
], transaction, 'message')
|
'./ns:Refs/ns:InstrId',
|
||||||
|
], transaction, 'note', join_str='\n')
|
||||||
|
# name
|
||||||
|
self.add_value_from_node(
|
||||||
|
ns, node, [
|
||||||
|
'./ns:AddtlTxInf',
|
||||||
|
], transaction, 'name', join_str='\n')
|
||||||
# eref
|
# eref
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, node, [
|
ns, node, [
|
||||||
'./ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref',
|
'./ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref',
|
||||||
'./ns:Refs/ns:EndToEndId',
|
'./ns:Refs/ns:EndToEndId',
|
||||||
],
|
],
|
||||||
transaction, 'eref'
|
transaction, 'ref'
|
||||||
)
|
)
|
||||||
# remote party values
|
# remote party values
|
||||||
party_type = 'Dbtr'
|
party_type = 'Dbtr'
|
||||||
@@ -88,15 +74,15 @@ class CamtParser(object):
|
|||||||
'./ns:RltdPties/ns:%s' % party_type, namespaces={'ns': ns})
|
'./ns:RltdPties/ns:%s' % party_type, namespaces={'ns': ns})
|
||||||
if party_node:
|
if party_node:
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, party_node[0], './ns:Nm', transaction, 'remote_owner')
|
ns, party_node[0], './ns:Nm', transaction, 'partner_name')
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, party_node[0], './ns:PstlAdr/ns:Ctry', transaction,
|
ns, party_node[0], './ns:PstlAdr/ns:Ctry', transaction,
|
||||||
'remote_owner_country'
|
'partner_country'
|
||||||
)
|
)
|
||||||
address_node = party_node[0].xpath(
|
address_node = party_node[0].xpath(
|
||||||
'./ns:PstlAdr/ns:AdrLine', namespaces={'ns': ns})
|
'./ns:PstlAdr/ns:AdrLine', namespaces={'ns': ns})
|
||||||
if address_node:
|
if address_node:
|
||||||
transaction.remote_owner_address = [address_node[0].text]
|
transaction['partner_address'] = [address_node[0].text]
|
||||||
# Get remote_account from iban or from domestic account:
|
# Get remote_account from iban or from domestic account:
|
||||||
account_node = node.xpath(
|
account_node = node.xpath(
|
||||||
'./ns:RltdPties/ns:%sAcct/ns:Id' % party_type,
|
'./ns:RltdPties/ns:%sAcct/ns:Id' % party_type,
|
||||||
@@ -106,35 +92,52 @@ class CamtParser(object):
|
|||||||
iban_node = account_node[0].xpath(
|
iban_node = account_node[0].xpath(
|
||||||
'./ns:IBAN', namespaces={'ns': ns})
|
'./ns:IBAN', namespaces={'ns': ns})
|
||||||
if iban_node:
|
if iban_node:
|
||||||
transaction.remote_account = iban_node[0].text
|
transaction['account_number'] = iban_node[0].text
|
||||||
bic_node = node.xpath(
|
bic_node = node.xpath(
|
||||||
'./ns:RltdAgts/ns:%sAgt/ns:FinInstnId/ns:BIC' % party_type,
|
'./ns:RltdAgts/ns:%sAgt/ns:FinInstnId/ns:BIC' % party_type,
|
||||||
namespaces={'ns': ns}
|
namespaces={'ns': ns}
|
||||||
)
|
)
|
||||||
if bic_node:
|
if bic_node:
|
||||||
transaction.remote_bank_bic = bic_node[0].text
|
transaction['account_bic'] = bic_node[0].text
|
||||||
else:
|
else:
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, account_node[0], './ns:Othr/ns:Id', transaction,
|
ns, account_node[0], './ns:Othr/ns:Id', transaction,
|
||||||
'remote_account'
|
'account_number'
|
||||||
)
|
)
|
||||||
|
|
||||||
def parse_transaction(self, ns, node, transaction):
|
def parse_transaction(self, ns, node):
|
||||||
"""Parse transaction (entry) node."""
|
"""Parse transaction (entry) node."""
|
||||||
|
transaction = {}
|
||||||
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)
|
|
||||||
|
transaction['amount'] = self.parse_amount(ns, node)
|
||||||
|
|
||||||
details_node = node.xpath(
|
details_node = node.xpath(
|
||||||
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns})
|
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns})
|
||||||
if details_node:
|
if details_node:
|
||||||
self.parse_transaction_details(ns, details_node[0], transaction)
|
self.parse_transaction_details(ns, details_node[0], transaction)
|
||||||
transaction.data = etree.tostring(node)
|
if not transaction.get('name'):
|
||||||
|
self.add_value_from_node(
|
||||||
|
ns, node, './ns:AddtlNtryInf', transaction, 'name')
|
||||||
|
if not transaction.get('name'):
|
||||||
|
transaction['name'] = '/'
|
||||||
|
if not transaction.get('ref'):
|
||||||
|
self.add_value_from_node(
|
||||||
|
ns, node, [
|
||||||
|
'./ns:NtryDtls/ns:Btch/ns:PmtInfId',
|
||||||
|
],
|
||||||
|
transaction, 'ref'
|
||||||
|
)
|
||||||
|
transaction['data'] = etree.tostring(node)
|
||||||
return transaction
|
return transaction
|
||||||
|
|
||||||
def get_balance_amounts(self, ns, node):
|
def get_balance_amounts(self, ns, node):
|
||||||
@@ -172,27 +175,28 @@ class CamtParser(object):
|
|||||||
|
|
||||||
def parse_statement(self, ns, node):
|
def parse_statement(self, ns, node):
|
||||||
"""Parse a single Stmt node."""
|
"""Parse a single Stmt node."""
|
||||||
statement = BankStatement()
|
result = {}
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, node, [
|
ns, node, [
|
||||||
'./ns:Acct/ns:Id/ns:IBAN',
|
'./ns:Acct/ns:Id/ns:IBAN',
|
||||||
'./ns:Acct/ns:Id/ns:Othr/ns:Id',
|
'./ns:Acct/ns:Id/ns:Othr/ns:Id',
|
||||||
], statement, 'local_account'
|
], result, 'account_number'
|
||||||
)
|
)
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, node, './ns:Id', statement, 'statement_id')
|
ns, node, './ns:Id', result, 'name')
|
||||||
self.add_value_from_node(
|
self.add_value_from_node(
|
||||||
ns, node, './ns:Acct/ns:Ccy', statement, 'local_currency')
|
ns, node, './ns:Dt', result, 'date')
|
||||||
(statement.start_balance, statement.end_balance) = (
|
self.add_value_from_node(
|
||||||
|
ns, node, './ns:Acct/ns:Ccy', result, 'currency')
|
||||||
|
result['balance_start'], result['balance_end_real'] = (
|
||||||
self.get_balance_amounts(ns, node))
|
self.get_balance_amounts(ns, node))
|
||||||
transaction_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns})
|
transaction_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns})
|
||||||
|
result['transactions'] = []
|
||||||
for entry_node in transaction_nodes:
|
for entry_node in transaction_nodes:
|
||||||
transaction = statement.create_transaction()
|
transaction = self.parse_transaction(ns, entry_node)
|
||||||
self.parse_transaction(ns, entry_node, transaction)
|
if transaction:
|
||||||
if statement['transactions']:
|
result['transactions'].append(transaction)
|
||||||
statement.date = datetime.strptime(
|
return result
|
||||||
statement['transactions'][0].execution_date, "%Y-%m-%d")
|
|
||||||
return statement
|
|
||||||
|
|
||||||
def check_version(self, ns, root):
|
def check_version(self, ns, root):
|
||||||
"""Validate validity of camt file."""
|
"""Validate validity of camt file."""
|
||||||
@@ -232,8 +236,14 @@ class CamtParser(object):
|
|||||||
ns = root.tag[1:root.tag.index("}")]
|
ns = root.tag[1:root.tag.index("}")]
|
||||||
self.check_version(ns, root)
|
self.check_version(ns, root)
|
||||||
statements = []
|
statements = []
|
||||||
|
currency = None
|
||||||
|
account_number = None
|
||||||
for node in root[0][1:]:
|
for node in root[0][1:]:
|
||||||
statement = self.parse_statement(ns, node)
|
statement = self.parse_statement(ns, node)
|
||||||
if len(statement['transactions']):
|
if len(statement['transactions']):
|
||||||
|
if 'currency' in statement:
|
||||||
|
currency = statement.pop('currency')
|
||||||
|
if 'account_number' in statement:
|
||||||
|
account_number = statement.pop('account_number')
|
||||||
statements.append(statement)
|
statements.append(statement)
|
||||||
return statements
|
return currency, account_number, statements
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<odoo>
|
||||||
<data>
|
<record id="camt_company_bank" model="res.partner.bank">
|
||||||
|
<field name="acc_number">NL77ABNA0574908765</field>
|
||||||
|
<field name="partner_id" ref="base.main_partner"></field>
|
||||||
|
<field name="company_id" ref="base.main_company"></field>
|
||||||
|
<field name="bank_id" ref="base.res_bank_1"/>
|
||||||
|
</record>
|
||||||
<record id="camt_bank_journal" model="account.journal">
|
<record id="camt_bank_journal" model="account.journal">
|
||||||
<field name="name">Bank Journal - (test camt)</field>
|
<field name="name">Bank Journal - (test camt)</field>
|
||||||
<field name="code">TBNKCAMT</field>
|
<field name="code">TBNKCAMT</field>
|
||||||
<field name="type">bank</field>
|
<field name="type">bank</field>
|
||||||
<field name="sequence_id" ref="account.sequence_bank_journal"/>
|
<field name="bank_account_id" ref="camt_company_bank" />
|
||||||
<field name="default_debit_account_id" ref="account.bnk"/>
|
|
||||||
<field name="default_credit_account_id" ref="account.bnk"/>
|
|
||||||
<field name="user_id" ref="base.user_root"/>
|
|
||||||
</record>
|
</record>
|
||||||
|
</odoo>
|
||||||
<record id="camt_company_bank" model="res.partner.bank">
|
|
||||||
<field name="owner_name">Your Company</field>
|
|
||||||
<field name="acc_number">NL77ABNA0574908765</field>
|
|
||||||
<field name="partner_id" ref="base.partner_root"></field>
|
|
||||||
<field name="company_id" ref="base.main_company"></field>
|
|
||||||
<field name="journal_id" ref="camt_bank_journal"></field>
|
|
||||||
<field name="state">bank</field>
|
|
||||||
<field name="bank" ref="base.res_bank_1"/>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
</openerp>
|
|
||||||
|
|||||||
24
account_bank_statement_import_camt/i18n/de.po
Normal file
24
account_bank_statement_import_camt/i18n/de.po
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * account_bank_statement_import_camt
|
||||||
|
#
|
||||||
|
# Translators:
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: bank-statement-import (8.0)\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2015-07-24 21:51+0000\n"
|
||||||
|
"PO-Revision-Date: 2015-10-04 11:43+0200\n"
|
||||||
|
"Last-Translator: Rudolf Schnapka <rs@techno-flex.de>\n"
|
||||||
|
"Language-Team: French (http://www.transifex.com/oca/OCA-bank-statement-import-8-0/language/fr/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: fr\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
"X-Generator: Poedit 1.8.3\n"
|
||||||
|
|
||||||
|
#. module: account_bank_statement_import_camt
|
||||||
|
#: model:ir.model,name:account_bank_statement_import_camt.model_account_bank_statement_import
|
||||||
|
msgid "Import Bank Statement"
|
||||||
|
msgstr "Kontoauszug importieren"
|
||||||
23
account_bank_statement_import_camt/i18n/pt_PT.po
Normal file
23
account_bank_statement_import_camt/i18n/pt_PT.po
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * account_bank_statement_import_camt
|
||||||
|
#
|
||||||
|
# Translators:
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: bank-statement-import (8.0)\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2016-08-18 10:27+0000\n"
|
||||||
|
"PO-Revision-Date: 2015-07-24 07:41+0000\n"
|
||||||
|
"Last-Translator: <>\n"
|
||||||
|
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/oca/OCA-bank-statement-import-8-0/language/pt_PT/)\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Language: pt_PT\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#. module: account_bank_statement_import_camt
|
||||||
|
#: model:ir.model,name:account_bank_statement_import_camt.model_account_bank_statement_import
|
||||||
|
msgid "Import Bank Statement"
|
||||||
|
msgstr "Importar Extrato Bancário"
|
||||||
4
account_bank_statement_import_camt/models/__init__.py
Normal file
4
account_bank_statement_import_camt/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
from . import account_bank_statement_import
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Add process_camt method to account.bank.statement.import."""
|
||||||
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
import logging
|
||||||
|
import StringIO
|
||||||
|
import zipfile
|
||||||
|
from openerp import api, models
|
||||||
|
from ..camt import CamtParser as Parser
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountBankStatementImport(models.TransientModel):
|
||||||
|
"""Add process_camt method to account.bank.statement.import."""
|
||||||
|
_inherit = 'account.bank.statement.import'
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _parse_file(self, data_file):
|
||||||
|
"""Parse a CAMT053 XML file."""
|
||||||
|
try:
|
||||||
|
parser = Parser()
|
||||||
|
_logger.debug("Try parsing with camt.")
|
||||||
|
return parser.parse(data_file)
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
with zipfile.ZipFile(StringIO.StringIO(data_file)) as data:
|
||||||
|
currency = None
|
||||||
|
account_number = None
|
||||||
|
transactions = []
|
||||||
|
for member in data.namelist():
|
||||||
|
currency, account_number, new = self._parse_file(
|
||||||
|
data.open(member).read()
|
||||||
|
)
|
||||||
|
transactions.extend(new)
|
||||||
|
return currency, account_number, transactions
|
||||||
|
except (zipfile.BadZipfile, ValueError):
|
||||||
|
pass
|
||||||
|
# Not a camt file, returning super will call next candidate:
|
||||||
|
_logger.debug("Statement file was not a camt file.",
|
||||||
|
exc_info=True)
|
||||||
|
return super(AccountBankStatementImport, self)._parse_file(data_file)
|
||||||
@@ -2,15 +2,15 @@
|
|||||||
<BkToCstmrStmt>
|
<BkToCstmrStmt>
|
||||||
<GrpHdr>
|
<GrpHdr>
|
||||||
<MsgId>TESTBANK/NL/1420561226673</MsgId>
|
<MsgId>TESTBANK/NL/1420561226673</MsgId>
|
||||||
<CreDtTm>2013-01-06T16:20:26.673Z</CreDtTm>
|
<CreDtTm>2014-01-06T16:20:26.673Z</CreDtTm>
|
||||||
</GrpHdr>
|
</GrpHdr>
|
||||||
<Stmt>
|
<Stmt>
|
||||||
<Id>1234Test/1</Id>
|
<Id>1234Test/1</Id>
|
||||||
<LglSeqNb>2</LglSeqNb>
|
<LglSeqNb>2</LglSeqNb>
|
||||||
<CreDtTm>2013-01-06T16:20:26.673Z</CreDtTm>
|
<CreDtTm>2014-01-06T16:20:26.673Z</CreDtTm>
|
||||||
<FrToDt>
|
<FrToDt>
|
||||||
<FrDtTm>2013-01-05T00:00:00.000Z</FrDtTm>
|
<FrDtTm>2014-01-05T00:00:00.000Z</FrDtTm>
|
||||||
<ToDtTm>2013-01-05T23:59:59.999Z</ToDtTm>
|
<ToDtTm>2014-01-05T23:59:59.999Z</ToDtTm>
|
||||||
</FrToDt>
|
</FrToDt>
|
||||||
<Acct>
|
<Acct>
|
||||||
<Id>
|
<Id>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<Amt Ccy="EUR">15568.27</Amt>
|
<Amt Ccy="EUR">15568.27</Amt>
|
||||||
<CdtDbtInd>CRDT</CdtDbtInd>
|
<CdtDbtInd>CRDT</CdtDbtInd>
|
||||||
<Dt>
|
<Dt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</Dt>
|
</Dt>
|
||||||
</Bal>
|
</Bal>
|
||||||
<Bal>
|
<Bal>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<Amt Ccy="EUR">15121.12</Amt>
|
<Amt Ccy="EUR">15121.12</Amt>
|
||||||
<CdtDbtInd>CRDT</CdtDbtInd>
|
<CdtDbtInd>CRDT</CdtDbtInd>
|
||||||
<Dt>
|
<Dt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</Dt>
|
</Dt>
|
||||||
</Bal>
|
</Bal>
|
||||||
<Ntry>
|
<Ntry>
|
||||||
@@ -52,10 +52,10 @@
|
|||||||
<CdtDbtInd>DBIT</CdtDbtInd>
|
<CdtDbtInd>DBIT</CdtDbtInd>
|
||||||
<Sts>BOOK</Sts>
|
<Sts>BOOK</Sts>
|
||||||
<BookgDt>
|
<BookgDt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</BookgDt>
|
</BookgDt>
|
||||||
<ValDt>
|
<ValDt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</ValDt>
|
</ValDt>
|
||||||
<BkTxCd>
|
<BkTxCd>
|
||||||
<Domn>
|
<Domn>
|
||||||
@@ -104,9 +104,9 @@
|
|||||||
</CdtrAgt>
|
</CdtrAgt>
|
||||||
</RltdAgts>
|
</RltdAgts>
|
||||||
<RmtInf>
|
<RmtInf>
|
||||||
<Ustrd>Insurance policy 857239PERIOD 01.01.2013 - 31.12.2013</Ustrd>
|
<Ustrd>Insurance policy 857239PERIOD 01.01.2014 - 31.12.2014</Ustrd>
|
||||||
</RmtInf>
|
</RmtInf>
|
||||||
<AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2013 - 31.12.2013</AddtlTxInf>
|
<AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2014 - 31.12.2014</AddtlTxInf>
|
||||||
</TxDtls>
|
</TxDtls>
|
||||||
</NtryDtls>
|
</NtryDtls>
|
||||||
</Ntry>
|
</Ntry>
|
||||||
@@ -116,10 +116,10 @@
|
|||||||
<RvslInd>true</RvslInd>
|
<RvslInd>true</RvslInd>
|
||||||
<Sts>BOOK</Sts>
|
<Sts>BOOK</Sts>
|
||||||
<BookgDt>
|
<BookgDt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</BookgDt>
|
</BookgDt>
|
||||||
<ValDt>
|
<ValDt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</ValDt>
|
</ValDt>
|
||||||
<BkTxCd>
|
<BkTxCd>
|
||||||
<Domn>
|
<Domn>
|
||||||
@@ -182,10 +182,10 @@
|
|||||||
<CdtDbtInd>CRDT</CdtDbtInd>
|
<CdtDbtInd>CRDT</CdtDbtInd>
|
||||||
<Sts>BOOK</Sts>
|
<Sts>BOOK</Sts>
|
||||||
<BookgDt>
|
<BookgDt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</BookgDt>
|
</BookgDt>
|
||||||
<ValDt>
|
<ValDt>
|
||||||
<Dt>2013-01-05</Dt>
|
<Dt>2014-01-05</Dt>
|
||||||
</ValDt>
|
</ValDt>
|
||||||
<BkTxCd>
|
<BkTxCd>
|
||||||
<Domn>
|
<Domn>
|
||||||
@@ -202,7 +202,7 @@
|
|||||||
<NtryDtls>
|
<NtryDtls>
|
||||||
<TxDtls>
|
<TxDtls>
|
||||||
<Refs>
|
<Refs>
|
||||||
<InstrId>INNDNL2U20130105000217200000708</InstrId>
|
<InstrId>INNDNL2U20140105000217200000708</InstrId>
|
||||||
<EndToEndId>115</EndToEndId>
|
<EndToEndId>115</EndToEndId>
|
||||||
</Refs>
|
</Refs>
|
||||||
<AmtDtls>
|
<AmtDtls>
|
||||||
BIN
account_bank_statement_import_camt/test_files/test-camt053.zip
Normal file
BIN
account_bank_statement_import_camt/test_files/test-camt053.zip
Normal file
Binary file not shown.
@@ -1,23 +1,5 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
"""Test import of bank statement for camt.053."""
|
"""Test import of bank statement for camt.053."""
|
||||||
##############################################################################
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
#
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
# Copyright (C) 2015 Therp BV <http://therp.nl>.
|
|
||||||
#
|
|
||||||
# All other contributions are (C) by their respective contributors
|
|
||||||
#
|
|
||||||
# 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 by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
from . import test_import_bank_statement
|
from . import test_import_bank_statement
|
||||||
|
|||||||
@@ -1,45 +1,54 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Run test to import camt.053 import."""
|
"""Run test to import camt.053 import."""
|
||||||
##############################################################################
|
# © 2013-2016 Therp BV <http://therp.nl>
|
||||||
#
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
# Copyright (C) 2015 Therp BV <http://therp.nl>.
|
import base64
|
||||||
#
|
from openerp.tests.common import TransactionCase
|
||||||
# This program is free software: you can redistribute it and/or modify
|
from openerp.tools.misc import file_open
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
from openerp.addons.account_bank_statement_import.tests import (
|
|
||||||
TestStatementFile)
|
|
||||||
|
|
||||||
|
|
||||||
class TestImport(TestStatementFile):
|
class TestImport(TransactionCase):
|
||||||
"""Run test to import camt import."""
|
"""Run test to import camt import."""
|
||||||
|
|
||||||
def test_statement_import(self):
|
|
||||||
"""Test correct creation of single statement."""
|
|
||||||
transactions = [
|
transactions = [
|
||||||
{
|
{
|
||||||
'remote_account': 'NL46ABNA0499998748',
|
'account_number': 'NL46ABNA0499998748',
|
||||||
'transferred_amount': -754.25,
|
'amount': -754.25,
|
||||||
'value_date': '2013-01-05',
|
'date': '2014-01-05',
|
||||||
'ref': '435005714488-ABNO33052620',
|
'ref': '435005714488-ABNO33052620',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
# statement name is account number + '-' + date of last 62F line:
|
|
||||||
self._test_statement_import(
|
def test_statement_import(self):
|
||||||
'account_bank_statement_import_camt', 'test-camt053.xml',
|
"""Test correct creation of single statement."""
|
||||||
'1234Test/1',
|
action = {}
|
||||||
local_account='NL77ABNA0574908765',
|
with file_open(
|
||||||
start_balance=15568.27, end_balance=15121.12,
|
'account_bank_statement_import_camt/test_files/test-camt053'
|
||||||
transactions=transactions
|
) as testfile:
|
||||||
)
|
action = self.env['account.bank.statement.import'].create({
|
||||||
|
'data_file': base64.b64encode(testfile.read()),
|
||||||
|
}).import_file()
|
||||||
|
for statement in self.env['account.bank.statement'].browse(
|
||||||
|
action['context']['statement_ids']
|
||||||
|
):
|
||||||
|
self.assertTrue(any(
|
||||||
|
all(
|
||||||
|
line[key] == self.transactions[0][key]
|
||||||
|
for key in ['amount', 'date', 'ref']
|
||||||
|
) and
|
||||||
|
line.bank_account_id.acc_number ==
|
||||||
|
self.transactions[0]['account_number']
|
||||||
|
for line in statement.line_ids
|
||||||
|
))
|
||||||
|
|
||||||
|
def test_zip_import(self):
|
||||||
|
"""Test import of multiple statements from zip file."""
|
||||||
|
with file_open(
|
||||||
|
'account_bank_statement_import_camt/test_files/test-camt053.zip'
|
||||||
|
) as testfile:
|
||||||
|
action = self.env['account.bank.statement.import'].create({
|
||||||
|
'data_file': base64.b64encode(testfile.read()),
|
||||||
|
}).import_file()
|
||||||
|
for statement in self.env['account.bank.statement'].browse(
|
||||||
|
action['context']['statement_ids']
|
||||||
|
):
|
||||||
|
self.assertTrue(statement.line_ids)
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
<record id="account_bank_statement_import_view" 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">
|
||||||
|
<ul id="statement_format" position="inside">
|
||||||
|
<li>CAMT</li>
|
||||||
|
<li>zipped CAMT</li>
|
||||||
|
</ul>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
||||||
Reference in New Issue
Block a user