From b8bb3ec77d4d54ff7509706b46cace728ed5343e Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 19 Mar 2024 20:10:13 +0100 Subject: [PATCH 1/2] [IMP] calculate opening debit, credit from balance of opening lines --- .../models/xaf_auditfile_export.py | 26 ++-- .../test_l10n_nl_xaf_auditfile_export.py | 132 ++++++++++++++++-- 2 files changed, 128 insertions(+), 30 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 c1b6796c8..643608da0 100644 --- a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py +++ b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py @@ -304,23 +304,15 @@ def get_taxes(self): 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 " - "where l.account_id = a.id " - "and l.parent_state = 'posted' " - "and l.display_type NOT IN ('line_section', 'line_note') " - "and l.date < %s " - "and l.company_id=%s " - "and a.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 def get_ob_lines(self): """return opening balance entries""" 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 55bd87b8f..43245e90b 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 @@ -3,6 +3,7 @@ import base64 import os +from datetime import timedelta from io import BytesIO from zipfile import ZipFile @@ -13,25 +14,36 @@ 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( ns_clean=True, recover=True, encoding="utf-8", 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 @@ -215,3 +227,97 @@ def test_08_invalid_characters(self): self.assertTrue(record) self.assertTrue(record.name) self.assertFalse(record.auditfile_success) + + def test_09_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( + [ + ( + "account_type", + "=", + "asset_receivable", + ), + ("company_id", "=", self.env.company.id), + ], + limit=1, + ) + acc_payable = self.env["account.account"].search( + [ + ("account_type", "=", "liability_payable"), + ("company_id", "=", self.env.company.id), + ], + limit=1, + ) + acc_revenue = self.env["account.account"].search( + [ + ("account_type", "=", "income"), + ("company_id", "=", self.env.company.id), + ], + limit=1, + ) + journal = self.env["account.journal"].search( + [ + ("company_id", "=", self.env.company.id), + ], + 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.action_post() + self.env.flush_all() + 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.action_post() + record = self.env["xaf.auditfile.export"].create({}) + self.env.flush_all() + 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 fae8e8f230264b892447389b8c5fabec7021b8f6 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Thu, 21 Mar 2024 08:33:09 +0100 Subject: [PATCH 2/2] [ADD] l10n_nl_xaf_auditfile_export: more rounding --- l10n_nl_xaf_auditfile_export/views/templates.xml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/l10n_nl_xaf_auditfile_export/views/templates.xml b/l10n_nl_xaf_auditfile_export/views/templates.xml index 2918c0e88..dc8615403 100644 --- a/l10n_nl_xaf_auditfile_export/views/templates.xml +++ b/l10n_nl_xaf_auditfile_export/views/templates.xml @@ -204,19 +204,23 @@ Opening balance - - + + - + - - + +