SLIDE Técnico openERP - Desarrollo de módulos - Ting!

65
TING! DESARROLLO DE MÓDULOS FORMACIÓN TÉCNICA MADRID 19-23 JULIO 2010 JULIO 2010 V2.0 © ting! Tecnologías Inteligentes de Software S.L.

Transcript of SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Page 1: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

TING! – DESARROLLO DE MÓDULOSFORMACIÓN TÉCNICA MADRID 19-23 JULIO 2010

JULIO 2010V2.0

© ting! – Tecnologías Inteligentes de Software S.L.

Page 2: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

i. INTRODUCCIÓN

ii. ESTRUCTURA DE UN MÓDULO

a. ESTUDIO COMPLETO DE UN MÓDULO EXISTENTE

b. DESCRIPCIÓN DE MÓDULOS BÁSICOS: BASE, SALE, PRODUCT, STOCK, PROJECT

c. HERENCIA

iii. MAPEADOR ORM

iv. OBJETOS, CAMPOS Y MÉTODOS

a. DEFINICIÓN DE OBJETOS

b. CAMPOS SIMPLES, FUNCIONALES, RELACIONALES, PROPIEDADES, PREDEFINIDOS Y ESPECIALES

c. RESTRICCIONES

v. VISTAS Y EVENTOS

a. ELEMENTOS DE LAS VISTAS: FIELD, BUTTON, SEPARATOR, LABEL, ...

b. ATRIBUTOS DE LOS ELEMENTOS: READONLY, VISIBLE, NOLABEL, ...

c. AGRUPACIÓN DE ELEMENTOS: GROUP, NOTEBOOK, PAGE, ...

d. ACCIONES, DOMINIOS

e. MENÚS

f. ATAJOS ENTRE OBJETOS

vi. MENUS Y ACCIONES

vii. SEGURIDAD DE OBJETOS

viii. EJERCICIO PRÁCTICO

índice

Page 3: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Una vez instalado, OpenERP tiene una estructura modular permitiendo

añadir módulos según vaya siendo necesario. El uso de los módulos es la

manera de ampliar la funcionalidad OpenERP. La instalación por

defecto de OpenERP se compone de un núcleo y varios módulos

dependiendo del tipo de instalación entre los cuales podemos distinguir:

– base: el módulo básico compuesto por ir.property, res.company, res.request, res.currency,

res.user, res.partner este módulo siempre es instalado.

– crm: gestión de la relación con los Clientes / Proveedores.

– sale: gestión de ventas.

– mrp: fabricación y planificación de recursos.

– ….

• Los nuevos módulos pueden programarse fácilmente y requieren un

poco de práctica en XML y Python.

Introducción

Page 4: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

– __terp__.py

– Objetos:

• nombre_de_modulo.py, y posiblemente otros

• __init__.py

– Archivos XML:

• nombre_de_modulo_view.xml

• nombre_de_modulo_workflow.xml (opcional)

• nombre_de_modulo_report.xml (opcional)

• nombre_de_modulo_wizard.xml (opcional)

• nombre_de_modulo_data.xml (opcional)

• nombre_de_modulo_demo.xml (opcional)

• posiblemente otros ficheros XML opcionales

– Subdirectorio report/

• report_name.xml / report_name.xsl

• report_name.rml / report_name.sxw / report_name.py (opcional)

• report_name.py

– subdirectorio wizard/

• __init__.py

• wizard_name.py

Estructura de un módulo

• Contenido de un módulo: (addons/nombre_de_modulo)

– subdirectorio security/

• ir_model_access.csv (permisos sobre objetos)

• modelo_security.xml (creación de grupos y acceso a opciones

de menú)

– Subdirectorio i18n/

• modulo.pot (plantilla)

• es_ES.po

• fr_FR.po

• ....

– SubdirectorioProcess, para incluir información de

procesos

– Otros Es una buena estrategia crear directorios

donde se contengan las modificaciones propias

de módulos externos

Page 5: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Los pasos básicos para generar un módulo son:

– Crear un subdirectorio en la raíz del servidor OpenERP dentro del directorio bin/addons.

– Crear un archivo con la descripción del módulo: __terp__.py

– Crear los archivos Python que contendrán los objetos.

– Crear los archivos xml para la obtención de datos (vistas, menús, datos de ejemplo,...)

– Opcionalmente crear listados, asistentes y flujos de trabajo.

