Skip to main content

Odoo Tips

//create a module
sudo odoo scaffold <module_name>

Run odoo in server from Command line


Run under root user permission

python3.6 ./odoo-bin --addons=~/odoo/odoo/addons,~/odoo/pranav/<custom module>,~/odoo/accounting_reports --xmlrpc-port=8085 -d <database name>

Run under different user with different DB server(Eg:Odoo)
  • First switch to odoo user:
sudo su - odoo -s /bin/bash
  • Run the script
./odoo-bin --addons-path=/opt/odoo/addons,/opt/test_addons --db_host=<ip address> --db_port=<port> --db_password=<password> --database=<db name> -u <user name> --db-filter=<db name> --xmlrpc-port=1122

Nohup-to run a service without writing service file :-

nohup python3.6 ./odoo-bin --addons=~/odoo/odoo/addons,~/odoo/pranav/<custom module>,~/odoo/accounting_reports --xmlrpc-port=8085 -d <database name> &

ODOO

QWEB

Datetime operation

------------------------------------
<span  t-set="d1" t-value="datetime.datetime.now()"/>
                     <t t-set="d2" t-value="datetime.datetime.strptime(line.date_maturity,'%Y-%m-%d')"/>
                     <span t-esc="(d1-d2).days"/>
                     <t t-esc="d1"/>


Change Date Format

----------------------------------------


<span t-esc="datetime.datetime.strptime(o.date_stop, '%Y-%m-%d').strftime('%m/%d/%Y')"/>





Add 2 decimal precision 

------------------------------
<span t-esc=”’%.2f’%(t.amount)”></span


Or


<span t-esc="'{0:,.2f}'.format(float(line['amount']))"/>


Add total under a field

-----------------------------
<table>
<tr>
…...
<td style="border:1px solid #000;border-collapse: collapse;">
                                 <span t-esc="line['number']"/>
<t t-set="total" t-value="total + line['number']"/>
                              </td>
………
</tr>
<tr>
…….
<td><span t-esc=”total”/>
</tr>
</table>


Time only Field

---------------------
start_time: fields.float('Start Time')

<field name="start_time" widget="float_time"/>

Space After invoice lines

------------------------------------------------

                            <tr t-foreach="range(10-int(len(o.invoice_line_ids)%10))" style="height:10mm;border-right:1px solid black;" t-as="i">
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                                <td style="border:1px solid black;"/>
                            </tr>



Odoo Tree/Form View



Confirm Message On Button Click

-----------------------------------------------
<button name="download_attendance" type="object" string="Download Data" class="oe_highlight" icon="fa-download " confirm="Are you sure you want to do this?" />


Tree view color

----------------------------------------


Version 11:




<tree colors="your_color:field== 'value'">
Eg: <tree colors="grey:state == 'cancel'">


decoration-bf - shows the line in BOLD 
decoration-it - shows the line in ITALICS 
decoration-danger - shows the line in LIGHT RED 
decoration-info - shows the line in LIGHT BLUE 
decoration-muted - shows the line in LIGHT GRAY 
decoration-primary - shows the line in LIGHT PURPLE 
decoration-success - shows the line in LIGHT GREEN 
decoration-warning - shows the line in LIGHT BROWN


<tree decoration-success="state=='done'">

Show total of a field in tree view

----------------------------------------
<field name=”name” sum=”total”>

Header button

------------------
<header>
                     <button class="oe_stat_button" type="action" name="271" context="{'search_default_partner_id': active_id, 'default_partner_id': active_id}" icon="fa-tasks" string="Contracts">
                     </button>
                 </header>

Add attribute to hide a field

----------------------------------


<field name="hours_spend_visa" attrs="{'invisible':[('is_visa', '=', False)]}"/>

Add multiple fields inline

------------------------------


<label for="hours_spend_visa" string="Hours Spend" class="oe_inline" attrs="{'invisible':[('is_visa', '=', False)]}"/>
<field name="hours_spend_visa" style="width:10%" class="oe_inline" attrs="{'invisible':[('is_visa', '=', False)]}"/>


Inherit Page/Notebook

