Odoo ‐ Inheritance - vec-ltd/odoo-docs GitHub Wiki
If changes are needed in an existing module in Odoo we use the inheritance process. Odoo modules should not be updated directly from their files instead we create a custom module and inherit a specific record (views, templates, rules, etc.).
To inherit a model, first you need to create a class and then inherit the model inside that class. After you inherit the model you can just add some fields and create functions in that class and it will just point to the inherited model.
class OdooClassNameInherit(models.Model):
_inherit = 'odoo.model.name'
custom_field = field.Char(string='Some Added field to the odoo.model.name')
def someFunction(self):
# Put codes here
return True
First thing to do is locate the view you want to edit in the Odoo addons folder. Then, you create a custom module and inherit the existing view and do your changes.
You use the xpath tag to point the specific block you want to change in the Odoo's view then you use the the position parameter (before, after, inside or replace) to adjust where you want to put your custom block.
Odoo:
<record id="odoo_view_form" model="ir.ui.view">
<field name="name">odoo.view.form</field>
<field name="model">odoo.model.name</field>
<field name="arch" type="xml">
<form>
<header>Some Random Header here!</header>
<sheet>
<div class="oe_button_box d-flex justify-content-end" name="button_box">
</div>
</sheet>
</form>
</field>
</record>
Custom module:
Position: before
<record id="odoo_view_form_inherit" model="ir.ui.view">
<field name="name">odoo.view.form.inherit</field>
<field name="model">odoo.model.name</field>
<field name="inherit_id" ref="odoo_module.odoo_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="before">
<div class="oe_button_box d-flex justify-content-end" name="button_box">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</div>
</xpath>
</field>
</record>
Position: after
<record id="odoo_view_form_inherit" model="ir.ui.view">
<field name="name">odoo.view.form.inherit</field>
<field name="model">odoo.model.name</field>
<field name="inherit_id" ref="odoo_module.odoo_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="after">
<div class="oe_button_box d-flex justify-content-end" name="button_box">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</div>
</xpath>
</field>
</record>
Position: inside
<record id="odoo_view_form_inherit" model="ir.ui.view">
<field name="name">odoo.view.form.inherit</field>
<field name="model">odoo.model.name</field>
<field name="inherit_id" ref="odoo_module.odoo_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</xpath>
</field>
</record>
Position: replace
<record id="odoo_view_form_inherit" model="ir.ui.view">
<field name="name">odoo.view.form.inherit</field>
<field name="model">odoo.model.name</field>
<field name="inherit_id" ref="odoo_module.odoo_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="replace">
<div class="oe_button_box d-flex justify-content-end" name="button_box">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</div>
</xpath>
</field>
</record>
First thing to do is locate the template you want to edit in the Odoo addons folder. Then, you create a custom module and inherit the existing template and do your changes.
You use the xpath tag to point the specific block you want to change in the Odoo's template then you use the the position parameter (before, after, inside or replace) to adjust where you want to put your custom block.
Odoo:
<template id="odoo_template_id" name="Odoo Template Name">
<t>
<div class="oe_button_box d-flex justify-content-end" name="button_box">
</div>
</t>
</template>
Custom module:
Position: before
<template_id="odoo_template_id_inherit name="Odoo Template Name Inherit" inherit_id="odoo_module.odoo_template_id">
<xpath expr="//div[hasclass('oe_button_box')]" position="before">
<div class="oe_button_box d-flex justify-content-end" name="button_box">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</div>
</xpath>
</template>
Position: after
<template_id="odoo_template_id_inherit name="Odoo Template Name Inherit" inherit_id="odoo_module.odoo_template_id">
<xpath expr="//div[hasclass('oe_button_box')]" position="after">
<div class="oe_button_box d-flex justify-content-end" name="button_box">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</div>
</xpath>
</template>
Position: inside
<template_id="odoo_template_id_inherit name="Odoo Template Name Inherit" inherit_id="odoo_module.odoo_template_id">
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</xpath>
</template>
Position: replace
<template_id="odoo_template_id_inherit name="Odoo Template Name Inherit" inherit_id="odoo_module.odoo_template_id">
<xpath expr="//div[hasclass('oe_button_box')]" position="replace">
<div class="oe_button_box d-flex justify-content-end" name="button_box">
<button name="button_function"
type="object"
icon="fa-star">
</button>
</div>
</xpath>
</template>
First thing to do is locate the menu you want to edit in the Odoo addons folder. Then, you create a custom module and inherit the existing menu and do your changes. In this example we will change the menus group access from user to manager. This menu will be accessed only by managers.
Evaluation for groups have numbers representation and each number represents a process.
There are actually 0-6 numbers for representing each job for a many2many/ one2many field
(0, 0, { values }) -- link to a new record that needs to be created with the given values dictionary
(1, ID, { values }) -- update the linked record with id = ID (write values on it)
(2, ID) -- remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well)
(3, ID) -- cut the link to the linked record with id = ID (delete the relationship between the two objects but does not delete the target object itself)
(4, ID) -- link to existing record with id = ID (adds a relationship)
(5) -- unlink all (like using (3,ID) for all linked records)
(6, 0, [IDs]) -- replace the list of linked IDs (like using (5) then (4,ID) for each ID in the list of IDs)
Odoo:
<menuitem id="odoo_menu" name="Odoo Menu Name"
sequence="10"
web_icon="odoo_module,static/description/random_pic.png"
groups="odoo_module.group_user"/>
Custom module:
<record id="odoo_module.odoo_menu" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('odoo_module.group_manager')])]"/>
</record>
First thing to do is locate the rule you want to edit in the Odoo addons folder. Then, you create a custom module and inherit the existing rule and do your changes. In this example we will change the rule inside the noupdate=1 data tag, this means that Odoo specifically don't allow editing through inheritance. However, there are cases that it needs to be updated in order to achieve some use cases.
In order to do that we will be calling the write function in the xml and update the noupdate field to False, then we do our changes and revert the noupdate field to True.
In this example we will be changing the domain_force field of the rule so that the users can only see their own records only. domain_force is usually used to set what records are only allowed to a specific user/group, you treat domain_force as some sort of a condition/filter you make to set your desired records in a specific model.
noupdate="1"
Odoo:
<data noupdate="1">
....
<!-- Other rules goes here --!>
....
<record id="odoo_user_rule" model="ir.rule">
<field name="name">Odoo User Rule Name</field>
<field name="model_id" ref="model_odoo_model_name"/>
<field name="domain_force">[]</field>
<field name="groups" eval="[(4, ref('group_user'))]"/>
</record>
</data>
Custom module:
<!-- Updating the Rule - Start -->
<!-- Function to set the noupdate field to False -->
<function name="write" model="ir.model.data">
<function name="search" model="ir.model.data">
<value eval="[('module', '=', 'odoo_module_name'), ('name', '=', 'odoo_user_rule')]"/>
</function>
<value eval="{'noupdate': False}"/>
</function>
<!-- Updating the rule's domain_force -->
<record id="odoo_module_name.odoo_user_rule" model="ir.rule">
<field name="domain_force">[('create_uid', '=', user.id)]</field>
</record>
<!-- Function to set the noupdate field to True again -->
<function name="write" model="ir.model.data">
<function name="search" model="ir.model.data">
<value eval="[('module', '=', 'odoo_module_name'), ('name', '=', 'odoo_user_rule')]"/>
</function>
<value eval="{'noupdate': True}"/>
</function>
<!-- Helpdesk Ticket User Rule Update - End -->
noupdate="0"/no noupdate tag
Odoo:
<data noupdate="0">
....
<!-- Other rules goes here --!>
....
<record id="odoo_user_rule" model="ir.rule">
<field name="name">Odoo User Rule Name</field>
<field name="model_id" ref="model_odoo_model_name"/>
<field name="domain_force">[]</field>
<field name="groups" eval="[(4, ref('group_user'))]"/>
</record>
</data>
Custom module:
<!-- Updating the rule's domain_force -->
<record id="odoo_module_name.odoo_user_rule" model="ir.rule">
<field name="domain_force">[('create_uid', '=', user.id)]</field>
</record>
Here are some useful tips you can use when dealing with inheritance. If you encounter some useful process that links to Odoo's inheritance topic please do add it here.
res.config.settings is a TransientModel and is connected to ir.config_parameter in order for your settings to be saved. So if you're planning to add a setting to Odoo's existing settings please do follow these steps.
First we will inherit the res.config.settings model and add our desired settings fields.
class ResConfigSettingsInherit(models.TransientModel):
_inherit = 'res.config.settings'
addtl_field_setting = fields.Char(string='Additional field setting')
So in order to save the values in your settings you need to use helper functions and the ir._config_parameter model. These helper functions are called set_values and get_values.
def set_values(self):
res = super(ResConfigSettingsInherit, self).set_values()
self.env['ir.config_parameter'].sudo().set_param('custom_module_name.addtl_field_setting', self.addtl_field_setting)
return res
@api.model
def get_values(self):
res = super(ResConfigSettingsInherit, self).get_values()
ICPSudo = self.env['ir.config_parameter'].sudo()
res.update(
addtl_field_setting=ICPSudo.get_param('custom_module_name.addtl_field_setting')
)
return res
To display your added fields in the settings page, you need to inherit the res_config_settings_view_form and add your fields in it.
<record id="res_config_settings_view_form_inherit" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='performance']" position="after">
<h2 groups="base.group_no_one">Additional Field</h2>
<div class="row mt16 o_settings_container" name="addtl_field">
<div class="col-12 col-lg-6 o_setting_box" id="addtl_field">
<label for="addtl_field_setting"/>
<field name="addtl_field_setting"/>
</div>
</div>
</xpath>
</field>
</record>