Está en la página 1de 55

Tema 5.

Desarrollo de módulos de Odoo con Python

Autora: Miriam Calavera


Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Tema 5. Desarrollo de módulos de


Odoo con Python

F P
¿Qué aprenderás? A
K I
N
• Conocerás los archivos mínimos necesarios para generar un
módulo en Odoo.
LI
O
• Revisarás el modelo de Odoo, con sus atributos posibles, para
N
generar clases dentro de un módulo.
U M
• Generarás las vistas necesarias para que los usuarios puedan
utilizar el módulo.
AL
• Utilizarás la herencia para modificar un módulo y personalizarlo
a gusto del cliente. L E
IB
• Crearás un esquema de seguridad para asegurar que cada

I M
usuario sólo accede a los datos que le corresponden.

P R
I
¿Sabías que…?
M
N
I Ó
•SEn términos de seguridad, es mucho más probable que alguien
R
E se introduzca en el sistema por una mala gestión de los perfiles
V de usuario que por agujeros en el código. La creación de perfiles
es una de las partes centrales del diseño de módulos en un ERP.
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Para adentrarnos en la generación de módulos deberemos usar el lenguaje de


programación de Odoo, Python y XML.

5.1. Preparación de nuestro módulo. El diagrama

Vamos a empezar el desarrollo de módulos de Odoo. De esta manera podremos adecuar


F P
empezaremos con la herramienta de confección de diagramas Dia Diagram Editor, queI A
nuestro sistema a cualquier necesidad de la empresa donde lo implantemos. Este diseño lo

permite efectuar diseños UML.


N K
Crearemos un módulo para el mantenimiento industrial y lo llamaremos
“manteni”. LI
N O
U M
AL
L E
I B
I M
R
Figura 30: Diagrama UML del módulo "manteni"

P
IM
Este software permite la realización de distintos tipos de diagrama. Evidentemente hemos
de tener seleccionados los diagramas UML en la parte izquierda de la pantalla.
N
Se han modelado clases para modelar los conceptos máquina, orden de trabajo, gama de
I Ó
mantenimiento e instrucción. Las clases creadas son:

R • SClase manteni.workorder modela las órdenes de trabajo (encargo puntual a realizar


sobre una máquina o grupo de máquinas para su mantenimiento)

V E • Clase manteni.machine: modela las máquinas.


• Clase manteni.program: modela las gamas de mantenimiento (conjunto de
instrucciones de mantenimiento relacionadas con un objetivo común).
• Clase manteni.program.instruction: modela las instrucciones asociadas a una gama
de mantenimiento.
Para desarrollar módulos de Odoo, hemos de tener en cuenta lo siguiente:
Todos los elementos de un diagrama se escriben en inglés. Si queremos otro idioma, más
tarde, se pueden usar las herramientas de traducción de Odoo.
2
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

No es obligatorio, pero sí práctico utilizar la notación siguiente: el nombre de las clases


debe estar en minúsculas con puntos para separar palabras. Todos estos nombres llevan
como prefijo, el nombre del módulo al que pertenecen. Todas las clases del diagrama
tienen como prefijo manteni, luego deduciremos que se trata del módulo manteni.
En cada clase hemos incorporado un estereotipo (nombre entre << y >>). Interpretamos
este estereotipo como la jerarquía de los menús dentro de Odoo. Usamos el símbolo / para
separar los diferentes niveles.
Hemos creado diferentes relaciones entre clases mediante conectores. Las relaciones
entre las clases son las siguientes:
F P
• Una orden de trabajo puede tener asociada una gama de mantenimiento
I A
para un torno. Es una relación many2one.
N K
(program). Por ejemplo, se puede utilizar una gama de mantenimiento mecánico


LI
Una orden de trabajo tiene una o varias máquinas asociadas, que serán sobre las
que se ha de actuar. Es una relación many2many.

N O
Una gama de mantenimiento tiene una o varias instrucciones asociadas. Es una


relación one2many.

U M
Aunque no aparecen en el diagrama, la clase manteni.workorder está asociada con

AL
la tabla hr_employee mediante el atributo employee_id (empleado que realizará el
mantenimiento). Es una relación many2one.

L E
Aunque no aparecen en el diagrama, la clase manteni.machine está asociada con la

Es una relación many2one. IB


tabla res_partner mediante el atributo suplier_id (empresa que vendió la máquina).

I M
P R
IM
N
I Ó
R S
VE

3
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.2. Creación del módulo vacío

Una vez hemos diseñado de manera teórica nuestro módulo, vamos a comenzar a escribir
su código Python.
Un módulo incorpora todos los elementos del patrón modelo-vista-controlador que es la
base del desarrollo de Odoo, estos son:
F P
IA
N K
LI
N O
U M
AL
L E
I B
I M
Figura 31: Patrón modelo vista controlador en Odoo


P R
El modelo: se define vía lenguaje Python, son los objetos que declararemos, y que


IM
se traducirán en tablas PostgreSQL.
Una vista: se define con lenguaje XML.
N

Ó
Un controlador: Podremos diseñar métodos en lenguaje Python que controlarán el
I
funcionamiento de Odoo.

R S
Vamos a ver ahora como diseñar módulos usando directamente el lenguaje Python. Para

V E ello empezamos viendo como es la estructura de un módulo, generando uno vacío. Para
instalaciones finales de Odoo, solamente hay que buscar el archivo odoo-bin y escribir el
siguiente comando:
odoo-bin scaffold <module name> <where to put it>
Esta instrucción nos creará toda la estructura de archivos y carpetas de un módulo vacío. Si
no hemos instalado Odoo, ya que estamos utilizando el código fuente sobre Pycharm, no
hay que preocuparse, ya que iremos creando uno por uno todos los archivos y carpetas.

4
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.3. Archivos iniciales de un módulo

Comenzaremos por los dos archivos que aparecen en la carpeta del módulo, __init__.py y
__manifest__.py.

F P
IA
N K
LI
N O
U M
Figura 32: Carpeta que contiene un módulo nuevo

AL
Archivo __init__.py
L E
I B
I M
El archivo __init__.py (dos guiones bajos antes y después de init) en el proceso de
inicialización del programa. En se colocan todos los archivos Python que hay que cargar
R
para la ejecución del programa. Por defecto se cargar los controladores y modelos.
P
IM
N
I Ó
R S
V E Figura 33: Archivo __init__.py

5
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Archivo __manifest__.py

Este archivo debe estar ubicado en la raíz de la carpeta del módulo y debe tener el formato
de un diccionario de Python. Es el responsable de determinar:
• Nombre, descripción, autores, licencia, versión, categoría,… del módulo.


Los archivos XML que se analizaran durante el arranque del servidor Odoo.
Las dependencias con otros módulos. F P
Los valores del diccionario Python que contiene este archivo son los siguientes: I A

N K
LI
name: Nombre del módulo en inglés.
• summary: Descripción del propósito del módulo en una frase.
• description: Texto que describe el módulo.
N O
• author: Autor del módulo.
• website: web del autor del módulo.
U M

AL
category: Categoría a la que pertenece el módulo. Texto separado por barras / con
la ruta jerárquica de las categorías.
• version: Versión del módulo.
L E

IB
depends: Lista Python de los módulos de los que depende este módulo.

I M
data: Lista Python de los nombres de archivos XML que se al instalar/actualizar el

módulo.
P R
módulo. La ruta de los archivos debe ser relativa a la carpeta donde se encuentra el


IM
demo: Lista de Python de nombres de ficheros XML que se cargaran si se ha
instalado Odoo con los datos de demostración o ejemplo. Las rutas de los archivos
N
deben ser relativas al directorio donde está el módulo.

I Ó
R S
V E

6
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

