From f74c386b4f94275de14fcf5ef762d3f378baadf4 Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Tue, 3 Dec 2019 22:12:01 +0000 Subject: [PATCH 1/4] [ADD] opening balance support --- .../models/xaf_auditfile_export.py | 42 +++++++++++++++++++ .../readme/CONTRIBUTORS.rst | 1 + .../views/templates.xml | 17 ++++++-- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py index 0b7674f89..dd1e2c0a4 100644 --- a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py +++ b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py @@ -251,6 +251,48 @@ def get_taxes(self): ('company_id', '=', self.company_id.id), ]) + @api.multi + def get_ob_totals(self): + """return totals of opening balance""" + self.env.cr.execute( + "select sum(l.credit), sum(l.debit), count(distinct a.id) " + "from account_move_line l, account_account a, " + " account_account_type t " + "where a.user_type_id = t.id " + "and l.account_id = a.id " + "and l.date < %s " + "and l.company_id=%s " + "and t.include_initial_balance = true ", + (self.date_start, self.company_id.id), + ) + row = self.env.cr.fetchall()[0] + return dict( + credit=round(row[0] or 0.0, 2), + debit=round(row[1] or 0.0, 2), + count=row[2] or 0, + ) + + @api.multi + def get_ob_lines(self): + """return opening balance entries""" + self.env.cr.execute( + "select a.id, a.code, sum(l.balance) " + "from account_move_line l, account_account a, " + " account_account_type t " + "where a.user_type_id = t.id " + "and a.id = l.account_id and l.date < %s " + "and l.company_id=%s " + "and t.include_initial_balance = true " + "group by a.id, a.code", + (self.date_start, self.company_id.id), + ) + for result in self.env.cr.fetchall(): + yield dict( + account_id=result[0], + account_code=result[1], + balance=round(result[2], 2), + ) + @api.multi def get_move_line_count(self): '''return amount of move lines''' diff --git a/l10n_nl_xaf_auditfile_export/readme/CONTRIBUTORS.rst b/l10n_nl_xaf_auditfile_export/readme/CONTRIBUTORS.rst index c4b3a740c..47b36c881 100644 --- a/l10n_nl_xaf_auditfile_export/readme/CONTRIBUTORS.rst +++ b/l10n_nl_xaf_auditfile_export/readme/CONTRIBUTORS.rst @@ -1,3 +1,4 @@ * Holger Brunn * Andrea Stirpe * Stefan Rijnhart +* Tom Blauwendraat diff --git a/l10n_nl_xaf_auditfile_export/views/templates.xml b/l10n_nl_xaf_auditfile_export/views/templates.xml index df767775e..2d19e95e8 100644 --- a/l10n_nl_xaf_auditfile_export/views/templates.xml +++ b/l10n_nl_xaf_auditfile_export/views/templates.xml @@ -100,9 +100,6 @@ - @@ -119,6 +116,20 @@ + + + + Opening balance + + + + + + + + + + From 352cf717100d94101bcdefda5e1fc8868b8a3651 Mon Sep 17 00:00:00 2001 From: Jeroen Vet Date: Wed, 9 Jun 2021 19:23:46 +0800 Subject: [PATCH 2/4] Rounded move totals and move line amounts in view as these amounts are not rounded in python code so could still occur too many decimals error. --- l10n_nl_xaf_auditfile_export/views/templates.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/l10n_nl_xaf_auditfile_export/views/templates.xml b/l10n_nl_xaf_auditfile_export/views/templates.xml index 2d19e95e8..6b5e7caee 100644 --- a/l10n_nl_xaf_auditfile_export/views/templates.xml +++ b/l10n_nl_xaf_auditfile_export/views/templates.xml @@ -147,7 +147,7 @@ - + - + From 30dd0e0e273b7d8d840aaff5e4bae0ce0d1ac7a1 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 19 Mar 2024 20:10:13 +0100 Subject: [PATCH 3/4] [IMP] calculate opening debit, credit from balance of opening lines only consider posted move lines for opening balance --- .../models/xaf_auditfile_export.py | 34 +++--- .../test_l10n_nl_xaf_auditfile_export.py | 103 +++++++++++++++--- 2 files changed, 106 insertions(+), 31 deletions(-) diff --git a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py index dd1e2c0a4..8b11c66d0 100644 --- a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py +++ b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py @@ -254,33 +254,31 @@ def get_taxes(self): @api.multi def get_ob_totals(self): """return totals of opening balance""" - self.env.cr.execute( - "select sum(l.credit), sum(l.debit), count(distinct a.id) " - "from account_move_line l, account_account a, " - " account_account_type t " - "where a.user_type_id = t.id " - "and l.account_id = a.id " - "and l.date < %s " - "and l.company_id=%s " - "and t.include_initial_balance = true ", - (self.date_start, self.company_id.id), - ) - row = self.env.cr.fetchall()[0] - return dict( - credit=round(row[0] or 0.0, 2), - debit=round(row[1] or 0.0, 2), - count=row[2] or 0, + result = dict( + credit=0.0, + debit=0.0, + count=0 ) + for line in self.get_ob_lines(): + balance = line['balance'] + if balance > 0: + result['debit'] += balance + else: + result['credit'] -= balance + result['count'] += 1 + return result @api.multi def get_ob_lines(self): """return opening balance entries""" self.env.cr.execute( - "select a.id, a.code, sum(l.balance) " + # pylint: disable=sql-injection + "select a.id, a.code, sum(l.balance) " + "from account_move_line l, account_account a, " - " account_account_type t " + " account_move m, account_account_type t " "where a.user_type_id = t.id " "and a.id = l.account_id and l.date < %s " + "and l.move_id = m.id and m.state = 'posted' " "and l.company_id=%s " "and t.include_initial_balance = true " "group by a.id, a.code", diff --git a/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py b/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py index 26a0f800b..9031b2f80 100644 --- a/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py +++ b/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py @@ -2,18 +2,18 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import base64 +from datetime import timedelta from lxml import etree from io import BytesIO import os from zipfile import ZipFile + from odoo.tests.common import TransactionCase from odoo.tools import mute_logger -def get_transaction_line_count_from_xml(auditfile): - ''' Helper XML method to parse and return the transaction line count ''' - line_count = 0 +def xaf_xpath(auditfile, query): with ZipFile(BytesIO(base64.b64decode(auditfile)), 'r') as z: contents = z.read(z.filelist[-1]).decode() parser = etree.XMLParser( @@ -23,16 +23,29 @@ def get_transaction_line_count_from_xml(auditfile): remove_blank_text=True ) root = etree.XML(bytes(contents, encoding='utf8'), parser=parser) - # xpath query to select all element nodes in namespace - # Source: https://stackoverflow.com/a/30233635 - query = "descendant-or-self::*[namespace-uri()!='']" - for element in root.xpath(query): - element.tag = etree.QName(element).localname - journals = root.xpath("/auditfile/company/transactions/journal") - for journal in journals: - transactions = journal.xpath("transaction/trLine") - for _ in transactions: - line_count += 1 + for element in root.xpath( + query, namespaces={'a': 'http://www.auditfiles.nl/XAF/3.2'} + ): + yield element + + +def get_transaction_line_count_from_xml(auditfile): + ''' Helper XML method to parse and return the transaction line count ''' + line_count = 0 + # xpath query to select all element nodes in namespace + # Source: https://stackoverflow.com/a/30233635 + query = "descendant-or-self::*[namespace-uri()!='']" + root = None + for element in xaf_xpath(auditfile, query): + element.tag = etree.QName(element).localname + root = root or element.getroottree() + if not root: + return 0 + journals = root.xpath("/auditfile/company/transactions/journal") + for journal in journals: + transactions = journal.xpath("transaction/trLine") + for _ in transactions: + line_count += 1 return line_count @@ -146,3 +159,67 @@ def test_06_include_moves_from_inactive_journals(self): line_count_after = record_after.get_move_line_count() parsed_count_after = get_transaction_line_count_from_xml(record_after.auditfile) self.assertTrue(parsed_line_count == parsed_count_after == line_count_after) + + def test_07_opening_balance(self): + """Test that we calculate the opening balance correctly""" + record = self.env['xaf.auditfile.export'].create({}) + + acc_receivable = self.env['account.account'].search([ + ( + 'user_type_id', '=', + self.env.ref('account.data_account_type_receivable').id + ), + ], limit=1) + acc_payable = self.env['account.account'].search([ + ('user_type_id', '=', self.env.ref('account.data_account_type_payable').id), + ], limit=1) + acc_revenue = self.env['account.account'].search([ + ('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id), + ], limit=1) + journal = self.env['account.journal'].search([], limit=1) + + move_receivable = self.env['account.move'].create({ + 'journal_id': journal.id, + 'date': record.date_start - timedelta(days=1), + 'line_ids': [ + (0, 0, {'account_id': acc_receivable.id, 'credit': 42, 'debit': 0}), + (0, 0, {'account_id': acc_revenue.id, 'credit': 0, 'debit': 42}), + ] + }) + move_payable = self.env['account.move'].create({ + 'journal_id': journal.id, + 'date': record.date_start - timedelta(days=1), + 'line_ids': [ + (0, 0, {'account_id': acc_payable.id, 'credit': 0, 'debit': 4242}), + (0, 0, {'account_id': acc_revenue.id, 'credit': 4242, 'debit': 0}), + ] + }) + + move_receivable.post() + record.button_generate() + + def xaf_val(auditfile, xpath): + return float(''.join(xaf_xpath(auditfile, xpath))) + + total_credit = xaf_val( + record.auditfile, '//a:openingBalance/a:totalCredit/text()') + self.assertEqual(total_credit, 42) + total_debit = xaf_val( + record.auditfile, '//a:openingBalance/a:totalDebit/text()') + self.assertEqual(total_debit, 0) + lines_count = xaf_val( + record.auditfile, '//a:openingBalance/a:linesCount/text()') + self.assertEqual(lines_count, 1) + + move_payable.post() + record = self.env['xaf.auditfile.export'].create({}) + record.button_generate() + total_credit = xaf_val( + record.auditfile, '//a:openingBalance/a:totalCredit/text()') + self.assertEqual(total_credit, 42) + total_debit = xaf_val( + record.auditfile, '//a:openingBalance/a:totalDebit/text()') + self.assertEqual(total_debit, 4242) + lines_count = xaf_val( + record.auditfile, '//a:openingBalance/a:linesCount/text()') + self.assertEqual(lines_count, 2) From b874a43d8cb76611fc547551a34d8f1ee2f0a453 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Thu, 21 Mar 2024 08:33:09 +0100 Subject: [PATCH 4/4] [ADD] l10n_nl_xaf_auditfile_export: more rounding --- l10n_nl_xaf_auditfile_export/views/templates.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/l10n_nl_xaf_auditfile_export/views/templates.xml b/l10n_nl_xaf_auditfile_export/views/templates.xml index 6b5e7caee..72e0159ce 100644 --- a/l10n_nl_xaf_auditfile_export/views/templates.xml +++ b/l10n_nl_xaf_auditfile_export/views/templates.xml @@ -121,19 +121,19 @@ Opening balance - - + + - + - - + +