From 83b5d6483ce4addb00e8fb1475ac31ca35114d04 Mon Sep 17 00:00:00 2001 From: Andrea Date: Wed, 29 Nov 2017 15:00:18 +0100 Subject: [PATCH] [11.0][MIG] account_bank_statement_import_camt --- account_bank_statement_import_camt/README.rst | 30 ++++---- .../__init__.py | 1 - .../__manifest__.py | 3 +- .../models/__init__.py | 1 - .../models/account_bank_statement_import.py | 5 +- .../models/parser.py | 47 ++++++------- .../tests/__init__.py | 1 - .../tests/test_import_bank_statement.py | 69 ++++++++++--------- 8 files changed, 81 insertions(+), 76 deletions(-) diff --git a/account_bank_statement_import_camt/README.rst b/account_bank_statement_import_camt/README.rst index a564f7a..50fa28d 100644 --- a/account_bank_statement_import_camt/README.rst +++ b/account_bank_statement_import_camt/README.rst @@ -1,25 +1,28 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License: AGPL-3 +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: https://www.gnu.org/licenses/agpl + :alt: License: AGPL-3 +========================= Bank Statement Parse Camt ========================= -Module to import SEPA CAMT.053 Format bank statement files. +Module to import SEPA CAMT.053 and CAMT.054 Format bank statement files. Based on the Banking addons framework. -Known issues / Roadmap -====================== -* None +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/174/11.0 + Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. -In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed feedback -`here `_. +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. Credits @@ -31,6 +34,9 @@ Contributors * Holger Brunn * Stefan Rijnhart * Ronald Portier +* Andrea Stirpe + +Do not contact contributors directly about support or help with technical issues. Maintainer ---------- @@ -45,6 +51,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit http://odoo-community.org. -This module should make it easy to migrate bank statement import -modules written for earlies versions of Odoo/OpenERP. +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_bank_statement_import_camt/__init__.py b/account_bank_statement_import_camt/__init__.py index 1eb5270..867022b 100644 --- a/account_bank_statement_import_camt/__init__.py +++ b/account_bank_statement_import_camt/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2013-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import models diff --git a/account_bank_statement_import_camt/__manifest__.py b/account_bank_statement_import_camt/__manifest__.py index 1ff167c..f2ca11a 100644 --- a/account_bank_statement_import_camt/__manifest__.py +++ b/account_bank_statement_import_camt/__manifest__.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- # © 2013-2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { 'name': 'CAMT Format Bank Statements Import', - 'version': '10.0.1.1.0', + 'version': '11.0.1.0.0', 'license': 'AGPL-3', 'author': 'Odoo Community Association (OCA), Therp BV', 'website': 'https://github.com/OCA/bank-statement-import', diff --git a/account_bank_statement_import_camt/models/__init__.py b/account_bank_statement_import_camt/models/__init__.py index 0251c8f..8b7d2c6 100644 --- a/account_bank_statement_import_camt/models/__init__.py +++ b/account_bank_statement_import_camt/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2013-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import parser diff --git a/account_bank_statement_import_camt/models/account_bank_statement_import.py b/account_bank_statement_import_camt/models/account_bank_statement_import.py index 4490f16..27b26af 100644 --- a/account_bank_statement_import_camt/models/account_bank_statement_import.py +++ b/account_bank_statement_import_camt/models/account_bank_statement_import.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- """Add process_camt method to account.bank.statement.import.""" # © 2013-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import logging -import StringIO +from io import BytesIO import zipfile from odoo import api, models @@ -23,7 +22,7 @@ class AccountBankStatementImport(models.TransientModel): return parser.parse(data_file) except ValueError: try: - with zipfile.ZipFile(StringIO.StringIO(data_file)) as data: + with zipfile.ZipFile(BytesIO(data_file)) as data: currency = None account_number = None transactions = [] diff --git a/account_bank_statement_import_camt/models/parser.py b/account_bank_statement_import_camt/models/parser.py index 51d7820..97f032a 100644 --- a/account_bank_statement_import_camt/models/parser.py +++ b/account_bank_statement_import_camt/models/parser.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Class to parse camt files.""" # © 2013-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). @@ -9,8 +8,8 @@ from odoo import models class CamtParser(models.AbstractModel): - _name = 'account.bank.statement.import.camt.parser' """Parser for camt bank statement import files.""" + _name = 'account.bank.statement.import.camt.parser' def parse_amount(self, ns, node): """Parse element that contains Amount and CreditDebitIndicator.""" @@ -78,10 +77,6 @@ class CamtParser(models.AbstractModel): if party_node: self.add_value_from_node( ns, party_node[0], './ns:Nm', transaction, 'partner_name') - self.add_value_from_node( - ns, party_node[0], './ns:PstlAdr/ns:Ctry', transaction, - 'partner_country' - ) address_node = party_node[0].xpath( './ns:PstlAdr/ns:AdrLine', namespaces={'ns': ns}) if address_node: @@ -96,12 +91,6 @@ class CamtParser(models.AbstractModel): './ns:IBAN', namespaces={'ns': ns}) if iban_node: transaction['account_number'] = iban_node[0].text - bic_node = node.xpath( - './ns:RltdAgts/ns:%sAgt/ns:FinInstnId/ns:BIC' % party_type, - namespaces={'ns': ns} - ) - if bic_node: - transaction['account_bic'] = bic_node[0].text else: self.add_value_from_node( ns, account_node[0], './ns:Othr/ns:Id', transaction, @@ -111,16 +100,12 @@ class CamtParser(models.AbstractModel): def parse_transaction(self, ns, node): """Parse transaction (entry) node.""" transaction = {} - self.add_value_from_node( - ns, node, './ns:BkTxCd/ns:Prtry/ns:Cd', transaction, - 'transfer_type' - ) + self.add_value_from_node( ns, node, './ns:BookgDt/ns:Dt', transaction, 'date') - self.add_value_from_node( - ns, node, './ns:BookgDt/ns:Dt', transaction, 'execution_date') - self.add_value_from_node( - ns, node, './ns:ValDt/ns:Dt', transaction, 'value_date') + if not transaction.get('date'): + self.add_value_from_node( + ns, node, './ns:ValDt/ns:Dt', transaction, 'date') transaction['amount'] = self.parse_amount(ns, node) @@ -140,7 +125,7 @@ class CamtParser(models.AbstractModel): ], transaction, 'ref' ) - transaction['data'] = etree.tostring(node) + return transaction def get_balance_amounts(self, ns, node): @@ -176,6 +161,19 @@ class CamtParser(models.AbstractModel): self.parse_amount(ns, end_balance_node) ) + def get_statement_date(self, ns, node): + """Return statement date. + + The date might be in the balance node: + CLBD = ClosingBalance + """ + code_expr = \ + './ns:Bal/ns:Tp/ns:CdOrPrtry/ns:Cd[text()="CLBD"]' \ + '/../../../ns:Dt/ns:Dt/text()' + date_node = node.xpath(code_expr, namespaces={'ns': ns}) + date = date_node and date_node[0] or None + return date + def parse_statement(self, ns, node): """Parse a single Stmt node.""" result = {} @@ -193,6 +191,7 @@ class CamtParser(models.AbstractModel): ns, node, './ns:Acct/ns:Ccy', result, 'currency') result['balance_start'], result['balance_end_real'] = ( self.get_balance_amounts(ns, node)) + result['date'] = self.get_statement_date(ns, node) transaction_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns}) result['transactions'] = [] for entry_node in transaction_nodes: @@ -210,10 +209,12 @@ class CamtParser(models.AbstractModel): ) if not re_camt.search(ns): raise ValueError('no camt: ' + ns) - # Check wether version 052 or 053: + # Check wether version 052 ,053 or 054: re_camt_version = re.compile( - r'(^urn:iso:std:iso:20022:tech:xsd:camt.053.' + r'(^urn:iso:std:iso:20022:tech:xsd:camt.054.' + r'|^urn:iso:std:iso:20022:tech:xsd:camt.053.' r'|^urn:iso:std:iso:20022:tech:xsd:camt.052.' + r'|^ISO:camt.054.' r'|^ISO:camt.053.' r'|^ISO:camt.052.)' ) diff --git a/account_bank_statement_import_camt/tests/__init__.py b/account_bank_statement_import_camt/tests/__init__.py index 06d3af2..5198b77 100644 --- a/account_bank_statement_import_camt/tests/__init__.py +++ b/account_bank_statement_import_camt/tests/__init__.py @@ -1,4 +1,3 @@ -# -*- encoding: utf-8 -*- """Test import of bank statement for camt.053.""" # © 2013-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). diff --git a/account_bank_statement_import_camt/tests/test_import_bank_statement.py b/account_bank_statement_import_camt/tests/test_import_bank_statement.py index b3c57aa..700976d 100644 --- a/account_bank_statement_import_camt/tests/test_import_bank_statement.py +++ b/account_bank_statement_import_camt/tests/test_import_bank_statement.py @@ -1,22 +1,13 @@ -# -*- coding: utf-8 -*- """Run test to import camt.053 import.""" # © 2013-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import base64 from odoo.tests.common import TransactionCase -from odoo.tools.misc import file_open +from odoo.modules.module import get_module_resource class TestImport(TransactionCase): """Run test to import camt import.""" - transactions = [ - { - 'account_number': 'NL46ABNA0499998748', - 'amount': -754.25, - 'date': '2014-01-05', - 'ref': '435005714488-ABNO33052620', - }, - ] def setUp(self): super(TestImport, self).setUp() @@ -35,34 +26,48 @@ class TestImport(TransactionCase): def test_statement_import(self): """Test correct creation of single statement.""" - action = {} - with file_open( - 'account_bank_statement_import_camt/test_files/test-camt053' - ) as testfile: - action = self.env['account.bank.statement.import'].create({ - 'data_file': base64.b64encode(testfile.read()), - }).import_file() + testfile = get_module_resource( + 'account_bank_statement_import_camt', + 'test_files', + 'test-camt053', + ) + datafile = open(testfile, 'rb').read() + action = self.env['account.bank.statement.import'].create({ + 'data_file': base64.b64encode(datafile), + }).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 - )) + self.assertTrue(statement.name) + self.assertEqual(statement.date, '2014-01-05') + self.assertEqual(statement.difference, -504.16) + self.assertEqual(statement.journal_type, 'bank') + self.assertEqual(len(statement.line_ids), 3) + for line in statement.line_ids: + self.assertIn(line.amount, [1405.31, -594.05, -754.25]) + self.assertEqual(line.date, '2014-01-05') + self.assertTrue(line.ref) + self.assertTrue(line.journal_id) + self.assertTrue(line.name) + self.assertTrue(line.note) + self.assertEqual(line.state, 'open') + self.assertIn( + line.bank_account_id.acc_number, + ['NL69ABNA0522123643', + 'NL46ABNA0499998748'] + ) 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() + testfile = get_module_resource( + 'account_bank_statement_import_camt', + 'test_files', + 'test-camt053.zip', + ) + datafile = open(testfile, 'rb').read() + action = self.env['account.bank.statement.import'].create({ + 'data_file': base64.b64encode(datafile), + }).import_file() for statement in self.env['account.bank.statement'].browse( action['context']['statement_ids'] ):