F P
IA
N K
LI
Figura 34: Archivo __manifest__.py
N O
U M
Los diccionarios de Python se definen entre {} y las palabras clave:valor separadas por

AL
comas. Las listas se definen entre [] y sus valores también van separados por comas.
Éste es el archivo __manifest__.py que resulta para el módulo “manteni”.

L E
I B
I M
P R
IM
N
I Ó
R S
VE

Figura 35: __manifest__.py del módulo manteni

7
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4. El modelo de Odoo. Carpeta models

El modelo de Odoo contendrá todos los objetos (clases) que se han definido anteriormente
con DIA. Toda la información se introducirá en la carpeta “models”. Esta carpeta contendrá
como mínimo dos archivos:
• P
__init__.py donde se mencionan todos los archivos que contiene la carpeta, y se
importarán para crear el módulo. F
• I A
nombre_modulo.py donde se generarán todas las clases que componen el módulo.

N K
El archivo nombre_modulo.py contiene, como hemos dicho, la definición del modelo del

LI
módulo de Odoo. Para definir un objeto (clase de Odoo), es necesario definir una clase de
Python y posteriormente instanciarla.

N O
U M
AL
Figura 36: Clase en Odoo

L E
El atributo _name es obligatorio, y tendrá el formato similar al que hemos utilizado para
definir nuestra cases en DIA.
I B
I M
P R
IM
N
I Ó
R S
V E

8
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4.1. Atributos de clase

Aparte del atributo _name obligatorio, podemos encontrar los siguientes:


• _rec_name: todas las clases por defecto tendrán un campo llamado name, el cual
almacenará el nombre de cada registro, que se utilizará para los campos
relacionales. En caso de querer almacenar como nombre otro campo diferente, se
indicará en _rec_name.
• _inherit: para trabajar el mecanismo de herencia. Se tratará más adelante en este
manual. F P
• _order: permite declarar el campo que se utilizará para ordenar los registros IA
cuando se haga una búsqueda sin especificar un orden concreto.
N K

LI
_auto: define si se debe crear una tabla de la base de datos con la información de la
clase. Es TRUE por defecto.
• O
_table: en caso de no querer que se genere el nombre de tabla por defecto
N
(nombre de la clase sustituyendo los puntos por guiones bajos), nombre que
tendrá.
U M
AL
• _sql_constraints: condiciones SQL que queremos que se revisen como medida de
seguridad. Por ejemplo, nos permite verificar que en el registro añadido no
estamos introduciendo un valor ya existente.

L E
I B
M
Figura 37: Ejemplo de uso del atributo _sql_constraints

I
P R
IM
N
I Ó
R S
VE

9
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4.2. Campos posibles en Odoo

A continuación se generan los atributos (campos), que pueden ser de varios tipos:
• Campos básicos
• Campos calculados (computed)


Campos relacionales (relational)
Campos relacionados (related) F P
I A
N K
5.4.2.1. Campos básicos
LI
N O
Se trata de campos simples, que contienen información que se almacena en la base de
datos. Pueden ser de varios tipos (numérico, carácter, texto, fecha…)

U M
Algunos de los parámetros comunes (todos son opcionales) a cualquier campo básico son:

AL
• string: Texto que verán los usuarios relacionado con el campo. Si no se incluye, los
usuarios verán el nombre del campo.

L E
help: Tooltip con ayuda que verán los usuarios.

IB
readonly: Campo de sólo lectura (FALSE por defecto).

M
required: Campo obligatorio (FALSE por defecto).
I

• P R
index: Generar un índice en la base de datos (FALSE por defecto).
default: valor por defecto que toma el campo. Puede utilizarse un valor concreto o

IM
llamar a una función (que se describirá después en el mismo archivo), para el
cálculo.
N

Ó
groups: lista separada por comas de los grupos con acceso a este campo.
I
R


SLos campos que se pueden utilizar en Odoo son:
Char: campo básico de texto. Tiene dos prámetros:

VE o size: tamaño máximo del campo


o translate: activa la traducción del campo si lo ponemos como TRUE.
• Boolean
• Integer
• Float: número en formato coma flotante. Tiene un parámetro:
o digits: un par de números (total,decimal), que representa la precisión del
número flotante.

10
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

• Text: es similar a char, pero utilizado para cadenas más largas. No se indica el
tamaño, y se muestra en pantalla mediante una caja multilínea. Tiene un
parámetro:
o translate: activa la traducción del campo si lo ponemos como TRUE.
• Selection: crea un combo desplegable para elegir un valor. Tiene un parámetro
obligatorio:
o selection: valores posibles del campo. Se presentan como una lista de


pares (valor, texto), separados por comas.
Date: campo tipo fecha. Se almacena en formato YYYY-MM-DD F P
IA
N K
LI
N O
U M
AL
L E
B
Figura 38: Clase "manteni.workorder”

I
I M
Es obligatorio e importante que en todas las clases se defina un campo llamado “name”, ya
que se utilizará para hacer referencia a la clase cuando se creen campos relacionales.

P R
A continuación se muestran varios un ejemplos del atributo default, tanto dándole un valor

IM
concreto como llamando a una función de Python.

N
S IÓ Figura 39: Campo "date_begin" de la clase "manteni.workorder"

R
VE Figura 40: Campo "state" de la clase "manteni.workorder"

11
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4.2.2. Campos calculados (computed)

Puede que nos interese crear un campo que, en lugar de utilizarse almacenando un valor
en la base de datos, se genere mediante un cálculo. Por ejemplo, podríamos calcular de
forma dinámica la edad de un trabajador de la empresa mediante su fecha de nacimiento y
el día actual. De esta manera, sin necesidad de ocupar espacio en la base de datos
tendríamos un dato actualizado y utilizable en cada momento.
Hacen referencia a un método que deberá definirse a continuación en lenguaje Python.
F P
I A
N K
Figura 41: Campo calculado

LI
N O
U M
AL
Figura 42: Función Python para calcular el campo

L E
IB
Campos relacionados (related)
5.4.2.3.

I M
PR
Los campos relacionados sirven para obtener un valor de otro modelo, siguiendo las
relaciones entre atributos. Esto evita tener que duplicar información en la base de datos.

IM
Por ejemplo, en la clase “manteni.machine” hemos creado el campo “suplier_id”, que hace
referencia a la tabla “res_partner”. Si además del nombre de la empresa quisiéramos
N
mostrar su dirección, podríamos utilizar un campo related, que utilizara “suplier_id” para

I Ó
consultar en la tabla “res_partner” sin necesidad de duplicar la información.

R S
VE Figura 43: Campo relacionado

12
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4.2.4. Campos relacionales (relational)

Entre las clases de Odoo se pueden establecer tres tipos de relaciones, similares a las del
modelo entidad-relación para las bases de datos. Estas relaciones se definen mediante los
atributos referenciales siguientes:
• many2one
• one2many
• many2many
F P
IA
a) Many2one
N K
LI
Representa una relación hacia una clase padre. Muchos objetos de la clase que contiene el
atributo pueden estar relacionados con el mismo objeto de la clase padre.

N O
Odoo muestra los campos many2one acompañados por una lista para seleccionar el objeto
de la clase padre. Esto obliga a que la case referenciada por el campo many2one contenga
el campo name.

U M
AL
L E
IB
I M
R
Figura 44: Campo many2one "employee" de la clase "manteni.workorder"

P
IM
N
Para definir un atributo many2one en Odoo podemos utilizar (entre otros) los siguientes
parámetros:
• I Ó
R •
Scomodel_name: nombre de la clase destino
domain (opcional): permite filtrar para no ver todos los valores.

VE • Ondelete: qué hacer cuando se borra el registro referido. Los valores posibles son
‘set_null”, ‘restrict’ y ‘cascade’.

