Search code examples
pythonpython-3.xxmlodooodoo-16

How can I set all form fields readonly in Odoo 16 depending on a field?


In Odoo 16, I'm trying to make all fields from a form view readonly depending on the value of other field of the same form.

First I've tried the following:

<xpath expr="//field" position="attributes">
    <attribute name="attrs">{'readonly': [('my_field', '=', True)]}</attribute>
</xpath>

With no result.

I can't use <form edit="false"> neither since I have to check the field value.

A rule with <field name="perm_write">1</field> works, but it doesn't behave as I need, since it allows you to modify the whole form until you click on Save and get the permission error.

And overwriting get_view is not a valid option, since cannot depend on my_field value.

The only solution I can find is to modify each field of the form with xpath, which is pretty disturbing, and is not consistent if in the future more fields are added to the form view via other apps.

Does anyone have a better solution for this?


Solution

  • Extending get_view actually is a good idea. There is a module in server-ux repo of the OCA where something similar is done: when something is saved in a one2many field, every field in the form view will be set to readonly. To do this, the readonly modifier is rewritten for each field.

    The module: base_tier_validation

    The interesting part of code: get_view

    Code for your case:

    @api.model
    def get_view(self, view_id=None, view_type="form", **options):
        res = super().get_view(
            view_id=view_id,
            view_type=view_type,
            **options,
        )
        if view_type == "form":
            doc = etree.XML(res["arch"])
            for field in doc.xpath("//field[@name][not(ancestor::field)]"):
                modifiers = json.loads(
                    field.attrib.get("modifiers", '{"readonly": false}')
                )
                if modifiers.get("readonly") is not True:
                    modifiers["readonly"] = OR(
                        [
                            modifiers.get(
                                "readonly", []
                            ) or [],
                            [("my_field", "=", True)],
                        ]
                    )
                    field.attrib["modifiers"] = json.dumps(modifiers)
            res["arch"] = etree.tostring(doc, pretty_print=True)
        return res