From d9c56b1f6f78262be61b493ad8b859fc24e38442 Mon Sep 17 00:00:00 2001 From: Ilyas Date: Mon, 11 Dec 2023 17:16:22 +0500 Subject: [PATCH] [IMP] web_field_required_invisible_manager: consider rel. fields with own views --- .../models/custom_field_restriction.py | 31 +++++-- .../models/models.py | 59 +++++++++++- ...st_web_field_required_invisible_manager.py | 89 ++++++++++++++++++- 3 files changed, 170 insertions(+), 9 deletions(-) diff --git a/web_field_required_invisible_manager/models/custom_field_restriction.py b/web_field_required_invisible_manager/models/custom_field_restriction.py index 573557060a23..b1d1f7496aad 100644 --- a/web_field_required_invisible_manager/models/custom_field_restriction.py +++ b/web_field_required_invisible_manager/models/custom_field_restriction.py @@ -56,13 +56,30 @@ class CustomFieldRestriction(models.Model): @api.onchange("field_id") def onchange_field_id(self): - self.update( - { - "required": self.field_id.required, - "field_invisible": False, - "field_readonly": self.field_id.readonly, - } - ) + vals = { + "required": self.field_id.required, + "field_invisible": False, + "field_readonly": self.field_id.readonly, + } + if self.env.context.get("default_readonly_model_id"): + vals["readonly_model_id"] = ( + self.env["ir.model"] + ._get(self.env.context.get("default_readonly_model_id")) + .id + ) + elif self.env.context.get("default_required_model_id"): + vals["required_model_id"] = ( + self.env["ir.model"] + ._get(self.env.context.get("default_required_model_id")) + .id + ) + elif self.env.context.get("default_invisible_model_id"): + vals["invisible_model_id"] = ( + self.env["ir.model"] + ._get(self.env.context.get("default_invisible_model_id")) + .id + ) + self.update(vals) @api.depends("required_model_id", "invisible_model_id", "readonly_model_id") def _compute_model_name(self): diff --git a/web_field_required_invisible_manager/models/models.py b/web_field_required_invisible_manager/models/models.py index a21dfb3a04ae..fa101ac0e44b 100644 --- a/web_field_required_invisible_manager/models/models.py +++ b/web_field_required_invisible_manager/models/models.py @@ -7,6 +7,8 @@ from odoo import api, fields, models from odoo.tools.safe_eval import safe_eval +from odoo.addons.base.models.ir_ui_view import NameManager + class IrModel(models.Model): _inherit = "ir.model" @@ -45,7 +47,62 @@ def fields_view_get( ] ) if restrictions: - return self.create_restrictions_fields(restrictions, view_type, arch) + arch = self.create_restrictions_fields(restrictions, view_type, arch) + arch = self.process_child_fields(arch, view_type) + return arch + + def process_child_fields(self, arch, view_type): + """Collect all relational fields and update its views""" + related_fields = [ + (k, v.comodel_name) for k, v in self._fields.items() if v.comodel_name + ] + related_models_names = [r[1] for r in related_fields] + restrictions = self.env["custom.field.restriction"].search( + [ + ("model_name", "in", related_models_names), + ("group_ids", "in", self.env.user.groups_id.ids), + ] + ) + if restrictions and view_type == "form": + for restr in restrictions: + todo_fields = list( + filter(lambda x: x[1] == restr.model_name, related_fields) + ) + for todo_field in todo_fields: + if not arch["fields"].get(todo_field[0]): + continue + for sub_view_type, sub_view in arch["fields"][todo_field[0]][ + "views" + ].items(): + if sub_view_type not in ["form", "tree"]: + continue + z_arch = sub_view + z_arch = self.create_restrictions_fields( + restr, view_type, z_arch + ) + z_arch["arch"] = z_arch["arch"].decode("utf-8") + name_manager = NameManager(False, self.env[restr.model_name]) + if restr.readonly_field_id and restr.readonly_model_id: + model_field_infos = name_manager.fields_get.get( + restr.readonly_field_id.name + ) + z_arch["fields"][ + restr.readonly_field_id.name + ] = model_field_infos + if restr.visibility_field_id and restr.invisible_model_id: + model_field_infos = name_manager.fields_get.get( + restr.visibility_field_id.name + ) + z_arch["fields"][ + restr.visibility_field_id.name + ] = model_field_infos + if restr.required_field_id and restr.required_model_id: + model_field_infos = name_manager.fields_get.get( + restr.required_field_id.name + ) + z_arch["fields"][ + restr.required_field_id.name + ] = model_field_infos return arch def create_restrictions_fields(self, restrictions, view_type, arch): diff --git a/web_field_required_invisible_manager/tests/test_web_field_required_invisible_manager.py b/web_field_required_invisible_manager/tests/test_web_field_required_invisible_manager.py index a8679ce376cd..39a3685d734d 100644 --- a/web_field_required_invisible_manager/tests/test_web_field_required_invisible_manager.py +++ b/web_field_required_invisible_manager/tests/test_web_field_required_invisible_manager.py @@ -1,13 +1,14 @@ # Copyright 2023 ooops404 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo.tests import common +from odoo.tests import Form, common class TestFieldRequiredIvisibleManager(common.SavepointCase): @classmethod def setUpClass(cls): super(TestFieldRequiredIvisibleManager, cls).setUpClass() + cls.view_model = cls.env["ir.ui.view"].sudo() cls.partner_name_field_id = cls.env["ir.model.fields"].search( [("model", "=", "res.partner"), ("name", "=", "name")] ) @@ -21,6 +22,9 @@ def setUpClass(cls): cls.partner_title_name_field_id = cls.env["ir.model.fields"].search( [("model", "=", "res.partner.title"), ("name", "=", "name")] ) + cls.partner_name_field_id = cls.env["ir.model.fields"].search( + [("model", "=", "res.partner"), ("name", "=", "name")] + ) cls.partner_title_shortcut_field_id = cls.env["ir.model.fields"].search( [("model", "=", "res.partner.title"), ("name", "=", "shortcut")] ) @@ -65,9 +69,92 @@ def setUpClass(cls): cls.partner_tree_view = cls.env.ref("base.view_partner_tree") cls.view_partner_title_form = cls.env.ref("base.view_partner_title_form") cls.view_partner_title_tree = cls.env.ref("base.view_partner_title_tree") + cls.users_model = cls.env["ir.model"]._get("res.users") cls.view_users_form = cls.env.ref("base.view_users_form") cls.view_users_tree = cls.env.ref("base.view_users_tree") + cls.company_model_id = cls.env["ir.model"]._get("res.company") + cls.company_name_field = cls.env["ir.model.fields"].search( + [("model", "=", "res.company"), ("name", "=", "name")] + ) + cls.company_street_field = cls.env["ir.model.fields"].search( + [("model", "=", "res.company"), ("name", "=", "street")] + ) + cls.company_city_field = cls.env["ir.model.fields"].search( + [("model", "=", "res.company"), ("name", "=", "city")] + ) + cls.company_name_readonly = cls.env["custom.field.restriction"].create( + { + "readonly_model_id": cls.company_model_id.id, + "field_id": cls.company_name_field.id, + "group_ids": [(6, 0, cls.env.ref("base.group_user").ids)], + "field_readonly": True, + "condition_domain": "[('id', '>', 0)]", + } + ) + cls.company_street_required = cls.env["custom.field.restriction"].create( + { + "required_model_id": cls.company_model_id.id, + "field_id": cls.company_street_field.id, + "group_ids": [(6, 0, cls.env.ref("base.group_user").ids)], + "required": True, + "condition_domain": "[('id', '>', 0)]", + } + ) + cls.company_city_invisible = cls.env["custom.field.restriction"].create( + { + "invisible_model_id": cls.company_model_id.id, + "field_id": cls.company_city_field.id, + "group_ids": [(6, 0, cls.env.ref("base.group_user").ids)], + "field_invisible": True, + "condition_domain": "[('id', '>', 0)]", + } + ) + cls.company_tree_view = cls.env["ir.ui.view"].create( + { + "name": "Test Tree", + "model": "res.company", + "type": "tree", + "mode": "primary", + "arch": "" + "" + "", + } + ) + cls.view_users_form.arch = cls.view_users_form.arch.replace( + "", + "" + "" + "", + ) + + def test_model_form(self): + """onchange should set correct model""" + + partner_form_view = self.view_model.default_view( + self.partner_model_id._name, "form" + ) + with Form(self.partner_model_id, view=partner_form_view) as partner_form: + with partner_form.custom_required_restriction_ids.new() as new_line: + self.assertTrue(new_line.required_model_id) + new_line.field_id = self.partner_name_field_id + with partner_form.custom_readonly_restriction_ids.new() as new_line: + self.assertTrue(new_line.readonly_model_id) + new_line.field_id = self.partner_name_field_id + with partner_form.custom_invisible_restriction_ids.new() as new_line: + self.assertTrue(new_line.invisible_model_id) + new_line.field_id = self.partner_name_field_id + + def test_relational_fields(self): + """res.users has company_ids field. It has restrictions. + Restrictions should be added into company tree view""" + user = self.env["res.users"].search([], limit=1) + arch = user.fields_view_get(view_id=self.view_users_form.id, view_type="form") + sub_arch = arch["fields"]["company_ids"]["views"]["tree"]["arch"] + self.assertIn("x_computed_res_company_name_readonly", sub_arch) + self.assertIn("x_computed_res_company_street_required", sub_arch) + self.assertIn("x_computed_res_company_city_visibility", sub_arch) + def test_all_web_field_required_invisible_manager(self): # related fields are created self.assertTrue(self.invisible_rec_id.visibility_field_id)