Figura 45: Campo many2one

13
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

b) One2many
Representa una relación hacia una clase hija. Un objeto de la clase que contiene el atributo
puede estar relacionado con muchos objetos de la clase hija. Es evidente que cada atributo
one2many debe ser complementario de un atributo may2one que debe estar
obligatoriamente en la clase hija.
Odoo muestra para los campos one2many una lista con todos los objetos relacionados, y la
posibilidad de añadir más.
F P
IA
N K
LI
N O
M
Figura 46: Campo one2many de la clase “manteni.program”
U
AL
Para definir un atributo one2many en Odoo podemos utilizar (entre otros) los siguientes
parámetros:

L
comodel_name: nombre de la clase destino.E

I B
inverse_name: nombre del campo inverso many2one que se encuentra en la clase
destino.
I M

R
domain (opcional): permite filtrar para no ver todos los valores.
P
IM Figura 47: Campo one2many

N
I Ó
R S Figura 48: Campo many2one relacionado con el one2many de la figura anterior

VE La existencia de un atributo one2many implica que debe existir un atributo may2one. Sin
embargo, la existencia de un atributo may2one no implica que deba existir un atributo
one2may.

14
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

c) Many2many
Representa una relación de muchos a muchos entre dos objetos. Cada clase de una clase A
pues estar relacionado con muchos objetos de la clase B y cada objeto de la clase B puede
estar relacionado con muchos objetos de la clase A.
En nuestro caso, en una orden de trabajo se puede pedir el mantenimiento de varias
máquinas, y una máquina aparecerá en varias órdenes de trabajo, a medida que va
sufriendo averías.
Odoo muestra para los campos many2many una lista con todos los objetos relacionados, y
la posibilidad de añadir más, al igual que en one2many.
F P
IA
N K
LI
N O
U M
AL
Figura 49: Campo many2many de la clase “manteni.workorder”

parámetros: L E
Para definir un atributo many2many en Odoo podemos utilizar (entre otros) los siguientes

• IB
comodel_name: nombre de la clase destino.
• I M
relation (opcional): nombre de la tabla de la base de datos que contendrá la
R
relación entre las dos clases.
P

IM
column1 (opcional): nombre de la columna referida para el registro de la clase
actual.
• N
column2 (opcional): nombre de la columna referida para el registro de la clase

I Ó
destino.

R
• Sdomain (opcional): permite filtrar para no ver todos los valores.

VE Los tres valores relation, column1 y column2 eran obligatorios en versiones anteriores
(cuando el ERP se llamaba OpenERP), y se pueden seguir añadiendo si se quisiera.

Figura 50: Campo many2many

15
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4.3. Funciones onchange

A veces puede resultarnos útil cambiar un valor antes manera inmediata, dependiendo del
valor que ha tomado otro campo, para ello utilizamos las funciones onchange.
Los campos calculados, definidos anteriormente, no necesitan una función onchange, ya
que se actualizan automáticamente. Esto es una novedad respecto a versiones anteriores.
La sintaxis será la siguiente:
F P
IA
N K
LI
Figura 51: Sintaxis para las funciones onchange

N O
Para la clase “manteni.workorder” hemos creado dos funciones de este tipo. La primera

U M
actualiza la fecha de finalización de la orden de trabajo si se elige el estado “Closed” a la
fecha actual. La segunda busca el identificador de usuario de un trabajador cuando

AL
cambiamos el empleado que llevará a cabo la orden de trabajo.

L E
I B
I M
P R
IM
Figura 52: Funciones onchange en la clase "manteni.workorder"

N
I Ó
R S
VE

16
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.4.4. Carpeta models del módulo “manteni”

Con toda la información de este apartado, construimos la carpeta models.

F P
IA
N K
LI
N O
U M
AL
Figura 53: Carpeta "models" del módulo "manteni"

Tal y como hemos definido anteriormente, existen los archivos __init__.py y manteni.py.

herencia. Se tratará más adelante. L E


Además, se ha creado un archivo llamado partner.py, que contiene una clase especial con

I B
5.4.4.1. Archivo __init__.py
I M
P R
Contendrá la importación de los dos archivos que componen el modelo.
# -*- coding: utf-8 -*-
IM
from . import manteni
N
I Ó
from . import partner

R S
5.4.4.2. Archivo manteni.py

V E Contiene la definición de las clases Odoo.


# -*- coding: utf-8 -*-

from odoo import models, fields, api

from datetime import datetime, timedelta

class Machine(models.Model):

# Maquinas objeto del mantenimiento"""

17
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

_name = 'manteni.machine'

name = fields.Char(size=32, string='Machine name', index=True)

serial = fields.Char(size=32, string='Serial no', index=True)

suplier_id = fields.Many2one('res.partner', string='Suplier', domain=[('parent_id', '=', False),


('machinery_seller', '=', True)])

date_begin = fields.Date(string='Date begin', default=fields.Datetime.now)


F P
date_first_maintenance = fields.Date(compute='_maintenance_date') I A
N K
state = fields.Selection([('on_use', 'On use'), ('repairing', 'Repairing'), ('out_order', 'Out of order')],

string='State', default='on_use')
LI
city = fields.Char(related='suplier_id.city', store=False)

hours_maint = fields.Integer(string='Hours till maintenances') N O