----------------------------
<xpath expr="//notebook[last()]" position="inside">
</xpath
Or
<xpath expr="//page[last()]" position="inside">
</xpath>

Comma Seperator

-----------------------------------


<td><span t-esc="'{:,}'.format(l.price_subtotal)"/></td>


Total in words

---------------


<strong>
Dirhams 
<span t-esc=”o.amount” t-esc-options=’{“widget”:”num2words”,”case”:”capital”}’/>
Only
</strong>


Drag and drop tree view lines

-----------------------------------------------------------


name="sequence" widget="handle"


Alter record rule with noupdate true

--------------------------------------------------------------------


Change noupdate to False first


   <function name="write" model="ir.model.data">
        <function name="search" model="ir.model.data">
            <value eval="[('module', '=', 'portal_sale'), ('name', '=', 'portal_personal_contact')]"/>
        </function>
        <value eval="{'noupdate': False}" />
    </function>


    <function name="write" model="ir.model.data">
        <function name="search" model="ir.model.data">
            <value eval="[('module', '=', 'base'), ('name', '=', 'res_partner_portal_public_rule')]"/>
        </function>
        <value eval="{'noupdate': False}" />
    </function>

Now alter the record rule

    <record id="portal_sale.portal_personal_contact" model="ir.rule">
        <field eval="False" name="active"/>
        <field eval="False" name="noupdate"/>
    </record>

    <record model="ir.rule" id="base.res_partner_portal_public_rule">
        <field eval="False" name="active"/>
        <field eval="False" name="noupdate"/>
    </record>

PYTHON



Decorators

Class methods required single invoking object (Single Browsable Record) to invoke the method and suppose it will call by multiple invoking objects (Browsable Recordsets) then method is not able to identify for which object it should process, therefore it will raise an error Expected Singleton.
New API decorator is used to define method calling pattern whether methods allows only single object or multiple objects to invoke this method.
@api.one
This decorator loops automatically on Records of RecordSet for you. Self is redefined as current record
Note: Caution: the returned value is put in a list. This is not always supported by the web client, e.g. on button action methods. In that case, you should use @api.multi to decorate your method, and probably call self.ensure_one() in the method definition.
@api.multi
Self will be the current RecordSet without iteration. It is the default behavior (multiple browsable objects). Methods which returns non premitive type data(list, dictionary, function) must be decorated with @api.multi
@api.model
This decorator will convert old API calls to decorated function to new API signature. It allows to be polite when migrating code. Self does not contain any record/recordset in methods which are decorated by this decorator.

Create Many2many field from script



