From 8daf28c46b377a53b2c8a7fe5396180535814495 Mon Sep 17 00:00:00 2001 From: Patryk Pyczko Date: Mon, 2 Sep 2024 15:38:25 +0200 Subject: [PATCH] [FIX] account_move_template: Fixed tax and payment term errors while generating journal entries from template --- .../models/account_move_template.py | 2 +- .../test_account_move_template_options.py | 190 ++++++++++++------ .../wizard/account_move_template_run.py | 13 +- 3 files changed, 135 insertions(+), 70 deletions(-) diff --git a/account_move_template/models/account_move_template.py b/account_move_template/models/account_move_template.py index a331bd6b3da..cb462cabbb1 100644 --- a/account_move_template/models/account_move_template.py +++ b/account_move_template/models/account_move_template.py @@ -182,7 +182,7 @@ class AccountMoveTemplateLine(models.Model): @api.depends("is_refund", "account_id", "tax_line_id") def _compute_tax_repartition_line_id(self): for record in self.filtered(lambda x: x.account_id and x.tax_line_id): - tax_repartition = "refund_tax_id" if record.is_refund else "invoice_tax_id" + tax_repartition = "tax_id" record.tax_repartition_line_id = self.env[ "account.tax.repartition.line" ].search( diff --git a/account_move_template/tests/test_account_move_template_options.py b/account_move_template/tests/test_account_move_template_options.py index bc152f18f7b..6d44291d332 100644 --- a/account_move_template/tests/test_account_move_template_options.py +++ b/account_move_template/tests/test_account_move_template_options.py @@ -1,6 +1,8 @@ # Copyright 2020 Ecosoft (http://ecosoft.co.th) # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from odoo import Command +from datetime import timedelta + +from odoo import Command, fields from odoo.exceptions import UserError, ValidationError from odoo.tests.common import Form, TransactionCase @@ -15,41 +17,75 @@ def setUpClass(cls): cls.Template = cls.env["account.move.template"] cls.Partner = cls.env["res.partner"] - cls.journal = cls.Journal.search([("type", "=", "general")], limit=1) - cls.ar_account_id = cls.Account.search( - [("account_type", "=", "asset_receivable")], limit=1 + cls.journal = cls._get_first_record(cls.Journal, [("type", "=", "general")]) + cls.ar_account_id = cls._get_first_record( + cls.Account, [("account_type", "=", "asset_receivable")] ) - cls.ap_account_id = cls.Account.search( - [("account_type", "=", "liability_payable")], limit=1 + cls.ap_account_id = cls._get_first_record( + cls.Account, [("account_type", "=", "liability_payable")] ) - cls.income_account_id = cls.Account.search( - [ - ("account_type", "=", "income_other"), - ("internal_group", "=", "income"), - ], - limit=1, + cls.income_account_id = cls._get_first_record( + cls.Account, + [("account_type", "=", "income_other"), ("internal_group", "=", "income")], ) - cls.expense_account_id = cls.Account.search( - [ - ("account_type", "=", "expense"), - ("internal_group", "=", "expense"), - ], - limit=1, + cls.expense_account_id = cls._get_first_record( + cls.Account, + [("account_type", "=", "expense"), ("internal_group", "=", "expense")], + ) + cls.automatic_balancing_account_id = cls._get_first_record( + cls.Account, [("code", "=", "101402")] + ) + cls.tax_paid_account_id = cls._get_first_record( + cls.Account, [("code", "=", "131000")] + ) + + cls.partners = cls._ensure_minimum_partners(3) + + cls.payment_term = cls._get_first_record( + cls.env["account.payment.term.line"], [("nb_days", "=", 30)] + ) + cls.tax = cls._get_first_record( + cls.env["account.tax"], [("type_tax_use", "=", "purchase")] + ) + + cls.move_template = cls._create_move_template("Test Template", with_tax=False) + cls.move_template_with_tax_and_payment_terms = cls._create_move_template( + "Test Template With Tax And Payment Terms", with_tax=True ) - cls.partners = cls.Partner.search([], limit=3) - # Create a simple move tempalte + @classmethod + def _get_first_record(cls, model, domain): + return model.search(domain, limit=1) + + @classmethod + def _ensure_minimum_partners(cls, min_count): + partners = cls.Partner.search([], limit=min_count) + if len(partners) < min_count: + for i in range(min_count - len(partners)): + new_partner = cls.Partner.create( + {"name": f"Test Partner {len(partners) + i + 1}"} + ) + partners += new_partner + return partners + + @classmethod + def _create_move_template(cls, name, with_tax=False): ar_line = { "sequence": 0, - "name": "AR Line 1", + "name": "AR Line 1" + (" With Tax And Payment Terms" if with_tax else ""), "account_id": cls.ar_account_id.id, "opt_account_id": cls.ap_account_id.id, "move_line_type": "dr", "type": "input", } + if with_tax: + ar_line.update( + {"payment_term_id": cls.payment_term.id, "tax_ids": cls.tax.ids} + ) + income_line1 = { "sequence": 1, - "name": "Income Line 2", + "name": "Income Line 1", "account_id": cls.income_account_id.id, "opt_account_id": cls.expense_account_id.id, "move_line_type": "cr", @@ -66,9 +102,9 @@ def setUpClass(cls): "python_code": "L0*2/3", } - cls.move_template = cls.Template.create( + return cls.Template.create( { - "name": "Test Template", + "name": name, "journal_id": cls.journal.id, "line_ids": [ Command.create(ar_line), @@ -78,56 +114,80 @@ def setUpClass(cls): } ) - def test_move_template_normal(self): - """Test normal case, input amount 300""" + def _run_template_and_validate( + self, template, input_amount, expected_values, sort_field + ): with Form(self.env["account.move.template.run"]) as f: - f.template_id = self.move_template + f.template_id = template template_run = f.save() template_run.load_lines() - template_run.line_ids[0].amount = 300 + template_run.line_ids[0].amount = input_amount res = template_run.generate_move() move = self.Move.browse(res["res_id"]) - self.assertRecordValues( - move.line_ids.sorted("credit"), - [ - {"account_id": self.ar_account_id.id, "credit": 0.0, "debit": 300.0}, - { - "account_id": self.income_account_id.id, - "credit": 100.0, - "debit": 0.0, - }, - { - "account_id": self.income_account_id.id, - "credit": 200.0, - "debit": 0.0, - }, - ], + self.assertRecordValues(move.line_ids.sorted(sort_field), expected_values) + + def test_move_template_normal(self): + """Test normal case, input amount 300""" + expected_values = [ + {"account_id": self.ar_account_id.id, "credit": 0.0, "debit": 300.0}, + {"account_id": self.income_account_id.id, "credit": 100.0, "debit": 0.0}, + {"account_id": self.income_account_id.id, "credit": 200.0, "debit": 0.0}, + ] + self._run_template_and_validate( + self.move_template, 300, expected_values, "credit" + ) + + def test_move_template_normal_with_tax_and_payment_terms(self): + """Test case with tax and payment terms, input amount 300""" + expected_maturity_date = fields.Date.today() + timedelta(days=30) + expected_values = [ + { + "account_id": self.ar_account_id.id, + "credit": 0.0, + "debit": 300.0, + "date_maturity": expected_maturity_date, + }, + { + "account_id": self.tax_paid_account_id.id, + "credit": 0.0, + "debit": 45.0, + "date_maturity": None, + }, + { + "account_id": self.automatic_balancing_account_id.id, + "credit": 45.0, + "debit": 0.0, + "date_maturity": None, + }, + { + "account_id": self.income_account_id.id, + "credit": 100.0, + "debit": 0.0, + "date_maturity": fields.Date.today(), + }, + { + "account_id": self.income_account_id.id, + "credit": 200.0, + "debit": 0.0, + "date_maturity": fields.Date.today(), + }, + ] + self._run_template_and_validate( + self.move_template_with_tax_and_payment_terms, + 300, + expected_values, + "credit", ) def test_move_template_optional(self): """Test optional case, input amount -300, expect optional account""" - with Form(self.env["account.move.template.run"]) as f: - f.template_id = self.move_template - template_run = f.save() - template_run.load_lines() - template_run.line_ids[0].amount = -300 # Negative amount - res = template_run.generate_move() - move = self.Move.browse(res["res_id"]) - self.assertRecordValues( - move.line_ids.sorted("debit"), - [ - {"account_id": self.ap_account_id.id, "credit": 300.0, "debit": 0.0}, - { - "account_id": self.expense_account_id.id, - "credit": 0.0, - "debit": 100.0, - }, - { - "account_id": self.expense_account_id.id, - "credit": 0.0, - "debit": 200.0, - }, - ], + expected_values = [ + {"account_id": self.ap_account_id.id, "credit": 300.0, "debit": 0.0}, + {"account_id": self.expense_account_id.id, "credit": 0.0, "debit": 100.0}, + {"account_id": self.expense_account_id.id, "credit": 0.0, "debit": 200.0}, + ] + self._run_template_and_validate( + self.move_template, -300, expected_values, "debit" ) def test_move_template_overwrite(self): diff --git a/account_move_template/wizard/account_move_template_run.py b/account_move_template/wizard/account_move_template_run.py index bc6fc4a2447..ff99a02c423 100644 --- a/account_move_template/wizard/account_move_template_run.py +++ b/account_move_template/wizard/account_move_template_run.py @@ -210,8 +210,12 @@ def _prepare_move(self): def _prepare_move_line(self, line, amount): date_maturity = False if line.payment_term_id: - pterm_list = line.payment_term_id.compute(value=1, date_ref=self.date) - date_maturity = max(line[0] for line in pterm_list) + date_maturity = max( + [ + line._get_due_date(self.date) + for line in line.payment_term_id.line_ids + ] + ) debit = line.move_line_type == "dr" values = { "name": line.name, @@ -225,10 +229,11 @@ def _prepare_move_line(self, line, amount): } if line.tax_ids: values["tax_ids"] = [Command.set(line.tax_ids.ids)] - tax_repartition = "refund_tax_id" if line.is_refund else "invoice_tax_id" + document_type = "refund" if line.is_refund else "invoice" atrl_ids = self.env["account.tax.repartition.line"].search( [ - (tax_repartition, "in", line.tax_ids.ids), + ("tax_id", "in", line.tax_ids.ids), + ("document_type", "=", document_type), ("repartition_type", "=", "base"), ] )