U M
AL
_sql_constraints = [('name_uniq', 'unique (name)', "Title name already exists !"), ('serial_uniq', 'unique
(serial)', "Serial code already exists !")]

L E
@api.multi
I B
def _maintenance_date(self):
I M
for record in self:

fecha=record.date_begin P R
IM
fecha_fin=datetime.strptime(fecha,'%Y-%m-%d')

N
record.date_first_maintenance = fecha_fin + timedelta(hours=record.hours_maint)

I Ó
S
class Program(models.Model):
R
V E
#Normas de mantenimiento, conjunto de medidas para el mantenimiento de una parte determinada"""

_name = 'manteni.program'

name = fields.Char(string='Name', size=64, required=True)

machine_ids = fields.Many2many('manteni.machine', string='Associated machines')

instruction_ids = fields.One2many('manteni.program.instruction', 'program_id', string='Instructions')

18
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

class ProgramInstruction(models.Model):

#Reglas de cada norma. Una regla puede pertenecer a varias normas"""

_name = 'manteni.program.instruction'

name = fields.Char(string='Name', size=64, required=True, translate=True)

description = fields.Text(string='Description', required=True, translate=True)

program_id = fields.Many2one('manteni.program', string='Program')


F P
I A
class Workorder(models.Model):

N K
LI
# Orden de trabajo para un trabajador concreto, repara una o varias maquinas"""

_name = 'manteni.workorder'

N O
name = fields.Char('Title', size=64, required=True, translate=True)

description = fields.Text('Description', translate=True)


U M
AL
date_begin = fields.Date(string='Opening date', default=fields.Datetime.now)

date_end = fields.Date(string='Closing date')

L E
domain="[('department_id','=','Maintenance')]")
IB
employee_id = fields.Many2one('hr.employee', string='Employee',

employee_user_id = fields.Integer()
I M
R
machine_ids = fields.Many2many('manteni.machine', string='Machines')
P
IM
program_id = fields.Many2one('manteni.program', string='Program')

state = fields.Selection([('not_started', 'Not started'), ('opened', 'Opened'), ('closed', 'Closed'), ('cancelled',


'Cancelled')],
N
I Ó
string='State', default='opened')

R S
type = fields.Selection([('corrective', 'Corrective'), ('preventive', 'Preventive')], string='Type of maintenance',
default='corrective')

V E
closing_info = fields.Text('Closing information')

@api.onchange('state')

def _onchange_state(self):

if self.state == 'closed':

self.date_end=datetime.now()

19
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

@api.onchange('employee_id')

def _onchange_employee_id(self):

self.employee_user_id=self.employee_id.resource_id.user_id

F P
I A
N K
LI
N O
U M
AL
L E
I B
I M
P R
IM
N
I Ó
R S
VE

20
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.5. La vista de Odoo. Carpeta Views

El concepto vista hace referencia a las pantallas que permiten que el usuario visualice la
información o la edite. Una vista (view) también genera los menús que permiten un acceso
organizado a la a las vistas. Estos menús y vistas se diseñan mediante archivos XML que, al
instalarse en una empresa de Odoo, obtienen un identificador único y que el sistema usa
para la gestión de la aplicación. Por ello, en la definición XML de menús y vistas se incluye
un identificador (texto) que debe ser único dentro del módulo y al que se puede
referenciar desde el propio módulo por su nombre o desde cualquier otro módulo vía la F P
sintaxis módulo.identificador.
I A
K
Todos los archivos xml necesarios para generar las vistas de Odoo se introducirán en la
N
LI
carpeta “Views”. De manera obligatoria tendremos que incluir solamente un archivo
llamado nombre_modulo.xml.

5.5.1. Vistas N O
U M
Las vistas son aquellas pantallas que facilitan el acceso la información al usuario. Desde

AL
estas pantallas, un usuario puede consultar y modificar la información. Tenemos diferentes
pantallas que sirven de interfaz entre el usuario y el programa. Todas ellas son dinámicas.

L E
Entendemos por vistas dinámicas aquellas que se van construyendo en tiempo de ejecución a

modificar incluso en tiempo de ejecución. IB


partir de las descripciones XML accesibles desde el cliente. Esto hace posible que se puedan

I M
Las vistas se declaran en el archivo XML nombre_modulo.xml (al igual que acciones y
menús).
P R
La sintaxis para definir una vista es la siguiente:
IM
<record model="ir.ui.view" id="view_id">

N
<field name="name">view.name</field>

I Ó
<field name="model">object_name</field>

R S
<field name="type">xxx</field>

V E <!...Valores posibles: form,tree,calendar,search,graph,gantt,Kanban-->

<field name="priority" eval="16"/>

<field name="arch" type="xml">

<!... view content: <form>, <tree>, <graph>, ... -->

</field>

</record>

21
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Los valores específicos para cada vista:


• Elemento record: contienen el atributo modelo con el valor ir.ui.view obligatorio
para las vistas, y el atributo id con el identificador XML de la vista dentro del
módulo.
• Elemento field name=”name”: nombre de la vista.
• Elemento field name=”model”: nombre del objeto (clase) sobre el que se define la
vista.
F P
• Elemento field name=”type”: tipo de vista (tree, form, calendar, search, graph,
I A

N K
grantt y kanban). No es obligatorio, pero en muchos casos ayuda al desarrollador.

LI
Elemento field name=”priority”: prioridad de la vista. Cuanto más pequeña, más
prioridad. Valor por defecto 16.

O
Elemento field name=”arch” type=”xml”: arquitectura o estructura de la vista. Se

N
define mediante diferentes etiquetas XML y es distinta para cada tipo de vista.

tree, calendar, search, graph, grantt y kanban).


U M
A partir de este esquema procederemos a construir los diferentes tipos de vistas (form,

5.5.1.1. Vistas form AL


L E
IB
La vista formulario para un objeto de Odoo, consiste en distribuir correctamente los campos
del objeto en la pantalla. De esta forma se facilita la visualización y/o edición de sus recursos.

I M
Utilizando la sintaxis que hemos definido para una vista, declararemos el tipo form de la

<field name="type">form</field> PR
siguiente manera (recordando que no es una sintaxis obligatoria):

IM
N
a) Colocación de los elementos
I Ó
Para colocar los elementos en el formulario de la manera adecuada, deben utilizarse

R S
etiquetas xml.

V E • Dentro de un elemento <form> deben definirse agrupaciones de datos, que se


marcarán con la etiqueta <group> (también puede utilizarse la etiqueta <div>
• Por defecto, el elemento <group> define dos columnas dentro, a menos que se
incluya el atributo “col=n”. Estas dos columnas pertenecen a la etiqueta del campo
y al contenido del campo respectivamente. Podemos utilizar un elemento <group>
dentro de otro para subdividir el espacio.
• Para añadir el título a una sección se incluye el atributo “string” en la etiqueta
<group>.

22
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

• Si un campo no está dentro de una etiqueta <group> no se mostrará


automáticamente su etiqueta. Se podría utilizar <label for=”field_name”>, aunque
se recomienda utilizar <group>
Además, podemos utilizar otras etiquetas para darle formato al formulario:
• newline: se utiliza dentro de <group>, termina la línea y salta inmediatamente a
una nueva.
• Separator: crea un pequeño espacio horizontal. Puede llevar el atributo string, para


crear un título.
F P
Sheet: Puede ir inmediatamente debajo de form, para crear que el layout sea más
estrecho y “responsive” (adaptable a cualquier formato de pantalla). IA
• Header: título cuando se utiliza sheet.
N K
LI
b) Utilización de etiquetas CSS

N O
Pueden utilizarse las etiquetas <div>, <h1>, <h2>… para producir los títulos. También

clase “oe_edit_only”.
U M
puede hacerse que la etiqueta de un campo sólo aparezca en modo edición, mediante la

AL
L E
IB
I M
P R
IMFigura 54: Etiquetas CSS para dar formato a un formulario

N
• I Ó
También podemos utilizar las siguientes clases:

R •
Soe_inline: cancela el salto de línea tras un campo
oe_left, oe_right: hace el campo flotante en la dirección correspondiente

VE • oe_read_only, oe_edit_only: sólo muestra el campo en la pantalla indicada


• oe_no_button: cancela el botón de navegar en el plugin many2one
• oe_avatar: para campos de imagen, la muestra como avatar (cuadrado, máximo
90x90)

23
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

c) Componentes semánticos de una vista form


Los componentes semánticos atan y permiten interacción con el sistema Odoo. Son los
siguientes:
• Field: Campo a visualizar: agunos de sus atributos son:
o name (obligatorio). Nombre del campo
o widget. Cada tipo de campo tiene un widget asociado por defecto, pero
puede cambiarse a otro tipo con este atributo.
F P
o groups. Sólo muestra la información a algunos grupos de usuarios.
I A
o domain: filtros para aplicar a campos relacionales.
N K
o readonly: campo de sólo lectura.
o required: campo obligatorio.
LI
o nolabel: campo sin etiqueta.
N O
• Button: muestra un botón.
U M
AL
d) Ejemplo de vista form
A continuación las vistas form para las clases workorder, program y machine.
<record model="ir.ui.view" id="manteni.machine_form">
L E
<field name="name">Machine list</field>
IB
M
<field name="model">manteni.machine</field>
I
<field name="arch" type="xml">

<form> P R
<sheet>
IM
N
<div class="oe_title">

I Ó
<label for="name" string="Machine's denomination" class="oe_edit_only"/>

R <h1> S
V E <field name="name" placeholder="Machine's denomination" modifiers="{'required': true}"/>

</h1>

</div>

<group>

<group>

<field name="serial"/>

<field name="state"/>

24
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

</group>

<group>

<field name="suplier_id"/>

<field name="city" />

</group>

</group>

<group>
F P
<field name="date_begin"/>
IA
<field name="hours_maint" />

N K
LI
</group>

<label for="date_firts_maintenance" string=" " class="fa fa-wrench" />

<field name="date_first_maintenance" />


N O
</sheet>

</form>
U M
</field>
AL
</record>

L E
IB
I M
P R
IM
N
I Ó
R S Figura 55: Formulario para la clase "machine"

