How to hide a column ‘dynamically’ in Tree View on Odoo

Odoo field has an attribute called ‘attrs’. This adds custom attribute to the Odoo form/tree views. You may use different kind of attributes with attrs like ‘required’, ‘readonly’ or ‘invisible’. For basic, to hide a field regardless of it be an individual entity or parent relation, we use the following:

<field name='field_name' invisible='1'/>

This is useful when we are triggering a computed field that we don’t want to show on a tree/form view. But what if we want to dynamically decide whether to invisible the field or not? For such cases, we usually use invisible with the ‘attrs’ attribute on fields, for example:

<field name='product_id' attrs="{ 'invisible': [('is_set', '=', True)]}"/>

You might set the field 'is_set' itself as invisible and a boolean computed field like the following:

is_set = fields.Boolean(compute="_set_is_set")

def _set_is_set(self):
if self.lot_id.life_date:
self.is_set = True
self.is_set = False

Seems easy, right? But there is a catch, the above won’t hide the whole column if you are on a place like ‘purchase.order.line’ or ‘stock.move.line’. How can you work on such cases? It only works on individual entry, but not on a relational column. There is an attribute called ‘column_invisible’ same like ‘invisible’ we have used above. But the difference is, you need to set this based on parent value, thus hides a relational column. Here is an example to hide a column called ‘show_expiry’ in a picking operation:

<field name="show_expiry" attrs="{ 'column_invisible' : [('parent.picking_type_code', 'in', ['incoming'])]}" />

Above code checks the ‘picking_type_code’ value from ‘stock.picking’ model, and hides the column if it’s an incoming shipment and shows when it’s an outgoing shipment. That means, the above, would show the column (show_expiry) if it’s a Delivery to customer location or you already have the product, but won’t show if you are doing a GRN, means you don’t have the stock yet, just arriving.

Pretty simple, isn’t it? Good luck.

How to use dynamic ‘domain’ in Odoo 12 Many2one relation

There are two ways you can have a model data selection in Odoo, one is to use Selection field and the Other is Many2one relational field. To dynamically create a Selection field, all you need to do is to pass the list of (value, string) tuple as the first parameter or use a reference of a function to get a return list of same. Creating dynamic selection field is quite simple, with one drawback! It won’t work on api onchange. As the values on the selection fields are already loaded, api onchange can not reverse and reload the selection fields like it can do on ‘relational objects’. The only way left is to use a Many2one relational field.

Now Many2one relational field now make it a bit complicated as, you can’t generate the list in a straightforward way like you can do in selection field. Most likely, you would like to pass a domain, that matches some attribute of ‘self’, and some from another relation. Here is how you can achieve this!

I will create a simple model with two fields, one is Char and the other is Many2one:

_name = 'my.product.manager'

sku = fields.Char(string='SKU', required=True)
basket = fields.Many2one('basket.location', string='Product Basket Location', required=True)

Now, for example, you would like to select these SKUs during the creation of purchase order, and would like the field to come up when a change is made on the purchase order line.

First, we create a new Many2one relation field on ‘purchase.order.line’ model in relation to ‘my.product.manager’

_inherit = 'purchase.order.line'
basket_location_id = fields.Many2one( 'my.product.manager', 'Basket Location')

Cool, now you don’t want to share all the baskets in the purchase order form for a product, instead you want to show only those baskets that are allocated for that specific SKU. Here is how, you can pass a dynamic domain to the basket_location_id and filter it

