Descarga masiva datos en Odoo

Odoo XML RPC Extract

Descargar script

Herramienta en Python para extraer datos de Odoo mediante XML-RPC y exportarlos a archivos CSV, con soporte especial para enriquecer reportes de ausencias (hr.leave.report) con información semanal del módulo OCA date.range.

🎯 Descripción general

Este proyecto se conecta a una instancia de Odoo a través del protocolo XML-RPC, autentica al usuario, consulta uno o varios modelos configurables y guarda los resultados en archivos CSV con marca de tiempo dentro de la carpeta output/.

Está diseñado con dos flujos de extracción:

  1. Extracción genérica — para cualquier modelo de Odoo (res.partner, sale.order, etc.).
  2. Extracción especializada de hr.leave.report — enriquece cada registro de ausencia con el número de semana, nombre de rango y año tomados del módulo OCA date.range. Si no encuentra coincidencia, calcula la semana ISO a partir de la fecha como respaldo.

📁 Estructura del proyecto

extract_data/
├── .env                  ← credenciales (no compartir)
├── .env.example          ← plantilla de credenciales
├── README.md             ← documentación breve original
├── DOCUMENTACION.md      ← este archivo (documentación extendida)
├── models_config.py      ← configuración de modelos, campos y filtros
├── odoo_extractor.py     ← script principal
├── requirements.txt      ← dependencias de Python
├── setup.sh              ← script de instalación automática
├── output/               ← carpeta donde se guardan los CSV generados
└── venv/                 ← entorno virtual de Python

⚙️ Requisitos

  • Python 3.8+
  • Acceso a una instancia de Odoo con API XML-RPC habilitada
  • Usuario con permisos de lectura sobre los modelos a extraer
  • Módulo OCA date.range instalado en Odoo (solo si se usa la extracción de hr.leave.report con enriquecimiento de semanas)

Dependencias (requirements.txt)

python-dotenv>=1.0.0

El módulo xmlrpc.client forma parte de la librería estándar de Python, no requiere instalación adicional.

🚀 Instalación

Opción A — Automática (recomendada)

bash setup.sh

El script setup.sh realiza lo siguiente:

  1. Crea un entorno virtual venv/.
  2. Activa el entorno virtual.
  3. Actualiza pip.
  4. Instala las dependencias de requirements.txt.
  5. Crea la carpeta output/ si no existe.
  6. Copia .env.example a .env si no está presente.

Opción B — Manual

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
mkdir -p output

🔐 Configuración de credenciales

Editar el archivo .env con los datos de conexión a Odoo:

ODOO_URL=https://tu-instancia-odoo.com
ODOO_DB=nombre_de_base_de_datos
ODOO_USER=usuario@correo.com
ODOO_PASSWORD=tu_contraseña

⚠️ Nunca subas el archivo .env a un repositorio público. Agrégalo a .gitignore.

🧩 Configuración de modelos (models_config.py)

Este archivo define qué extraer de Odoo. Tiene tres elementos principales:

1. MODELS_CONFIG — Modelos y campos

Diccionario donde cada clave es el nombre técnico del modelo de Odoo y el valor es la lista de campos a extraer.

MODELS_CONFIG = {
    "hr.leave.report": [
        "id",
        "name",
        "employee_id",
        "leave_type",
        "category_id",
        "holiday_type",
        "department_id",
        "holiday_status_id",
        "date_from",
        "date_to",
        "number_of_days",
    ],
    # "res.partner": ["id", "name", "email", "phone"],
}

📌 Importante: los campos week_number, week_name y week_year se agregan automáticamente en la extracción de hr.leave.report. No se deben listar aquí.

2. MODELS_FILTERS — Filtros por modelo

Filtros en formato de dominio Odoo (lista de tripletas [campo, operador, valor]).

MODELS_FILTERS = {
    "hr.leave.report": [
        ["state", "in", ["validate", "validate1"]],   # solo ausencias aprobadas
        ["date_from", ">=", "2026-01-01"],            # desde inicio de año
    ],
}

Si un modelo no aparece en este diccionario o tiene filtros [], se traerán todos los registros.

3. MAX_RECORDS — Límite de registros

MAX_RECORDS = 0    # 0 = sin límite; usar 100 para pruebas

▶️ Ejecución

source venv/bin/activate
python odoo_extractor.py

Salida esperada en consola

=======================================================
  Odoo Data Extractor — hr.leave.report + Semanas
=======================================================
12:34:56 [INFO] Connecting to https://tu-odoo.com  |  DB: mi_db  |  User: correo@...
12:34:57 [INFO] Authenticated successfully (uid=7)

▶ Model: hr.leave.report
  Fetching 'hr.leave.report'  fields=[...]  filter=[...] ...
  → 245 records retrieved

▶ Fetching week ranges from date.range (OCA)...
  → Found weekly range type(s): ['Semanas']
  → 260 date ranges loaded
  → 243/245 records matched to a week range
  ✓ Saved → output/hr_leave_report_20260416_123501.csv
=======================================================
  Done! Archivos guardados en ./output/
=======================================================

🗂️ Salida (archivos CSV)

Cada modelo genera un archivo CSV independiente en la carpeta output/, con timestamp para evitar sobrescribir ejecuciones previas:

output/hr_leave_report_20260416_123501.csv
output/res_partner_20260416_123502.csv

Transformaciones aplicadas al guardar

