141 lines
5.5 KiB
Python
141 lines
5.5 KiB
Python
# Copyright 2018 ForgeFlow S.L.
|
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
|
|
|
from odoo import Command, fields
|
|
from odoo.exceptions import ValidationError
|
|
from odoo.tests import Form
|
|
from odoo.tests.common import new_test_user, tagged
|
|
|
|
from odoo.addons.base.tests.common import BaseCommon
|
|
|
|
|
|
@tagged("post_install", "-at_install")
|
|
class TestAccountTierValidation(BaseCommon):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.group_system = cls.env.ref("base.group_system")
|
|
cls.group_account_manager = cls.env.ref("account.group_account_manager")
|
|
cls.test_user_1 = new_test_user(
|
|
cls.env,
|
|
name="John",
|
|
login="test1",
|
|
groups="base.group_system,account.group_account_manager",
|
|
)
|
|
cls.test_user_2 = new_test_user(
|
|
cls.env,
|
|
name="Mike",
|
|
login="test2",
|
|
groups="base.group_system,account.group_account_manager",
|
|
)
|
|
cls.account_move_model = cls.env["ir.model"]._get("account.move")
|
|
|
|
# Ensure the company has a document layout configured.
|
|
if not cls.company.external_report_layout_id:
|
|
# Try to find a common default layout by XML ID
|
|
default_layout = cls.env.ref(
|
|
"web.external_layout_standard", raise_if_not_found=False
|
|
)
|
|
if not default_layout:
|
|
# Fallback: try other common layouts if standard
|
|
# is not found by that XML ID directly
|
|
common_layouts_xml_ids = [
|
|
"web.external_layout_boxed",
|
|
"web.external_layout_bold",
|
|
]
|
|
for layout_xml_id in common_layouts_xml_ids:
|
|
default_layout = cls.env.ref(
|
|
layout_xml_id, raise_if_not_found=False
|
|
)
|
|
if default_layout:
|
|
break
|
|
if not default_layout:
|
|
# As a last resort, find the first available report.layout
|
|
default_layout = cls.env["report.layout"].search([], limit=1)
|
|
|
|
if default_layout:
|
|
cls.company.external_report_layout_id = default_layout.id
|
|
|
|
def test_01_tier_definition_models(self):
|
|
res = self.env["tier.definition"]._get_tier_validation_model_names()
|
|
self.assertIn("account.move", res)
|
|
|
|
def test_02_form(self):
|
|
for move_type in ("in_invoice", "out_invoice", "in_refund", "out_refund"):
|
|
self.env["tier.definition"].create(
|
|
{
|
|
"model_id": self.account_move_model.id,
|
|
"definition_domain": f"[('move_type', '=', '{move_type}')]",
|
|
}
|
|
)
|
|
with Form(
|
|
self.env["account.move"].with_context(default_move_type=move_type)
|
|
) as form:
|
|
form.save()
|
|
self.assertTrue(form.hide_post_button)
|
|
|
|
def test_03_move_post(self):
|
|
self.env["tier.definition"].create(
|
|
{
|
|
"model_id": self.account_move_model.id,
|
|
"definition_domain": "[('move_type', '=', 'out_invoice')]",
|
|
"reviewer_id": self.test_user_1.id,
|
|
}
|
|
)
|
|
partner = self.env["res.partner"].create({"name": "Test Partner"})
|
|
product = self.env["product.product"].create({"name": "Test product"})
|
|
invoice = self.env["account.move"].create(
|
|
{
|
|
"move_type": "out_invoice",
|
|
"partner_id": partner.id,
|
|
"invoice_date_due": fields.Date.to_date("2024-01-01"),
|
|
"invoice_line_ids": [
|
|
Command.create(
|
|
{"product_id": product.id, "quantity": 1, "price_unit": 30}
|
|
)
|
|
],
|
|
}
|
|
)
|
|
invoice.with_user(self.test_user_2.id).request_validation()
|
|
invoice = invoice.with_user(self.test_user_1.id)
|
|
invoice.invalidate_model()
|
|
invoice.validate_tier()
|
|
with self.assertRaisesRegex(
|
|
ValidationError, "You are not allowed to write those fields"
|
|
):
|
|
invoice._post()
|
|
# Calls _post method by passing context skip_validation_check set to True
|
|
invoice.action_post()
|
|
self.assertEqual(invoice.state, "posted")
|
|
|
|
# --- Simulate Sending Invoice by Email ---
|
|
# The 'action_invoice_sent' method on 'account.move' usually returns
|
|
# an action to open the 'account.move.send.wizard' wizard.
|
|
action = invoice.action_invoice_sent()
|
|
self.assertTrue(
|
|
action, "Action 'action_invoice_sent' should return an action dictionary."
|
|
)
|
|
self.assertEqual(
|
|
action.get("res_model"),
|
|
"account.move.send.wizard",
|
|
"Action should open 'account.move.send.wizard' wizard.",
|
|
)
|
|
|
|
# Get the context from the action to create the wizard instance
|
|
wizard_context = action.get("context", {})
|
|
mail_composer = (
|
|
self.env["account.move.send.wizard"]
|
|
.with_context(**wizard_context)
|
|
.create({})
|
|
)
|
|
|
|
# we should test action_send_and_print because that fails if
|
|
# not all necesary fields are excluded
|
|
if hasattr(mail_composer, "action_send_and_print"):
|
|
mail_composer.action_send_and_print()
|
|
else:
|
|
self.fail(
|
|
"Could not find a 'action_send_and_print' "
|
|
"action on the account.move.send.wizard."
|
|
)
|