V E
<record model="ir.ui.view" id="manteni.program_form">

<field name="name">manteni.program.form</field>

<field name="model">manteni.program</field>

<field name="type">form</field>

<field name="arch" type="xml">

<form string="Maintenance Programs">

<group>

25
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

<field name="name" />

</group>

<group>

<field name="instruction_ids" colspan="4" />

<field name="machine_ids" colspan="4" />

</group>
F P
</form>
IA
</field>

N K
LI
</record>

N O
U M
AL
L E
Figura 56: Formulario para la clase "program"

IB
M
<record model="ir.ui.view" id="manteni.manager_workorder_form">
I
P R
<field name="name">manteni.workorder.form</field>

<field name="model">manteni.workorder</field>

IM
<field name="type">form</field>

N
<field name="arch" type="xml">

I Ó
<form string="manteni.workorder">

R S
<div class="oe_title">

V E <label for="name" string="Workorder name" class="oe_edit_only"/>

<h1>

<field name="name" modifiers="{'required': true}"/>

</h1>

</div>

<group>

<group string="Workorder info">

<field name="state" />


26
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

<field name="date_begin" string="Opening date"/>

<field name="date_end" string="Closing date" attrs="{'invisible':[('state','!=', 'closed')]}"/>

</group>

<group string="Assignation">

<field name="employee_id" />

<field name="employee_user_id" invisible="1"/>

<field name="type" />


F P
<field name="program_id" attrs="{'invisible':[('type', '=', 'corrective')]}"/>
I A
</group>

N K
LI
</group>

<group>

<field name="description" />


N O
</group>

<group string="Machines to repair/revise">


U M
<field name="machine_ids" />
AL
</group>

L E
<group>

I B
<field name="closing_info" attrs="{'invisible':[('state','!=', 'closed')]}"/>

</group> I M
</form>
P R
</field>
IM
</record>
N
I Ó
R S
VE

27
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

F P
IA
N K
LI
N O
U M
Figura 57: Formulario para la clase "workorder"

AL
e) Vistas list (tree)
L E
IB
Este tipo de vistas consisten en una distribución de líneas con el objetivo de facilitar la
I M
visualización y/o edición de un conjunto de recursos de un objeto.

P R
IM
Al igual que para el resto de vistas, generaremos el código estándar, personalizando la
siguiente linea:

N
I Ó
<field name="type">tree</field>

R S
Existen, entre otro, los siguientes parámetros:

V E • editable: por defecto, para editar una lista hacemos clic sobre una de las líneas, y se
abrirá el formulario definido para la edición. Sin embargo, el atributo “editable” nos
permite hacerlo sobre la misma lista. Puede tomar los valores “top” o “bottom”.
• default_order: cambia el orden por defecto por uno personalizado.
• decoration-{$name}: permite cambiar el color de las líneas de la lista, en función de
una variable determinada. Se introduce una expresión Python para ser evaluada.
{$name} puede ser sustituido por los valores siguientes:
o Valores html (por ejemplo bf, font-weight: bold, it, font-style: italic)

28
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

o Etiquetas predeterminadas (danger, info, muted, primary, success,


warning)

Figura 58: Parámetro "decoration"

• create, edit, delete: permite deshabilitar estas funciones si el atributo se coloca a


valor FALSE.
Bajo la etiqueta <tree> podemos encontrar los siguientes elementos: F P
• button: muestra un botón. Entre otros lleva los atributos: I A
o icon: icono del botón
N K
o string: texto del botón LI
o type: tipo del botón (workflow, object, action)
N O
o states: hace el botón invisible si no se cumple la condición
M
o confirm: mensaje de confirmación para que el usuario acepte.
U
AL
• Field: muestra un campo. Entre otros lleva los atributos:
o name: nombre del campo.

L E
o string: texto de la columna (por defecto la etiqueta del campo)

I B
o invisible: se tiene en cuenta por Odoo, pero no aparece en la lista.

I M
Imprescindible si el campo es una de las condiciones para cambiar la
decoración de la tabla.

P R
o groups: grupos que pueden ver el campo.

IM
o A continuación mostramos un ejemplo de vista de lista para la clase
“manteni.workorder”.
N
Ó
<record model="ir.ui.view" id="manteni.workorder_tree">

I
R S
<field name="name">manteni.workorder.tree</field>

<field name="model">manteni.workorder</field>

VE <field name="type">tree</field>

<field name="arch" type="xml">

<tree string="manteni.workorder">

<field name="date_begin"/>

<field name="name"/>

<field name="employee_id"/>

<field name="state" />

29
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

</tree>

</field>

</record>

F P
I A
N K
LI
N O
U M
AL
L E
I B
M
Figura 59: Formulario para la clase "manteni.workorder"

I
f) Vista calendar
P R
IM
Permite añadir un calendario a partir de la información de la clase. Su elemento raíz es
<calendar>. Sus atributos son:
• N
date_start (obligatorio): campo que marca la fecha de comienzo del evento.
• I Ó
date_stop: campo que marca la fecha de finalización. Si está incorporado el evento

R S se puede mover en el calendario (drag & drop).


VE •
date_delay: alternativo a date_stop. Duración del evento.
color
• all_day: booleano para indicar que el registro dura todo el día.
• mode: modo de visualización por defecto. Puede ser day, week o month.
A continuación mostramos un ejemplo:
<record model="ir.ui.view" id="manteni.workorder_calendar">

<field name="name">workorder.calendar</field>

<field name="model">manteni.workorder</field>
30
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

<field name="arch" type="xml">

<calendar string="Session Calendar" date_start="date_begin"

color="program_id" mode="month">

<field name="name"/>

</calendar>

</field>

</record>
F P
I A
N K
LI
N O
U M
AL
L E
I B
I M
P R
IM
Figura 60: Vista calendar para la clase "workorder"

N
I Ó
g) Vista search

R • S Se utilizan para definir criterios de búsqueda por defecto en las vistas de lista.
Cualquier usuario podría crear estas búsquedas por el interfaz web, pero esta vista

VE pretende ahorrar trabajo al usuario. Utiliza la etiqueta <search> y no tiene


atributos. Los posibles elementos que puede llevar a continuación son los
siguientes:
• field: campo por el que buscar. Lleva los siguientes atributos:
o name: nombre del campo
o string: texto del campo
o filter_domain: permite filtrarlos resultados de la búsqueda en el campo
o groups: campo sólo accesible para ciertos grupos
31
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

• filter: criterio de filtrado de respuestas. Sólo puede ser activado o desactivado.


o string (obligatorio): texto del filtro.
o domain: criterio del filtro.
o help: tooltip aclaratorio para el usuario.
o groups: filtro sólo accesible para ciertos grupos.
• group: agrupa filtros.
F P
• separator. Separa grupos de filtros.
IA
A continuación mostramos un ejemplo de la clase “workorder”

N K
LI
<record id="manteni.workorder_search_view" model="ir.ui.view">

<field name="model">manteni.workorder</field>

<field name="arch" type="xml">


N O
<search>

<field name="name"/>
U M
<field name="description" string="Name and description"
AL
E
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>

L
<field name="employee_id"/>

<field name="program_id" widget="selection"/> I B


I M
<filter name="my_workorders" string="My Ideas"

P R
domain="[('employee_id', '=', uid)]"/>

IM
<group string="Group By">

N
<filter name="group_by_program" string="Program"

I Ó
context="{'group_by': 'program_id'}"/>

R
</group>S
V E </search>

</field>

</record>

32
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.5.2. Acciones