Tipo de campo Odoo Valor original Valor en CSV
Many2one (ej. employee_id) [7, 'Juan Pérez'] Juan Pérez
Campo vacío False "" (cadena vacía)
Fecha / fecha-hora '2026-03-15' o '2026-03-15 10:30:00' sin cambios
Otros valores tal cual tal cual

🧠 Funciones principales (odoo_extractor.py)

connect_odoo()

Carga credenciales desde .env, autentica contra el endpoint /xmlrpc/2/common y devuelve el proxy de modelos junto al uid, db y password necesarios para las llamadas posteriores a /xmlrpc/2/object.

flatten_value(value)

Normaliza los valores devueltos por Odoo. Convierte los campos Many2one [id, 'Nombre'] en solo 'Nombre', y los False en cadena vacía.

parse_odoo_date(date_str)

Convierte cadenas de fecha de Odoo ('YYYY-MM-DD' o 'YYYY-MM-DD HH:MM:SS') a objetos date de Python, tolerando valores vacíos o mal formateados.

fetch_week_ranges(models, uid, db, password)

Consulta los tipos de rango disponibles en date.range.type y filtra aquellos cuyo nombre contenga palabras como week, semana, wk o sem. Luego carga todos los registros de date.range de esos tipos, extrae el número de semana desde el nombre del rango (ej. "Semana 10 2026") o, si no es posible, lo calcula con isocalendar(). Devuelve una lista ordenada por fecha de inicio para permitir búsqueda rápida.

find_week_for_date(record_date, week_ranges)

Dado una fecha y la lista de rangos semanales, devuelve el diccionario de la semana donde cae la fecha o None si no hay coincidencia.

fetch_model(models, uid, db, password, model_name, fields, filters, limit)

Ejecuta search_read sobre un modelo arbitrario de Odoo y devuelve la lista de diccionarios resultante.

save_to_csv(records, model_name, fields, extra_fields=None)

Escribe los registros a un CSV con encabezado, aplicando flatten_value a cada celda. Acepta columnas extra (usadas para week_number, week_name, week_year).

extract_leave_report(models, uid, db, password)

Flujo especializado: descarga los registros de hr.leave.report, obtiene los rangos semanales del módulo date.range, empareja cada ausencia con su semana correspondiente usando date_from como fecha de referencia y agrega tres columnas (week_number, week_name, week_year). Si un registro no coincide con ningún rango OCA, calcula la semana ISO como respaldo.

extract_generic(models, uid, db, password, model_name)

Flujo estándar sin enriquecimiento, aplicado a cualquier modelo distinto de hr.leave.report.

main()

Punto de entrada. Itera sobre MODELS_CONFIG y decide qué flujo usar por modelo, capturando errores por modelo para que un fallo no detenga el resto de la extracción.

🔄 Flujo de ejecución (resumen)

  1. Se cargan variables de entorno desde .env.
  2. Se autentica contra Odoo vía XML-RPC.
  3. Por cada modelo en MODELS_CONFIG:
    • Si es hr.leave.report → se ejecuta el flujo enriquecido con semanas OCA.
    • En caso contrario → se ejecuta el flujo genérico.
  4. Se guarda un CSV por modelo con timestamp en output/.
  5. Los errores por modelo se registran pero no abortan la ejecución.

🛠️ Casos de uso comunes

Agregar un nuevo modelo a extraer

En models_config.py:

MODELS_CONFIG = {
    "hr.leave.report": [...],
    "res.partner": ["id", "name", "email", "phone", "country_id"],
    "sale.order":  ["id", "name", "partner_id", "date_order", "amount_total", "state"],
}

MODELS_FILTERS = {
    "sale.order": [["state", "=", "sale"]],
}

Probar con pocos registros

MAX_RECORDS = 50

Cambiar la fecha de referencia para el cálculo de la semana

En extract_leave_report(), cambiar la línea:

date_field = "date_from"   # o "date_to"

⚠️ Consideraciones y notas

  • hr.leave.report es una vista SQL de Odoo, por lo que es solo lectura. Este script no la modifica.
  • Los errores de autenticación o de credenciales faltantes se reportan con mensajes claros y el script termina sin continuar.
  • Un fallo en la extracción de un modelo (xmlrpc.client.Fault u otras excepciones) no interrumpe el procesamiento de los modelos restantes.
  • Si el módulo OCA date.range no está instalado o no hay tipos con nombre tipo "semana/week", el script cae en la estrategia de respaldo usando isocalendar().
  • El archivo .env debe tener permisos restrictivos (chmod 600 .env) para proteger las credenciales.

🧪 Solución de problemas

Síntoma Causa probable Solución
Missing credentials. Check your .env file Variables vacías en .env Completar ODOO_URL, ODOO_DB, ODOO_USER, ODOO_PASSWORD
Authentication failed Usuario/contraseña incorrectos o XML-RPC deshabilitado Verificar credenciales y que el endpoint /xmlrpc/2/common responda
Odoo error on 'xxx': Object xxx doesn't exist Nombre de modelo mal escrito Revisar el nombre técnico en Odoo (Ajustes → Técnico → Modelos)
No weekly date range type found Módulo date.range no instalado o sin tipos semanales Instalar el módulo OCA date.range y crear un tipo "Semanas"
CSV vacío Filtros demasiado restrictivos en MODELS_FILTERS Ajustar el dominio o usar [] temporalmente

📄 Licencia y autoría

Proyecto interno para extracción de datos de Odoo. Adaptar y redistribuir según las necesidades del equipo.