def onchange_basket(self):
res = {
'domain' : {
'basket_dest_id' : [('sku', '=', self.product_id.default_code)],
return res

Neat! Pretty straight forward, isn’t it? Odoo 12 doesn’t give you the opportunity to choose a predefined location for a product. If you combine change.qty with the above, you can soon have a great module to use to let Odoo choose a product from default location. Cool Idea?

Happy coding!

How to setup Postfix relay with authentication in CentOS 7

To configure postfix to relay mail using another MTA, you may do the following steps:

postconf -e 'relayhost ='
postconf -e 'smtp_sasl_auth_enable = yes'
postconf -e 'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd'
postconf -e 'smtp_sasl_security_options='

Replace with the original MTA hostname that you going to use for relaying. Now, create the sasl_passwd file in /etc/postfix with the following inside: smtp_username:smtp_password

Now, use postmap to generate postfix hash db:

postmap /etc/postfix/sasl_passwd

You can verify if it’s working with the following:

postmap -q /etc/postfix/sasl_passwd

This will return the username and password for your smtp relay host.

Now all you need to do is to restart the postfix

service postfix restart

How to Stop Redirecting All Traffic Trough OpenVPN

There are cases, where you might want to use OpenVPN to redirect only a fraction of traffic, but not all. By default, after you connect to OpenVPN, server would push the call 'redirect-gateway' to the client to make the client divert all the traffic through tun network.

This behavior can be override with the following command line argument:

--pull-filter ignore redirect-gateway

You can add it in the openvpn command line as following:

openvpn --pull-filter ignore redirect-gateway --config "your_file.ovpn"

Once this is done, remember that, you have to route the targetted traffic using either the route command or 'ip route' command, otherwise no traffic will route through your openvpn tunnel network.

How to Save OpenVPN Username & Password

If you are using OpenVPN in a Linux platform through command line, it is always handy to be able to save the authentication information in a file and let openvpn use them. There are two ways you can do it.

First Method

First save the password in a file e.g auth.txt with two lines:


First line is for username and the second line is for password.

If you are using .ovpn files for configuration, open the .ovpn file and simply add the following:

auth-user-pass auth.txt

Now, your authentication would use the authentication given in that file

Second Method

You may add the auth-user-pass in the openvpn command line argument, but you have to make sure, this is passed after the --config. Here is an example

openvpn --config "your_file.ovpn" --auth-user-pass "auth.txt"

That should be enough.

How to Add Custom Sale Order Line in Odoo 12

There are two ways you can add custom sale order line in Odoo 12.

First Method

You can search the sale order first with the name or browse with the ID

sale_order = self.env['sale.order'].search([('name', '=', 'SO009')])

Now, you can see the sale order line IDs using the following:


As this is a One2many relation, we need to use a tuple in the Odoo ORM write() method. Here is the list of data you can pass in a tuple to change data that has One2many or Many2many relation

Odoo ORM Documentation

You can now pass this as python dictionary for ‘order_line’ to sale.order of desired product as following:

'order_line': [
(0,0, {
'product_id': 2003,
'price_unit': 3000.0,
'product_uom_qty': 2.0,
'name': ''

Second Method

In this method, you can simply define the order dictionary, and create a sale.order.line item with the order_id in reference. Here is an example

# define dictionary to add order_line
order_line_dict = { 'order_id' : 9, 'product_id': 2003, 'price_unit': 3000.0, 'product_uom_qty': 2.0, 'name': '' }

# search the order line for the sale order
sale_order_line = self.env['sale.order.line'].browse(9)

# create a new order line

# print sale order lines


If you are doing/testing this on the Odoo Shell, then make sure to run the following after the changes to reflect on database:

Odoo doesn’t call database cursor commit if you are coding on Odoo shell, it calls automatically though if you are doing it in a module. Just a friendly reminder!

Troubleshoot: -bash: fuser: command not found

If you are trying to use a command, fuser, that is used to identify process using lock file or socket file, and having the following error:

-bash: fuser: command not found

that means, your system doesn’t have the psmisc package installed. Usually, killall, fuser type of commands are under this package. CentOS 7 sometimes, do not install the package by default. To install it, run the following:

yum install psmisc -y

Once done, you should be able to use fuser command.

How To: Use SSH Password in a Script

You can obviously use RSA public/private keypair to access servers without password, although, sometimes, it may be desirable to use ssh password on a command line and run a remote command on another server. This can be done using a tool called ‘sshpass’. You can create a simple bash script using sshpass, that can help you monitor and control multiple servers from a single location.

How to use ssh password in script

First install sshpass:

# yum install sshpass -y

Once done, you can use sshpass command as following:

# sshpass -p "SSH_Password" ssh -o StrictHostKeyChecking=no SSH_Username@remote-ssh-server "yourcommand"

Just replace, the password, username, remote-ssh-server and your command with your desired setup, and viola!

Note: If yum says, the following:

No package sshpass* available.

then you would need to install epel repository to install sshpass. To install epel, run the following:

# yum install epel* -y

Programming: How To Check if an IP is Available or Not in Bash

How To Check if an IP is Available or Not in Bash

A quick trick I use is ‘ping’ command. PING will return 0 on success and 1 or above on failure while using it with -c 1 (Means only one ICMP packet). That makes it useful to use with a if condition shell code as following:

if ping -c 1 -w 5 >/dev/null
echo "IP Available"
echo "IP Not Available"

Programming: How to Check If A File Exists or Not in Bash Script

How to Check If A File Exists or Not in Bash Script

You can use if condition in bash script to do that. If conditions takes ‘-f’ to test if a file exists or not. Syntax would be the following:

$FILE = $1
if [ -f $FILE ]; then
echo "File Exists"
echo "File Do Not Exist"

Now, if your script only demands to check if the file do not exist, you can use a unary operator for negate the boolean value as following:

$FILE = $1
if[ ! -f $FILE ]; then
echo "File Do Not Exist"