(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


HR Payroll



If creating allowance or deduction with dynamic value


In salary rule mention below fields like:-


Amount Type Python Code


From Payslip:-
result = -payslip.total_paid(For deduction)
result = payslip.total_paid(For allowance)
From Salary Rule Category:-
result = categories.BASIC(Give category total)
Mention a float field in employee payslip , it should have same name as mentioned above.


OR

/*Add below python script in salary rule with corresponding methord*/
  result=payslip.env['hr.payslip'].advance_grat(employee.id,payslip.date_from,payslip.date_to)

/*In ‘hr.payslip’ class add below method for transactions’*/   
@api.multi
 def advance_grat(self,emp_id,date_from,date_to):
        rule_id  = self.env['hr.salary.rule'].search([('code','=','AGR')])
        amount = 0
        if rule_id:
            amount=self.env['hr.payroll.transactions'].search([('rule_id','=',rule_id.id),
('date','<=',date_to),('date','>=',date_from),
('employee_id','=',emp_id)]).amount
        return amount


SCRIPTING



Create key value easily



c_exist.setdefault(follower.channel_id.id, list()).append(follower.res_id)


Smart Button

@api.multi
def action_show_booking(self):
     action = self.env.
ref('orchid_travels_v10.act_od_view_booking').read()[0]
     opp_id = self.id
     booking_ids = []
     booking_lines = self.env['travel.booking'].search([('opportunity_id','=',opp_id)])
     for line in booking_lines:
         booking_ids.append(line.opportunity_id and line.opportunity_id.id)
         
     domain = []
     if not booking_ids:
         raise Warning("no contract found")
         
     domain.append(('id','in',booking_ids))


     action['domain'] = domain
     action['context'] = "{'default_opportunity_id':"+str(self.id)+"}"
     return action

Server action



id=[310]
orders = env['pos.order'].browse(id)
for order in orders:
discount_product_id = order and order.session_id and order.session_id.config_id and order.session_id.config_id.discount_product_id and order.session_id.config_id.discount_product_id.id or False
if order.statement_ids:
     for stmt in order.statement_ids:
         if stmt.journal_id.od_is_discount:
             vals={
             'product_id':discount_product_id,
             'qty':1,
             'price_unit':-(stmt.amount),
             'order_id':order.id,
             'od_cost':0,              
             }
             env['pos.order.line'].create(vals)

//No need of self


Create lines from onchange

    @api.onchange('kg_sf_id')
    def onchange_sale_forcast(self):
        prod_shft_line_objs = self.env['kg.prod.shift.line']
        for record in self:
            if self.kg_sf_id:
                for line in self.kg_sf_id.kg_lines:
                    data = {
                        'kg_product':line.kg_product_id and line.kg_product_id.id,
                        'kg_qty':line.kg_net,
                    }
                    line = prod_shft_line_objs.new(data)
                    prod_shft_line_objs += line
            record.kg_shift_lines = prod_shft_line_objs



XML



Filters for Date Field

 

 

This week


<filter string="This Week"  name="This Week" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d')))]"
                        help="This Week"/>

Last Week


<filter string="Last Week"  name="Last Week" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=-7)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()).strftime('%Y-%m-%d')))]"
                        help="This Week"/>

yesterday



<filter string="Yesterday"  name="Yesterday" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=-1)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=-1)).strftime('%Y-%m-%d')))]"
                        help="Yesterday"/>


Today



<filter string="Today"  name="Today" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=0)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=0)).strftime('%Y-%m-%d')))]"
                        help="Today"/>


Tomorrow


<filter string="Tomorrow"  name="Tomorrow" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d')))]"
                        help="Tomorrow"/>


Expiry


<filter string="Immediate Expiry"  name="Immediate Expiry" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=0)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=45)).strftime('%Y-%m-%d')))]"
                        help="Immediate Expiry"/>

Last Month



<filter icon="terp-go-month" string="Last Month"
                      domain="[('date_from','&lt;=', (context_today()-relativedelta(day=31, months=1)).strftime('%Y-%m-%d')),
                      ('date_from','&gt;=',(context_today()-relativedelta(day=1,months=1)).strftime('%Y-%m-%d'))]"
                      help="last month"/>


Current Month



<filter string="Current Month" name="current_month" domain="[('date_from','&lt;',(context_today()+relativedelta(months=1)).strftime('%Y-%m-01')), ('date_from','&gt;=',time.strftime('%Y-%m-01'))]"/>

Last Year

<filter  icon="terp-go-month" string="Last Year"
                domain="[('date', '&gt;=' ,(context_today()-relativedelta(years=1)).strftime('%Y-01-01')),('date','&lt;=',time.strftime('%Y-01-01'))]" help="last year"/>

This Year

<filter icon="terp-go-year" string="Year"
                         domain="[('date_from','&lt;=', time.strftime('%Y-%m-%d')),('date_from','&gt;=',time.strftime('%Y-01-01'))]"
                         help="Current Year"/>





Filters for Date Field

 

 

This week


<filter string="This Week"  name="This Week" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d')))]"
                        help="This Week"/>

Last Week


<filter string="Last Week"  name="Last Week" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=-7)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()).strftime('%Y-%m-%d')))]"
                        help="This Week"/>

yesterday



<filter string="Yesterday"  name="Yesterday" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=-1)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=-1)).strftime('%Y-%m-%d')))]"
                        help="Yesterday"/>


Today



<filter string="Today"  name="Today" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=0)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=0)).strftime('%Y-%m-%d')))]"
                        help="Today"/>


Tomorrow


<filter string="Tomorrow"  name="Tomorrow" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=1)).strftime('%Y-%m-%d')))]"
                        help="Tomorrow"/>


Expiry


