Importando y actualizando datos en Odoo con xmlrpc y archivos xlsx
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
Apasionado de la programación, implementa Odoo para distintos tipos de negocios desde el año 2010. En Moldeo Interactive es Socio fundador y Programador; además de escribir en el Blog sobre distintos temas relacionados a los desarrollos que realiza.