Dynamically change mode on one2many field in a form

Hi everyone,

I have a model named MissionOrder, with a one2many field named invoicing_elements. I display this field in the MissionOrder form, and the user can manage the list of InvoicingElement just fine.
I was able to dynamically set readonly property of the field, based on the MissionOrder state, like shown below :

    _states = {
        'readonly': Eval('state', '').in_(["invoicing_ready", "invoiced"]),
    }
    _depends = ['state']
    invoicing_elements = fields.One2Many('transport.invoicing_element', 'mission_order', 'Invoicing Elements',
        states={
            'invisible': Eval('state', '') == "not_invoiced",
            'readonly': _states["readonly"]
        },
        depends=_depends
    )

My problem is that when the field is readonly, the user can still double-click on each InvoicingElement, and a popup will allow him to upate the object.

In order to prevent that, I tried to dynamically set the mode attribute to ‘tree’ instead of ‘form,tree’ when the state of the MissionOrder is ‘invoicing_ready’ or ‘invoiced’, by using the view_attributes() function :

    @classmethod
    def view_attributes(cls):
        return super().view_attributes() + [
            ('/tree/field[@name="record_ok"]', 'visual', If(Eval('record_ok', False), 'success', 'danger')),
            ('/tree/field[@name="state"]', 'visual', If(Equal(Eval('state', ""), "not_invoiced"), 'danger', If(Equal(Eval('state', ""), "invoiced"), 'success', 'warning'))),
            ('/tree/field[@name="invoicing_elements"]', 'mode', If(Eval('state', '').in_(["invoicing_ready", "invoiced"]), 'tree', 'tree,form'))
        ]

This does not seem to work, and the user can still update the InvoicingElement records. Is there a way to dynamically set the mode attribute on a one2many field ?

No there is no way.

Any way it is not by preventing the popup form that will solve your problem correctly. Instead you should do like for example on the sale line and set readonly state on the element’s field based on the state of the order. The best is to have a state function field that compute the order state. This has the benefit that the readonly state will also be set if the element is opened from a different place than the order One2Many.

Hi @ced,

Thank you for your response.
Yes I thought about adding a computed state on the InvoicingElement. But since there was this “mode” attribute, I gave it a try, it seemed simpler. But as you said, there are other cases that would not have been covered with it.

So I will indeed compute the state of the MissionOrder in the InvoicingElement, and use that to set the fields as readonly if needed.
Thanks again.