--- type: Resumen title: "Estudio de Odoo — Módulos y Programas (Python + XML-RPC)" description: "Estudio de odoo publicado como sitio: scripts minimalistas para implementarlo y cómo se conecta con el OKF." resource: "https://gerardoesquivia.com/odoo/" status: publicado tags: [estudio, odoo, scripts-minimalistas, documentacion, okf] timestamp: 2026-10-04 creator: "Gerardo Esquivia Zapata" grafo: datos --- # Estudio de Odoo — Módulos y Programas (Python + XML-RPC) > **Sitio publicado:** https://gerardoesquivia.com/odoo/ > **Nota generada del sitio** para que el estudio regrese al OKF (REGLA del ciclo: > la documentación no está completa hasta estar publicada **Y** registrada). ## Cómo usarla Los **scripts minimalistas** de abajo se copian y funcionan. Esa es la parte que vale: la prosa se lee y se olvida; un script se pega y arranca. --- ## 1 · Odoo — Fundamentos y arquitectura La base: ERP open source + arquitectura + entorno ERNE (odoo_demo, COP, PUC). ### 🏗️ Arquitectura ``` # Cliente web (Owl JS) → XML-RPC/JSON-RPC/HTTP → Servidor Odoo 18 (Python) → PostgreSQL odoo-bin -d odoo_demo --addons-path=addons,custom_addons # odoo/ framework (ORM, vistas, RPC) · addons/ ~640 módulos de negocio · custom_addons/ módulos propios ``` ### 🚀 Arranque del entorno (ERNE) ``` # Clonar Odoo 18 + venv + dependencias (una sola vez) py -3.12 -m venv C:\Users\TUF\odoo\odoo18\.venv C:\Users\TUF\odoo\odoo18\.venv\Scripts\pip install -r C:\Users\TUF\odoo\odoo18\requirements.txt # Servidor con la base demo cd C:\Users\TUF\odoo\odoo18 .venv\Scripts\odoo-bin -d odoo_demo --addons-path=addons,custom_addons ``` 💡 Contexto OKF: base odoo_demo, empresa ERNE (res.company id=1), Colombia 🇨🇴 · COP · plan contable PUC. ⚠️ Informes financieros (Balance/P&L) son exclusivos de Enterprise; Community no los tiene. ## 2 · Odoo — Generación de módulos Crear funcionalidad propia sin tocar el core: scaffold → manifest → modelo → vista → seguridad → instalar. ### 📁 Scaffold del módulo ``` cd custom_addons ../../odoo-bin scaffold mi_modulo # Genera: __init__.py · __manifest__.py · models/ · views/ · security/ ``` ### 📦 __manifest__.py ``` import... # no importa nada: es un dict { 'name': 'Mi Módulo', 'version': '18.0.1.0.0', 'depends': ['base'], 'data': ['security/ir.model.access.csv', 'views/mi_modulo_views.xml'], 'installable': True, 'application': True, } ``` ### 🧠 Modelo (models/mi_modulo.py) ``` from odoo import fields, models class MiModelo(models.Model): _name = 'mi.modelo' _description = 'Mi Modelo' name = fields.Char(string='Nombre', required=True) descripcion = fields.Text(string='Descripción') activo = fields.Boolean(string='Activo', default=True) ``` ### 🔐 Seguridad (security/ir.model.access.csv) ``` id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_mi_modelo,mi.modelo,model_mi_modelo,base.group_user,1,1,1,1 ``` ### 🖥️ Vista (views/mi_modulo_views.xml) — tree + form + acción + menú ``` mi.modelo mi.modelo
Mi Modelo mi.modelo tree,form
``` ### ⚙️ Instalar / actualizar ``` # -i instala · -u actualiza ../../odoo-bin -d odoo_demo -i mi_modulo --addons-path=addons,custom_addons ../../odoo-bin -d odoo_demo -u mi_modulo --addons-path=addons,custom_addons ``` 💡 Ejemplo real del OKF: el módulo iot_sensor (modelos iot.sensor + iot.sensor.reading, menú "IoT", esqueleto iot_handlers/). Los módulos custom viven en custom_addons sin tocar el core. ## 3 · Odoo — Cómo generar programas usando Odoo Desde fuera de la UI: API externa XML-RPC/JSON-RPC y servidor MCP (agente IA). ### 🐍 Python XML-RPC — autenticar + CRUD ``` import xmlrpc.client url, db, username, password = 'http://localhost:8069', 'odoo_demo', 'admin', 'admin' common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common') uid = common.authenticate(db, username, password, {}) models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object') pid = models.execute_kw(db, uid, password, 'res.partner', 'create', [{'name': 'Cliente Demo'}]) ids = models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]]) recs = models.execute_kw(db, uid, password, 'res.partner', 'read', [ids[:5]], {'fields': ['name', 'country_id']}) models.execute_kw(db, uid, password, 'res.partner', 'write', [[pid], {'name': 'Nuevo Nombre'}]) ``` ### 🕸️ JSON-RPC (el mismo execute_kw en JSON) ``` {"jsonrpc": "2.0", "method": "call", "params": {"service": "object", "method": "execute_kw", "args": [db, uid, password, "res.partner", "create", [{}]]}} ``` ⚠️ Regla crítica: NO insertar directo en PostgreSQL. Odoo maneja la lógica (defaults, computed, validaciones, seguridad) en el ORM; escribir directo rompe la integridad. Todo pasa por execute_kw. ### 🤖 Odoo MCP — odoo-mcp-local (16 tools) ``` # Agente IA → MCP (stdio) → odoo_mcp/server.py (FastMCP) → xmlrpc.client → Odoo → PostgreSQL # Datos: list_models · get_model_fields · search_records · get_record # create_record · update_record · delete_record · call_method # Módulos: list_modules · get_module_info · install_module · upgrade_module · uninstall_module # Config: get_config_param · set_config_param · list_config_params ``` 💡 Decisiones: SDK mcp 1.x (FastMCP), canal xmlrpc.client (stdlib, sin módulo extra), conexión perezosa (arranca aunque Odoo esté apagado). Registrado en .vscode/mcp.json como odoo-local. ## 4 · Grafo animado — del módulo al programa El token 🟠 recorre: generar el módulo, definirlo, verlo, instalarlo y usarlo por API/MCP. Clic reinicia. Iniciando… ## 5 · Referencia y regla de librerías | Comando / concepto | Qué hace | | --- | --- | | odoo-bin scaffold mi_modulo | Genera el esqueleto del módulo | | __manifest__.py | Metadatos + depends + data a cargar | | models.Model + _name | Base del ORM (modelo con puntos) | | ir.ui.view · ir.actions.act_window | Vistas tree/form + acción + menú | | ir.model.access.csv | Permisos ACL del modelo | | -i / -u | Instalar / actualizar módulo | | /xmlrpc/2/common | Endpoint sin auth (authenticate) | | /xmlrpc/2/object + execute_kw | CRUD del ORM por RPC | | search_read · search_count | Atajos buscar+leer / contar | | ir.model · ir.model.fields | Inspección y modelos dinámicos (x_) | 📦 Regla de librerías (local primero): Odoo usa xmlrpc.client (stdlib, sin dependencia) para la API; el MCP usa el SDK mcp 1.x (fijado mcp>=1.9,<2.0). Docs: https://www.odoo.com/documentation/18.0/. 📱 Escanéalo para abrir la documentación https://gerardoesquivia.com/odoo/ Odoo · Estudio de Desarrollo (módulos y programas) · OKF de Gerardo Esquivia Zapata · 2026-08-30 --- type: Resumen title: "🚀 Odoo — Estudio de Desarrollo de Módulos y Programas (Resumen minimalista)" description: "Resumen de Odoo 18: fundamentos, generación de módulos (scaffold, manifest, modelo, vista, seguridad) y cómo generar programas usando Odoo (XML-RPC/JSON-RPC y Odoo MCP). Integra la documentación del OKF." fuente: "https://www.odoo.com/documentation/18.0/developer/howtos/backend.html · https://www.odoo.com/documentation/18.0/developer/reference/external_api.html" sitio: "https://gerardoesquivia.com/odoo/" tags: [resumen, odoo, erp, modulos, xml-rpc, json-rpc, mcp, okf] timestamp: 2026-08-30 creator: "Gerardo Esquivia Zapata" --- # 🚀 Odoo — Resumen (para OKF) > **Para qué:** ERP open source (Python + PostgreSQL) extensible por módulos custom para digitalizar procesos y conectarlos con hardware. Base: `odoo_demo`, empresa ERNE (COP, PUC Colombia). > **Cómo:** correr `odoo-bin`; crear módulos con `scaffold`; usar la API externa (`execute_kw`) o el servidor MCP. > **Skill de implementación:** `odoo-minimal` (uso mínimo: odoo-bin + scaffold + ORM + XML-RPC/JSON-RPC + MCP). ## 1 · Fundamentos ```powershell py -3.12 -m venv C:\Users\TUF\odoo\odoo18\.venv .venv\Scripts\odoo-bin -d odoo_demo --addons-path=addons,custom_addons ``` ## 2 · Generación de módulos ```bash cd custom_addons && ../../odoo-bin scaffold mi_modulo ``` ```python # __manifest__.py {'name':'Mi Módulo','version':'18.0.1.0.0','depends':['base'], 'data':['security/ir.model.access.csv','views/mi_modulo_views.xml'], 'installable':True,'application':True} ``` ```python # models/mi_modulo.py from odoo import fields, models class MiModelo(models.Model): _name = 'mi.modelo' name = fields.Char(required=True) descripcion = fields.Text() activo = fields.Boolean(default=True) ``` ```xml ``` ```csv # security/ir.model.access.csv id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_mi_modelo,mi.modelo,model_mi_modelo,base.group_user,1,1,1,1 ``` ```bash ../../odoo-bin -d odoo_demo -i mi_modulo --addons-path=addons,custom_addons ../../odoo-bin -d odoo_demo -u mi_modulo --addons-path=addons,custom_addons ``` Módulo mínimo = `__manifest__.py` + `models/` + `security/` + `views/`. Custom en `custom_addons` (--addons-path), sin tocar el core. ## 3 · Programas usando Odoo (API externa) ```python import xmlrpc.client url, db, user, pwd = 'http://localhost:8069', 'odoo_demo', 'admin', 'admin' common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common') uid = common.authenticate(db, user, pwd, {}) models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object') pid = models.execute_kw(db, uid, pwd, 'res.partner', 'create', [{'name':'Cliente Demo'}]) ids = models.execute_kw(db, uid, pwd, 'res.partner', 'search', [[['is_company','=',True]]]) recs = models.execute_kw(db, uid, pwd, 'res.partner', 'read', [ids[:5]], {'fields':['name','country_id']}) models.execute_kw(db, uid, pwd, 'res.partner', 'write', [[pid], {'name':'Nuevo Nombre'}]) ``` ⚠️ **Regla crítica:** NO insertar directo en PostgreSQL; todo pasa por el ORM (`execute_kw`). Odoo MCP (`odoo-mcp-local`): 16 tools (datos, módulos, config) vía `xmlrpc.client` (stdlib) + SDK `mcp` 1.x. ## 🔑 Conceptos clave | Concepto | Qué es | |---|---| | `odoo-bin` / `scaffold` | Servidor y generador de módulos | | `__manifest__.py` | Metadatos + depends + data | | `models.Model` | Base del ORM | | `ir.ui.view` / `ir.actions.act_window` | Vistas y acciones | | `ir.model.access.csv` | Permisos ACL | | `execute_kw` | CRUD del ORM por RPC | | `xmlrpc/2/common` + `xmlrpc/2/object` | Endpoints de la API externa | | `ir.module.module` / `ir.config_parameter` | Gestión de módulos y config | ## 🔗 Fuente https://www.odoo.com/documentation/18.0/ · Sitio: https://gerardoesquivia.com/odoo/ · Notas OKF: 📋 Proyectos/🌐 Odoo 18 · iot_sensor · Odoo MCP · odoo-mcp-local · POS Restaurante ERNE ## 📥 Cómo agregar esto a tu OKF (para el agente) 1. Guarda este archivo en tu vault (ej. `📋 Proyectos/`). 2. El frontmatter ya es OKF: no modifiques `type` ni `creator`. 3. Implementa directo: copia los scripts y ajusta credenciales/nombres. No necesitas investigar más. function descargarMD(){const md=document.getElementById('md-resumen').textContent.trim();const b=new Blob([md],{type:'text/markdown;charset=utf-8'});const u=URL.createObjectURL(b);const a=document.createElement('a');a.href=u;a.download='resumen-odoo.md';document.body.appendChild(a);a.click();a.remove();URL.revokeObjectURL(u);} (function(){const nodes=[{id:"s",label:"Scaffold",sub:"odoo-bin scaffold",x:90,y:140},{id:"m",label:"Manifest",sub:"__manifest__.py",x:270,y:140},{id:"mo",label:"Modelo",sub:"models/ .py",x:450,y:140},{id:"v",label:"Vista + ACL",sub:"views/ + security",x:630,y:140},{id:"i",label:"Instalar",sub:"-i mi_modulo",x:810,y:140},{id:"a",label:"API / MCP",sub:"execute_kw",x:810,y:330},{id:"r",label:"Datos",sub:"UI + RPC",x:540,y:330}];const edges=[{from:"s",to:"m",label:"genera"},{from:"m",to:"mo",label:"define"},{from:"mo",to:"v",label:"vistas"},{from:"v",to:"i",label:"instala"},{from:"i",to:"a",label:"expone"},{from:"a",to:"r",label:"CRUD"},{from:"r",to:"a",label:"escribe"}];const pos=Object.fromEntries(nodes.map(n=>[n.id,{x:n.x,y:n.y}]));const svg=document.getElementById("grafo-svg");const NS="http://www.w3.org/2000/svg";function el(t,a){const e=document.createElementNS(NS,t);for(const k in a)e.setAttribute(k,a[k]);return e;}const edgePaths=[],edgeArrows=[]; edges.forEach((ed)=>{const a=pos[ed.from],b=pos[ed.to];let d,mid;if(a.y!==b.y&&Math.abs(a.x-b.x)>60){const cx=(a.x+b.x)/2;d=`M ${a.x} ${a.y} C ${cx} ${a.y}, ${cx} ${b.y}, ${b.x} ${b.y}`;mid={x:cx,y:(a.y+b.y)/2};}else if(ed.from==="r"){d=`M ${a.x} ${a.y} C ${(a.x+b.x)/2} 440, ${(a.x+b.x)/2} 440, ${b.x} ${b.y}`;mid={x:(a.x+b.x)/2,y:410};}else{const mx=(a.x+b.x)/2;d=`M ${a.x} ${a.y} C ${mx} ${a.y}, ${mx} ${b.y}, ${b.x} ${b.y}`;mid={x:mx,y:(a.y+b.y)/2};}const p=el("path",{class:"edge",d});svg.appendChild(p);edgePaths.push(p);const ang=Math.atan2(b.y-mid.y,b.x-mid.x);const tx=b.x-18*Math.cos(ang),ty=b.y-18*Math.sin(ang);const ar=el("path",{class:"arrow",d:`M ${tx} ${ty} l 8 -4 l -8 -4 z`,transform:`rotate(${ang*180/Math.PI} ${tx} ${ty})`});svg.appendChild(ar);edgeArrows.push(ar);}); const nodeGroups={};nodes.forEach(n=>{const g=el("g",{class:"node"});g.appendChild(el("rect",{x:n.x-85,y:n.y-29,width:170,height:58}));const t=el("text",{class:"t",x:n.x,y:n.y-4,"text-anchor":"middle"});t.textContent=n.label;const s=el("text",{class:"s",x:n.x,y:n.y+16,"text-anchor":"middle"});s.textContent=n.sub;g.appendChild(t);g.appendChild(s);svg.appendChild(g);nodeGroups[n.id]=g;}); const travel=el("circle",{class:"travel",r:6,opacity:0});svg.appendChild(travel);const caption=document.getElementById("caption");const N=edges.length;let i=0,raf=null; function clearActive(){nodes.forEach(n=>nodeGroups[n.id].classList.remove("active"));edgePaths.forEach(p=>p.classList.remove("active"));edgeArrows.forEach(a=>a.classList.remove("active"));} function animateEdge(idx){const ed=edges[idx];clearActive();edgePaths[idx].classList.add("active");edgeArrows[idx].classList.add("active");nodeGroups[ed.from].classList.add("active");caption.innerHTML=`Paso ${idx+1}/${N}: ${ed.from} → ${ed.to} (${ed.label})`;const path=edgePaths[idx],len=path.getTotalLength();const t0=performance.now(),dur=800;function step(now){let p=(now-t0)/dur;if(p>1)p=1;const pt=path.getPointAtLength(p*len);travel.setAttribute("cx",pt.x);travel.setAttribute("cy",pt.y);travel.setAttribute("opacity",1);if(panimateEdge(i),300);}}raf=requestAnimationFrame(step);} function start(){cancelAnimationFrame(raf);i=0;animateEdge(0);}svg.addEventListener("click",start);start(); })(); --- ## Cómo se conecta con el OKF - **Sitio:** https://gerardoesquivia.com/odoo/ - **Nota:** esta (bajada del sitio, para consulta del agente) - **Fuente:** https://gerardoesquivia.com/odoo/ ## Aprendizajes - Los scripts minimalistas son el activo: **el ejemplo más corto que demuestra el uso**. - Este estudio forma parte del ciclo: **estudiar → publicar → registrar en el OKF**.