-
chevron_right
Upgrading to Odoo 12
jnanar · Saturday, 23 February, 2019 - 11:00 · 5 minutes
Odoo 12.0 is out since october. I am currently investigating the differences with previous versions to update the instance of the association Les Compagnons du CEP . A lot of changes have been made in a few years but the workflow stays about the same. This article describes my workflow, the backup policy, how a module was used and fixed to restore a missing feature. Finally, the changes in my custom product import function are presented.
Production and debug setup
Agayon.be instance of Odoo runs inside a Docker container on a small VPS. Postgresql is installed as a core package. This setup is great in production but it is difficult to debug some python code with this configuration. The first step is to run Odoo with an IDE (I personally use the excellent Pycharm ).
Running and debugging Odoo
The first step is the creation of the virtualenv. Once the Postgresql instance is ready , you can build the environment.
git clone https://www.github.com/odoo/odoo --depth 1 --branch 12.0$ virtualenv myenv$ source myenv/bin/activate(myenv)$ pip install -r odoo/requirements.txt(myenv)$ mkdir custom-addons(myenv)$ chown odoo: odoo11-custom-addons
Edit odoo.conf and then run odoo:
odoo/odoo-bin -c odoo.conf
Merge purchase order
UPDATE: 23/02/2019: The following paragraph is not needed anymore. Odoo 12 restored the automatic merge of purchase orders.
Unfortunately, a major feature has disappeared in version 12.0: automatic merge of purchase order. I don't know why since it seems unrealistic to send each quotation separately to your vendor. Fortunately a free module can be used to perform the merge but it has a critical bug. Some quotation lines are merged even if they concerns different products .
Fix
After forking it, I decided to start by refactoring it. The module is quite small but a lot of code is duplicated. As I try to avoid spaghetti code , it needed to be refactored .I think the new code may be improved but no line is duplicated. Finally, the bug has been fixed .
Backup management
Since a few version, the filestore
is mandatory in Odoo. If it is incoherent with the database, some really annoying errors are raised and the solution is quite tedious. My backup procedure has been updated to avoid losing any data. It is based on the article from zeroheure . The backups are saved with the auto_backup module. Restoring the data is not possible with the web interface because the process reaches the memory limit but it can be performed with the following shell script.
#!/bin/bashBACKUPLOCATION="/path/to/backup.zip"DBNAME="db_name"FILESTORE_DIR="/path/to/filestore"if[ -z "$FILESTORE_DIR"]||[ -z "$DBNAME"]||[ -z "$BACKUPLOCATION"]thenecho"verify your variables"elsecd$BACKUPLOCATION rm filestore unzip -q $DBNAME.zip cp -r filestore $DBNAME sudo rm -rf $FILESTORE_DIR/$DBNAME sudo mv $DBNAME$FILESTORE_DIR sudo chown -R odoo:odoo $FILESTORE_DIR/$DBNAME dropdb -U odoo $DBNAME createdb -U odoo $DBNAME psql $DBNAME --quiet < dump.sqlfi
Wine import with Django website
Version 12.0 needs some minor changes in the code displayed in the previous article .These modifications includes:
- removing state property in the product template.
- Adding the invoice_policy and purchase_method in the product template. 1
- Add a reference to the standard price in the product_supplierinfo dictionary. This value is used in the orders when purchasing wines to suppliers.
defresearch(default_code,supplier_code,wine_name):# 1) search if default code is used?)# 2) search if suppliers is in the database# 3) search if the name is already used# Retrieve the dataframes. This example comes from a jupyter nootebook.# df_product and df_sellers are already defined.# In a real case, we should use class variables.n_code,df_code=search_df(df=df_product,col_name='default_code',search_item=default_code,search_int=False)n_supplier,df_suppliers=search_df(df=df_suppliers,col_name='function',search_item=supplier_code,search_int=False)n_name,df_name=search_df(df=df_product,col_name='name',search_item=wine_name,search_int=False)try:# ids_product = list(df_code['id'])ids_product=df_code['id'].tolist()exceptAttributeError:ids_product=[]ifn_code==0andn_name==0andn_supplier!=0:return'success',ids_product,n_supplier,n_nameifn_code!=0andn_name!=0:# Another product uses the same name with another codereturn'e_code_used_same_name',ids_product,n_supplier,n_nameifn_code!=0:# the code is already usedreturn'e_code_used',ids_product,n_supplier,n_nameifn_supplier==0:# Cannot find the supplierreturn'e_missing_seller',ids_product,n_supplier,n_nameifn_name!=0:# A product with the same name and another code exists.return'e_code_used_different_name',ids_product,n_supplier,n_namedefimport2odoo():route_warehouse0_mto=1route_warehouse0_manufacture=5[...]# iterate over all rows, read the cells and assign the wine parameters to variables# each row correspond to one wineforrowinrows:seller_name=row[0]default_code=row[1]name=row[2]do_import=row[2]comment=row[3]name=row[4]default_code=row[5]standard_price=row[6]list_price=row[7]seller_code=row[8]res_search,ids_product,n_supplier,n_name=research(default_code,seller_code,name)ifres_search=='success'anddo_import=="1":product_template={'name':name,'active':True,'standard_price':standard_price,'list_price':list_price,'description':comment,'default_code':default_code,'purchase_ok':1,'sale_ok':1,'uom_id':1,'uom_po_id':1,'type':'product','cost_method':'standard','invoice_policy':'order',# ordered quantities'purchase_method':'receive',# control received quantities (or ordered ones, test to delivery)'route_ids':[(6,0,[route_warehouse0_mto,route_warehouse0_manufacture])]}# For each wine, a template must be createdtemplate_id=sock.execute(dbname,uid,pwd,'product.template','create',product_template)# Create the supplier information for the wineproduct_supplierinfo={'name':name,'product_code':row[1],# code for supplier'product_name':row[15],# name for supplier'min_qty':1,'delay':300,'product_tmpl_id':template_id,'price':standard_price,}# Create the supplier information for the wineproduct_supplierinfo_id=sock.execute(dbname,uid,pwd,'product.supplierinfo','create',product_supplierinfo)logging.info("Wine {} : {} has been added".format(default_code,name))[...]# Here we take into account the exceptions and several cases: the wine is already present, the seller is missing etc.
Conclusions
After using Odoo in production for 4 years, I still love it. My users are happy to use it daily and the improvements over the year are impressive. Like any other alive project, some changes may break the workflow but Odoo and it's community make it relatively simple to adapt with plugins. Odoo 12 is strong and I look forward to use it for the next 3 years :-).