Las acciones definen el comportamiento del sistema en respuesta a una acción: login,
presionar un botón, seleccionar un valor…
Existen varios tipos:
• Abrir una ventana: ir.actions.act_window
• Abrir una web: ir.actions.act_url
• Ejecutar un método en el servidor: ir.actions.server
F P
• Ejecutar un informe: ir.actions.report.xml
I A

N K
Ejecutar una acción implementada enteramente en el cliente: ir.actions.client
En este manual nos ceñiremos exclusivamente a las acciones de ventana.
LI
N O
Acciones ir.actions.act_window
U M
AL
La más común, sirve para abrir una ventana de visualización de un modelo mediante sus
vistas. Se definirá el conjunto de vistas posibles a abrir.

L E
Una vista se ejecuta a partir de un evento creado por un usuario que está vinculado a una

Sus campos son: IB


acción window, que es la responsable de poner ejecutar la vista.

• I M
name: nombre de la acción.

P R
res_model: clase de la que proviene la acción

IM
view_mode: lista separada por comas de las vistas disponibles, poniendo la primera
la que queremos que aparezca por defecto.
• N
Ó
view_type (optativo): indicar si la vista es jerárquica (tree) o no (form)
I
R S
A continuación presentamos un ejemplo para la clase “machine”.
<!-- actions opening views on models -->

VE
<record model="ir.actions.act_window" id="manteni.machine_action_window">

<field name="name">Machine window</field>

<field name="res_model">manteni.machine</field>

<field name="view_mode">tree,form</field>

</record>

33
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.5.3. Generación de menús

Para generar un menú para un módulo introduciremos código dentro del archivo
nombre_modulo.xml. Utilizaremos las etiquetas xml <menuitem>. Su formato será el
siguiente:
<menuitem

name="título_del_menú"
F P
id=”identificador”
I A
action="action_id"

N K
LI
web_icon="nombre_icono_web"

parent="menuitem_id"

groups="grupos_usuarios"/>
N O
Los valores específicos de cada menú son:
U M
AL
• Atributo name: es el título del menú, es opcional, si no lo ponemos el menú tomará
el nombre de la acción que ejecuta.

E
Atributo id: contiene el identificar XML del menú, debe ser único dentro del
módulo. L
• IB
Atributo action: identificador de la acción que ejecuta el menú. Si no especificamos

I M
la acción el sistema entiende que se trata de un menú raíz y por tanto que contiene

PR
otros menús i/u opciones. El diseño de la correspondiente acción depende del tipo
de ejecución que lleva asociada (abrir ventana, ejecutar informe, arrancar un
asistente,…). Se explicarán las acciones en el siguiente apartado.
• IM
Atributo web_icon: icono que muestra el cliente web en la página inicial.
• N
Atributo parent: identificador del menú padre al que pertenece. Si no lo
I Ó
especificamos el sistema entiende que se trata de un menú raíz (menú principal).

R • SAtributo groups: grupo de usuarios que pueden ver el menú. Si queremos

V E especificar más de un grupo hay que separarlos por comas (groups= “admin,user”).

34
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.6. Herencia en Odoo

El mecanismo de herencia permite a los programadores adaptar módulos existentes


garantizando que las actualizaciones no provoquen funcionamientos inesperados.
Como consultores de Odoo, puede ser muy habitual que el cliente nos solicite añadir
nuevos campos, hacer invisibles o modificar otros, incluso cambiar métodos. Para esto, al
ser Odoo de código abierto podríamos modificar el módulo en cuestión, pero no es

F
recomendable. Existe el mecanismo de la herencia, que permite lo mismo pero de maneraP
más inocua para el sistema.
I A
N
nuevas, y en la vista, que nos permitirá adaptarla a nuestras necesidades.
K
Diferenciaremos herencia para el modelo, que nos permitirá ampliar las clases o diseñar

LI
N O
U M
AL
L E
IB
I M
P R
IM
N
I Ó
R S
V E

35
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.6.1. Herencia en el modelo

Odoo permite tres tipos diferentes de herencia: herencia clásica o de clase, herencia de
prototipo y herencia por delegación.

F P
I A
N K
LI
N O
U M
AL
L E
I B
I M
P R
IM
N Figura 61: Herencia en el modelo de Odoo

I Ó
R S
5.6.1.1. Herencia clásica

VE Consiste en generar un nuevo modelo a partir de uno existente. El nuevo modelo contiene
todos los campos y métodos del anterior. Las vistas antiguas siguen siendo compatibles
con el nuevo modelo. No se crea ninguna tabla nueva, sino que se añaden las nuevas
columnas.
Para llevarlo a cabo utilizaremos el atributo _inherit, indicando la clase que estamos
heredando. La nueva clase deberá llamarse igual que la clase origen.
Para nuestro módulo “manteni”, se ha creado una clase que hereda la clase “res.partner”,
y le añade un campo para saber si esta empresa es vendedora de maquinaria. Esta
información se introduce en el archivo partner.py en la carpeta “models”.
36
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

# -*- coding: utf-8 -*-

# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import models, fields, api

class Partner(models.Model):
F P
_inherit = 'res.partner'
I A
N K
LI
machinery_seller=fields.Boolean(string="Machinery seller", default=False)

5.6.1.2. Herencia por prototipo


N O
U M
La herencia simple con atributo _name diferente al del objeto padre, se denomina
herencia por prototipo, y en ella se crea un nuevo objeto que aglutina los datos (_columns)

AL
y métodos que tenía el objeto del cual deriva, juntamente con los nuevos datos y métodos
que pueda incorporar el nuevo objeto. En este caso, siempre se crea una nueva tabla en la
E
base de datos para mapear el nuevo objeto.
L
Herencia por delegaciónIB
5.6.1.3.

I M
PR
La herencia multiple (_inherits), también denominada herencia por delegación, siempre
provoca la creación de una nueva tabla en la base de datos. El objeto derivado deberá

IM
incluir, para cada derivación, un campo many2one que apuntará al objeto del que deriva,
con la propiedad ondelete=’cascade’. Este tipo de herencia obliga a que cada recurso del

N
objeto derivado apunte a un recurso de cada uno de los objetos de los que deriva. Puede

I Ó
ocurrir que haya varios recursos del objeto derivado que apunten a un mismo recurso para
alguno de los objetos de los cuales deriva.

R S
VE

37
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.6.2. Herencia en la vista

Cuando hacemos herencia en una clase se pueden seguir usando las vistas del objeto padre.
Sin embargo también nos puede interesar disponer de una versión retocada. En tal caso, lo
mejor es heredar de las vistas existentes y modificar, añadir o eliminar campos y no
reemplazarlas totalmente.
El diseño de una vista heredada es idéntico al de la vista no heredada, sólo hay que añadir
el siguiente elemento:
F P
<field name="inherit_id" ref="id_xml_vista_padre"/>
IA
N
Si la vista id_xml_vista_padre reside en un módulo diferente al que estamos diseñando, K
LI
hemos de añadir delante el nombre del módulo:
<field name="inherit_id" ref="modulo.id_xml_vista_padre"/>

N O
Cuando el motor de herencia encuentra una vista heredada procesa el contenido del

U M
elemento arch. Para cada hijo de este elemento que tenga algún atributo, busca en la vista
padre una etiqueta con los atributos coincidentes, salvo el de la posición, y, acto seguido,

AL
combina los campos de la vista padre con los de las vista heredada. Establecerá la posición
de las nuevas etiquetas a partir de los siguientes valores:


E
inside (por defecto): los valores se añaden dentro de la etiqueta.
L

after: después de la etiqueta.
before: antes de la equiqueta. IB
• I M
P R
replace: reemplazando el contenido de la etiqueta
Por ejemplo, utilizamos el archivo partner.xml, para la vista de la clase heredada que

IM
hemos creado en el apartado anterior.
<?xml version="1.0" encoding="utf-8"?>
N
<odoo>
I Ó
<data>

