Vous êtes sur la page 1sur 45

Instalacin del ambiente para el curso

--------------------------------------

* Descargar ubuntu 14.04 LTS http://www.ubuntu.com/download

* Luego de instalado y reiniciado el sistema actualizar a los ltimos paquetes


disponibles

sudo apt-get update


sudo apt-get upgrade

* Instalar el software que necesitaremos para el taller

sudo apt-get install eclipse pgadmin3

Instalar Odoo 8.0


--------------------

* Descargue la ltima versin para Linux, desde la lnea de comandos ejecutar:

sudo su
wget -O - https://nightly.odoo.com/odoo.key | apt-key add -
echo "deb http://nightly.odoo.com/8.0/nightly/deb/ ./" >>
/etc/apt/sources.list
apt-get update
apt-get install odoo
apt-get install -f

* Para no generar conflictos entre la versin que se corre a travs de eclipse y


la existente en el sistema, debe desactivar el inicio del servicio Odoo con el
comando

sudo update-rc.d odoo disable


sudo /etc/init.d/odoo stop

* Configurar el usuario de base de datos `odoo` con clave `odoo`

sudo su postgres
createuser -d -S -R odoo
psql -c "ALTER USER odoo WITH PASSWORD 'odoo';"

## Configuracin de Eclipse como ambiente de desarrollo

* Instalar el mdulo PyDEV para desarrollo en Python


* Ingresar a la opcin del men **Help > Install New Software**
* En el cuadro de dialogo diligenciar **Work with:** con el valor
http://pydev.org/updates y presionar la tecla **enter**
* Desactivar el campo **Show only the latest versions of available software**
para que muestre todas las versiones disponibles
* Seleccionar para instalar la **versin 3.5.xxxxxx**, con versiones ms
actualizadas no se puede hacer debug de Odoo.
* Continue con el proceso de instalacin del plugin

* Instalar el mdulo Web Tools para incluir editor para archivos XML
* Ingresar a la opcin del men **Help > Install New Software**
* En el cuadro de dialogo diligenciar **Work with:** con el valor
http://download.eclipse.org/webtools/repository/indigo y presionar la tecla
**enter**
* Seleccionar en la lista que aparece seleccione para instalar **Eclipse XML
Editors and Tools**, se ha probado con la versin 3.3.2, pero cualquier versin
reciente debe funcionar.
* Continue con el proceso de instalacin del plugin

## Crear un proyecto y configurar el entorno para ejecutar Odoo

- En eclipse crear un nuevo proyecto PyDEV, si no se encuentra configurado el


entorno de python eclipse le preguntar si desea auto configurarlo, ud debe hacer
click en el botn **auto config** y aceptar los valores por defecto.
- Ingrese a travs del men a la opcin **Run > Run configurations**
- Haga click en el icono (parte superior izquierda) **New Launch Configuration**
- En **Name** digite **servidor Odoo**
- En **Project** seleccione el nombre del nuevo proyecto
- En **Main Module** digite **/usr/bin/openerp-server**, este es el comando
para iniciar el openerp
- En la pestaa **Arguments** en el campo **program arguments** ingrese:

-r odoo -w odoo --db_host=localhost

Estos son los parmetros que se pasarn al servidor de Odoo

- -r es el nombre del usuario para conectarse a PostgreSQL


- -w la clave asignada para conectarse a PostgreSQL

- Luego haga click en el boton **Apply** y **Run**


- Otro parmetro importante para el resto del curso es **`--addons-path`** el
cual indica al servidor donde buscar el cdigo de mdulos adicionales de Odoo,
podemos indicar que use la carpeta del proyecto eclipse con la variable **`$
{project_loc:NombreDeMiProyecto}`**, quedando el parmetro:

-r openerp -w openerp --db_host=localhost --addons-path=$


{project_loc:NombreDeMiProyecto}

**Nota**: :white_up_pointing_index: Recuerde cambiar **NombreDeMiProyecto**


por el nombre del proyecto que usted acaba de crear

Si uds adiciona este campo en este momento, al arrancar el servidor fallar


indicando que la carpeta no es vlida como addons-path, esto es porque an no
existen modulos Odoo en el proyecto.

openerp-server: error: option --addons-path: The addons-path


'/home/usuario/workspace/lecciones_odoo' does not seem to a be a valid Addons
Directory!

Tambin puede ejecutar el servidor llamando un cdigo disponible fuera de


eclipse, por ejemplo:

-r openerp -w openerp --db_host=localhost --addons-


path=/directorio/otros/modulos

Si ud indica un directorio que no existe el error que desplegar ser:

openerp-server: error: option --addons-path: The addons-path


'/home/carpeta_vacia' does not seem to a be a valid Addons Directory!

:happy_person_raising_one_hand: Uds puede utilizar el --addons-path para


indicar donde se encuentra el cdigo de la leccin que este estudiando, ejemplo.

-r openerp -w openerp --db_host=localhost --addons-


path=/home/usuario/curso-taller-openerp/lecciones/01/src

[Mayor informacin acerca de los parmetros de arranque del servidor Odoo]