<filter string="Immediate Expiry"  name="Immediate Expiry" separator="1"
                      domain="[('date_from','&gt;=', ((context_today()+datetime.timedelta(days=0)).strftime('%Y-%m-%d'))), ('date_from','&lt;=', ((context_today()+datetime.timedelta(days=45)).strftime('%Y-%m-%d')))]"
                        help="Immediate Expiry"/>

Last Month



<filter icon="terp-go-month" string="Last Month"
                      domain="[('date_from','&lt;=', (context_today()-relativedelta(day=31, months=1)).strftime('%Y-%m-%d')),
                      ('date_from','&gt;=',(context_today()-relativedelta(day=1,months=1)).strftime('%Y-%m-%d'))]"
                      help="last month"/>


Current Month



<filter string="Current Month" name="current_month" domain="[('date_from','&lt;',(context_today()+relativedelta(months=1)).strftime('%Y-%m-01')), ('date_from','&gt;=',time.strftime('%Y-%m-01'))]"/>

Last Year

<filter  icon="terp-go-month" string="Last Year"
                domain="[('date', '&gt;=' ,(context_today()-relativedelta(years=1)).strftime('%Y-01-01')),('date','&lt;=',time.strftime('%Y-01-01'))]" help="last year"/>

This Year

<filter icon="terp-go-year" string="Year"
                         domain="[('date_from','&lt;=', time.strftime('%Y-%m-%d')),('date_from','&gt;=',time.strftime('%Y-01-01'))]"
                         help="Current Year"/>





ODOO-8.0


SCRIPTING

Server action



id=[21]
vals = self.pool['sale.order'].browse(cr, uid, 21, context)
for val in vals:
if val.id==21:
     val.write({'state':'draft'})







Odoo Setup

Create a custom module

sudo odoo scaffold <module_name>
Or
python ../odoo/odoo-bin scaffold <module_name>



POSTGRES

Kill session from psql



SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname ='aasons_live';

CREATE NEW USER

createuser --createdb --username postgres --no-createrole --pwprompt <user_name>


JOINING TABLES

 

a)Table:CUSTOMERS

b)Table:ORDERS









Now, let us join these two tables in our SELECT statement as follows:


SELECT ID, NAME, AGE, AMOUNT FROM CUSTOMERS, ORDERS
WHERE  CUSTOMERS.ID = ORDERS.CUSTOMER_ID;


This would produce the following result:









1.Left Joining



The SQL LEFT JOIN returns all rows from the left table, even if there are no matches in the right table. This means that if the ON clause matches 0 (zero) records in right table, the join will still return a row in the result, but with NULL in each column from right table.


This means that a left join returns all the values from the left table, plus matched values from the right table or NULL in case of no matching join predicate.
Syntax:


The basic syntax of LEFT JOIN is as follows:


SELECT table1.column1, table2.column2...
FROM table1
LEFT JOIN table2
ON table1.common_field = table2.common_field;
Now, let us join these two tables using LEFT JOIN as follows:


SELECT  ID, NAME, AMOUNT, DATE FROM CUSTOMERS
LEFT JOIN ORDERS
ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;














2.Inner Joining



The INNER JOIN creates a new result table by combining column values of two tables (table1 and table2) based upon the join-predicate. The query compares each row of table 1 with each row of table2 to find all pairs of rows which satisfy the join-predicate. When the join-predicate is satisfied, column values for each matched pair of rows of A and B are combined into a result row.
Syntax:


The basic syntax of INNER JOIN is as follows:


SELECT table1.column1, table2.column2...
FROM table1
INNER JOIN table2
ON table1.common_field = table2.common_field;


Example:
Now, let us join these two tables using INNER JOIN as follows:


SELECT  ID, NAME, AMOUNT, DATE FROM CUSTOMERS
INNER JOIN ORDERS
ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;
















3.Right Joining



The SQL RIGHT JOIN returns all rows from the right table, even if there are no matches in the left table. This means that if the ON clause matches 0 (zero) records in left table, the join will still return a row in the result, but with NULL in each column from left table.


This means that a right join returns all the values from the right table, plus matched values from the left table or NULL in case of no matching join predicate.
Syntax:


The basic syntax of RIGHT JOIN is as follows:


SELECT table1.column1, table2.column2...
FROM table1
RIGHT JOIN table2
ON table1.common_field = table2.common_field;

Now, let us join these two tables using RIGHT JOIN as follows:


SELECT  ID, NAME, AMOUNT, DATE FROM CUSTOMERS
RIGHT JOIN ORDERS
ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;


This would produce the following result:















4.Full Joining



The SQL FULL JOIN combines the results of both left and right outer joins.
The joined table will contain all records from both tables, and fill in NULLs for missing matches on either side.
Syntax:


The basic syntax of FULL JOIN is as follows:


SELECT table1.column1, table2.column2...
FROM table1
FULL JOIN table2
ON table1.common_field = table2.common_field;


Now, let us join these two tables using FULL JOIN as follows:


 SELECT  ID, NAME, AMOUNT, DATE  FROM CUSTOMERS
 FULL JOIN ORDERS
 ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;


This would produce the following result:





















5.Self Joining



The SQL SELF JOIN is used to join a table to itself as if the table were two tables, temporarily renaming at least one table in the SQL statement.
Syntax:


The basic syntax of SELF JOIN is as follows:


SELECT a.column_name, b.column_name...
FROM table1 a, table1 b
WHERE a.common_field = b.common_field;

Now, let us join this table using SELF JOIN as follows:


SELECT  a.ID, b.NAME, a.SALARY FROM CUSTOMERS a, CUSTOMERS b
WHERE a.SALARY < b.SALARY;


This would produce the following result:






































6.Cartesian Product



The CARTESIAN JOIN or CROSS JOIN returns the Cartesian product of the sets of records from the two or more joined tables. Thus, it equates to an inner join where the join-condition always evaluates to True or where the join-condition is absent from the statement.
Syntax:


The basic syntax of CARTESIAN JOIN is as follows:


SELECT table1.column1, table2.column2...
FROM  table1, table2 [, table3 ]


Now, let us join these two tables using CARTESIAN JOIN as follows:


SELECT  ID, NAME, AMOUNT, DATE
FROM CUSTOMERS, ORDERS;


This would produce the following result:







Comments

Popular posts from this blog

How to create multiple services of Odoo(above version 10) on windows

In this post, I will explain how we can create multiple Odoo services in a Windows Server. Step 1 First, you need to get the executable file from the Odoo link mentioned below Or open the already existing executable file.   https://www.odoo.com/page/download   If you are running the executable file for the second time uncheck Postgres installation since it is already done in the first install. Keep a note of your installation path. Step 2 Go to the below path where "Odoo 12.0 Test" is the directory your new installation files belong to: C:\Program Files (x86)\Odoo 12.0 Test\nssm\win64\ Open the command prompt  and type the below command: nssm install odoo-server-TEST   A User Interface similar to the image below will popup, you have to fill the three empty fields with values I mentioned below Step 3 Path : C:\Program Files (x86)\Odoo 12.0 Test\Python\python.exe Startup directory : C:\Program Files (x86)\Odoo 12.0 Test\server Arguments : "C:\Program Files (x86)\Odoo 1...

INSTALL ODOO-10.0 Community version in debian based system(ubuntu)

INSTALL ODOO-10.0 Community version in debian based system(ubuntu) ====================================================== >>sudo wget -O - https://nightly.odoo.com/odoo.key | sudo apt-key add - Type the below code and paste "deb http://nightly.odoo.com/10.0/nightly/deb/ ./" >>sudo nano /etc/apt/sources.list.d/odoo.list >>sudo apt-get update && sudo apt-get install odoo Do you want to continue? [Y/n] (type y) Source code --------------- Now odoo is installed in your linux system. Use " sudo service odoo restar t" to restart odoo if you are changing the conf file settings. You will get the source code in git. "git clone https://github.com/odoo/odoo.git" to clone from git Note:Better to download the zip file from above link as cloning consumes lot of time. Odoo dependencies: ------------------------ * python 2.7(already available in linux) * NodeJS(already available)  To upgrade:  >>sudo apt-get ins...