R S
<record id="view_partner_seller" model="ir.ui.view">

V E<field name="name">partner.seller</field>

<field name="model">res.partner</field>

<field name="inherit_id" ref="base.view_partner_form"/>

<field name="arch" type="xml">

<!--<field name="lang" position="after">

<field name="machinery_seller" domain="[('parent_id', '=', False)]"/>

</field> -->

38
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

<page name="internal_notes" position="before">

<page name="Maintenance" string="Maintenance">

<group>

<field name="machinery_seller" domain="[('parent_id', '=', False)]"/>

</group>

</page>

</page>
F P
</field>
IA
</record>

N K
LI
</data>

</odoo>

N O
U M
AL
L E
I B
I M
P R
IM
N
I Ó
R S
V E

39
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.7. Seguridad

Para gestionar la seguridad de Odoo tenemos dos apartados dentro de configuración:


Usuarios (subapartados Usuarios y Grupos) y Seguridad (subapartados Reglas de registro y
Lista de controles de acceso). Desde estos apartados, un usuario con permisos de
administración, puede configurar la política de seguridad de la empresa.
Dentro del apartado Configuración/Usuarios/Grupos veremos los grupos de privilegios F P
I A
sobre los módulos instalados en Odoo. A su vez, cada grupo de privilegios puede tener

N K
asociados usuarios. En la siguiente figura podemos ver los grupos de usuarios del usuario
demo, que se instaló durante la instalación de Odoo al activar la casilla datos de
demostración.
LI
N O
U M
AL
L E
I B
I M
P R
IM
N
I Ó
R S
V E Figura 62: Privilegios del usuario demo

En el apartado Configuración/Usuarios/Grupos podemos ver todos los grupos de


privilegios definidos para los módulos que hemos instalado. Vemos que es establece una
jerarquía en los grupos de privilegios definidos (categoría/nombreGrupo).

40
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

F P
I A
N K
LI
N O
U M
AL
E
Figura 63: Grupos de usuario
L
I B
A continuación vamos a explicar cómo incorporamos esquemas de seguridad en los

I M
módulos que diseñemos, de forma que cuando se instale el módulo se instale también al
menos un grupo de privilegios y el administrador sólo tenga que asignar usuarios a este
grupo.
P R
IM
El esquema de seguridad básico de un módulo se define en dos archivos situados en la
carpeta security (no es obligatorio), estos archivos serán referenciados en el apartado
N
update_xml del archivo __manifest__.py. Veamos a continuación como se configuran estos

Ó
dos archivos:
I
R S
VE

41
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.7.1. security.xml

Contiene la definición de los grupos y, opcionalmente, usuarios, menús y reglas de negocio


asignadas a cada grupo.
Debe seguir una plantilla que incluye un elemento record para cada una de las definiciones
que puede contener el archivo y que será diferente según el tipo de definición: grupo o
usuario/menú/regla. La plantilla a seguir es la siguiente:
F P
<?xml version="1.0" encoding="UTF-8"?>

IA
<odoo>

N K
LI
<data noupdate="1">

<record id="idGrup" model="res.groups">

<field name="name">nomGrup</field>

<field name="category_id" ref="..."/> N O


<field name="implied_ids" eval="..."/>
U M
<field name="users" eval="..."/>
AL
</record>

<record id="idUser" model="res.users"> L E


I B
<!-- Crea/Modifica el usuario "idUser" asignándole grupos -->

</record>
I M
P R
<record id="idMenu" model="ir.ui.menu">

IM
<!-- Crea/Modifica el menú "idMenu" asignándole grupos -->

</record>
N
Ó
<record id="idRegla" model="ir.rule">
I
R S
<!-- Definición de reglas de negocio y asignación a grupos y/o empresas -->

</record>

V E
</data>

</odoo>

El atributo noupdate del elemento data toma el valor 1 para indicar que en caso de
actualización del módulo no se instale el esquema de seguridad que incorpora el módulo,
de esta forma no se sobrescribirá el esquema configurado por el administrador de la
empresa. El valor 0 indica que se instala siempre, sobrescribiendo el esquema existente. Si
hay artes que no se deben sobrescribir y otras que sí, se separan con dos elementos data
diferentes, un con un noupdate=”1” y otro con un noupdate=”0”.

42
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Como puede verse en el esquema, podremos añadir grupos, usuarios, limitar el acceso a
menús (también podíamos hacerlo desde la vista con el atributo groups), o incluso
imponer reglas para diferentes usuarios.
Presentamos como ejemplo el archivo security.xml del módulo “manteni”.

F P
IA
N K
LI
N O
U M
AL
L E
IB
I M
P R
IM
N
I Ó
R S
VE

43
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

<?xml version="1.0" encoding="utf-8"?>

<odoo>

<data noupdate="0">

<record model="ir.module.category" id="module_category_manteni">

<field name="name">Maintenance</field>
F P
<field name="description">Helps you manage your factory's industrial maintenance</field>
IA
<field name="sequence">104</field>

N K
LI
</record>

<record id="group_manteni_user" model="res.groups">

<field name="name">Maintenance Officer</field>


N O
<field name="category_id" ref="module_category_manteni"/>

</record>
U M
AL
E
<record id="group_manteni_manager" model="res.groups">

L
<field name="name">Maintenance Manager</field>
IB
<field name="category_id" ref="module_category_manteni"/>

</record> I M
P R
IM
<record id="view_your_own_workorders" model="ir.rule">

N
<field name="name">Only view your own workorders</field>

I Ó
<field name="model_id" ref="model_manteni_workorder"/>

S
<field name="groups" eval="[(4, ref('group_manteni_user'))]"/>

R
V E<field name="perm_read" eval="1"/>

<field name="perm_write" eval="0"/>

<field name="perm_create" eval="0"/>

<field name="perm_unlink" eval="0" />

<field name="domain_force">[('employee_user_id','=',user.id),('state','=','opened')]</field>

</record>

</data>
44
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

</odoo>

5.7.2. ir.model.access.csv

Es un archivo CSV, cuyo nombre no se puede cambiar. Contiene los privilegios de cada
grupo sobre los diferentes objetos del módulo. Si este archivo estuviese el XML podría
tener cualquier nombre, pero como la información que contiene proviene de una tabla es
más cómodo que sea del tipo CSV para exportarlo rápidamente desde cualquier hoja de
cálculo.
F P
El archivo ir.model.access.csv contiene toda la información de los privilegios asignados a
I
cada grupo de privilegios sobre la totalidad de los objetos del módulo. La primera línea A
contiene, obligatoriamente, el título de las columnas:
N K
LI
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"

que:
N O
Las siguientes líneas contienen las diferentes asignaciones de privilegios. Hemos de saber



M
id es el identificador a decidir, debe ser único y no puede contener ningún punto.
U
AL
name es un nombre que describe el privilegio (puede contener puntos)
• model_id: id es el nombre del objeto del modelo sobre el que se aplica el privilegio

L E
y debe ir precedido, obligatoriamente, por el prefijo model_. Si se aplica sobre un
objeto definido en otro módulo, hay que usar el prefijo nombreMódulo.model_.
• IB
group_id: id es el identificador del grupo de privilegios (definido en el fichero XML
previo).
I M

R
perm_read, perm_write, perm_create i perm_unlink son valores 0/1 para indicar,
P
respectivamente, privilegios de lectura, escritura, creación y eliminación sobre el

IM
objeto.
Si en la definición de los grupos y privilegios se hace referencia a una categoría o grupo,
N
esta o este debe estar previamente definida. Por tanto, la inclusión del archivo

I Ó
ir.model.access.csv en el archivo __manifest__.py debe hacerse posteriormente a la