(https://www.odoo.com/documentation/8.0/reference/cmdline.html#running-the-server)

* Abrir en el navegador: http://localhost:8069 y acceder a la interfaz de Odoo


* Ahora puede crear una base de datos haciendo click en **Manage Databases**
* Master Password: es el password de super administrador de Odoo por defecto
*admin*
* New Database Name: Indique el nombre de la nueva base de datos a crear
* Load Demonstration data: Indica si quiere que los mdulos se instalen con
datos de prueba
* Default language: Indica el lenguaje a instalar por defecto
* Admin password: Indica el password de administracin de la nueva base de
datos
* El proceso de creacin tomar algunos segundos, luego se presentar la pantalla
con el listado de mdulos disponibles en el sistema, puede elegir uno cualquiera
ejemplo CRM

## Continuar con las lecciones del curso

Ya con esto esta listo Odoo y eclipse para continuar con el resto de las lecciones,
El objetivo es ir creando nuestro mdulo del taller en eclipse a medida que vamos
avanzando de leccin, cada leccin tiene un archivo **README** que contiene la
teoria de la leccin y una carpeta **src** donde puede esta el cdigo de ejemplo
para leccin, este cdigo lo puede copiar y pegar en su proyecto de eclipse a
medida que avanza en las lecciones.

Al final de cada leccin existe un ejercicio propuesto el cual le ayudar a


afianzar lo visto en la leccin.

## Ejercicio Propuesto

Explore la instalacin de Odoo que realiz en las secciones anteriores y


familiarcese con la interfaz y los diferentes elementos de la misma (mens,
formularios, busquedas, listados, etc)

LecciOn 01: Estructura de un mOdulo Odoo


========================================

Directorios y archivos bAsicos


------------------------------

El mOdulo de Odoo tiene la siguiente estructura bAsica:

mi_modulo
__init__.py
mi_modulo.py
mi_modulo_view.xml
__openerp__.py

- **`__init__.py`**: Define el paquete python. El archivo incluye los mOdulos que


hacen parte del paquete.

import mi_modulo
- **`__openerp__.py`**: Define los metadatos del modulo Odoo. En la documentaciOn
de referencia de Odoo puede encontrar [mayor informaciOn de como definir un mOdulo]
(https://www.odoo.com/documentation/8.0/reference/module.html)

{
"name" : "mi_modulo",
"version" : "1.0",
"author" : "xx",
"category" : "xx",
"description" : "xx",
"depends" : ['base',],
"data" : ['mi_modulo_view.xml','mi_modulo_datos.xml',],
"demo" : ['mi_modulo_demo.xml',],
"installable" : True,
}

- **name**: Nombre del mOdulo en Odoo


- **data**: Archivos xml/csv a ser cargados en el momento de la
instalaciOn/actualizaciOn del mOdulo, de esta forma se puede cargar datos
iniciales, configuraciOn de vistas, flujos de trabajo, configuraciOn de seguridad.
- **demo**: Archivos xml/csv a ser cargados en el momento de la instalaciOn del
mOdulo pero cuando la base de datos se creO con la opciOn de cargar datos de
ejemplo.
- **depends**: Lista los mOdulos que deben estar instalados en el sistema como
requisito para instalar este mOdulo.

- **`mi_modulo.py`**: MOdulo python que contiene los objetos de negocio de nuestro


mOdulo. Ejemplo:

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


from openerp import models, fields

class mi_modulo_mi_tabla(models.Model):
_name = "mi_modulo.mi_tabla"

name = fields.Char('Nombre', size=25)


description = fields.Char('DescripciOn', size=255)

- **`mi_modulo_view.xml`**: Archivo XML que contiene la definiciOn de las vistas,


acciones y mens a ser desplegados. Ejemplo:

<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="mi_tabla_form">
<field name="model">mi_modulo.mi_tabla</field>
<field name="arch" type="xml">
<form>
<group>
<field name="name"/>
<field name="description"/>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="mi_tabla_tree">
<field name="model">mi_modulo.mi_tabla</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="description"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="mi_tabla_action">
<field name="name">Tabla</field>
<field name="res_model">mi_modulo.mi_tabla</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_root" name="Mi MOdulo"/>
<menuitem id="menu_mi_modulo" name="Mi MOdulo" parent="menu_root"/>
<menuitem id="menu_mi_modulo_mi_tabla" parent="menu_mi_modulo" name="Mi
Tabla" action="mi_tabla_action"/>
</data>
</openerp>

La estructura y nombre de archivos puede ajustarse de acuerdo a las preferencias


del desarrollador, lo importante es ajustar las referencias a los archivos a
cargarse en el momento de la instalaciOn en el archivo __openerp__.py, por ejemplo:

mi-carpeta-de-modulos
nombre_modulo
__init__.py
models
__init__.py
nombre_modulo.py
__openerp__.py
views
nombre_modulo.xml
otro_modulo
__init__.py
models.py
__openerp__.py
views.xml
mi_modulo
__init__.py
__openerp__.py
mi_modulo.py
mi_modulo_view.xml

Carga de datos con archivos XML


--------------------------------

Como se ve en el secciOn anterior un archivo XML se puede usar para cargar datos al
Odoo en el momento de instalar o actualizar un mOdulo, por cada registro que se
desea cargar en la base de datos se debe utilizar las etiquetas **record** y
**field**.

<?xml version="1.0"?>
<openerp>
<data>
<record model="res.users" id="mi_usuario">
<field name="name">Usuario creado</field>
<field name="login">username</field>
</record>
<record model="mi_modulo.mi_tabla" id="dato_1">
<field name="name">dato 1</field>
<field name="description">Esto es un dato que se carga al instalar el
mOdulo</field>
<field name="usuario_id" ref="mi_usuario"/>
</record>
</data>
</openerp>

- **`<record>`**: Tag utilizado para insertar registros en la base de datos


asociados a un Modelo que se indica en el atributo model, este tag no es solo
utilizado para definiciOn de vistas, sino para cualquier dato que se quiera
almacenar en Odoo a travs de XML.

- Atributo **`model`**: Indica en que Modelo se va a crear el nuevo registro de


datos, para el caso de las vistas todo se almacena en: *ir.ui.view*.
- Atributo **`id`**: Es un identificador unico para el registro, este
identificador sirve para referenciar el registro en otros elementos y documentos
XML en este y otros mOdulos.

- **`<field>`**: Este tag es utilizado para almacenar un valor en un campo


especifico del Modelo.
- atributo **`name`**: Indica el nombre del campo en la base de datos en el
cual se va a almacenar el valor
- atributo **`ref`**: Se indica el ID utilizado en otro registro en este
archivo XML o en alguno creado en otro mOdulo. Para otro mOdulo o archivo XML debe
indicarse el id incluyendo el nombre del mOdulo ej. `otro_modulo.id_del_objeto`

[Mayor informaciOn acerca de como cargar datos en Odoo]


(https://www.odoo.com/documentation/8.0/reference/data.html)

InstalaciOn del mOdulo


----------------------

1. Para instalar el mOdulo este debe estar disponible en la carpeta addons del
servidor Odoo, se pueden utilizar varias carpetas addons en una instalaciOn de
Odoo, las carpetas se definen en el archivo de configuraciOn */etc/odoo/openerp-
server.conf* en el parametro *addons_path*, ejemplo:

[options]
db_host = False
db_port = False
db_user = openerp
db_password = False
addons_path = /usr/lib/python2.7/dist-packages/openerp/addons,/opt/mi-
carpeta-de-modulos

Igualmente se puede pasar el parametro `--addons-path=/ruta/addons` al iniciar


el servidor de Odoo

1. Luego se reinicia el servidor

1. Buscar el nuevo mOdulo creado en *ConfiguraciOn > MOdulos locales*, si no


aparece en el listado luego de buscarlo por el nombre es porque debe registrar el
nuevo mOdulo en la base de datos ya creada, para esto entra como administrador a la
opciOn *ConfiguraciOn -> MOdulos -> Actualizar lista de mOdulos -> Actualizar* (Si
no aparece la opciOn debe ingresar a *ConfiguraciOn > Usuarios > Administrador* y
en la pestaa de *Permisos de Acceso* activar la opciOn *Caractersticas
teccnicas* y luego recargar la pAgina).
1. Para instalar el mOdulo solo debe hacer clic en instalar en el mOdulo.

Actualizar un mOdulo
--------------------

- Cuando se realizan **cambios en los archivos Python** es necesario reiniciar el


servidor de Odoo para que los cambios sean tomados, para esto debe detener el
proceso que se esta ejecutando o de lo contratio obtendrA un mensaje **error:
[Errno 98] Address already in use** en la consola de eclipse como se ve a
continuaciOn:

Exception in thread openerp.service.httpd:


Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
[ ... mas mensajes removidos para facilitar la lectura ... ]
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 98] Address already in use

Si hay cambios en archivos XML estos no se van a aplicar con solo reiniciar el
servidor.

- Cuando los **cambios son solo en archivos XML** se puede hacer la actualizaciOn a
traves de la interfaz web de administraciOn del Odoo. Para esto debe:

1. Ingresar a *ConfiguraciOn > MOdulos locales*


1. Buscar el mOdulo a actualizar por el nombre
1. Hacer click en el botOn **Actualizar**

- Cuando se esta desarrollado se requiere constantemente actualizar los mOdulos


sobre los que se trabaja, para esto se puede adicionar como parAmetro de inicio del
servidor Odoo el argumento `--update=nombre_modulo` o `-u nombre_modulo`. En
eclipse adicionar este argumento en el Run Configuration que este utilizando. Esto
ejecutarA la atualizaciOn automAtica del mOdulo cada vez que reinicia el Odoo
server, evitando hacer la actualizaciOn a traves de la interfaz web como se mostrO
en el paso anterior.

Ejercicio propuesto
-------------------

1. Cree un nuevo proyecto PyDev en eclipse y use el cOdigo disponible en la carpeta


*$RUTA_CURSO_TALLER/lecciones/01/src/*

1. Cree un nuevo perfil de ejecuciOn de Odoo a travs de *Run > Run


Configurations* que incluya el parAmetro *--addons-path* y este apunte a la carpeta
donde esta el cOdigo del proyecto creado en eclipse.

1. Instale el mOdulo en la base de datos de Odoo que creO en la lecciOn anterior.

1. Examine como se adicionan y editan registros a travs del menu *Mi MOdulo > Mi
Tabla*

1. Abra el archivo **mi_modulo_datos.xml** y adicione un nuevo registro. Debe


actualizar el mOdulo luego de cambiar el archivo XML.

1. Modifique el archivo **mi_modulo_datos.xml** y adicion un nuevo registro,


actualice el mOdulo para ver el nuevo registro creado.
Leccin 02: Modelos Odoo
========================

Esta leccin explica la forma bsica de construir Modelos Odoo y definir sus
campos.

[TOC]

Mi primer Modelo Odoo


---------------------

Cada Modelo contiene campos y mtodos. Para crear un modelo solo es necesario crear
una clase python que herede de **models.Model**, models.Model es la clase base que
se encarga de servir como [ORM - Object Relational Mapping]
(http://es.wikipedia.org/wiki/Mapeo_objeto-relacional) y gestiona el acceso y
almacenamiento de datos en PostgreSQL.

Estructura bsica de un objeto de negocio:

```python
class mi_modulo_mi_objeto_de_negocio(osv.osv):
_name = 'mi_modulo.mi_objeto_de_negocio'
_description = 'descripcin del objeto de negocio'

nombre_campo_1 = fields.tipo_dato(parametros),
nombre_campo_2 = fields.tipo_dato(parametros),
```

Ejemplo:

```python
class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'
_description = 'Contiene la informacin de libros'

name = fields.Char('Titulo', size=255, help='Ttulo del libro')


active = fields.Boolean('Active', help='Activo/Inactivo')
```

En este ejemplo se crea el objeto de negocio Libro que corresponde al mdulo


Bibloteca, el objeto esta compuesto por dos campos *name* y *active*, esta
definicin va a crear una tabla **biblioteca_libro** en la base de datos PostgreSQL
para almacenar todos los registros de este objeto de negocio.

- **_name** indica el nombre con el cual se va a hacer referencia a este objeto de


negocio la plataforma OpenERP el objeto se llama **biblioteca.libro**.

- **_description** contiene la descripcin del Modelo como forma de documentar el


mismo. No usar Tldes o carcteres especiales en esta seccin.

Definicin de campos
--------------------

Los campos que hace parte del Modelo se definen como atributos de la clase python y
son instancias del mdulo python **fields.Field**. Al crear un campo en el Modelo
puede definir los siguientes atributos bsicos:
* **string:** Etiqueta/label que se despliega en la interfaz de usuario
* **help:** Ayuda que se despliega en la interfaz como un tooltip
* **readonly:** Indica que el campo es de solo lectura, por defecto *False*
* **required:** Indica que el campo es obligatorio, por defecto *False*
* **index:** Crea un [indice en la base de datos](http://es.wikipedia.org/wiki/
%C3%8Dndice_%28base_de_datos%29), por defecto *False*

Puede consultar [mayor informacin acerca de los campos que se pueden crear en
Odoo](https://www.odoo.com/documentation/8.0/reference/orm.html#fields) en la
documentacin de referencia del sitio de Odoo.

### Tipos de datos

Odoo permite crear diferentes tipos de campos en un Modelo, los bsicos son:

- fields.Char(string=None, otros_parametros)
- fields.Boolean(string=None, otros_parametros)
- fields.Integer(string=None, otros_parametros)
- fields.Float(string=None, digits=None, otros_parametros)
- fields.Text(string=None, otros_parametros)
- fields.Selection(selection=None, string=None, otros_parametros)
- fields.Html(string=None, otros_parametros)
- fields.Date(string=None, otros_parametros)
- fields.Datetime(string=None, otros_parametros)

Ejemplo:

```python
class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'
_description = 'Contiene la informacin de libros'

name = fields.Char('Titulo', size=255, help='Ttulo del libro')


active = fields.Boolean('Active', help='Activo/Inactivo')
descripcion = fields.Text('Descripcin')
fecha_publicacion = fields.Date('Fecha', help='Fecha de publicacin')
precio = fields.Float('Precio', help='Precio de compra', digits=(10,2))
state = fields.Selection(
[
('solicitud', 'Solicitado'),
('en_compra', 'Proceso de compra'),
('adquirido', 'Adquirido'),
('catalogado', 'Catalogado'),
('baja', 'De baja')
],
'Estado',
)
```

### Tip

El campo llamado **active** tiene un significado especial en la plataforma, por


defecto la interfaz que lista los registros del Modelo no muestra los registros que
tengan el valor de active igual a *False*.

Desplegar Modelos en la interfaz


--------------------------------
1. Para visualizar un Modelo en la interfaz web, lo primero que se requiere es
instalar el mdulo donde esta el cdigo del Modelo (o actualizar si el mdulo ya
estaba instalado y tiene cambios en el cdigo), siguiendo las instrucciones de la
leccin anterior y usando el cdigo de ejemplo de la leccin.

1. Luego se requiere crear una entrada de men (menu item) que permita acceder al
Modelo, para esto debe

1. Ingresar a *Tcnico >> Estructura de la base de datos >> Modelos*, en esta


pgina se despliega un listado de todos los Modelos instalados en Odoo.
1. Buscar y seleccionar el Modelo **biblioteca.libro**, en la pgina del Modelo
se despliega la metadata que almacena Odoo acerca del Modelo creado a travs del
cdigo python
1. Al final de la pgina aparece un botn llamado **Crear un men**, hacer clic
en l y llenar el formulario con los siguientes datos:
- Nombre del men: **Libro**
- Men padre: **Configuracin/Configuracin**

El men padre **Configuracin/Configuracin** es uno ya existente en la


plataforma, se puede usar uno cualquiera de los que existe o crear uno nuevo.

1. Recargar la pgina, luego de esto podr observar que se despliega el submen


*Configuracin* y el men item *Libro*. Al hacer click en l se despliega el
listado de libros y el botn para crear un nuevo registro. Estas vistas son
autogeneradas, ms adelante en el taller se indica como construir las vistas con
cdigo XML.

Ejercicio propuesto
-------------------

Tomando como base el cdigo fuente disponible en la leccin:

1. Revisar la metadata que almacena Odoo para los Modelos y Campos de los mdulos
instalados.
1. Explore la base de datos PostgreSQL utilizando el programa *pgadmin3*, busque y
revise la tabla *biblioteca_libro*, hacer una captura de pantalla para tenerlo como
referencia y poder comparar la tabla luego de realizar los cambios de los
siguientes ejercicios de esta leccin.
1. Adicionar nuevos estados al campo de tipo seleccin *state*: solicitado, proceso
de compra, adquirido.
1. Adicionar los campos:

- isbn tipo char tamao 13


- paginas tipo integer
- fecha_compra tipo date
- nombre_autor tipo char tamao 255

1. Adicionar un texto de ayuda para cada uno de los campos que no lo tenga y
verifique en la interfaz que se despliega.
1. Crear un nuevo Modelo llamado **biblioteca.prestamo** y adicione los campos:

- fecha tipo datetime


- duracion_dias tipo integer
- fecha_devolucion tipo datetime.

1. Crear un men de acceso al objeto **biblioteca.libro_prestamo** que tenga como


men padre **Configuracin/Configuracin**.
1. Adicione, modifique y elimine registros para el Modelo **biblioteca.libro**,
revise que pasa cuando el campo active esta en True o en False.
1. Explore la base de datos utilizando el programa *pgadmin3*, busque y revise como
ha cambiado la tabla *biblioteca_libro* luego de los cambios realizados en el
mdulo.

Leccin 03: Vistas Bsicas


=============================

[TOC]

Para ingresar, actualizar, eliminar y desplegar registros para los Modelos


definidos en Odoo se hace uso de la interfaz web, esta interfaz se define a travs
de vistas.

Al crear un mdulo la interfaz de usuario se define a travs de archivos XML, estos


archivos son cargados en la base de datos en el momento de instalarse el mdulo. La
interfaz web es creada dinmicamente utilizando la configuracin de vistas para
cada Modelo disponible en la base de datos a partir de los archivos XML instalados.

Existen diferentes tipos de vistas disponibles en OpenERP, un Modelo puede tener


asociadas varias vistas, las vistas bsicas son:

- form: formulario
- tree: listado/rbol
- search: bsqueda

Cada tipo de vista permite una presentacin diferente de los datos almacenados.
Para el despliegue de las vistas se utiliza comunmente un enlace desde el men de
opciones de la interfaz web, estos mens son creados en conjunto con las vistas en
el XML y cargadas posteriormente a la base de datos. En la leccin anterior creamos
un men item directamente en la base de datos, pero para poder replicar este item
en otras instalaciones de Odoo, es necesario que exista la definicin del men en
el cdigo de un mdulo.

Definicin de una vista


-----------------------

La estructura para la creacin de una vista a travs de un archivo XML es la


siguiente:

<record model="ir.ui.view" id="nombre_modelo_tipo_vista">


<field name="name">Nombre de la vista</field>
<field name="model">nombre_modulo.nombre_modelo</field>
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<tree>
<field name="campo_1"/>
<field name="campo_2"/>
<field name="campo_3"/>
.
.
.
<field name="campo_n"/>
</tree>
</field>
</record>
- **`name`**: Es el nombre con el cual se identifica la vista
- **`model`**: Indica el modelo al cual esta vista estar enlazado
- **`priority`**: Indica el orden de prioridad de la vista para el Modelo, la vista
con menor prioridad ser la vista por defecto a utilizarse. Por defecto el valor es
16. Tambin se usa para indicar el orden en que se aplican los cambios cuando se
hereda la vista.
- **`arch`**: Indica la estructura de la vista, dentro de este tag se coloca en
forma de documento XML la definicin de la vista, esta puede cambiar de acuerdo al
tipo de vista definido.

[Ms informacin acerca de la definicin de vistas]


(https://www.odoo.com/documentation/8.0/reference/views.html#common-structure)

Vista tipo listado


------------------

El tipo de vista listado o tree, se utiliza para visualizar el listado de registros


que existe en la base de datos para el Modelo que se visualiza
en la vista; en este tipo de vista se deben adicionar los campos ms relevantes
para ser desplegados.
Cada lista puede ser definido utilizando los siguientes elementos bsicos:

- **`default_order`**: Permite indicar el criterio de organizacin de los registros


del listado.
- **`colors`**: Se puede asignar un color a la fuente de letra a los registros que
cumplan con una condicin especifica. [Consulte los colores vlidos]
(http://www.w3.org/TR/css3-color/#colorunits)
- **`fonts`**: Se puede asignar un estilo de fuente de letra a los registros que
cumplan con una condicin especifica. Los estilos permitidos son `bold`, `italic`,
`underline`.
- **`editable`**: Se puede indicar que el registro sea editable desde la vista tipo
lista sin necesidad de abrir el objeto en un formulario. Los valores permitidos son
`top` o `bottom`.

[Ms informacin acerca de la definicin de vistas tipo listado]


(https://www.odoo.com/documentation/8.0/reference/views.html#lists)

Ejemplo para la creacin de una vista tipo lista:

<record model="ir.ui.view" id="biblioteca_libro_tree">


<field name="name">biblioteca.libro.tree</field>
<field name="model">biblioteca.libro</field>
<field name="arch" type="xml">
<tree colors="blue:state=='solicitud';green:state=='catalogado'"
editable="top" fonts="bold:state=='en_compra'">
<field name="isbn"/>
<field name="titulo"/>
<field name="autor"/>
<field name="paginas"/>
<field name="state"/>
</tree>
</field>
</record>

Vista tipo formulario


---------------------

Los formularios permiten creacin y/o edicin de registros, cada formulario puede
ser definido utilizando los siguientes elementos bsicos:

- **`notebook`**: Crea un contenedor de pestaas (tabs).


- **`page`**: Crea una pestaa dentro del *notebook*, requiere un atributo `string`
con el nombre de la pestaa.
- **`newline`**: Crea un salto de lnea, obligando a que los elementos siguientes
se ubiquen en la siguiente lnea.
- **`separator`**: Crea una linea separadora con una etiqueta definida en el
atributo `string`
- **`label`**: Crea una etiqueta de texto
- **`group`**: Permite agrupar elementos y opcionalmente asignar una etiqueta
- atributo **`colspan`**: Indica el nmero de columnas que va a tomar el grupo
- atributo **`col`**: Indica el nmero de columnas que el elemento va a
contener para organizar los elementos incluidos en el grupo. Por defecto un grupo
tiene dos columnas.
- **`sheet`**: Permite agrupar los elementos de un formulario dentro de un recuadro
que emula una pgina impresa, dandole margen al formlario.
- **`header`**: Permite organizar una cabecera donde incluir botones de accin y
desplegar el estado del objeto.
- **`HTML Tags`**: Tambin se pueden adicionar tags HTML para personalizar la
estructura de la vista.
- **`field`**: Despliega o permite la edicin del dato del registro para un campo
especifico del Modelo.
- atributo **`name`**: Obligatorio. Indica el nombre del campo en el modelo.
- atributo **`widget`**: Permite indicar que el campo tenga una visualizacin
diferente a la predefinida. Algunos widgets son: `statusbar`, `progressbar`,
`selection`
- atributo **`class`**: Indica una clase CSS usada para darle estilo al campo.
Algunas clases predefinidas son: `oe_inline`, `oe_left`, `oe_right`,
`oe_read_only`, `oe_edit_only`, `oe_no_button`, `oe_avatar`.

[Ms informacin acerca de la definicin de vistas tipo formulario]


(https://www.odoo.com/documentation/8.0/reference/views.html#forms)

Ejemplo para la creacin de una vista tipo formulario:

<record model="ir.ui.view" id="libro_form">


<field name="name">biblioteca.libro.form</field>
<field name="model">biblioteca.libro</field>
<field name="arch" type="xml">
<form>
<header>
<field name="state" widget="statusbar" clickable="1"/>
</header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Ttulo" />
<h1><field name="name"/></h1>
</div>
<separator string="Detalles"/>
<group>
<field name="isbn"/>
<field name="nombre_autor"/>
<field name="paginas"/>
<field name="active"/>
</group>
<notebook>
<page string="Descripcin">
<field name="descripcion" placeholder="Descripcin del
libro"/>
</page>
<page string="Fechas">
<group>
<label string="Fechas importantes en la gestin del
libro" colspan="2" class="oe_read_only"/>
<field name="fecha_compra"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>

Window Actions y Menu Items


---------------------------

Los Actions indican a Odoo como debe responder frente a una accin del usuario,
existen varios tipos de actions, el ms utilizado es el Window Action, el cual
define que modelo se va a desplegar, que vistas van a estar disponibles y la
configuracin general de las mismas. Para generar un action utilizamos el `record`
para el model `ir.actions.act_window` a continuacin se listan los atributos ms
relevantes para configurar el action:

- **`name`**: Un nombre para el action, se utiliza para desplegarse en la interfaz


web.
- **`res_model`**: Se indica el nombre del Modelo del cual se va a presentar la
informacin.
- **`view_type`**: Cuando se abre el tipo de vista listado, este parmetro indica
si este se abre como un listado normal `form` o como un rbol desplegable `tree`.
- **`view_mode`**: Indica los tipos de vista que van a estar disponibles.
- **`limit`**: Se indica cuantos registros se van a desplegar en los listados. Por
defecto se despliegan 80.
- **`view_id`**: Se puede indicar el ID de una vista especifica para ser
desplegada.

[Ms informacin acerca de la definicin de window actions]


(https://www.odoo.com/documentation/8.0/reference/actions.html#window-actions-ir-
actions-act-window)

Ejemplo para la creacin de un action a ser utilizado en el men:

<record model="ir.actions.act_window" id="libro_action">


<field name="name">Catlogo de Libros</field>
<field name="res_model">biblioteca.libro</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="limit">10</field>
</record>

La estructura de mens se define al igual que las vistas usando un documento XML.
Para este caso vamos a usar el tag `menuitem`.

- atributo **`id`**: Identificador del menuitem para ser referenciado en otros


menuitems
- atributo **`name`**: Indica el nombre a desplegarse en el men.
- atributo **`parent`**: Indica el ID de otro menuitem que va a ser el item padre
de este menu, esto permite generar el rbol de navegacin. Si no tiene padre, el
menuitem va a aparecer en la barra superior de navegacin.
- atributo **`action`**: Indica el ID de una accin que va a ser ejecutada. Esta
accin indica que Modelo va a ser desplegado y que vistas se van a incluir.

Acontinuacin un ejemplo de como crear men para ul mdulo:

<menuitem id="biblioteca_nav_menu" name="Biblioteca"/>


<menuitem id="biblioteca_menu" name="Ctalogo" parent="biblioteca_nav_menu"/>
<menuitem id="biblioteca_libro_menu" parent="biblioteca_menu" name="Libros"
action="libro_action"/>

Ejercicios propuestos
---------------------

Tomando como base el cdigo fuente disponible en la leccin:

- Adiciones varios registros en el men *Libros*. :white_up_pointing_index: Cuando


esta en la vista formulario de un registro puede hacer click en la opcin que
aparece en la parte superior central *Ms >> Duplicar*, para crear una copia del
registro actual.
- Cambie el estado de algunos registros a *solicitud* o *catalogado* y vea como
cambia de colores el listado de libros.
- Adicione a la vista tipo listado del Modelo *biblioteca.libro* el campo
`fecha_publicacion`.
- Asigne nuevos colores a la vista tipo listado para los estados en *Proceso de
compra* y *De baja* del Modelo *biblioteca.libro*
- Ingrese al men *Biblioteca >> Catlogo >> Editar precios* y edite los precios de
los libros.
- Haga clic en el botn crear y adicione un nuevo registro
- Modifique la vista con el id `precio_libro_tree` y coloque
`editable="bottom"`
- Actualice y cree un nuevo registro. Nota la diferencia?
- Ingrese al men *Configuracin >> Tcnico >> Interfaz de usuario >> Elementos
men*, bsque los menus creados para el mdulo y revise los datos que se almacenan
en la base de datos a partir del XML.
- Ingrese al men *Configuracin >> Tcnico >> Interfaz de usuario >> Vistas*,
bsque las vistas creadas para el Modelo *biblioteca.libro* y revise los datos que
se almacenan en la base de datos a partir del XML.
- Ingrese al men *Configuracin >> Tcnico >> Acciones >> Acciones de ventana*,
bsque las acciones creadas para el Modelo *biblioteca.libro* y revise los datos
que se almacenan en la base de datos a partir del XML.
- Active el **modo desarrollador**, ingresando a la opcin *Acerca de Odoo* que se
despliega en el men de la parte superior derecha en la barra negra de navegacin
donde dice *Administrador*.
- Abra la vista listado del Modelo *biblioteca.libro*, en la parte superior
del formulario, abajo del men de navegacin ver que aparece un campo de seleccin
que dice *Depurar vista#xx*, haga clic y seleccione la opcin *Editar TreeVista*.
- En el cuadro de dialogo que se despliega puede observar que aparece la
vista definida, modifique el campo en la pestaa *estructura* y adicione el campo
`<field name="fecha_publicacion"/>`
- Guarde y cierre el cuadro de dilogo y recargue la pgina. Ver que la
interfaz se actualiza basado en el dato actualizado de la base de datos.
- Ahora reinicie el servidor Odoo en el eclipse y note como los cambios que
hizo en la base de datos se reversan luego de actualizado el mdulo.
- Crear el item del men para el Modelo *biblioteca.prestamo*
- Cree las vistas tree y form para el Modelo *biblioteca.prestamo*
Leccin 04: Reglas Bsicas y Restricciones en Modelos
=====================================================

[TOC]

Los Modelos en Odoo permiten configuraciones adicionales que agregan reglas que
permiten manejar la consistencia de los datos basado en las necesidades de la
aplicacin.

Campos requeridos, de solo lectura y valores por defecto


--------------------------------------------------------

Cada campo puede ser definido como requerido, de solo lectura o asignarsele un
valor por defecto, un campo del Modelo puede asignarsele uno o varios de estos
atributos. A continuacin un ejemplo:

```python
import random

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'

def _precio_aleatorio(self):
return random.random()

name = fields.Boolean('Active', help='Activo/Inactivo', required=True)


active = fields.Boolean('Active', help='Activo/Inactivo', default=True)
fecha_publicacion = fields.Date('Fecha de Publicacin', help='Fecha de
publicacin', default=fields.Date.today)
precio = fields.Float('Precio', help='Precio de Compra', digits=(10, 2),
default=_precio_aleatorio, readonly=True)
isbn = fields.Char('ISBN', size=255, help="International Standard Book Number",
copy=False)

```

- Atributo **`required`** se usa para indicar si el **campo es obligatorio** o no


en la creacin/edicin de un registro en el Modelo. True indica que el campo es
requerido y False que el campo es no requerido.

Si no se define el atributo required en el campo, por defecto toma el valor de


required = False.

En la interfaz web el campo va a tener un fondo de color azul claro que va a


indicar que el campo es obligarotio

- Atributo **`readonly`** se usa para indicar si el campo **puede o no ser


editable** por el usuario. use True si el campo es no editable y False que pueda
ser editable.

Si no se define el atributo readonly en el campo, por defecto toma el valor de


readonly = False.

- Atributo **`default`** se usa para indicar el valor por defecto que va a tener el
campo cuando se cree un registro nuevo. Se puede indicar el valor a tomarse o una
funcin que retornara el valor por defecto a utilizarse. En este diccionario se
adiciona como llave el nombre del campo y como valor lo que deseamos sea el valor
por defecto o una funcin que hace el clculo del mismo. Se pueden utilizar
funciones lambda o mtodos de la clase. Debe recordar que los mtodos de la clase
deben estar previamente definidos para poder utilizarlos. [Ms informacin acerca
de valores por defecto]
(https://www.odoo.com/documentation/8.0/howtos/backend.html#default-values)

- Atributo **`copy`** se usa para indicar que cuando se duplique un registro el


campo debe o no ser copiado. `copy=False` evita que se copie, por defecto el valor
es `True`

Restricciones de Modelo: @api.constrains


----------------------------------------

Si se desea que los Modelos tengan restricciones que sean verificadas antes de
almacenar los registros, estas se deben definir como mtodos de la clase donde se
utiliza el decorador @api.constrains.

```python
from openerp.exceptions import ValidationError
import datetime

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'

@api.one
@api.constrains('fecha_publicacion','fecha_compra')
def _check_fechas(self):
present = datetime.now()
if self.fecha_compra and self.fecha_compra > present:
raise ValidationError("Fecha de compra incorrecta")
if self.fecha_publicacion and self.fecha_publicacion > present:
raise ValidationError("Fecha de publicacin incorrecta")

```

Restricciones SQL: _sql_constraints


-----------------------------------

Otro tipo de restriccin que se puede utilizar para programar validaciones es a


travs del diccionario _sql_constraints, donde se pueden adicionar restricciones
programadas con sentencias SQL.

_sql_constraints = [
('unique_isbn','unique(isbn)','El ISBN debe ser nico'),
]

*En este ejemplo se restringe al usuario la duplicacin de registros validados por


el campo isbn definido como campo nico.*

Las restricciones SQL se definen como un arreglo de tuplas que contienen:

* Nombre de la restriccin
* Restriccin SQL a aplicar
* El mensaje de error a ser desplegado en caso de que se viole la restriccin
Si la base de datos ya tiene datos que violan la restriccin, esta no va a crearse,
ni aplicarse. Cuando esto pase, va a aparecer un error en el log del servidor como
el siguiente:

2015-01-20 13:34:29,959 10290 INFO nombre_basedatos openerp.modules.module:


module biblioteca: creating or updating database tables
2015-01-20 13:34:30,009 10290 WARNING nombre_basedatos openerp.models.schema:
Table 'biblioteca_libro': unable to add 'unique(isbn)' constraint !
If you want to have it, you should update the records and execute manually:
ALTER TABLE "biblioteca_libro" ADD CONSTRAINT "biblioteca_libro_unique_isbn"
unique(isbn)

Para aplicar la restriccin SQL ud debe corregir los datos primero, para este caso
eliminando los ISBN duplicados y actualizar nuevamente el mdulo.

Ejercicios propuestos
---------------------

Utilizando el cdigo de la leccin:

- Crear un nuevo registro y verificar que los campos `active`, `fecha_publicacion`


y `precio` se llenan con el valor por defecto indicado en el cdigo.
- Modificar el cdigo para que el campo `fecha_compra` tenga un valor por defecto.
- Modificar el cdigo para que el valor por defecto del campo `state` sea
*Solicitud*
- Modificar el cdigo para que el campo `nombre_autor` tenga un valor por defecto
generado aleatoriamente utilizando [generador de nombres en python]
(https://pypi.python.org/pypi/names/)
- Cambie el atributo `copy` del campo `name` a *False*, verifique que sucede cuando
se utiliza la opcin de *Ms >> Duplicar* en la vista formulario de un registro de
libro. Revise nuevamente dejando `copy` con el valor de *True*
- Verifique que no puede crear/editar un libro y asignar un ISBN ya utilizado por
otro libro. Ajuste los datos para poder activar la restriccin si esta no fue
aplicada.
- Adicionar una restriccin utilizando el decorador `@api.constraints` para que el
campo `paginas` no acepte valores menores a 0 ni valores mayores a 5000
- Utilizando `_sql_constraints` adicione un constraint para que el campo `precio`
no acepte valores negativos. Ver [sentencia SQL soportada por posgreSQL para CHECK]
(http://www.postgresql.org/docs/9.4/static/ddl-constraints.html)

Leccin 05: Dominios, Busquedas, Filtros y Agrupamientos


========================================================

[TOC]

Dominios
--------

Los dominios en Odoo son utilizados para filtrar los registros a los que se tiene
acceso en las vistas o en consultas dentro del cdigo del Modelo.

Estos dominios se pueden asimilar a las condiciones que se agregan en un WHERE en


una sentencia SQL. Si para nuestro ejemplo de la biblioteca normalmente en SQL
ejecutamos

SELECT * FROM biblioteca_libre WHERE paginas > 100 AND nombre_autor ILIKE
'%cervantes%'
en Odoo el dominio se estructurara

[('paginas','>',100),('nombre_autor','ilike','%cervantes%')]`

Un dominio es un listado de criterios, en el ejemplo anterior hay dos criterios,


estos criterios estan formados por:

- **`Nombre del campo`** del Modelo sobre el cual se aplica el filtro.


- **`Operador`** a utilizarse para la bsqueda a realizar [=, !=, >, >=, <, <=, =?,
=like, like, not like, ilike, not ilike, =ilike, in, not in, child_of]
(https://www.odoo.com/documentation/8.0/reference/orm.html#domains)
- **`Valor`**: Valor sobre el cual se compara para la bsqueda

Los criterios se pueden combinar utilizando operadores lgicos en [notacin prefijo


o polaca](http://es.wikipedia.org/wiki/Notaci%C3%B3n_polaca) usando los operadores
siguientes:

- '&' AND, operador por defecto


- '|' OR
- '!' NOT

Para una consulta SQL como esta:

SELECT * FROM biblioteca_libro WHERE paginas > 100 AND nombre_autor ILIKE
'%cervantes%' OR nombre_autor ILIKE '%marquez%'

El dominio sera:

[('paginas','>',100),'|',('nombre_autor','ilike','%cervantes%'),
('nombre_autor','ilike','%marquez%')]

Bsquedas
---------

Las bsquedas (search) son un tipo de vista que se asocia a un Modelo con el objeto
de permitir realizar bsquedas por campos especificos, adicionar filtros
predeterminados y agrupaciones sobre los registros que se despliegan en las vistas
tipo listado. A continuacin un ejemplo de una vista search.

<record model="ir.ui.view" id="libro_search">


<field name="name">biblioteca.libro.search</field>
<field name="model">biblioteca.libro</field>
<field name="arch" type="xml">
<search>
<field name="isbn" string="ISBN del libro"/>
<field name="name" string="Ttulo del libro"/>
<separator string="Filtros por Estados"/>
<filter name="solicitud" string="En Solicitud" help="Estado del
regristro En progreso"
domain="[('state','=','solicitud')]"
/>
<filter name="catalogado" string="Catalogado" help="Estado del
registro Catalogado"
domain="[('state','=','catalogado')]"
/>
<filter name="no_catalogado" string="No catalogado" help="Libros no
catalogados"
domain="[('state','!=','catalogado')]"
/>
<separator string="tamao"/>
<filter name="grandes" string="Libros grandes" help="Libros con ms
de 1000 pginas"
domain="[('paginas','>=',1000)]"
/>
<filter name="pequenos" string="Libros pequeos" help="Libros con
menos de 1000 pginas"
domain="[('paginas','&lt;',1000)]"
/>
<group string="Group By...">
<filter string="Clasificacin del Libro"
context="{'group_by':'clasificacion'}"/>
<filter string="Gnero del Libro"
context="{'group_by':'genero'}"/>
<filter string="Editorial" context="{'group_by':'editorial'}"/>
<filter string="Estado" context="{'group_by':'state'}"/>
</group>
</search>
</field>
</record>

- **Bsquedas por campos**: Para permitir la bsqueda por campos especificos del
modelo solo se debe agregar una etiqueta `field` e indicar el nombre del campo por
el cual que se pemite realizar la bsqueda. En el momento de escribir en el cuadro
de bsqueda que aparece en la parte superior derecha, se va a desplegar un listado
de los campos sobre los cuales se va a aplicar la bsqueda. Estas bsquedas son
abiertas, ud define el valor por el cual buscar.

- **Filtros predeterminados**: estos son bsquedas predeterminadas que le usuario


simplemente aplica haciendo clic sobre el filtro. Para adicionar un filtro necesita
adicionar una etiqueta `filter` e indicar en el parmetro `domain` un dominio
siguiendo la sintaxis vista en la seccin anterior. Los filtros pueden agruparse
utilizando la etiqueta `separator`, estos grupos sirven para indicar si al aplicar
varios filtros se va a usar los operadores lgicos *AND* u *OR*. Si dos filtros
aparecen en el mismo grupo se aplica *OR*, si estan en grupos aparte se aplica
*AND*. Visualmente el cuadro de bsqueda en la interfaz web va a desplegar los
filtros aplicados de manera separada si se usa un *AND* y unidos si se aplica *OR*
tal como se muestra en la imagen a coninuacin:
![filtros en Odoo](odoo_filtros.png)

- **Agrupaciones**: Se pueden agrupar los registros por campos, estas agrupaciones


son defidas con la etiqueta `filter` y el atributo `context` donde se incluye un
diccionario con la clave `group_by` y el nombre del campo por el cual se va a
agrupar.

(Mayor informacin acerca de las vistas tipo bsqueda en Odoo)


[https://www.odoo.com/documentation/8.0/reference/views.html#search]

Ejercicios propuestos
---------------------

Tomando como base el cdigo de la leccin:

1. Cargue en el Odoo los datos del archivo [src/biblioteca/biblioteca_libro.csv]


(src/biblioteca/biblioteca_libro.csv), esto lo puede hacer a travs del link
*_importar_* que aparece en la vista de listado del Modelo *biblioteca.libro*. [Ms
informacin acerca de importar archivos .csv]
(https://www.odoo.com/documentation/8.0/reference/data.html#csv-data-files)
1. Utilizar las busquedas, filtros y agrupamientos ya programados para la leccin.
1. Revise como se comportan los filtros de los grupos 'Estados' y 'Tamaos', luego
del cdigo de la vista elimine el separador `<separator string="tamao"/>`,
actualice el mdulo y vea como se comportan los filtros ahora.
1. Selecciones varias opciones del formulario de bsqueda, luego use la opcin
llamada *Guardar Filtro Actual* y active la opcin *Usar por defecto*. Haga click
en el menuitem *Libros* para ver como siempre se aplica el filtro guardado.
1. Utilice la opcin llamada *Bsqueda Avanzada* en el formulario de bsqueda.
1. Cree una vista de bsqueda para el Modelo *biblioteca.prestamo*

Leccin 06: Vistas Dinmicas


============================

[TOC]

Actualizar formulario al cambiar valores: @api.onchange


--------------------------------------------------------

Muchas veces es necesario que algunos campos del formulario se actualicen basados
en las selecciones o datos que se ingresan en otros campos del formulario, para
esto se utiliza el decorador `@api.onchange` en cualquier mtodo python que se
implemente en el Modelo. Ejemplo:

```python
from openerp import models, fields, api

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'

@api.onchange('precio')
def onchange_precio(self):
if self.precio and self.precio > 1000:
self.descripcion = 'Ta muy caro el libro'

```

De igual forma se puede utilizar un mtodo onchange para enviarle al usuario


mensajes de validacin a medida que va llenando el formulario, esto no es un
remplazo para las restricciones que se adicionen con _sql_constraints o
@api.constraints, ya que onchange solo aplica a nivel de vista y no se llama en el
momento de guardar los datos.

```python
from openerp import models, fields, api

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'

@api.onchange('isbn')
def onchange_warning_isbn(self):
if self.isbn and len(self.isbn) < 10:
self.descripcion = 'Verifique el ISBN cumpla con la norma'
return {
'warning': {
'title': "ISBN",
'message': "El largo del ISBN debe ser mayor o igual a 10
caracteres",
}
}

```

Si desea que un metodo @api.constraints sea tambin llamado cuando el usuario


cambia el valor en el formulario web puede hacerlo adicionando el @api.onchange
decorator. Pero debe tener en cuenta que el error se llama utilizando `raise
ValidationError` y no retornando un diccionario como en el ejemplo anterior.

```python
from openerp import models, fields, api

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'

@api.one
@api.constrains('paginas')
@api.onchange('paginas')
def _check_paginas(self):
if self.paginas < 0 or self.paginas > 5000:
raise ValidationError("Un libro debe tener entre 0 y 5000 pginas")

```

Si no se desea que se llame el onchange en una vista en particular puede adicionar


en la vista:

<field name="NOMBRE_DEL_CAMPO" on_change="0"/>

Mayor informacin del uso de onchange en:

- https://www.odoo.com/documentation/8.0/reference/orm.html#onchange-updating-ui-
on-the-fly
- https://www.odoo.com/documentation/8.0/howtos/backend.html#onchange

Cambios basado en otros campos: attrs


-------------------------------------

La interfaz tambin puede cambiar dinmicamente utilizando el atributo **attrs** en


las etiquetas `button`,`field`,`notebook`. El atributo *attrs* permite que se
cambie los valores definidos para los campos en las opciones `invisible`,
`required` y `readonly` de acuerdo a una regla de dominio que se cumpla.

- **Invisible**: El atributo invisible permite mostrar u ocultar un campo en la


vista, el valor `True` oculta el campo. Ejemplo:

<field name= "descripcion" attrs= "{'invisible': [('state', '=',


'baja')]}"/>

En el ejemplo se indica que el campo descripcin se oculta cuando el estado es


del libro es **De baja**.

- **Required**: El atributo required permite indicar si el campo es o no


obligatorio a nivel de la vista, esto no cambia el valor de required para el campo
a nivel de modelo. Ejemplo:
<field name="paginas" attrs="{'required': [('state', '=', 'en_compra')]}"/>

En el ejemplo se indica que el campo *paginas* es obligatorio a nivel de vista


si el estado del libro es **Proceso de Compra**.

- **Readonly**: El atributo readonly permite indicar si el campo es o no de solo


lectura a nivel de la vista. Ejemplo:

<field name="name" attrs="{'readonly': [('state','=','catalogado')]}"/>

En el ejemplo se indica que el campo titulo es unicamente de lectura en la


vista cuando el estado del libro es **Catalogado**.

Igualmente puede incluir todos los atributos en **attrs**. Ejemplo:

<field name="name" attrs="{'invisible': [('state', '=', 'baja')], 'required':


[('state', '=', 'compra')], 'readonly': [('precio','>',100)]}"/>

El ejemplo anterior hace que el campo titulo no aparezca en el formulario cuando el


*state* es *baja*; el campo va a ser obligatorio si el estado es *compra* y quedar
en modo solo lectura cuando el estado es *catalogado*

Igualmente si ud quiere en la vista utilizar los atributos `invisible`, `required`


y `readonly` sin depender de una condicin lo puede hacer como se muestra
acontinuacin:

<field name="nombre_campo" invisible="1" required="1" readonly="1"/>

Ejercicios propuestos
---------------------

Utilizando el cdigo de la leccin:

1. Verifique que el precio no puede ser editable a travs de la vista formulario


del libro, pero si a travs del men editar precios. Verifique en la definicin de
la vista como se hizo.
1. Cambie un libro de estado y vea como se comporta la pestaa de *fechas* cuando
esta en modo edicin.
1. Ajuste los campos de *Editorial*, *Clasificacin* y *Gnero* para que sean
obligatorios cuando el estado del libro sea *Adquirido*
1. Ajuste los campos de *Editorial*, *Clasificacin* y *Gnero* para que sean de
solo lectura cuando el estado es *Catalogado* y *De baja*

Leccin 07: Relaciones entre Modelos


====================================

[TOC]

Las aplicaciones comunes requieren que los datos esten relacionados, veremos a
continuacin como manejar las relaciones entre Modelos, a travs de nuevos tipos de
campos one2many, many2one y many2many.

Relaciones Many2one
-------------------
Utilizando un campo de tipo Many2one creamos una relacin directa entre el Modelo
actual (donde se define el campo) y algn otro Modelo, este campo crea la llave
foranea entre las tablas de dos Modelos. Su estructura bsica es la siguiente:

nombre_campo_id = fields.Many2one('Nombre del Modelo', 'Etiqueta', [...])

Los parmetros recibidos por este tipo de campo son:

- **Nombre del Modelo**: Nombre del Modelo con el cual crear la [relacin de llave
fornea](http://www.postgresql.org/docs/9.4/static/tutorial-fk.html), ej.
`biblioteca.libro`, `res.partner`, `res.users`
- **Etiqueta**: Etiqueta a desplegarse en la vista web para este campo
- **ondelete**: Indica a la base de datos como manejar la relacin cuando el
registro del modelo relacionado sea eliminado. Los valores disponibles son: `set
null`, `restrict`, `cascade`; por defecto se usa `set null`
- **domain**: Criterio que limita el listado de registros a ser listados para ser
relacionados con el Modelo actual. ej. Ver solo los libros catalogados y no los que
estan en compra. :white_up_pointing_index: Ud puede agregar el dominio como un
*string* `domain="[('state', '=', 'catalogado')]"` o como una *lista de tuplas*
`domain=[('state', '=', 'catalogado')]`, cuando se adiciona como string el dominio
se evalua en el lado del cliente y puede usar nombres de campos despues del
operador, pero cuando es una lista de tuplas se evalua en el lado del servidor y no
permite el manejo de campos, solo de valores.

[Mayor informacin del campo Many2one en la informacin oficial de referencia de


Odoo]
(https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.fields.Many2one)

Ejemplo:

```python
from openerp import models, fields, api

class biblioteca_prestamo(models.Model):
_name = 'biblioteca.prestamo'
_description = 'Registro de prestamo'

libro_id = fields.Many2one('biblioteca.libro', 'Libro prestado',


domain=[('state', '=', 'catalogado')])
```

### Despliegue en la vista

Para que el campo se despliegue en la vista debe simplemente agregar en el


documento XML el tag `field` con el nombre del campo, como se hace regularmente.
Pero de manera adicional tiene la posibilidad de adicionar los siguientes
atributos:

- Atributo **`widget`**: permite indicar que se utilice `selection`, para que la el


widget de seleccin sea mucho ms simple que el que viene por defecto y no
despliegue la opcin de crear o editar.

- Atributo **domain**: Permite a nivel de vista adicionar restriciones de campos a


desplegar para la seleccin de registros a ser relacionados.

Relaciones One2many
-------------------
Un campo One2many permite que el Modelo actual (donde se define el campo) pueda
acceder a todos los registros relacionados, este campo requiere que el Modelo
relacionado tenga creado un campo tipo Many2one que haga referencia al Modelo
actual. Su estructura es la siguiente:

nombre_campo_ids = fields.One2many('Nombre del Modelo Relacionado', 'Nombre


del campo que contine la relacin', 'Etiqueta', [...])

Los parmetros recibidos por este campo son:

- **Nombre del Modelo Relacionado**: Nombre del Modelo que contiene el campo
Many2one que apunta a este Modelo. Ej. `biblioteca.prestamo`
- **Nombre del campo que contine la relacin**: Nombre del campo Many2one que
existe en el Modelo relacionado. Ej. `libro_id`

Por convencin el nombre del campo se le adiciona el sufijo **_ids**

[Mayor informacin del campo One2many en la informacin oficial de referencia de


Odoo]
(https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.fields.One2many)

Ejemplo:

```python
from openerp import models, fields, api

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'
_description = 'Libro de la biblioteca'

prestamo_ids = fields.One2many('biblioteca.prestamo', 'libro_id', 'Prestamos


realizados')
```

### Despliegue en la vista

Para que el campo se despliegue en la vista debe simplemente agregar en el


documento XML el tag `field` con el nombre del campo, como se hace regularmente. ej
`<field name="prestamo_ids"/>`. Pero de manera adicional puede indicar como
desplegar los registros relacionados:

- Atributo **`mode`**: Por defecto se despliegan los registros relacionados


utilizando la vista tipo listado o `tree` del Modelo relacionado, pero se puede
indicar si se desa utilizar una vista tipo [`graph`]
(https://www.odoo.com/documentation/8.0/reference/views.html#graphs) o [`kanban`]
(https://www.odoo.com/documentation/8.0/reference/views.html#kanban), estas vistas
se explicarn en otra leccin.

Se puede definir la estructura de la vista a ser utilizada dentro de la misma


etiqueta `field` tal como se muestra a continuacin:

<field name="prestamo_ids">
<tree>
<field name="fecha"/>
<field name="fecha_devolucion"/>
</tree>
</field>

Relaciones many2many
--------------------

La relacin many2many consiste en que un Modelo A puede tener relacin con uno o
varios registros del Modelo B y a su vez el Modelo B se puede relacionar con varios
registros del Modelo A, a diferencia de one2many donde la cardinalidad es de muchos
a uno. Para esto se requiere de una tabla intermedia que almacena la relacin entre
los Modelos, esta tabla es generada automticamente y no se puede acceder como un
Modelo independiente. Su estructura es la siguiente:

nombre_campo_ids = fields.Many2many('Nombre Modelo del Relacionado',


string='Etiqueta')

Los parmetros recibidos por este campo son:

- **Nombre del Modelo Relacionado**: Nombre del Modelo que contiene el campo
Many2one que apunta a este Modelo. Ej. `biblioteca.prestamo`
- **domain**: Criterio que limita el listado de registros a ser listados para ser
relacionados con el Modelo actual.

Por defecto Odoo genera el nombre de la tabla intermedia y de los campos


relacionados, pero estos pueden ser indicados explicitamente utilizando

- **relation**: Nombre de la tabla a utilizar para almacenar los registros de la


relacin
- **column1**: Nombre de la columna en la tabla de relacin que va a contener los
IDs del **Modelo actual** (donde se esta definiendo el campo)
- **column2**: Nombre de la columna en la tabla de relacin que va a contener los
IDs del **Modelo relacionado**

Por convencin el nombre del campo se le adiciona el sufijo **_ids**

Ejemplo:

```python
from openerp import models, fields, api

class biblioteca_libro(models.Model):
_name = 'biblioteca.libro'
_description = 'Libro de la biblioteca'

genero_ids = fields.Many2many('biblioteca.genero', string="Generos")

class biblioteca_genero(models.Model):
_name = 'biblioteca.genero'
_description = 'Genero literario'

libro_ids = fields.Many2many('biblioteca.libro', string="Libros")

```

:white_up_pointing_index: El ejemplo va a crear una tabla para la relacin llamada


`biblioteca_genero_biblioteca_libro_rel` y con los campos: `biblioteca_libro_id` y
`biblioteca_genero_id`

### Despliegue en la vista

Para que el campo se despliegue en la vista debe simplemente agregar en el


documento XML el tag `field` con el nombre del campo, como se hace regularmente. ej
`<field name="genero_ids"/>`. Pero de manera adicional puede indicar como desplegar
los registros relacionados:

- Atributo **`widget`**: Por defecto se despliegan los registros relacionados


utilizando la vista tipo listado o `tree` del Modelo relacionado, pero se puede
indicar si se desea utilizar un widget diferente como **`many2many_tags`**.

Ejercicios propuestos
---------------------

Utilizando el cdigo de ejemplo de la leccin:

1. Crear un prestamo y ver como el campo libro solo muestra los libros en estado
*catalogado*.
1. Adicione generos a un registro del Modelo libro.
1. En la vista tipo formulario del Modelo *prestamo* adicionar el atributo
`widget="selection"` en el campo `libro_id`. Nota la diferencia?
1. En la vista tipo formulario del Modelo *libro* adicionar el atributo
`widget="many2many_tags"` en el campo `genero_ids`. Nota la diferencia? Adicione
nuevos generos a varios registros del Modelo libro.
1. En la vista tipo formulario del Modelo *libro* adicionar en el listado de
prestamos el campo `duracion_dias`.
1. Crear un Modelo **biblioteca.editorial** con el campo `name`
1. Crear una relacin many2one de *libro* a *editorial* y el inverso one2many de
*libro* a *editorial*, desplegarlos en las vista formulario.
1. Crear un Modelo **biblioteca.autor** con el campo `name`
1. Crear una relacin many2many de *libro* a *autor* y el inverso de *autor* a
*libro*, desplegarlos en las vista formulario.
1. Verifique a travs de pgadmin3 la estructura de las tablas y los *constraints*
creados.

Leccin 08: Campos funcionales, atributos y decoradores avanzados


=================================================================

[TOC]

Campos Related
--------------
En algunos casos es necesario tener disponible el valor de un campo de un Modelo
relacionado, como si fuera un campo del Modelo actual, por ejemplo si tenemos los
Modelos Persona -> Ciudad -> Pais, podemos adicionar un campo en Persona que nos
diga directamente cual es el Pais, basado en la seleccin de la Ciudad. Para esto
definimos un proxy a travs de un campo con el atributo `related`.

```python
from openerp import models, fields, api

class pais(models.Model):
_name = 'mi_modulo.pais'
_description = 'Pais'

name = fields.Char('Nombre')

class ciudad(models.Model):
_name = 'mi_modulo.ciudad'
_description = 'Ciudad'

name = fields.Char('Nombre')
pais_id = fields.Many2one('mi_modulo.pais','Pas')

class persona(models.Model):
_name = 'mi_modulo.persona'
_description = 'Persona'

ciudad_id = fields.Many2one('mi_modulo.ciudad', 'Ciudad de Residencia')


pais = fields.Many2one(related='ciudad_id.pais_id')

```

Ud puede modificar el campo `persona->pais_id` y eso cambiar el valor en el


registro `ciudad->pais_id`, tambin automticamente la interfaz web va a mostrar el
pas cuando se selecciones la ciudad. Se pueden adicionar otros atributos propios
del campo que aplicarian solo al Modelo actual (persona) tales como: string, help,
readonly, required y estos no afectaran la definicin original del campo.
`
Campos computados
-----------------

Muchas veces los campos tienen valores que deben calcularse de automticamente,
para esto se utiliza el atributo: `compute` y el nombre del mtodo del Modelo que
har el clculo del valor. Por ejemplo:

```python
from openerp import models, fields, api
import datetime.timedelta

class biblioteca_prestamo(models.Model):
_name = 'biblioteca.prestamo'
_description = 'Informacion de prestamo de libros'

fecha = fields.Datetime(
'Fecha del Prestamo',
help="Fecha en la que se presta el libro",
)
duracion_dias = fields.Integer(
'Duracin del Prestamo(das)',
help="Nmero das por los cuales se presta el libro",
)
fecha_devolucion = fields.Datetime(
'Fecha Devolucin',
compute='_compute_fecha_devolucion',
help="Fecha de devolucin del libro",
)

@api.one
def _compute_fecha_devolucion(self):
"""Calcula la fecha de devolucin basado en la fecha inicial y la duracin
en das del prestamo"""
fecha = fields.Datetime.from_string(self.fecha)
self.fecha_devolucion = fecha + timedelta(days=10)

```
Con el cdigo anterior el clculo se va a realizar cuando se guarde el registro en
la base de datos y en la interfaz el campo se va a mostrar como de solo lectura. Si
se desea que se pueda tambin definir manualmente la fecha de devolucin, se debe
usar el atributo `inverse` y el nombre del mtodo del Modelo que har el clculo
inverso. Para nuestro ejemplo el mtodo inverson debera calcular la duracin en
das a partir de la fecha del prestamo y la fecha de devolucin.

```python
from openerp import models, fields, api
import datetime.timedelta

class biblioteca_prestamo(models.Model):
_name = 'biblioteca.prestamo'

[...]

fecha_devolucion = fields.Datetime(
'Fecha Devolucin',
compute='_compute_fecha_devolucion',
inverse='_compute_inv_fecha_devolucion',
help="Fecha de devolucin del libro",
)

[...]

@api.one
def _compute_inv_fecha_devolucion(self):
"""Calcula la fecha duracin en das del prestamo basado en la fecha de
devolucin"""
if self.fecha and self.fecha_devolucion:
fecha = fields.Datetime.from_string(self.fecha)
fecha_devolucion = fields.Datetime.from_string(self.fecha_devolucion)
delta = fecha_devolucion - fecha
self.duracion_dias = delta.days

```

Por defecto el valor del campo es calculado en el momento en que se carga el


registro y no es almacenado en la base de datos, si se desea que se almacene en la
base de datos se debe adicionar el atributo `store=True`.
:happy_person_raising_one_hand: Cuando se utiliza store=True se recomienda utilizar
el decorador depends, para que que se le indique cuando debe ser recalculado el
valor del campo basado en los valores de otros campos del modelo, ms detalles en
la siguiente seccin.

Decorador: depends
------------------

@api.depends('fecha', duracion_dias')

Decorador: multi
----------------

Decorador: one
--------------

Decorador: model
----------------
Atributo: states
----------------

Manejo de rboles
------------------

- related
- depends
- multi
- states
- parent

Related
-------

Los campos related se utiliza cuando el campo es una referencia de un id de otra


tabla. Esto es para hacer referencia a la relacin de una relacin.

**Estructura de definicin**

'nombre_campo_related': fields.related (
'id_busqueda',
'campo_busqueda',
type = "tipo_campo",
relation = "objeto_negocio_a_relacionar",
string = "Texto del campo",
store = False
)

* **id_busqueda**: nombre de campo id de referencia del objeto de negocio


relacionado para realizar la bsqueda.
* **campo_busqueda**: nombre del campo de referencia, el cual devuelve el valor de
ese campo segn la busqueda realizada por el id_busqueda en el objeto de negocio a
relacionar.
* **type**: Tipo del campo related. Tipo de relacin para el campo related con el
objeto de negocio.
* **relation**: Nombre del objeto de negocio al cual se aplica la relacin con el
campo tipo related.
* **string**: Texto para el campo tipo related.
* **store**: Este puede ser definida como True o False, segun lo requerido, con
este valor estamos indicando si el valor devuelto por campo_busqueda es almacenado
o no en la base de datos.

**Ejemplo de aplicacin**:

'titulo': fields.related(
'libro_id','titulo',
type="char",
string="Titulo",
store=False,
readonly=True
),

En este ejemplo se crea el campo titulo de tipo related el cual devuelve el titulo
del libro segn el valor del campo libro_id.

Domain
------
El atributo domain es un atributo aplicado a los campos para definir una
restriccin de dominio en un campo relacional, su valor por defecto es vacio.

**Estructura de definicin**

domain = [('campo', 'operador_comparacion', valor)])

* **campo**: nombre del campo del objeto de negocio, este campo ser utilizado para
la restriccin.
* **operador_comparacion**: operador para comparar el campo con el valor
establecido.
* **valor**: valor asignado para evaluar la restriccin de dominio.

**Ejemplo de aplicacin**:

Function
--------

Un campo funcional es un campo cuyo valor se calcula mediante una funcin, en lugar
de ser almacenado en la base de datos.

**Estructura de definicin**

'nombre_campo_function' : fields.function(
_nombre_metodo,
type='tipo_campo',
obj= "objeto_de_negocio.function",
method= True,
string= "Texto del campo"
)

* **_nombre_metodo**: nombre del mtodo creado para realizar el calculo.


* **type**: Tipo del campo funtion. Tipo de relacin para el campo function con el
objeto de negocio obj.
* **obj**: objeto de negocio al cual se aplica la relacion con el campo function.
* **method**: True.
* **string**: Texto para el campo tipo function.

**Ejemplo de aplicacin**:

Ejercicios propuestos
---------------------

1. Revisar los cambios realizados en el mdulo ejemplo biblioteca.


1. Adicionar un campo tipo function.

[[
title: Leccin 09: Navegar Registros
author: STRT Grupo I+D+I
]]

Leccin 09: Navegar Registros


=============================

[TOC]
Aadir un botn a la vista formulario
--------------------------------------

Se puede adicionar botones de accin a la vista formulario, los botones de accin


permiten al usuario realizar diversas acciones en el registro actual. Maneja los
siguientes atributos:
Identificador del botn, que se utiliza para indicar qu mtodo debe ser llamado,
que envi la seal o que la accin ejecutada.

* ***name***: Nombre de la funcin que se activiara por medio del boton.


Identificador del botn, se utiliza para indicar qu mtodo debe ser llamado, que
seal o que accin se ejecutar.
* ***string***: Etiqueta que se mostrar en el botn.
* ***type***: Define el tipo de accin realizada cuando se activa el botn.
* *workflow* (default): El botn enviar una seal de workflow al modelo
actual con el Name del botn como seal del workflow y retornar como parmetro el
ID del registro (en una lista). La seal del workflow puede retornar una accin la
cual ser ejecutada, de lo contrario devolver False.
* *object*: El botn ejecutar el mtodo de nombre Name en el modelo actual,
retornar como parmetro el ID del registro (en una lista). Retorna una accin la
cual ser ejecutada.
* action: El botn activar la ejecucin de una accin (ir.actions.actions).
El ID de esta accin es el Name del botn.
* ***special***: Slo tiene un valor *cancelar*, lo que indica que el popup debe
cerrarse sin realizar ninguna llamada RPC o accin. Se usa en ventanas popup-type,
por ejemplo wizard.El atributo special y type son incompatibles.
* ***confirm***: Ventana de confirmacin antes de ejecutar la tarea del botn.
* ***icon***: Mostrar un icono en el botn.
* ***states, attrs, invisible***: Significado estndar para esos atributos de
vista.
* ***default_focus***: Si se establece en un valor Truthy, automticamente se
selecciona el botn, tambien usado si se presiona RETURN en la vista formulario.

**Estructura para adicionar un botn en la vista**

<button name="nombre_funcion" type="object"></button>

Ejemplo de adicion de un botn:

<button name="confirmar_compra" states="solicitud" string="Confirmar proceso


de Compra" icon="gtk-execute"/>
<button special="cancel" string="Cancelar Solicitud"/>

Mtodo Search
-------------

Este mtodo realiza la bsqueda de regristros, basndose en el dominio de bsqueda


indicado. Maneja los siguientes parmetros:

* ***offset***: Nmero de registros a omitir. Parmetro opcional, por defecto 0.


* ***limit***: Nmero mximo de registros a devolver. Parmetro opcional, por
defecto None.
* ***order***: Columnas para establecer el criterio de ordenacin. Opcional. Por
defecto self._order=id.
* ***count***: Devuelve slo el nmero de registros que coinciden con el criterio
de bsqueda.
* ***args***: Lista de tuplas que especifican el dominio de bsqueda. Cada tupla de
la lista del dominio de bsqueda necesita 3 elementos en la forma ('field_name',
'operator', value), donde:
* *field_name*: Nombre del campo del objeto de negocio
* *operator*: Operador de comparacin (=, !=, >, >=, <,<=, like, ilike, in, not
in, child_of, parent_left, parent_right).
* *value*: Valor con que realizar la comparacin.

El dominio de bsqueda puede ser una combinacin que use 3 operadores lgicos que
pueden aadirse entre tuplas:

* '&': Y lgico. Por defecto,se omite el operador.


* '|': O lgico.
* '!': No lgico o negacin.

**Estructura de definicin del mtodo**

search(cr, uid, args, offset=0, limit=None, order=None, context=None,


count=False)

Ejemplo:

libros_pool = self.pool.get('biblioteca.libro')
libros_ids = libros_pool.search(cr, uid,[('state','=','compra')],
context=context)

En este ejemplo el mtodo search realiza una bsqueda por todos los registros del
objeto *biblioteca.libro* y cuando un registro coincida con el criterio de bsqueda
'state','=','compra', el id del registro se almacenar en libros_ids.

Mtodo Read
-----------

Obtiene una lista de los valores de los campos fields de los registros ids,
devuelve un diccionario con el nombre y valor de los campos solicitados. Tiene los
siguientes parmetros:

* ***fields***: Lista de campos.

**Estructura de definicin del mtodo**

read (cr, uid, ids, fields=None, context=None)

Ejemplo de aplicacin read:

libros_pool = self.pool.get('biblioteca.libro')
libros_ids = libros_pool.search(cr, uid,[('state','=','compra')],
context=context)
libros_records = libros_pool.read(cr, uid, libros_ids, ['titulo','autor'])

En este ejemplo del mtodo read obtiene una lista de los valores de los campos
*'titulo', 'autor'* de los registros que coincidan con los ids almacenados en
libros_ids, esta lista se almacena en libros_records como un diccionario con nombre
y valor de los campos indicados.

Ejemplo de aplicacin del mtodo read:

**Adicin de funcin en el objeto de negocio biblioteca.libro_prestamo**

def obtener_promedio_prestamo_metodo_read(self,cr,uid,ids,context=None):
prestamo_ids = self.read(cr, uid, ids, ['prestamo_ids'], context=context)
prestamo_pool = self.pool.get('biblioteca.libro_prestamo')
prestamo_records = prestamo_pool.read(cr, uid, prestamo_ids[0]
['prestamo_ids'], ['fecha_prestamo', 'fecha_regreso'], context=context)
tiempo_total = 0
for record in prestamo_records:
tiempo_dias = (datetime.strptime(record['fecha_regreso'],'%Y-%m-%d') -
datetime.strptime(record['fecha_prestamo'],'%Y-%m-%d')).days
tiempo_total = tiempo_total + tiempo_dias
raise osv.except_osv('Promedio de tiempo de prstamo','{0}
das'.format(tiempo_total))
return True

**Adicin de boton en la vista formulario del objeto de negocio


biblioteca.libro_prestamo**

<button name="obtener_promedio_prestamo_metodo_read" string="Promedio de


Prstamo (read)" type="object"/>

En este ejemplo de aplicacin se realiza una bsqueda en los registros de prstamos


que correspondan al estado entregado de los libros con id libro_id, se realiza un
clculo del promedio de tiempo de prstamo del libro. record_ids solo almacena una
lista con los campos 'fecha_prestamo' y 'fecha_regreso' por cada registro
encontrado.

Mtodo Browse
-------------

El mtodo browse obtiene registros como objetos permitiendo utilizar la notacin de


puntos para explorar los campos y las relaciones, permite consultar con facilidad
campos relacionados de forma encadenada a partir de un objeto.

**Estructura de definicin del mtodo**

browse (cr, uid, ids, context=None)

Ejemplo:

libros_pool = self.pool.get('biblioteca.libro')
libros_ids = libros_pool.search(cr, uid,[('state','=','compra')],
context=context)
libros_records = libros_pool.browse(cr, uid, libros_ids, context=context)

En este ejemplo el mtodo browse obtiene los registros que correspondan a los ids
almacenados en libros_ids, estos registros se almacenan en libros_records.

Ejemplo de aplicacin del mtodo browse:

**Adicin de funcin en el objeto de negocio biblioteca.libro_prestamo**

def obtener_promedio_prestamo_metodo_browse(self,cr,uid,ids,context=None):
prestamo_ids = self.read(cr, uid, ids, ['prestamo_ids'], context=context)
prestamo_pool = self.pool.get('biblioteca.libro_prestamo')
prestamo_records = prestamo_pool.browse(cr, uid, prestamo_ids[0]
['prestamo_ids'], context=context)
tiempo_total = 0
for record in prestamo_records:
tiempo_dias = (datetime.strptime(record['fecha_regreso'],'%Y-%m-%d') -
datetime.strptime(record['fecha_prestamo'],'%Y-%m-%d')).days
tiempo_total = tiempo_total + tiempo_dias
raise osv.except_osv('Promedio de tiempo de prstamo','{0}
das'.format(tiempo_total))
return True

**Adicin de boton en la vista formulario del objeto de negocio


biblioteca.libro_prestamo**

<button name="obtener_promedio_prestamo_metodo_browse" string="Promedio de


Prstamo (browse)" type="object"/>

Este ejemplo realiza la misma tarea que la funcin


obtener_promedio_prestamo_metodo_read, con la diferencia que record_ids almacena el
registro completo de los prestamo_ids encontrados.

Ejercicios propuestos
---------------------

1. Adicionar una restriccin al prstamo por libros. Solo debe existir un prstamo
activo por cada libro.

[[
title: Leccin 10: Extensin de Mdulos Base
author: STRT Grupo I+D+I
]]

Leccin 10: Extensin de Mdulos Base


=====================================

[TOC]

Extender Objetos
----------------

Los objetos de negocio pueden heredar de un mdulo base, esta herencia se puede
utilizar para modificar, extender, utilizar mtodos.

**Estructura de definicin**

_inherit = 'nombre_objeto_base_a_heredar'

**_inherit**: Se utiliza cuando heredamos Modelos o Clases en OpenERP.


**_inherits**: La lista de objetos base que el objeto hereda. Esta lista es un
diccionario de la forma: {'name_of_the_parent_object': 'name_of_the_field', ...}.

Existen dos formas de extender un objeto. Ambas formas generan una nueva clase, que
tiene campos y funciones heredadas, as como campos y mtodos adicionales.

* **Forma 1**: Las instancias de estas clases son visibles por las vistas (views or
trees) que operan con la clase padre. Este tipo de herencia se denomina herencia de
clase (class inheritance), es de utilidad para sobreescribir mtodos de la clase
padre.

Ejemplo:

class nombre_clase(osv.osv):
_name = 'nombre_objeto_base'
_inherit = 'nombre_objeto_base'
_columns = {
'campo_1: fields.tipo_campo('text_campo'),
}
nombre_clase()

* **Forma 2**: Las instancias de estas clases no son visibles por las vistas (views
or trees) que operan con la clase padre. Las instancias de estas clases contienen
todos las propiedades y mtodos de la instancia padre junto con las propiedades y
mtodos definidos en la nueva entidad. Este tipo de herencia se denomina herencia
por prototipos (inheritance by prototyping). La nueva subclase contiene una copia
de las propiedades de la clase padre.

Ejemplo:

class nombre_clase(osv.osv):
_name = 'nombre_objeto_negocio'
_inherit = 'nombre_objeto_base'
_columns = {
'campo_1: fields.tipo_campo('text_campo'),
}
nombre_clase()

**Ejemplo de aplicacin**:

class res_users(osv.osv):
_inherit = "res.users"
_columns = {
'prestamo_id' : fields.one2many('biblioteca.libro_prestamo',
'user_id', 'Prstamos'),
}

res_users()

Se adiciona el campo 'user_id' al objeto biblioteca.libro_prestamo:

'user_id': fields.many2one('res.users', 'Usuario solicitante',


help= 'Usuario que solicita el prstamo'
),

Con este ejemplo relacionamos el objeto de negocio res.users con los prstamos de
los libros. Se extieden el objeto res.users y se le adiciona el campo prestamo_id.

Extender Vistas
---------------

Tambin podemos heredar vistas, al igual que se puede heredar objetos. Parmetros:

* ***inherid_id***: ID de la vista ha heredar. La '<carpetapadre> es la primera


carpeta que se encuentra en ADDONS, en la cul se encuentra el fichero xml, en el
que est definida la vista.

**Estructura de definicin**

<record model="ir.ui.view" id="nombre_form_inherit">


<field name="name">nombre.form.inherit</field>
<field name="model">nombre</field>
<field name="type">form</field>
<field name="inherit_id" ref="carpetapadre.idVistaPadre" />
<field name="arch" type="xml">
<field name="campoareemplazar" position="after">
<field name="nuevocampo" />
</field>
<notebook position="inside">
<page string="texto para la nueva pestaa">
<group col="2" colspan="2">
<separator string="texto del separador" colspan="2"/>
<field name="nuevocampo2"/>
<field name="nuevocampo3" nolabel="1"/>
</group>
</page>
</notebook>
</field>
</record>

id es el nuevo identificador de la nueva vista. Por definicin manejar el nombre


del id terminado en 'form_view_inh' para identificar que es una vista heredada.

**Ejemplo de aplicacin**:

<record id="res_users_form_inherit" model="ir.ui.view">


<field name="name">res.users.form.inherit</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<page string="Access Rights" position="after">
<page string="Detalles Adicionales">
<group col="2">
<field name="prestamo_id"/>
</group>
</page>
</page>
</field>
</record>

En este ejemplo se extiende la vista base.view_users_form y se adiciona el nuevo


campo prestamo_id.

Ejercicios propuestos
---------------------

1. Revisar la extensin del objeto y la vista realizada en la leccin.


1. Consultar los prstamos realizados por los usuarios, igresando al men usuarios
ubicado en configuracin, pestaa detalles adicionales.

Leccin 11: Otros Widgets y Vistas


==================================

[TOC]

Widgets
-------

Widget es la clase base para todos los componentes visuales, un widget es un


componente genrico dedicado a mostrar el contenido al usuario.

Los widgets son utilizados de manera automtica de acuerdo al tipo de dato del
campo a mostrar, pero estos widgets pueden ser manualmente seleccionados si es
necesario. Existen diferentes widgets que pueden seleccionarse:

**widget="many2many_tags"**: Permite la seleccin para un campo Many2many al estilo


de tags de la web 2.0
**widget="monetary"**: Permite visualizar el simbolo moneda, requiere que en el
atributo `options` se indique el campo de tipo *res.currency* (tipo de moneda) a
ser utilizado.
**widget="mail_followers"**: Permite adicionar seguidores a las notificaciones de
un registro, el Modelo debe heredar de `mail.thread`
**widget="mail_thread"**: Despliega las notificaciones que tiene un registro, el
Modelo debe heredar de `mail.thread`
**widget="statusbar"**: Muestra los valores de campo Selection en una barra,
sealando el que esta actualmente seleccionado. En el widget se puede indicar por
defecto cuales valores desplegar `statusbar_visible` y si es clickable para poder
hacer cambiar la seleccin actual `clickable="1"`. Las opciones statusbar_visible y
clickable son mutuamente excluyentes.
**widget="progressbar"**: Muestra el valor del campo en forma de una barra de
progreso
**widget="url"**: Muestra el campo como un enlace web
**widget="integer"**: Permite almacenar solo valores enteros
**widget="image"**: Muestra el valor de un campo binary como una imagen
**widget="handle"**: Permite organizar un listado de registros y almacenar la
posicin en un campo con el nombre **sequence**. Para que los listados se
desplieguen utilizando el campo sequences se debe adicionar en el Mdelo el
atributo _order="sequence ASC"
**widget="selection"**: Despliega un campo Many2one sin las opciones de buscar,
crear o editar.

Ejemplo de aplicacin de widget:

<field name="state" widget="statusbar"/>


<field name="presupuesto" widget="monetary" options="{'currency_field':
'currency_id'}"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,sent,progress,invoiced,done"/>
<field name="state" widget="statusbar" clickable="1"/>

Vista tipo kanban


-----------------

Las vistas tipo kanban permiten manejar informacin importante (campos principales)
en imgenes o tarjetas, es util para poder identificar los registros de una forma
ms rpida y as agilizar la consulta sobre los datos.

Ejemplo para la creacin de una vista tipo kanban:

<record model="ir.ui.view" id="libro_kanban">


<field name="name">libro.kanban</field>
<field name="model">biblioteca.libro</field>
<field name="type">kanban</field>
<field name="arch" type="xml">
<kanban version="7.0" class="oe_background_grey">
<field name="titulo"/>
<field name="autor"/>
<field name="user_id"/>
<templates>
<t t-name="kanban-box">
<div class="oe_resource_vignette">
<div t-attf-
class="oe_kanban_color_#{kanban_getcolor(record.state.value)} oe_kanban_card
oe_kanban_global_click">
<div class="oe_kanban_project_avatars">
<img t-att-src="kanban_image('res.users',
'image', record.user_id.raw_value)"
t-att-title="record.user_id.value"
width="24" height="24"
class="oe_kanban_avatar"
/>
</div>
</div>
<div class="oe_resource_details">
<ul>
<li><field name="state"/></li>
<field name="titulo"/>
<field name="autor"/>
</ul>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>

Para que la vista se despliegue es necesario adicionar en el action_libro el tipo


de vista kanban.

<record model="ir.actions.act_window" id="action_libro">


<field name="name">Libro</field>
<field name="res_model">biblioteca.libro</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph,kanban</field>
</record>

Vista tipo gantt


----------------

Las vistas tipo gantt permiten mostrar el tiempo planificado o transcurrido para el
desarrollo de tareas o actividades, es una vista dinmica, se puede hacer click en
cualquier parte del grfico, arrastrar y soltar el objeto en otra ubicacin.

Ejemplo para la creacin de una vista tipo gantt:

<record id="biblioteca_libro_prestamo_gantt" model="ir.ui.view">


<field name="name">biblioteca.libro_prestamo.gantt</field>
<field name="model">biblioteca.libro_prestamo</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<gantt date_start="fecha_prestamo" date_stop="fecha_regreso"
string="Prstamos" default_group_by="libro_id">
</gantt>
</field>
</record>

Para que la vista se despliegue es necesario adicionar en el action_libro_prestamo


el tipo de vista gantt.

<record model="ir.actions.act_window" id="action_libro_prestamo">


<field name="name">Prestamo</field>
<field name="res_model">biblioteca.libro_prestamo</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,gantt</field>
</record>

Vista tipo calendar


-------------------

Las vistas tipo calendar permiten visualizar la planificacin en tiempo para el


desarrollo de tareas o actividades, es una vista dinmica, se puede hacer click en
cualquier parte del grfico, arrastrar y soltar el objeto en otra ubicacin.

Ejemplo para la creacin de una vista tipo calendar:

<record id="biblioteca_libro_prestamo_calendar" model="ir.ui.view">


<field name="name">biblioteca.libro_prestamo.calendar</field>
<field name="model">biblioteca.libro_prestamo</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<calendar color="libro_id" date_start="fecha_prestamo"
date_stop="fecha_regreso" string="Informe de Prstamos">
<field name="libro_id"/>
</calendar>
</field>
</record>

Para que la vista se despliegue es necesario adicionar en el action_libro_prestamo


el tipo de vista calendar.

<record model="ir.actions.act_window" id="action_libro_prestamo">


<field name="name">Prestamo</field>
<field name="res_model">biblioteca.libro_prestamo</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,gantt,calendar</field>
</record>

Vista tipo Grfica


------------------

Esta vista permite desplegar los datos disponibles en una grafica. Cada vista
grfica puede ser definida utilizando los siguientes elementos bsicos:

* atributo **`type`**: Indica el tipo de grfica a utilizarse (pie, bar), por


defecto pie
* atributo **`orientation`**: Indica la orientacin de las barras (horizontal,
vertical)
* **`field`**: Se debe ingresar como mnimo dos campos field (eje X, eje Y, eje Z),
un tercero es opcional 3
* atributo **`group`**: Se coloca en 1 para el campo a ser utilizado en el GROUP BY
* atributo **`operator`**: Indica el tipo de operador de agregacin a ser utilizado
(+,*,**,min,max)
Ejemplo para la creacin de una vista tipo grfico:

<record model="ir.ui.view" id="libro_graph">


<field name="name">libro.graph</field>
<field name="model">biblioteca.libro</field>
<field name="arch" type="xml">
<graph type="bar" orientation="horizontal" string="Grfico">
<field name="state"/>
<field name="paginas" operator="min"/>
</graph>
</field>
</record>

Botones
-------
- confirm
- states
- magic

<div class="oe_button_box oe_right">


<button name="button_fecha_compra_hoy" type="object"
class="oe_inline oe_stat_button" icon="fa-calendar-o"
string="Comprado hoy"
confirm="Se marcar el libro como adquirido en la fecha
de hoy, esta seguro?"
states="en_compra"
/>
</div>

@api.one
def button_fecha_compra_hoy(self):
self.fecha_compra = fields.Date.today()
self.state = 'adquirido'

Ejercicios propuestos
---------------------

1. Verificar las diferentes vistas creadas.


1. Coloque el libro en estado *Proceso de compra* y haga click en el botn
*Comprado hoy*, vea como cambian los campos *fecha de compra* y el *estado* del
libro.
1. Adicion un botn llamado *Devolver compra* que aparezca cuando el estado sea
*Adquirido* y que cambie la fecha de compra a vacio y el estado a *Proceso de
Compra*

[[
title: LecciOn 12: Wizards
author: STRT Grupo I+D+I
]]

LecciOn 11: Wizards


===================

[TOC]
Wizards
-------

Los Wizards son secuencias de interacciOn entre el cliente y el servidor. Para


definir un wizard, se debe crear una clase que hereda de wizard.interface e
instanciarla, cada wizard debe tener un nombre nico.

COmo adicionar un nuevo Wizard?


--------------------------------

1. Crear subdirectorio wizard en el mOdulo, adicionar el archivo __init__.py y el


archivo .py para crear el wizard.
1. Adicionar el subdirectorio wizard a la lista de declaraciones de importaciOn en
el archivo __init__.py del mOdulo.
1. Adicionar el nombre del archivo .py en el archivo __init__.py del subdirectorio
wizard.
1. Adicionar el archivo .xml para la vista del archivo .py
1. La acciOn que ejecuta el objeto debe ser: *<field name="target">new</field>*
1. Adicionar en el archivo _openerp_.py del mOdulo la vista .xml creada para el
wizard, as:

"data" : [
'wizard/radicar_prestamo_view.xml',
'biblioteca_view.xml',
]

**Ejemplo de aplicaciOn Wizard**:

Wizard para radicar un prstamo a un libro.

* **Crear archivo .py**

class biblioteca_wizard_radicar_prestamo(osv.osv_memory):
_name = "biblioteca.wizard.radicar_prestamo"
_description = "Permite radicar un prestamo"

_columns={
'libro_id':
fields.many2one('biblioteca.libro_prestamo','Codigo prstamo',
required=False,
readonly=True,
),
'fecha_prestamo': fields.date('Fecha de Prstamo'),
'duracion_prestamo': fields.integer('das prstamo',
required= True,
),
'user_id': fields.many2one('res.users', 'Usuario
solicitante',
required= True,
help= 'Usuario que solicita el prstamo'
),
}

_defaults = {
'libro_id': lambda self, cr, uid, context :
context['libro_id'] if context and 'libro_id' in context else None,
}
def action_radicar(self, cr, uid, ids, context=None):
context['prestamo_actual'] = True
form_id = ids and ids[0] or False
form = self.browse(cr, uid, form_id, context=context)
prestamo_pool = self.pool.get('biblioteca.libro_prestamo')
vals = {
'libro_id': form.libro_id.id,
'state': 'prestado',
'fecha_prestamo': form.fecha_prestamo,
'duracion_prestamo': form.duracion_prestamo,
'user_id': form.user_id.id
}
id = prestamo_pool.create(cr, uid, vals, context=context)
return self.redirect_to_prestamo_view(cr, uid, id,
context=context)

def redirect_to_prestamo_view(self, cr, uid, id, context=None):


return {
'name': 'Radicar Prestamo',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'biblioteca.libro_prestamo',
'res_id': int(id),
'type': 'ir.actions.act_window',
}
biblioteca_wizard_radicar_prestamo()

* **Crear archivo .xml**

<?xml version="1.0"?>
<openerp>
<data>
<!-- View Form Wizard -->
<record id="view_biblioteca_wizard_radicar_prestamo"
model="ir.ui.view">
<field name="name">Radicar Prestamo</field>
<field
name="model">biblioteca.wizard.radicar_prestamo</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Radicar Prestamo" version="7.0">
<group colspan="2">
<field name="libro_id" readonly="1"/>
<field name="user_id"/>
<field name="fecha_prestamo"/>
<field name="duracion_prestamo"/>
</group>
<footer>
<button name="action_radicar"
string="Radicar solicitud" type="object" class="oe_highlight" />
</footer>
</form>
</field>
</record>

<!-- Action -->


<record id="action_biblioteca_wizard_radicar_prestamo"
model="ir.actions.act_window">
<field name="name">Radicar Prestamo</field>
<field name="type">ir.actions.act_window</field>
<field
name="res_model">biblioteca.wizard.radicar_prestamo</field>
<field
name="src_model">biblioteca.wizard.radicar_prestamo</field>
<field name="view_id"
ref="view_biblioteca_wizard_radicar_prestamo"/>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

Ejercicios propuestos
---------------------

1. Revisar y registrar un prstamo a un libro utilizando el wizard de ejemplo.

[[
title: LecciOn 13: Campos y Atributos Avanzados
author: STRT Grupo I+D+I
]]

LecciOn 13: Workflow


====================

[TOC]

Que es Workflow?
-----------------

Los Workflow nos permiten gestionar las actividades relacionadas a los objetos de
negocio, se representan como grafos dirigidos donde los nodos son las actividades y
los conectores son las transiciones. La actividades son las tareas a realizar y las
transiciones indica como el workflow cambia de una actividad a otra con el fin de
gestionar los ciclos de vida de los objetos.

CreaciOn de Workflow
--------------------

En la definiciOn de un Workflow, se pueden indicar condiciones, seales, y


transiciones, por lo que el comportamiento del workflow depende de las acciones
realizadas por usuario sobre el objeto de negocio.

Lo primero a tener en cuenta es que el Worklow es definido en objetos de negocio


con campo 'state'.

* **id**: id como identificador del workflow. Se define como wkf_


+objeto_de_negocio
* **model**: Se define como workflow.
* **Name**: Nombre para el Workflow.
* **Osv**: Nombre del objeto de negocio al cual se le define el Workflow.
* **on_create**: Crea el Workflow al crear el objeto.
Ejemplo de una declaraciOn del workflow:

<?xml version="1.0" encoding="UTF8"?>


<openerp>
<data>
<record id="wkf_nombreobjetodelworkflow" model="workflow">
<field name="name">nombremodulo.basic</field>
<field name="osv">object.name</field>
<field name="on_create">True</field>
</record>
</data>
</openerp>

Restricciones para Workflow


---------------------------

Seguridad para Workflow


-----------------------

Ejercicios propuestos
---------------------

1. Revisar el workflow definido para el objeto de negocio bliblioteca.libro del


mOdulo ejemplo biblioteca.
1. Definir el workflow para el objeto de negocio biblioteca.libro_prestamo.

Vous aimerez peut-être aussi