Set up a development environment with PyCharm
- Create an Odoo? folder and clone Odoo with the command git clone –depth 1 –branch ?.0 https://www.github.com/odoo/odoo.
- Create a virtual environment in that folder (with Python3 since Odoo 11) …
- virtualenv ./venv -p /usr/bin/python(3)
- source ./venv/bin/activate
- pip(3) install -r odoo/requirements.txt (If psycopg2 is version 2.7.1 in this file, set it to 2.7.3.1 first.)
- deactivate
- Open the Odoo? folder in PyCharm …
- Change the standard Python interpreter of your project to the newly created environment … File > Settings > Project: Odoo? > Python Interpreter > Cog icon + Add > Select Odoo?/venv/bin/python(2.7).
- Make a run configuration …
- + Python
- Script path = Odoo?/odoo/odoo -bin (or openerp-server before Odoo10)
- Parameters
- Odoo should be able to connect to your database, so make sure the params –db_user and –db_password are correctly set.
- If you have more environments of Odoo of even different versions, it’s a good idea to force the selection of the correct database by setting –db-filter=^Odoo?$ as parameter.
How to rename an installed module?
Data is lost when you uninstall and reinstall, so https://gist.github.com/antespi/38978614e522b1a99563.
Python
How to trigger an onchange event?
@api.onchange('code_prefix_start')
def _onchange_code_prefix_start(self):
if not self.code_prefix_end or self.code_prefix_end < self.code_prefix_start:
self.code_prefix_end = self.code_prefix_start
How to add a value to a many2one or many2many field?
if electronic not in self.inbound_payment_method_ids:
self.inbound_payment_method_ids = [(4, electronic.id)]
XML
General tips
- AVOID COMMENTS IN YOUR XML FILES WHICH LEAD TO UNCLEAR ERROR MESSAGES!
- Add a space with ampersand hashtag 160 ;
AssertionError: Element odoo has extra content: record, line 3
1/ If you are extending a view, check if your model name is the one of the parent view.
2/ To spot invalid syntax, go to an online relax ng validator like https://www.liquid-technologies.com/online-relaxng-validator. Add the contents of your view in the first input field, the contents of odoo/odoo/import_xml.rng in the second and validate. The errors here will give you precise info on the error. Here is an example …

<record></record>
How to extend/overrule/override <record>?
<record>s of model ‘ir.ui.view’ have an inherit_id property …
<record id="product_template_search_view" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view" />
<field name="arch" type="xml">
<field name="name" position="after">
<field name="product_brand_id" />
</field>
</field>
</record>
<record>s of models other than ‘ir.ui.view’ do not work with an inherit_id. If you want to change a field value of a record, you should copy the definition of the <record> in your module, prefix the id with the original module name (+ dot) and include the field you wish to change like for example …
<record id="purchase_requisition.type_multi" model="purchase.requisition.type">
<field name="exclusive">exclusive</field>
</record>
If that <record> is wrapped in a noupdate=”1″ you should make the record writable first (and unwritable again after) like this …
<odoo noupdate="0">
<function name="write" model="ir.model.data">
<function name="search" model="ir.model.data">
<value eval="[('module', '=', 'purchase_requisition'), ('name', '=', 'type_multi')]"/>
</function>
<value eval="{'noupdate': False}" />
</function>
<record id="purchase_requisition.type_multi" model="purchase.requisition.type">
<field name="exclusive">exclusive</field>
</record>
<function name="write" model="ir.model.data">
<function name="search" model="ir.model.data">
<value eval="[('module', '=', 'purchase_requisition'), ('name', '=', 'type_multi')]"/>
</function>
<value eval="{'noupdate': True}" />
</function>
</odoo>
Views
How to add default views for a model?
Just create an action and menu item for the model …
<record id="product_template_attribute_action" model="ir.actions.act_window">
<field name="name">Product Template Attributes</field>
<field name="res_model">product.template.attribute.line</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_product_template_attribute_action"
action="gun_product.product_template_attribute_action"
parent="sale.prod_config_main"
groups="product.group_product_variant"
sequence="2"/>
How to control the order of view inheritance?
<record id="product_template_tree_view" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_tree_view"/>
<field name="priority" eval="32"/>
The default priority of a view is 16. The definition above will apply this extension after most inherited views.
How to create xpath expressions?
https://docs.python.org/3/library/xml.etree.elementtree.html#supported-xpath-syntax
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='company_id']" position="after">
<xpath expr="//div[hasclass('o_primary')]" position="after">
<xpath expr="//link[last()]" position="after">
<xpath expr="." position="inside">
<xpath expr="//templates/descendant::field[@name='partner_id']" position="after">
<xpath expr="//button[@name='action_timer_start'][hasclass('btn-primary')]" position='after'>
How to move a field in a view?
<data>
<xpath expr="//field[@name='active']" position="before">
<xpath expr="//field[@name='barcode']" position="move"/>
</xpath>
</data>
Before Odoo 12 you first have to set the moving field to invisible and adding it again at the right position!
<field name="product_brand_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="name" position="before">
<field name="product_brand_id"/>
</field>
Search view > How to set a default filter in search bar?
https://www.odoo.com/nl_NL/forum/help-1/how-to-set-a-default-filter-in-search-bar-146233
<template></template>
Reports
How to create a new report?
<template id="report_saleorder_document">
<t t-call="web.external_layout">
<t t-set="doc" t-value="doc.with_context(lang=doc.partner_id.lang)" />
<div class="page">
<div class="oe_structure"/>
...
<template id="report_saleorder">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="sale.report_saleorder_document" t-lang="doc.partner_id.lang"/>
</t>
</t>
</template>
How to extend a report?
<template id="report_saleorder_document" inherit_id="sale.report_saleorder_document">
<xpath expr="//div[@t-if='doc.user_id.name']" position="replace"/>
...
How to create a new report based on an existing one?
<template id="report_saleorder_document2" inherit_id="sale.report_saleorder_document" primary="True">
...
<template id="report_saleorder">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="sale.report_saleorder_document2" t-lang="doc.partner_id.lang"/>
</t>
</t>
</template>
Domain examples
[('applicability', '=', 'taxes'), ('country_id', '=', tax_fiscal_country_id)]
['|', '|', ('name','ilike',self), ('company_name','ilike',self), ('email_normalized','ilike',self)]
['|', ('product_ids', 'ilike', self), ('line_ids.product_id','ilike',self)]
Dot notation can be used in domain!
Javascript
Button on Odoo form that triggers a Javascript onclick event
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="action_create_variants" model="ir.actions.client">
<field name="name">Create variants</field>
<field name="tag">product_product_matrix_create_variants</field>
</record>
<record id="product_template_form_view" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//header/button" position="before">
<button string="Creeer varianten"
name="%(action_create_variants)d" type="action"
attrs="{'invisible': ['|', ('attribute_line_ids', '<=', 0), ('is_product_variant', '=', True)]}"
groups="product.group_product_variant"/>
</xpath>
</field>
</record>
</data>
</odoo>
odoo.define('product_product_matrix.create_variants', function (require) {
"use strict";
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var CreateVariants = AbstractAction.extend({
init: function () {
this.call_function();
},
call_function: function (event) {
console.log('Click');
alert("Click");
},
});
core.action_registry.add('product_product_matrix_create_variants', CreateVariants);
});