Search code examples
odooodoo-17

View inheritance by multiple modules


I need to inherit the point of sale orders search view to add a custom filter. The view is defined like this

<record id="view_pos_order_filter" model="ir.ui.view">
        <field name="name">pos.order.list.select</field>
        <field name="model">pos.order</field>
        <field name="arch" type="xml">
            <search string="Search Sales Order">
                <field name="name"/>
                <field name="pos_reference"/>
                <field name="date_order"/>
                <field name="tracking_number"/>
                <field name="user_id"/>
                <field name="partner_id"/>
                <field name="session_id"/>
                <field name="config_id"/>
                <field name="lines" string="Product" filter_domain="[('lines.product_id', 'ilike', self)]"/>
                <filter string="Invoiced" name="invoiced" domain="[('state', '=', 'invoiced')]"/>
                <filter string="Posted" name="posted" domain="[('state', '=', 'done')]"/>
                <separator/>
                <filter string="Order Date" name="order_date" date="date_order"/>
                <group expand="0" string="Group By">
                    <filter string="Session" name="session" domain="[]" context="{'group_by': 'session_id'}"/>
                    <filter string="User" name="user_id" domain="[]" context="{'group_by': 'user_id'}"/>
                    <filter string="Point of Sale" name="config_id" domain="[]" context="{'group_by': 'config_id'}"/>
                    <filter string="Customer" name="customer" domain="[]" context="{'group_by': 'partner_id'}"/>
                    <filter string="Status" name="status" domain="[]" context="{'group_by': 'state'}"/>
                    <filter string="Order Date" name="order_month" domain="[]" context="{'group_by': 'date_order'}"/>
                </group>
            </search>
        </field>
    </record>

My inheriting view is like this:

<record id="pos_order_view_search_inherit" model="ir.ui.view">
    <field name="name">pos.order.view.search.inherit</field>
    <field name="model">pos.order</field>
    <field name="inherit_id" ref="point_of_sale.view_pos_order_filter"/>
    <field name="arch" type="xml">
      <xpath expr="//filter[@name='user_id']" position='after'>
        <filter name="group_by_sales_rep" string="Sales Representative" domain="[]" context="{'group_by':'sales_rep_id'}"/>
      </xpath>
    </field>
  </record>

The inheritance seems to be fine (atleat during view parsing at startup) and odoo starts without any errors. However when I go the orders view in the browser I get an error, which reads in part...

ValueError: Element '<xpath expr="//filter[@name=&#39;user_id&#39;]">' cannot be located in parent view

I found that the same view is also inherited elsewhere and the user_id filter replaced like this

    <record id="pos_order_list_select_inherit" model="ir.ui.view">
        <field name="name">pos.order.list.select.inherit</field>
        <field name="model">pos.order</field>
        <field name="inherit_id" ref="point_of_sale.view_pos_order_filter"/>
        <field name="arch" type="xml">
            <xpath expr="//field[@name='user_id']" position="replace">
                <field name="cashier"/>
            </xpath>
            <xpath expr="//filter[@name='user_id']" position="replace">
                <filter string="Cashier" name="by_cashier" domain="[]" context="{'group_by': 'cashier'}"/>
            </xpath>
        </field>
    </record>

I know I could use a different xpath expression to do what I need but I'm curious how inheritance is supposed to work in such a case. ?


Solution

  • Views are ordered by fields priority and id when combined together. And modules are installed by dependencies, first the dependencies are installed then it's dependents. So in your case you have the parent view "installed" first. Probably another odoo module was installed so the view with xml id "pos_order_list_select_inherit" is the first dependent because of its database ID. Both your new and the other modules view don't have a priority set in the view definition, which give them the default of 16.

    Your views should look like that:

    short name priority database id
    parent 16 lowest
    other module 16 medium
    yours 16 highest

    That will Odoo sequentially combine the views by

    • beginning with the parent view as base
    • adding the other modules view (same priority as yours, but lower database ID)
    • adding your view at the end

    And that's why you get that error: after combining the parent with the other module's view there is no filter with name="user_id" anymore.

    One solution therefore is to set the priority on your view to guarantee it's loaded in the right order.

    <record id="pos_order_view_search_inherit" model="ir.ui.view">
        <field name="name">pos.order.view.search.inherit</field>
        <field name="model">pos.order</field>
        <field name="inherit_id" ref="point_of_sale.view_pos_order_filter"/>
        <field name="priority">1</field>
        <field name="arch" type="xml">
          <xpath expr="//filter[@name='user_id']" position='after'>
            <filter name="group_by_sales_rep" string="Sales Representative" domain="[]" context="{'group_by':'sales_rep_id'}"/>
          </xpath>
        </field>
    </record>
    

    Another one is ofcourse changing the XPath by considering other view extensions. But that could also lead to problems in other databases where modules where installed in another order.