• Los archivos xml ubicados en el directorio del módulo se pueden utilizar

para modificar la estructura de la base de datos también son utilizados

para otros propósitos entre los que podemos destacar:

– Cargar datos iniciales o datos de demostración.

– Declaración de vistas.

– Declaración de listados.

– Declaración de asistentes.

– Declaración de flujos de trabajo.

Estructura de un módulo

Page 6: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• La estructura general de los ficheros xml es la siguiente

<?xml version="1.0"?>

<openerp>

<data>

<record model="workflow" id=workflow_id>

<field name="name">workflow.name</field>

<field name="osv">resource.model</field>

<field name="on_create">True | False</field>

</record>

</data>

</openerp>

• Ejemplo: sale_workflow.xml

– id (en el ejemplo "workflow_id") es un identificador del flujo de trabajo. Cada flujo de

trabajo debe tener un identificador único.

– name (en el ejemplo "workflow.name") es el nombre del flujo de trabajo. El nombre del

flujo de trabajo debe respetar la sintaxis de OpenERP "nombres punteados".

– osv (en el ejemplo "resource.model") es el nombre del objeto OpenERP que vamos a utilizar

como modelo [- (Recuerde que OpenObjects hereda de osv.osv, de ahí "<field

name="osv">')-].

– on_create es verdadero cuando workflow.name se instancia automáticamente cuando

resource.model es creado y falso en el caso contrario.

Estructura de un módulo

Page 7: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• __init__.py: El archivo __init__.py, como cualquier módulo de Python, es

ejecutado al inicio del programa. En el incluiremos los archivos de Python

que necesiten ser cargados.Por lo tanto, si creamos un archivo

"modulo.py", que contiene la descripción de nuestros objetos, tenemos

que incluir una línea en __init__.py:

– import modulo

• __terp__.py : Cualquier módulo que creemos debe contener un un

archivo con este nombre __terp__.py y debe estar ubicado en la raíz de

nuestro módulo. Este archivo, que debe tener el formato Phyton es

responsable de determinar:

– Los archivos XML que serán analizados durante la inicialización del servidor OpenERP.

– Las dependencias del módulo que hemos creado.

Estructura de un módulo

Page 8: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Este archivo __terp__.py debe contener los siguientes valores de Python:

– name: nombre del módulo.

– version: versión del módulo

– description: descripción del módulo.

– author: autor del módulo

– website: sitio web del modulo

– license: licencia del módulo (por defecto GPL-2)

– depends: lista de módulos de los que depende este módulo. El módulo base se debe

incluir casi siempre en las dependencias ya que algunos datos de este módulo son

necesarios para las vistas, informes .....

– init_xml: lista de archivos xml que se cargaran al iniciar el servidor OpenERP con la opción "-

init=modulo". Las rutas de los archivos debe ser relativas al directorio donde está el módulo.

– update_xml: lista de archivos xml que se cargaran al iniciar el servidor OpenERP con la

opción "-update=modulo". Las rutas de los archivos debe ser relativas al directorio donde

está el módulo.

– installable: acepta valores true o false y determina si el módulo es instalable o no.

– active: acepta valores true o false y determina los si el módulo sera instalado cuando se

cree la base de datos (por defecto false)

Estructura de un módulo

Page 9: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• El mapeador se encuentra en la carpeta bin/osv, es una técnica de

programación para convertir datos entre el sistema de tipos utilizado en

un lenguaje de programación orientado a objetos y el utilizado en una

base de datos relacional. En nuestro caso: Python - PostgreSQL

• La estructura es sencilla: 4 ficheros:

– fields.py : donde se definen las estructuras básicas (columnas y tipos de campos)

– orm.py : donde se crean las clases que van a albergar los objetos y se define su

funcionamiento íntimo. (En teoría, todo el SQL debería estar aquí...)

– osv.py: Instancia los objetos

– expression.py : permite evaluar expresiones complejas para dominios de datos (AND, OR,

etc.)

Mapeador ORM

Page 10: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Todos los datos de OpenERP son accesibles a través de "objetos". Por

ejemplo, existe un objeto "res.partner" para acceder a la información

concerniente a las empresas (partners), un objeto "account.invoice" para

acceder a los datos relativos a las facturas, etc.

• Localización: addons/nombre_modulo/nombre_modulo.py

• Existe un objeto para cada tipo de recurso, y no un objeto por recurso.

Así tenemos un único objeto res.partner para manejar a todas las

empresas y no un res.partner para cada empresa, es decir, existe un

objeto por nivel.

• La principal consecuencia de éste hecho es que todos los métodos de

los objetos tienen un parámetro común: el parámetro "ids". Este

especifica sobre qué recursos (por ejemplo, sobre que empresa) el

método debe aplicarse. Precisamente este parámetro contiene una lista

de identificadores de recurso (ids) sobre los que se aplicará el método.

Objetos (modelo)

Page 11: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• boolean

• integer

• float

– parámetro opcional “digits”

• Ex: 'rate': fields.float('Relative Change rate', digits=(12,6))

• char

– parámetro “size”

• Ex: 'zip': fields.char('Zip', size=24),

• text

• date

• datetime

• binary

Objetos : tipos simples

Page 12: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Heredan de una clase base denominada _column (columna), definida

en fields.py

• Clase _column, atributos más importantes:

− _type : se utiliza para mapear su equivalente en la base de datos posteriormente (método

get_pg_type de orm.py)

class integer_big(_column):

_type = 'integer_big'

....

type_dict = {

fields.boolean: 'bool',

fields.integer: 'int4',

fields.integer_big: 'int8', ....

Objetos: Los elementos básicos.... fields

Page 13: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Objetos: Atributos

− _multi : Se utiliza en campos 'funcionales' cuando el valor de varios campos se devuelve

simultaneamente

− string: Almacena el valor de la cadena a mostrar (etiqueta)

− readonly: Especifica si el campo es de sólo lectura

− required: Si es obligatorio (¡ojo! A nivel de base de datos...)

− size: el tamaño. Obligatorio para algunos tipos de campo como 'char'

− help: Cadena de texto para ayuda contextual

− change_default: Si es verdadero permite definir al usuario valores por defecto de otros campos

basados en el valor de éste.

− ondelete: En campos relacionados permite definir a nivel de base de datos el comportamiento con los

campos relacionados (... el ON DELETE CASCADE, SET NULL o en su caso RESTRICT). Por defecto “set null”

− translate: Si es verdadero, el contenido del campo será traducible

− _domain: si existe un dominio sobre el campo

− _context: información de contexto

− select : Permite definir si el campo se utilizará en los formularios de búsqueda de registros

− states: permite definir el valor de los demás atributos dependiendo del valor de la columna 'state'.

Page 14: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Ejemplo típico: campo 'active'. Si el campo 'active' existe para un objeto

por defecto las búsquedas filtrarán solamente los registros activos. Si

además no ponemos en campo 'active' un atributo 'select' no habrá

forma de seleccionar nunca los registros no activos.

base/res/partner/partner.py: 'active': fields.boolean('Active'),ó

base/res/partner/partner.py: 'customer': fields.boolean('Customer',

help="Check this box if the partner if a customer."),

Objetos: boolean

Page 15: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Además de los usos habituales de los enteros se utiliza también en

campos como 'sequence'. Es una convención dentro de la aplicación

usar un campo llamado 'sequence' para ordenar los registros.

• Rango: -2147483648 a +2147483647

• Ejemplo: product/product.py clase: product.category

_columns = {

'name': fields.char('Name', size=64, required=True, translate=True),

'complete_name': fields.function(_name_get_fnc, method=True, type="char", string='Name'),

'parent_id': fields.many2one('product.category','Parent Category', select=True),

'child_id': fields.one2many('product.category', 'parent_id', string='Childs Categories'),

'sequence': fields.integer('Sequence'),

}

_order = "sequence"

• Big Integer apenas se utiliza

Objetos: integer

Page 16: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Se utiliza para crear una referencia a otro objeto que no es siempre del

mismo tipo.

• Ejemplo: requests -> permite enlazar a los mensajes referencias a

facturas, pedidos de ventas, tareas, etc.

• En la base de datos se almacena como una cadena de texto donde

figura el nombre de modelo y su identificador: account.invoice,7 sería

una referencia a la factura número 7.

• El campo se muestra como 2: un desplegable con los objetos a enlazar

y un campo para seleccionarlo. (Ver ejemplo)

Objetos: reference

Page 17: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Son cadenas de texto.

• El campo 'name' es normalmente de tipo char. (Es un campo “semi-

obligatorio” por lo que podemos encontrar definiciones en

prácticamente todas las clases).

• Obligatorio: indicar tamaño mediante atributo size

• Ejemplo:

'name':fields.char('Name',size=64,invisible=True)

Objetos: char

Page 18: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Texto (sin límite)

• Se utiliza normalmente para observaciones, etc.

• Es texto “sin formato”

Objetos: text

Page 19: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Numéricos de punto flotante

• En la definición se pueden especificar los dígitos

• Se traduce en la base de datos por:

− “double” si no establecemos un número de dígitos

− “numeric” si los establecemos

• Ejemplo: en account/account_move_line.py

− La mayor parte de los campos numéricos tienes establecida una

precisión

− El campo 'amount_currency' no la tiene....

Objetos: float

Page 20: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Campos para almacenar valores de tiempo:

− “date”: fecha (sin hora)

− “datetime”: almacena fecha y hora

− “time”: hora (apenas utilizado)

• La forma de evitar problemas.....

− AAAA-MM-DD HH:MM:SS

Objetos: date, datetime, time

Page 21: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Guarda datos binarios

• En muchas ocasiones se almacenan codificados en formato

base64

• Permite almacenar imágenes, ficheros, etc.

Objetos: binary

Page 22: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• En el objeto es un campo que puede tomar valores de una lista

• En la base de datos se mapea a un tipo text

Objetos: selection

Page 23: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Se utiliza para relaciones “muchos a uno”

• El mapeador crea una columna en la tabla “muchos”, clave foranea

de la tabla “uno”. (La clave principal siempre es id)

• Ejemplo: lineas de pedido -> pedidos:'order_id': fields.many2one('sale.order', 'Order Ref', required=True,

ondelete='cascade', select=True)

En la base de datos:

CONSTRAINT sale_order_line_order_id_fkey FOREIGN KEY (order_id)

REFERENCES sale_order (id) MATCH SIMPLE

ON UPDATE NO ACTION ON DELETE CASCADE,

• Cuando creamos un campo many2one, la aplicación

automáticamente genera en la base de datos la clave foránea, pero

NO crea un índice sobre esa clave

• Si el campo en cuestión lleva un “select”, esto es, prevemos que vamos

a utilizarlo en búsquedas, la aplicación genera un índice sobre dicho

campo

Objetos: many2one

Page 24: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Es la visión inversa de la relación anterior

• Es posible definir la relación en un sentido y no en el otro. La única

consecuencia es que programáticamente no podremos utilizarla. En la

base de datos no hay diferencia.

• Ejemplo:

'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={'draft':[('readonly',False)]}),

Objetos: one2many

Page 25: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Permite crear relaciones “muchos a muchos”

• En la base de datos se utiliza una tabla intermedia (normalmente

terminada en _rel) que almacena los identificadores de los

registros relacionados

• Automáticamente se crean índices sobre ambas columnas

Objetos:many2many

Page 26: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Existe la posibilidad de definir campos funcionales

• En principio éstos no tienen un mapeo a la base de datos excepto que utilicemos

el argumento store=True, que almacena el resultado de la función en una

columna en la base de datos del tipo adecuado.

• Existe la posibilidad de definir varios campos funcionales con la opción multi . De

esta manera, se pueden calcular varios simultáneamente. Ejemplo:

account/partner.py

_columns = {

'credit': fields.function(_credit_debit_get, fnct_search=_credit_search, method=True,

string='Total Receivable', multi='dc', help="Total amount this customer owns you."),

'debit': fields.function(_credit_debit_get, fnct_search=_debit_search, method=True,

string='Total Payable', multi='dc', help="Total amount you have to pay to this supplier."),

..................

def _credit_debit_get(self, cr, uid, ids, field_names, arg, context): ......

Objetos: function

Page 27: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Campos “relacionados” (derivan de los campos funcionales)

• En versiones antiguas, no era sencillo mostrar campos

perteneciente a objetos relacionados (más allá de su nombre)

• Ejemplo: Un campo de “alerta” en clientes.

• Con este tipo de campos es posible acceder y mostrar esos

campos alojados en otras tablas.

Objetos: related

Page 28: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Es un tipo de campo diseñado para almacenar objetos serializados

(persistentes)

• Utiliza el método repr() de Python para serializar los objetos por defecto,

pero puede ser reemplazado por otro método mediante el parámetro

serialize_func

Objetos: serialized

Page 29: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• La clase fields.property hereda de fields.function y sobreescribe

los métodos read y write. El tipo de este campo es 'many2one',

de modo que en la vista se representa de la misma manera que

un campo many2one.

• Pero el valor de la propiedad se almacena en la clase ir.property

(tabla ir_property) como un registro independiente. El valor

almacenado es un campo del tipo 'reference' (referencia, no

muchos a uno) porque cada propiedad puede apuntar a un

objeto diferente. Si se editan los valores de las propiedades (en el

menú de administración), estas están representadas como

campos de tipo referencia.

Objetos: property

Page 30: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Cuando se lee una propiedad el programa devuelve la

propiedad adjunta a la instancia del objeto que se está leyendo.

Si el valor de la propiedad no está definido el sistema devolverá

la propiedad por defecto.

• La definición de un a propiedad es almacenada en la clase

ir.model.fields como cualquier otro campo. En la definición de la

propiedad se pueden añadir los grupos que tienen permiso para

modificarla.

Objetos: property (2)

Page 31: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• class orm_template(object) / class orm(orm_template)

• Las clases que albergan los objetos con los que normalmente

trabajamos descienden de la clase osv.osv que hereda de orm

que a su vez hereda de orm_template.

• Todos los datos del ERP son accesibles a través de "objetos". Por

ejemplo, existe un objeto "res.partner" para acceder a la

información concerniente a las empresas (partners), un objeto

"account.invoice" para acceder a los datos relativos a las

facturas, etc.

Clases definidas en OpenERP

Page 32: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• La principal consecuencia de éste hecho es que todos los

métodos de los objetos tienen un parámetro común: el

parámetro "ids". Este especifica sobre qué recursos el método

debe aplicarse.

• Normalmente llamaremos a un método con una serie de

parámetros, de los cuales algunos prácticamente siempre están

presentes:

− objeto.metodo(cr, uid, ids, ......)

− cr : es una referencia al cursor que conecta a la base de datos

− uid: identificador de usuario que hace la petición

− ids: lista de identificadores

Clases definidas en OpenERP

Page 33: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principales atributos:

_name = None

_columns = {}

_constraints = []

_defaults = {}

_rec_name = 'name'

_parent_name = 'parent_id'

_parent_store = False

_date_name = 'date'

_order = 'id'

_sequence = None

_description = None

_inherits = {}

_table = None

_sql_constraints = []

_log_access = True

_table = None

_sql = ''

_auto = False

Objetos: orm_template y orm

Page 34: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principales métodos:

– _auto_init: se ejecuta automáticamente al cargar el objeto. En

algunos casos se sobreescribe para añadir la creación de índices

adicionales. (Ej: stock/stock.py)

– check_recursion: Se utiliza en estructuras arbóreas para prevenir

ciclos infinitos. Si la estructura la hemos creado “a mano” también

podemos utilizar el método pasándole como argumento parent el

nombre del campo padre

– Browse: Se utiliza continuamente. Devuelve un conjunto de objetos

navegables de una clase.

– Copy: Es el método que se invoca cuando “duplicamos” un registro.

Puede ser interesante reescribirlo. Ejemplo: pedidos de venta

– Create: Se ejecuta al crear un nuevo objeto. En muchos casos

puede ser interesante manipular éste método. Ejemplo:

account.move.line (al crear un apunte contable)

– default_get: Devuelve los valores por defecto establecidos por un

usuario, etc. Ejemplo de utilización: account.move.line

Objetos: orm_template y orm

Page 35: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principales métodos:

– distinct_field_get: Devuelve todos los distintos valores introducidos en un campo. Se utiliza normalmete para autocompletar campos (es automático).

– fields_get: Devuelve los campos pertenecientes a un objeto. Ejemplo de utilización: si fuesemos a escribir nuestra propia aplicación “cliente” utilizaríamos este método remotamente para obtener los campos y sus tipos. Hay un ejemplo de manipulación de este método en base/res/partner/partner.py en la definición de los bancos.

– export_data / import_data: Son los métodos utilizados en la importación / exportación de datos desde el cliente. El hecho de que sean métodos de clase nos permite sobreescribirlos, en caso necesario, para los objetos que queramos. (No hay un sólo caso en todo el repositorio, pero es posible hacerlo)

– fields_view_get: Devuelve la vista correspondiente a un objeto (en su contexto). Es el método que entre otras cosas se encarga de la aplicación de las herencias en las vistas. Ejemplo de manipulación: en stock/product.py o en ir/ir_model.py (ver éste último en funcionamiento)

Objetos: orm_template y orm

Page 36: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principales métodos:

– name_get: Es un método trivial que devuelve el valor del campo

name o el especificado en _rec_name. Ejemplo de utilización: Las

categorías de producto.

– name_search: Define la búsqueda a través del nombre de un

objeto. Ejemplo de utilización: búsqueda de productos.

– _parent_store_compute: Para la optimización de determinadas

consultas en la base de datos de estructuras arbóreas es preciso

calcular para cada nodo sus ramas izquierda y derecha. Es este

método el encargado de realizar el cálculo. Ejemplo de utilización:

este tipo de estructuras se utilizan actualmente con las cuentas

contables y las localizaciones de almacén. (enlace)

– perm_read: Permite consultar los permisos sobre un objeto y los datos

de creación y última modificación. Este método es a veces

conveniente ya que los campos “internos” (create_uid, create_date,

etc.) son accesibles directamente sólo si los hemos redeclarado (en

_columns). Con este método podemos acceder a leerlos sin

necesidad de dicha declaración

Objetos: orm_template y orm

Page 37: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principales métodos:

– Read: Se utiliza para leer el contenido de diversos campos de un

conjunto de registros. Se recomienda utilizar browse en lugar de

read, ya que no es más lento y nos permite realizar lo mismo con una

sintaxis más clara.

– search_count: Devuelve el número de registros como resultado de

una búsqueda.

– search : Es otro de los métodos muy utilizados. Devuelve una lista de

ids que cumplen con una serie de requisitos. Ejemplo de utilización:

en stock/stock.py hay un bucle que recorre todas las localizaciones

hijas de otra.

– Unlink: Para borrar o eliminar registros

– view_header_get: Se utiliza si queremos cambiar la etiqueta de una

pestaña, dependiendo del contexto.

– Write: Es el método que se utiliza habitualmente para escribir valores

en un objeto

Objetos: orm_template y orm

Page 38: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• readonly (boolean)

– Valor por defecto: False.

• required (boolean)

– Valor por defecto: False.

• translate (boolean)

– Valor por defecto: False.

• change_default (boolean)

– Valor por defecto: False.

RESUMEN: atributos de campo

Page 39: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• states

– Uso: establecer parámetros dependiendo del estado

– Sintaxis: {'nombre_estado': lista_atributos, ...}

• donde lista_atributos es una lista de tuplas de la forma [('nombre_atributo', valor), ...]

– Valor por defecto: {}.

– Ejemplo:

'partner_id': fields.many2one('res.partner', 'Partner', states={'posted': [('readonly',True)]}),

Objetos: Atributos de campo

Page 40: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• function (nombre_metodo, tipo_metodo, ...)

– Ejemplo:

def _get_installed_version(self, cr, uid, ids, field_name=None, arg=None,

context={}):

res = {}

for m in ...:

res[m.id] = ...

return res

'installed_version': fields.function(_get_installed_version, method=True,

string='Installed version', type='char'),

• selection (opciones, ...)

– Ejemplo:

'state': fields.selection(

(('n','Unconfirmed'),('c','Confirmed')), 'State', required=True)

Objetos: campos complejos

Page 41: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• many2one (obj, ...)

Ejemplo:

'commercial': fields.many2one('res.users', 'Commercial'),

Parámetros opcionales:

ondelete = ”cascade”

- Valor por defecto: “set null”

domain = [('field_name', 'operator', value), ...]

- Valor por defecto: []

• one2many (obj, campo_id, ...)

Ejemplo:

'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),

Objetos: campos relación

Page 42: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• many2many (obj, rel, id1, id2)

– obj es el otro objeto relacionado

– rel es el nombre de la tabla que hace la relación

– id1 e id2 son los nombres de los campos en la tabla de relación

– Ejemplo:

'category_id':

fields.many2many( res.partner.category', 'res_partner_category_rel', 'partner_id', 'category_id', 'Categories'),

Objetos: campos relación

Page 43: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• reference (string, optiones, size)

– Ejemplo:

'ref': fields.reference('Field label',

selection = ((('object.name', 'Object Label'), ...), size=128),

– Selección dinámica:<record model="res.request.link">

<field name="name">Project Task</field>

<field name="object">project.task</field>

</record>

Objetos: campos relación

Page 44: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principios

– son funciones

– toman 4 parámetros (obj, cr, uid, context)

• Sintaxis:

_defaults = {'field_name': function,

...

}

• Ejemplo

_defaults = {'date': lambda obj,cr,uid,context: time.strftime('%Y-%m-%d'),

'state': lambda *a: 'draft'

}

Objetos: valores por defecto

Page 45: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principios: son restricciones en código

• Sintaxis:

– [(metodo, 'mensaje error', lista_campos), ...]

• Example

def _constraint_sum(self, cr, uid, ids):

...

return res < 1000

_constraints = [

(_constraint_sum, 'Error: el resultado debería ser < 1000.', ['name'])

]

Objetos: restricciones

Page 46: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principios:

• Sintaxis:

– _inherit = 'object.name'

• Ejemplo:

class custom_material(osv.osv):

_name = 'network.material'

_inherit = 'network.material'

_columns = {

'manuf_warranty': fields.boolean('Manufacturer warranty?'),

}

_defaults = {

'manuf_warranty': lambda *a: False,

}

custom_material()

Objetos: herencia simple

Page 47: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Principios: (ver ejemplo biblio)

• Sintaxis:

– _inherits = { 'nombre.objeto': nombre_columna, .....}

• Ejemplo:– Ver product.product y product.template

Objetos: herencia compleja

Page 48: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• _table

– Valor por defecto: nombre del objeto (“.” sustutuidos por “_”)

• _rec_name

– Valor por defecto: 'name'.

• _order

– Valor por defecto: 'id'.

Objetos: otros atributos de objeto

Page 49: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Acceso directo (desde dentro de un objeto)

– self.pool.get('nombre.objeto')

– Ejemplo:

• partner_object = self.pool.get('res.partner')

• partner_object.nombre_del_metodo(parámetros_metodo)

• Acceso a través de Netservice (en el servidor pero desde fuera de los objetos)

– service = netsvc.LocalService("object_proxy")

– result = service.execute(user_id, object_name, method_name, parameters)

Objetos: acceso a los objetos

Page 50: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Acceso XML-RPC

– sock = xmlrpclib.ServerProxy('http://servidor:puerto/xmlrpc/object')

– result = sock.execute(user_id, password, object_name, method_name, parameters)

Objetos: acceso a los objetos

Page 51: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

■ create

def create(self, cr, uid, vals, context={})

devuelve el id

■ search

def search(self, cr, uid, args, offset=0, limit=80)

args = [('nombre_campo', 'operador', valor), ...]

devuelve lista de ids

■ read

def read(self, cr, uid, ids, fields=None, context={})

devuelve lista de diccionarios: [{'nombre_campo': valor}]

Objetos: métodos predefinidos más importantes

Page 52: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

■ write def write(self, cr, uid, ids, vals, context={})

vals = {'field_name': value, ...}

devuelve True

■ unlink def unlink(self, cr, uid, ids)

devuelve True

■ browse def browse(self, cr, uid, ids, offset=0, limit=2000)

Ejemplo:addr_obj = self.pool.get('res.partner.address').browse(cr, uid,

contact_id)

contact_name = addr_obj.name

contact_bank = addr_obj.partner_id.bank

Objetos: métodos predefinidos más importantes

Page 53: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

■ name_get

def name_get(self, cr, uid, ids,

context={})

Devuelve

[(id, name), ...]

■ name_search

Objetos: métodos predefinidos más importantes

Page 54: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Vistas sirven para definir como mostrar los objetos. tienes que saber que

la interfaz de usuario de OpenERP es dinámica. Esto quiere decir que

no esta descrita estáticamente por algún código, pero es

dinámicamente construida desde las descripciones en XML de la

pantalla del cliente.

• Puede haber varias vistas para el mismo objeto

• Diferentes tipos de vista:

– Formularios

• form

• tree

– Tree (con atajos)

– Graph (* Versión 5)

– Calendar (* Versión 5)

Vistas

Page 55: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Acciones– Abrir una ventana (form o tree)– Imprimir un informe– Ejecutar un wizar

• Items de Menú

Vistas: principios

Page 56: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• Como los otros ficheros XML (usanlas etiquetas “record”)

• objeto que almacena vistas = ir.ui.view<openerp>

<data><record model=”ir.ui.view” id=”...”>...

</record>

</data>

</openerp>

Vistas: sintaxis

Page 57: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

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

<field name="name">nombre_vista</field>

<field name="model">nombre_objecto</field>

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

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

<form string="Etiqueta">

<field name="nombre_campo" .../>

...

</form>

</field>

</record>

Vistas: sintaxis (formulario)

Page 58: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

• <record model="ir.ui.view"

id="view_organisation_form">• <field name="name">account.organisation.form</field>

• <field name="model">account.organisation</field>

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

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

• <form string="Company">

• <field name="partner_id"/>

• <field name="partner_contact_id"/>

• <field name="note"/>

• </form>

• </field>

• </record>

Vista: ejemplo

Page 59: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

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

<field name="name">action_name</field>

<field name="res_model">object_name</field>

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

<field name="view_id" ref="view_id"/>

</record>

<menuitem name="Network/All Materials" action="action_id"/>

Crean la acción “abrir ventana”

Crean el correspondiente item de menú

Menus y acciones

Page 60: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Seguridad de objetos

• Es importante definir permisos de acceso a los objetos de openERP paraque puedan acceder a ellos otros usuarios que no sean administradores.

• Para ello es necesario definir politicas de seguridad a los módulos que se definirían, tal y como hemos visto en la estructura del módulo, dentro de la

carpeta security y sobre los archivos ir_model_access.csv y modulo_security.xml

• Ir_model_access.csv: Este archivo contiene los permisos que se les dan a los objetos para un determinado grupo. Este archivo contiene las siguientescolumnas:

• Id: Indica el identificador de esa línea de seguridad especifica

• Name: Nombre del registro

• Model_id:id: Identificador del modelo de objeto sobre el que se van a aplicar esos permisos. Ej: model_res_partner si se llama desde el módulo

que lo crea. Si lo hiciesemos desde otro módulo se llamaría con: base.model_res_partner (Pertenece al módulo base)

• Group_id:id: Identificador del grupo de usuarios para el cual se estánestableciendo los permisos. Ej: base.group_partner_manager

Page 61: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Seguridad de objetos

• ir_model_access.csv:

• Perm_read: Indica si al grupo definido le está permitida la lectura sobreese objeto. Al ser boolean se define con 0 o 1

• Perm_write: Indica si le está permitida la escritura sobre el objeto.

• Perm_create: Indica si se les permite crear esa clase de objetos.

• Perm_unlink: Indica si les está permitido borrar objetos de esa clase.

Page 62: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Seguridad de objetos

• Archivo modulo_security.xml: En este archivo se define la creación de grupos, reglas de registros y los permisos de un grupo sobre los menús.

• Creación de grupos:

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

<field name="name">Administrator / Configuration</field>

</record>

• Permisos sobre menús:

<record id="base.menu_security" model="ir.ui.menu">

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

</record>

Page 63: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Seguridad de objetos

• Archivo modulo_security.xml: En este archivo se define la creación de grupos, reglas de registros y los permisos de un grupo sobre los menús.

• Creación de Reglas: Sirven para crear dominios especificos sobre los grupos que las tienen definidas. En el ejemplo se creará una regla para quelos usuarios vean solamente sus ventas.

<record model="ir.rule.group" id="filter_sale_orders_rule_group">

<field name="name">User Sale Orders</field>

<field name="model_id" search="[('model','=','sale.order')]" model="ir.model"/>

<field name="global" eval="False"/>

</record>

<record model="ir.rule" id="filter_sale_orders_rule">

<field name="field_id" search="[('model','=','sale.order'),('name','=','user_id')]" model="ir.model.fields"/>

<field name="operator">in</field>

<field name="operand">','.join(map(lambda x: str(x.id), user.child_id))</field>

<field name="rule_group" ref="filter_sale_orders_rule_group"/>

</record>

Page 64: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Seguridad de objetos

• Archivo modulo_security.xml: En este archivo se define la creación de grupos, reglas de registros y los permisos de un grupo sobre los menús.

• Asignación de reglas a grupos:

A la hora de crear un grupo podemos asignarle las reglas definidasanteriormente:

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

<field name="name">Administrator / Configuration</field>

<field name="rule_groups" eval="[(6,0,[ref('filter_sale_orders_rule_group')])]"/>

</record>

Page 65: SLIDE Técnico openERP - Desarrollo de módulos - Ting!

Ejercicio práctico