From 2df730966b65b83d15fb5966b0eaa64cb5ff55d3 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Wed, 4 Sep 2024 16:08:29 +0200 Subject: [PATCH 1/5] [IMP] l10n_it_account: Compute tax amounts by journal --- l10n_it_account/README.rst | 4 ++ l10n_it_account/models/account_tax.py | 29 ++++++++- l10n_it_account/readme/CONTRIBUTORS.md | 2 + l10n_it_account/static/description/index.html | 4 ++ l10n_it_account/tests/test_l10n_it_account.py | 61 +++++++++++++++++++ 5 files changed, 99 insertions(+), 1 deletion(-) diff --git a/l10n_it_account/README.rst b/l10n_it_account/README.rst index a666beea971b..78cd15444625 100644 --- a/l10n_it_account/README.rst +++ b/l10n_it_account/README.rst @@ -84,6 +84,10 @@ Contributors - Simone Rubino +- `Aion Tech `__: + + - Simone Rubino + Other credits ------------- diff --git a/l10n_it_account/models/account_tax.py b/l10n_it_account/models/account_tax.py index afb6a1d54c12..5a22ff61782e 100644 --- a/l10n_it_account/models/account_tax.py +++ b/l10n_it_account/models/account_tax.py @@ -1,4 +1,5 @@ # Copyright 2022 Simone Rubino - TAKOBI +# Copyright 2024 Simone Rubino - Aion Tech # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models @@ -25,10 +26,17 @@ class AccountTax(models.Model): deductible_balance = fields.Float(compute="_compute_deductible_balance") undeductible_balance = fields.Float(compute="_compute_undeductible_balance") + @api.depends_context( + "l10n_it_account_journal_ids", + ) + def _compute_balance(self): + return super()._compute_balance() + @api.depends_context( "from_date", "to_date", "company_ids", + "l10n_it_account_journal_ids", "target_move", ) def _compute_deductible_balance(self): @@ -49,6 +57,7 @@ def _compute_deductible_balance(self): "from_date", "to_date", "company_ids", + "l10n_it_account_journal_ids", "target_move", ) def _compute_undeductible_balance(self): @@ -148,6 +157,24 @@ def _get_tax_name(self): name = self.parent_tax_ids[0].name return name + def get_balance_domain(self, state_list, type_list): + domain = super().get_balance_domain(state_list, type_list) + journal_ids = self.env.context.get("l10n_it_account_journal_ids") + if journal_ids: + domain.append( + ("move_id.journal_id", "in", journal_ids), + ) + return domain + + def get_base_balance_domain(self, state_list, type_list): + domain = super().get_base_balance_domain(state_list, type_list) + journal_ids = self.env.context.get("l10n_it_account_journal_ids") + if journal_ids: + domain.append( + ("move_id.journal_id", "in", journal_ids), + ) + return domain + def _compute_totals_tax(self, data): """ Args: @@ -163,7 +190,7 @@ def _compute_totals_tax(self, data): } registry_type = data.get("registry_type", "customer") if data.get("journal_ids"): - context["vat_registry_journal_ids"] = data["journal_ids"] + context["l10n_it_account_journal_ids"] = data["journal_ids"] tax = self.env["account.tax"].with_context(**context).browse(self.id) tax_name = tax._get_tax_name() diff --git a/l10n_it_account/readme/CONTRIBUTORS.md b/l10n_it_account/readme/CONTRIBUTORS.md index 9fda3d53a89c..e0e5fecd8012 100644 --- a/l10n_it_account/readme/CONTRIBUTORS.md +++ b/l10n_it_account/readme/CONTRIBUTORS.md @@ -7,3 +7,5 @@ - Marco Colombo - Phi S.r.l. \<\> - [TAKOBI](https://takobi.online): - Simone Rubino \<\> +- [Aion Tech](https://aiontech.company/): + - Simone Rubino \<\> diff --git a/l10n_it_account/static/description/index.html b/l10n_it_account/static/description/index.html index bc8f01c17890..ee72f4b6c70d 100644 --- a/l10n_it_account/static/description/index.html +++ b/l10n_it_account/static/description/index.html @@ -424,6 +424,10 @@

