web/web_field_required_invisibl.../models/custom_field_restriction.py

169 lines
5.9 KiB
Python

# Copyright 2023 ooops404
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
from odoo import api, fields, models
from odoo.tools.safe_eval import safe_eval
class CustomFieldRestriction(models.Model):
_name = "custom.field.restriction"
_description = "Make field invisible or required"
field_id = fields.Many2one(
"ir.model.fields",
ondelete="cascade",
required=True,
string="Field",
)
field_name = fields.Char(
related="field_id.name",
store=True,
string="Field Name",
)
required_model_id = fields.Many2one(
"ir.model",
ondelete="cascade",
string="Model (required)",
index=True,
)
invisible_model_id = fields.Many2one(
"ir.model",
ondelete="cascade",
string="Model (visibility)",
index=True,
)
readonly_model_id = fields.Many2one(
"ir.model",
ondelete="cascade",
string="Model (readonly)",
index=True,
)
model_name = fields.Char(
compute="_compute_model_name",
store=True,
string="Model Name",
index=True,
)
condition_domain = fields.Char()
group_ids = fields.Many2many("res.groups", required=True)
default_required = fields.Boolean(
related="field_id.required", string="Required by Default"
)
required = fields.Boolean()
field_invisible = fields.Boolean()
field_readonly = fields.Boolean()
# generated technical fields used in form attrs:
visibility_field_id = fields.Many2one("ir.model.fields")
readonly_field_id = fields.Many2one("ir.model.fields")
required_field_id = fields.Many2one("ir.model.fields")
@api.onchange("field_id")
def onchange_field_id(self):
vals = {}
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):
for rec in self:
if rec.required_model_id:
rec.model_name = rec.required_model_id.model
rec.required = True
elif rec.invisible_model_id:
rec.model_name = rec.invisible_model_id.model
rec.field_invisible = True
elif rec.readonly_model_id:
rec.model_name = rec.readonly_model_id.model
rec.field_readonly = True
@api.model
def create(self, vals):
rec = super().create(vals)
if rec.invisible_model_id and rec.field_invisible:
rec.create_restriction_field("visibility")
elif rec.readonly_model_id and rec.field_readonly:
rec.create_restriction_field("readonly")
elif rec.required_model_id and rec.required:
rec.create_restriction_field("required")
return rec
def write(self, vals):
res = super().write(vals)
if vals.get("field_id"):
if self.visibility_field_id:
self.visibility_field_id.unlink()
self.create_restriction_field("visibility")
elif self.readonly_field_id:
self.readonly_field_id.unlink()
self.create_restriction_field("readonly")
elif self.required_field_id:
self.required_field_id.unlink()
self.create_restriction_field("required")
return res
def create_restriction_field(self, f_type):
field_name = self.get_field_name(f_type)
field_id = self.env["ir.model.fields"].search(
[("name", "=", field_name), ("state", "=", "manual")]
)
if f_type == "required":
rec_model_id = self.required_model_id.id
rec_field_name = "required_field_id"
elif f_type == "readonly":
rec_model_id = self.readonly_model_id.id
rec_field_name = "readonly_field_id"
elif f_type == "visibility":
rec_model_id = self.invisible_model_id.id
rec_field_name = "visibility_field_id"
if not field_id:
deps = ""
if self.condition_domain:
deps = ",".join(
{r[0] for r in safe_eval(self.condition_domain)} - {"id", "&", "|"}
)
field_id = self.env["ir.model.fields"].create(
{
"name": field_name,
"model_id": rec_model_id,
"state": "manual",
"field_description": "%s %s field" % (self.field_id.name, f_type),
"store": False,
"ttype": "boolean",
"compute": "for r in self: r._compute_restrictions_fields()",
"depends": deps,
}
)
self[rec_field_name] = field_id
def get_field_name(self, f_type):
# e.g. x_computed_res_partner_name_readonly
res = "x_computed_%s_%s_%s" % (
self.field_id.model.replace(".", "_"),
self.field_id.name,
f_type,
)
return res
def unlink(self):
for rec in self:
rec.visibility_field_id.unlink()
rec.readonly_field_id.unlink()
rec.required_field_id.unlink()
return super(CustomFieldRestriction, self).unlink()