R S
inclusión del archivo security.xml.

V E

Figura 64: ir.model.access para "manteni"

45
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

5.8. Carga de datos de ejemplo

A veces hay que realizar una carga masiva de datos en los objetos de un módulo. Esto
puede darse por varios motivos:
• Migración de datos de arranque de Odoo al sustituir un sistema informático.
• Carga de datos de demostración.
F P
I A
Esta carga no se debe efectuar nunca actuando directamente sobre la base de datos, pues

N K
podría conducir al mal funcionamiento del sistema. Odoo proporciona mecanismos para la
carga de datos desde ficheros CSV (solo permite la carga de recursos, registros, de un

LI
mismo objeto, tabla) o XML (permite la introducción de datos que afectan a diversos
objetos, tablas).

N O
El nombre del archivo CSV debe coincidir con el nombre del objeto (tabla donde se
añadirán o actualizaran los recursos (registros). Si primera línea debe contener,

contendrán los datos de los recursos a introducir. U M


obligatoriamente, el nombre de los campos de cada columna, y las siguientes líneas

AL
Los archivos XML siguen una plantilla como la siguiente, en la que cada elemento record
contienen datos de un recurso y el modelo al que pertenece, pudiendo incorporar datos de
recursos de diferentes modelos.
L E
<?xml version="1.0" encoding="UTF-8"?>
IB
<odoo>
I M
<data noupdate="1">

P R
<record id="idRecurso" model="nombreObjeto">

IM
<field name="campo1">valor</field>

N
<field name="campo2">valor</field>

…I Ó
R
</record>S
V E <record id="idRecurso" model="nombreObjeto">

<field name="campo1">valor</field>

<field name="campo2">valor</field>

</record>

</data>

46
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

</odoo>

El atributo id de cada elemento record que ha de ser único dentro del módulo, es un
identificador XML para el recurso, al que se puede hacer referencia desde el propio
módulo vía su nombre o desde cualquier otro módulo vía la sintaxis
nombreMódulo.identificador.
Los archivos con datos de demostración (sean CSV o XML) se deben indicar en el archivo
__manifest__.py del módulo en el apartado init_xml.
A continuación se adjunta el archivo demo.xml del módulo “manteni”. Como puede verse,
se añaden usuarios de prueba (tienen información en la tabla res_users y en la
F P
hr_employees), gamas de mantenimiento, instrucciones, máquinas y órdenes de trabajo.
I A
<odoo>

N K
LI
<data>

<!--Users-->

N O
<record id="base.user_root" model="res.users">

U M
AL
<field name="groups_id" eval="[(4,ref('manteni.group_manteni_manager'))]" />

</record>

L E
<record id="base.user_paco" model="res.users">
I B
<field name="name">Paco</field>
I M
<field name="login">paco</field>

P R
<field name="password">paco</field>

IM
<field name="groups_id" eval="[(6, 0, [ref('group_manteni_user'), ref('base.group_user')])]" />

</record>
N
I Ó
R S
<!--Employees-->

V E <record id="employee_paco" model="hr.employee">

<field name="name">Paco Fernández</field>

<field name="user_id" ref="base.user_paco"/>

<field name="department_id" ref="dep_maintenance"/>

<field name="job_id" ref="job_maintenance_officer"/>

<field name="work_location">Barcelona</field>

<field name="work_phone">+3281813700</field>
47
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

<field name="work_email">paco@odoo.com</field>

</record>

<!-- Machines -->

<record id="torno1" model="manteni.machine">


F P
<field name="name">Torno Wilkinson 1</field>
I A
<field name="serial">TW-001</field>

N K
LI
<field name="state">on_use</field>

<field name="date_begin">2017-05-01</field>

<field name="suplier_id" ref="base.res_partner_2"/>


N O
<field name="hours_maint">1000</field>

</record>
U M
AL
<!--Maitenance programs-->

L E
I
<record id="program0" model="manteni.program">
B
I M
<field name="name">Gama electrica tornos</field>

</record>
P R
IM
N
<record id="program1" model="manteni.program">

I Ó
<field name="name">Gama mecanica tornos</field>

R S
</record>

VE
<!--Maitenance instructions-->

<record id="instruction1" model="manteni.program.instruction">

<field name="name">Revision fusibles</field>

<field name="description">Revisar si los fusibles funcionan</field>

<field name="program_id" ref="program0"/>


48
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

</record>

<record id="instruction2" model="manteni.program.instruction">

<field name="name">Engrasado</field>

<field name="description">Engrasar todas las juntas</field>

<field name="program_id" ref="program1"/>

</record>
F P
I A
<record id="instruction0" model="manteni.program.instruction">

N K
LI
<field name="name">Comprobacion de continuidad</field>

<field name="description">Revisar la continuidad con un tester</field>

<field name="program_id" ref="program0"/>


N O
</record>

U M
AL
<!-- Workorders -->

L E
<record id="workorder1" model="manteni.workorder">

<field name="date_begin" >2017-05-01</field> I B


I M
<field name="description" >Mantenimiento ordinario eléctrico</field>

P R
<field name="employee_id" ref="employee_paco"></field>

IM
<field name="employee_user_id" ref="base.user_paco" />

N
<field name="machine_ids" eval="[(6, 0, [ref('torno1'), ref('torno2'), ref('torno3'), ref('torno4'),

Ó
ref('torno5'), ref('torno6')])]"></field>

I
R S
<field name="program_id" ref="program0"></field>

<field name="state" >opened</field>

V E <field name="name" >Preventivo eléctrico tornos</field>

<field name="type" >preventive</field>

</record>

</data>

</odoo>

49
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

F P
I A
N K
LI
N O
U M
AL
L E
IB
I M
P R
IM
N
I Ó
RS
VE

50
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Recursos y enlaces
Canal de Youtube de Marlon Hernández, experto en Odoo, con infinidad de tutoriales.

F P
I A
N K
Conceptos clave LI
N O
• M
El comando odoo-bin para crear el esqueleto de un módulo.
U
AL
• El archivo __manifest__.py. Incorpora toda la información que se necesita para
crear un módulo Odoo.

E
El modelo de Odoo. Conocer los diferentes tipos de campos que se pueden
L
incorporar, con sus correspondientes atributos.
• I B
Las vistas de Odoo. Permiten presentar la información de diferentes maneras, para
su explotación.
I M
• R
La herencia de Odoo. Permite modificar módulos existentes sin modificar su código
fuente. P

IM
La seguridad de Odoo. Permite que cada usuario sólo disponga de los permisos que

N
el administrador le quiera dar.

I Ó
R S
VE

51
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

Ponlo en práctica

Actividad 1

1. Intenta generar un módulo nuevo de Odoo. Parte de un diagrama UML, y genera su


modelo y sus vistas. Utiliza Pycharm para depurar.
F P
I A
N K
LI
N O
U M
AL
L E
IB
I M
P R
IM
N
I Ó
R S
VE

52
Desarrollo de Aplicaciones Multiplataforma. Sistemas de gestión empresarial
Tema 5. Desarrollo de módulos Odoo con Python

SOLUCIONARIOS

Ponlo en práctica

Actividad 1

1. Intenta generar un módulo nuevo de Odoo. Parte de un diagrama UML, y genera su


F P
modelo y sus vistas. Utiliza Pycharm para depurar.
I A
N K
Solución Actividad 1
LI
N O
La respuesta a la cuestión es “como ejemplo de esta actividad puedes consultar el módulo
“manteni” que se encuentra en el material de esta UF”.

U M
AL
L E
I B
I M
P R
IM
N
I Ó
R S
VE

53
F P
IA
N K
LI
N O
U M
AL
L E
I B
I M
P R
IM
N
I Ó
RS
VE

También podría gustarte