Importando y actualizando datos en Odoo con xmlrpc y archivos xlsx

Gustavo Orrillo
- 05/12/2022 - 2 min. de lectura

Es muy común tener que actualizar datos maestros de Odoo (por ejemplo productos y clientes) con archivos Excel (formato xlsx u csv). Para ello uno puede utilizar la interface de importación de Odoo, pero muchas veces la misma o no puede acomodar lógica del negocio para procesar las actualizaciones o no puede importar/actualizar miles de registros. 

Para ello una opción que tenemos es utilizar scripts de python con xmlrpc. En Python podemos leer archivos de Excel (hay librerías como xlrd, openpyxl o pandas que permiten hacerlo), entonces la idea es habiendo leído el archivo de Excel con Python, actualizar Odoo mediante xmlrpc. En este ejemplo tomaremos un archivo de productos con tres columnas: nombre, código y precio. Y con el mismo actualizaremos el maestro de productos de Odoo.


Este archivo tiene solo tres columnas las cuales se mapean al objeto product.template de la siguiente manera:

  • Nombre: name

  • Referencia: default_code

  • Precio: list_price

Debajo tenemos el código donde leemos el archivo de Excel con cada una de sus celdas

#!/usr/bin/python3

from xmlrpc import client
import openpyxl

url = 'http://localhost:8069'
common = client.ServerProxy('{}/xmlrpc/2/common'.format(url))

res = common.version()
dbname = 'mrputilsv1'
user = 'admin'
pwd = 'admin'
uid = common.authenticate(dbname, user, pwd, {})

# prints Odoo version and UID to make sure we are connected
print(res)
print(uid)

models = client.ServerProxy('{}/xmlrpc/2/object'.format(url))

# Define la variable para leer el workbook y lee el archivo
workbook = openpyxl.load_workbook("demo_products.xlsx")
# Define variable para la planilla activa
worksheet = workbook.active

# Itera las filas para leer los contenidos de cada celda
rows = worksheet.rows
for x,row in enumerate(rows):
    # Saltea la primer fila porque tiene el nombre de las columnas
    if x == 0:
        continue
    # Lee cada una de las celdas en la fila
    for i,cell in enumerate(row):
        print(i,cell.value)

Este código lista los contenidos de las celdas


Ahora necesitamos por cada fila, generar un diccionario con el valor de los campos a actualizar

# Lee cada una de las celdas en la fila
vals = {}
for i,cell in enumerate(row):
    if i == 0:
        col = 'name' 
    if i == 1:
        col = 'default_code' 
    if i == 2:
        col = 'list_price' 
    vals[col] = cell.value

El resultado del código es un diccionario con el diccionario que deberá insertarse o actualizar. Paso siguiente, es buscar el código del producto y determinar si se va a actualizar o crear el producto. Esto es fundamental, ya que garantiza que se pueda ejecutar los scripts de importación múltiples veces sin comprometer la integridad de los datos (que se corrompe al duplicarse la información).

# Busca el codigo de producto
product_tmpl_id = models.execute_kw(dbname,uid,pwd,'product.template','search',[[['default_code','=',vals.get('default_code')]]])
# si no se encuentra el producto, lo crea. Caso contrario lo actualiza
if not product_tmpl_id:
    return_id = models.execute_kw(dbname,uid,pwd,'product.template','create',[vals])
else:
    return_id = models.execute_kw(dbname,uid,pwd,'product.template','write',[product_tmpl_id,vals])
print(return_id)

Lo que al ejecutarse, actualiza los productos en Odoo y deja este resultado final


El código de ejemplo de lo que acabamos de describir, lo pueden descargar del repositorio de github

https://github.com/ctmil/tutorial_xmlrpc/blob/master/sync_xlsx.py

Acerca de:

Gustavo Orrillo

Passionate about programming, he has implemented Odoo for different types of businesses since 2010. In Moldeo Interactive he is a founding Partner and Programmer; In addition to writing on the Blog about different topics related to the developments he makes.