Contributors

  • Simone Rubino <sir@takobi.online>
  • +
  • Aion Tech: +
  • diff --git a/l10n_it_account/tests/test_l10n_it_account.py b/l10n_it_account/tests/test_l10n_it_account.py index f258d9650202..50720860b404 100644 --- a/l10n_it_account/tests/test_l10n_it_account.py +++ b/l10n_it_account/tests/test_l10n_it_account.py @@ -1,4 +1,5 @@ # Copyright 2022 Simone Rubino - TAKOBI +# Copyright 2024 Simone Rubino - Aion Tech # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import datetime @@ -256,3 +257,63 @@ def check_date_balance(self, tax, date, deductible, not_deductible): ) self.assertEqual(tax.deductible_balance, deductible) self.assertEqual(tax.undeductible_balance, not_deductible) + + def test_compute_totals_tax_journal_change(self): + """Compute the amount of a tax for specific journals: it changes.""" + # Arrange + invoice_date = datetime.date(2020, month=1, day=1) + tax = self.iva_22I5 + bill = self.init_invoice( + "in_invoice", + invoice_date=invoice_date, + amounts=[100], + post=True, + taxes=tax, + ) + + # Assert + bill_journal = bill.journal_id + other_journals = self.env["account.journal"].search( + [("id", "!=", bill_journal.id)] + ) + date_context = { + "from_date": invoice_date, + "to_date": invoice_date, + } + self.assertRecordValues( + tax.with_context(**date_context), + [ + { + "base_balance": -100, + "balance": -22, + "deductible_balance": -11, + "undeductible_balance": -11, + } + ], + ) + self.assertRecordValues( + tax.with_context( + **date_context, l10n_it_account_journal_ids=bill_journal.ids + ), + [ + { + "base_balance": -100, + "balance": -22, + "deductible_balance": -11, + "undeductible_balance": -11, + } + ], + ) + self.assertRecordValues( + tax.with_context( + **date_context, l10n_it_account_journal_ids=other_journals.ids + ), + [ + { + "base_balance": 0, + "balance": 0, + "deductible_balance": 0, + "undeductible_balance": 0, + } + ], + ) From 46673b1622910976211eb8125e5e286b6f98d601 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Wed, 4 Sep 2024 16:10:32 +0200 Subject: [PATCH 2/5] [REF] l10n_it_vat_registries: Use common tax amounts overrides The overrides have been moved to l10n_it_account --- l10n_it_vat_registries/models/account.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/l10n_it_vat_registries/models/account.py b/l10n_it_vat_registries/models/account.py index 1098b1a0170a..941e76b46215 100644 --- a/l10n_it_vat_registries/models/account.py +++ b/l10n_it_vat_registries/models/account.py @@ -7,27 +7,3 @@ class AccountTax(models.Model): _inherit = "account.tax" exclude_from_registries = fields.Boolean(string="Exclude from VAT registries") - - def get_balance_domain(self, state_list, type_list): - domain = super().get_balance_domain(state_list, type_list) - if self.env.context.get("vat_registry_journal_ids"): - domain.append( - ( - "move_id.journal_id", - "in", - self.env.context["vat_registry_journal_ids"], - ) - ) - return domain - - def get_base_balance_domain(self, state_list, type_list): - domain = super().get_base_balance_domain(state_list, type_list) - if self.env.context.get("vat_registry_journal_ids"): - domain.append( - ( - "move_id.journal_id", - "in", - self.env.context["vat_registry_journal_ids"], - ) - ) - return domain From 0f4e78cb0b45505cbadcc61454072d4042f7d6c7 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Wed, 4 Sep 2024 16:12:24 +0200 Subject: [PATCH 3/5] [IMP] account_vat_period_end_statement: Journal groups --- .../__manifest__.py | 2 + .../models/account.py | 37 +++++++ .../report/vat_statement.py | 30 +++++- .../tests/test_vat_statement.py | 101 +++++++++++++++++- .../views/account_view.xml | 10 ++ .../views/report_vatperiodendstatement.xml | 75 +++++++++++++ 6 files changed, 253 insertions(+), 2 deletions(-) diff --git a/account_vat_period_end_statement/__manifest__.py b/account_vat_period_end_statement/__manifest__.py index c0f9e5740a49..e26fea9a6da6 100644 --- a/account_vat_period_end_statement/__manifest__.py +++ b/account_vat_period_end_statement/__manifest__.py @@ -4,6 +4,7 @@ # Copyright 2015 Associazione Odoo Italia () # Copyright 2021 Gianmarco Conte # - Dinamiche Aziendali Srl () +# Copyright 2024 Simone Rubino - Aion Tech # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { @@ -16,6 +17,7 @@ "website": "https://github.com/OCA/l10n-italy", "depends": [ "account", + "account_journal_group_included", "account_tax_balance", "date_range", "l10n_it_account", diff --git a/account_vat_period_end_statement/models/account.py b/account_vat_period_end_statement/models/account.py index d246d1249bbd..63399163e2b9 100644 --- a/account_vat_period_end_statement/models/account.py +++ b/account_vat_period_end_statement/models/account.py @@ -7,6 +7,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import math +from contextlib import contextmanager, nullcontext from odoo import api, fields, models from odoo.exceptions import UserError @@ -347,6 +348,11 @@ def _get_default_interest_percent(self): string="Accounts filter", domain=lambda self: self._get_domain_account(), ) + journal_group_ids = fields.Many2many( + comodel_name="account.journal.group", + string="Journal groups", + help="The report will show amounts for the groups and journals selected.", + ) def _get_domain_account(self): domain = [("vat_statement_account_id", "!=", False)] @@ -354,6 +360,33 @@ def _get_domain_account(self): account_ids = tax_ids.mapped("vat_statement_account_id") return [("id", "in", account_ids.ids)] + @contextmanager + def _recompute_amounts_on_change(self, field_name): + """Recompute statement amounts when `field_name` changes.""" + statement_to_previous_value = { + statement: statement[field_name] for statement in self + } + + yield + + statements_to_recompute = self.browse() + for statement in self: + previous_value = statement_to_previous_value.get(statement) + if statement[field_name] != previous_value: + statements_to_recompute |= statement + + if statements_to_recompute: + statements_to_recompute.compute_amounts() + + def write(self, vals): + if "journal_group_ids" in vals: + recompute_context = self._recompute_amounts_on_change("journal_group_ids") + else: + recompute_context = nullcontext() + + with recompute_context: + return super().write(vals) + def unlink(self): for statement in self: if statement.state == "confirmed" or statement.state == "paid": @@ -740,12 +773,14 @@ def compute_amounts(self): def _set_debit_lines(self, debit_tax, debit_line_ids, statement): total = 0.0 + selected_journals = statement.journal_group_ids.included_journal_ids for period in statement.date_range_ids: total += debit_tax._compute_totals_tax( { "from_date": period.date_start, "to_date": period.date_end, "registry_type": "customer", + "journal_ids": selected_journals.ids, } )[3] # position 3 is deductible part debit_line_ids.append( @@ -758,12 +793,14 @@ def _set_debit_lines(self, debit_tax, debit_line_ids, statement): def _set_credit_lines(self, credit_tax, credit_line_ids, statement): total = 0.0 + selected_journals = statement.journal_group_ids.included_journal_ids for period in statement.date_range_ids: total += credit_tax._compute_totals_tax( { "from_date": period.date_start, "to_date": period.date_end, "registry_type": "supplier", + "journal_ids": selected_journals.ids, } )[3] # position 3 is deductible part credit_line_ids.append( diff --git a/account_vat_period_end_statement/report/vat_statement.py b/account_vat_period_end_statement/report/vat_statement.py index 9596fd1d3d93..39a7313bd3c5 100644 --- a/account_vat_period_end_statement/report/vat_statement.py +++ b/account_vat_period_end_statement/report/vat_statement.py @@ -3,6 +3,7 @@ # Copyright 2015 Associazione OpenERP Italia () # Copyright 2015 Openforce di Alessandro Camilli () # Copyright 2015 Link It S.p.a. () +# Copyright 2024 Simone Rubino - Aion Tech # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import time @@ -26,6 +27,8 @@ def _get_report_values(self, docids, data=None): "account_vat_amounts": self._get_account_vat_amounts, "formatLang": formatLang, "env": self.env, + "sum_tax_code_amounts": self.sum_tax_code_amounts, + "all_journal_groups": self.env["account.journal.group"].search([]), } return vals @@ -36,9 +39,32 @@ def _get_statement(self, statement_id): statement = statement_obj.browse(statement_id) return statement - def _get_taxes_amounts(self, period_id, tax_ids=None, registry_type="customer"): + @api.model + def sum_tax_code_amounts(self, tax_code_amounts, other_tax_code_amounts): + """Sum two tax amounts dictionaries.""" + sum_tax_code_amounts = tax_code_amounts.copy() + for code, amounts in other_tax_code_amounts.items(): + sum_amounts = sum_tax_code_amounts.get(code) + if sum_amounts is None: + sum_tax_code_amounts[code] = amounts + else: + for amount_name in sum_amounts: + if amount_name in [ + "vat", + "vat_deductible", + "vat_undeductible", + "base", + ]: + sum_amounts[amount_name] += amounts[amount_name] + return sum_tax_code_amounts + + def _get_taxes_amounts( + self, period_id, tax_ids=None, registry_type="customer", journal_ids=None + ): if tax_ids is None: tax_ids = [] + if journal_ids is None: + journal_ids = [] res = {} date_range = self.env["date.range"].browse(period_id) tax_model = self.env["account.tax"] @@ -50,6 +76,7 @@ def _get_taxes_amounts(self, period_id, tax_ids=None, registry_type="customer"): "from_date": date_range.date_start, "to_date": date_range.date_end, "registry_type": registry_type, + "journal_ids": journal_ids, } ) @@ -63,6 +90,7 @@ def _get_taxes_amounts(self, period_id, tax_ids=None, registry_type="customer"): "from_date": date_range.date_start, "to_date": date_range.date_end, "registry_type": registry_type, + "journal_ids": journal_ids, } ) # return tax_name, base, tax_val, deductible, undeductible diff --git a/account_vat_period_end_statement/tests/test_vat_statement.py b/account_vat_period_end_statement/tests/test_vat_statement.py index 34ea9caf7248..5bff496eb987 100644 --- a/account_vat_period_end_statement/tests/test_vat_statement.py +++ b/account_vat_period_end_statement/tests/test_vat_statement.py @@ -5,7 +5,7 @@ import re -from odoo import fields +from odoo import Command, fields from odoo.tests import Form, tagged from .common import TestVATStatementCommon @@ -328,3 +328,102 @@ def test_report_multiple_payment_info(self): report_content.decode(), ) self.assertEqual(len(payment_infos), 1) + + def test_report_journal_groups(self): + """Journal groups are shown in the report.""" + date_range = self.current_period + bill = self.init_invoice( + "in_invoice", + invoice_date=self.recent_date, + amounts=[500], + taxes=self.account_tax_22_credit, + post=True, + ) + bill_journal = bill.journal_id + invoice = self.init_invoice( + "out_invoice", + invoice_date=self.recent_date, + amounts=[1000], + taxes=self.account_tax_22, + post=True, + ) + invoice_journal = invoice.journal_id + journal_group = self.env["account.journal.group"].create( + { + "name": "Test group", + "included_journal_ids": [ + Command.set((bill_journal + invoice_journal).ids), + ], + } + ) + statement = self._get_statement( + date_range, + self.last_year_date, + self.env["account.account"].browse(), + ) + statement.journal_group_ids = journal_group + # pre-condition + self.assertEqual( + statement.journal_group_ids.included_journal_ids, + bill_journal + invoice_journal, + ) + + # Act + report_content, report_type = self.env["ir.actions.report"]._render_qweb_html( + "account_vat_period_end_statement.report_vat_statement", statement.ids + ) + + # Assert + report_content = report_content.decode() + self.assertIn(bill_journal.name, report_content) + self.assertIn(invoice_journal.name, report_content) + self.assertIn(journal_group.name, report_content) + + def test_recompute_amounts_for_journal_groups(self): + """Statement amounts are recomputed based on the selected groups.""" + # Arrange + self.init_invoice( + "in_invoice", + invoice_date=self.recent_date, + amounts=[500], + taxes=self.account_tax_22_credit, + post=True, + ) + self.init_invoice( + "out_invoice", + invoice_date=self.recent_date, + amounts=[1000], + taxes=self.account_tax_22, + post=True, + ) + + new_journal_form = Form(self.env["account.journal"]) + new_journal_form.name = "Test Journal" + new_journal_form.code = "TJ" + new_journal_form.type = "general" + new_journal = new_journal_form.save() + + journal_group = self.env["account.journal.group"].create( + { + "name": "Test group", + "included_journal_ids": [ + Command.set(new_journal.ids), + ], + } + ) + statement = self._get_statement( + self.current_period, + self.last_year_date, + self.env["account.account"].browse(), + ) + # pre-condition + self.assertFalse(statement.journal_group_ids) + self.assertTrue(sum(statement.credit_vat_account_line_ids.mapped("amount"))) + self.assertTrue(sum(statement.debit_vat_account_line_ids.mapped("amount"))) + + # Act + statement.journal_group_ids = journal_group + + # Assert + self.assertFalse(sum(statement.credit_vat_account_line_ids.mapped("amount"))) + self.assertFalse(sum(statement.debit_vat_account_line_ids.mapped("amount"))) diff --git a/account_vat_period_end_statement/views/account_view.xml b/account_vat_period_end_statement/views/account_view.xml index 9a951a00c1a6..1d24d085d030 100644 --- a/account_vat_period_end_statement/views/account_view.xml +++ b/account_vat_period_end_statement/views/account_view.xml @@ -1,6 +1,7 @@ @@ -63,6 +64,15 @@ + + + + + +

    Summary

    + + + + + + + + +

    + + [] +

    + + + + + + + + + + + + + + + + +

    All Journals

    + @@ -30,8 +98,14 @@ + @@ -98,6 +172,7 @@ From 042ae1ee6681a89dcb6cece5bf1bcb932c514cf8 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Thu, 5 Sep 2024 11:53:58 +0200 Subject: [PATCH 4/5] [DON'T MERGE] test-requirements.txt --- test-requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 test-requirements.txt diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 000000000000..739b615ca4a4 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +# https://github.com/OCA/account-invoicing/pull/1793 +odoo-addon-account_journal_group_included @ git+https://github.com/OCA/account-invoicing.git@refs/pull/1793/head#subdirectory=setup/account_journal_group_included From e8d0b2c21d01eddad35158243cdd322a3e61b8f1 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Mon, 23 Sep 2024 16:07:52 +0200 Subject: [PATCH 5/5] [IMP] account_vat_period_end_statement: More explicit title --- .../views/report_vatperiodendstatement.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/account_vat_period_end_statement/views/report_vatperiodendstatement.xml b/account_vat_period_end_statement/views/report_vatperiodendstatement.xml index 16a952d39203..4bab3505ea83 100644 --- a/account_vat_period_end_statement/views/report_vatperiodendstatement.xml +++ b/account_vat_period_end_statement/views/report_vatperiodendstatement.xml @@ -15,7 +15,9 @@ Periods detail --> -

    Summary

    +

    VAT Statement summary