Documente Academic
Documente Profesional
Documente Cultură
DESARROLLO DE MDULOS
ting! Tecnologas Inteligentes de Software S.L.
JULIO 2010
V2.0
ndice
i. ii. a. b. c. iii. iv. a. b. c. v. a. b. c. d. e. f. vi. vii. viii. INTRODUCCIN ESTRUCTURA DE UN MDULO ESTUDIO COMPLETO DE UN MDULO EXISTENTE DESCRIPCIN DE MDULOS BSICOS: BASE, SALE, PRODUCT, STOCK, PROJECT HERENCIA MAPEADOR ORM OBJETOS, CAMPOS
Y MTODOS
DEFINICIN DE OBJETOS CAMPOS SIMPLES, FUNCIONALES, RELACIONALES, PROPIEDADES, PREDEFINIDOS Y ESPECIALES RESTRICCIONES VISTAS Y EVENTOS ELEMENTOS DE LAS VISTAS: FIELD, BUTTON, SEPARATOR, LABEL, ... ATRIBUTOS DE LOS ELEMENTOS: READONLY, VISIBLE, NOLABEL, ... AGRUPACIN DE ELEMENTOS: GROUP, NOTEBOOK, PAGE, ... ACCIONES, DOMINIOS MENS ATAJOS ENTRE OBJETOS MENUS Y ACCIONES SEGURIDAD DE OBJETOS EJERCICIO PRCTICO
Introduccin
Una vez instalado, OpenERP tiene una estructura modular permitiendo
aadir mdulos segn vaya siendo necesario. El uso de los mdulos es la manera de ampliar la funcionalidad OpenERP. La instalacin por defecto de OpenERP se compone de un ncleo y varios mdulos dependiendo del tipo de instalacin entre los cuales podemos distinguir:
base: el mdulo bsico compuesto por ir.property, res.company, res.request, res.currency, res.user, res.partner este mdulo siempre es instalado. crm: gestin de la relacin con los Clientes / Proveedores. sale: gestin de ventas. mrp: fabricacin y planificacin de recursos. .
Los nuevos mdulos pueden programarse fcilmente y requieren un poco de prctica en XML y Python.
Estructura de un mdulo
subdirectorio security/
ir_model_access.csv (permisos sobre objetos) modelo_security.xml (creacin de grupos y acceso a opciones de men)
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 i18n/
modulo.pot (plantilla) es_ES.po
fr_FR.po
....
Subdirectorio report/
report_name.xml / report_name.xsl
Otros Es una buena estrategia crear directorios donde se contengan las modificaciones propias de mdulos externos
subdirectorio wizard/
__init__.py
wizard_name.py
Estructura de un mdulo
Los pasos bsicos para generar un mdulo son:
Crear un subdirectorio en la raz del servidor OpenERP dentro del directorio bin/addons. Crear un archivo con la descripcin del mdulo: __terp__.py Crear los archivos Python que contendrn los objetos.
Crear los archivos xml para la obtencin de datos (vistas, mens, datos de ejemplo,...)
Opcionalmente crear listados, asistentes y flujos de trabajo.
Los archivos xml ubicados en el directorio del mdulo se pueden utilizar para modificar la estructura de la base de datos tambin son utilizados para otros propsitos entre los que podemos destacar:
Cargar datos iniciales o datos de demostracin. Declaracin de vistas. Declaracin de listados. Declaracin de asistentes. Declaracin de flujos de trabajo.
Estructura de un mdulo
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
Estructura de un mdulo
__init__.py: El archivo __init__.py, como cualquier mdulo 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 descripcin de nuestros objetos, tenemos que incluir una lnea en __init__.py:
import modulo
Estructura de un mdulo
Este archivo __terp__.py debe contener los siguientes valores de Python:
name: nombre del mdulo. version: versin del mdulo description: descripcin del mdulo.
incluir casi siempre en las dependencias ya que algunos datos de este mdulo son
necesarios para las vistas, informes ..... init_xml: lista de archivos xml que se cargaran al iniciar el servidor OpenERP con la opcin "init=modulo". Las rutas de los archivos debe ser relativas al directorio donde est el mdulo. update_xml: lista de archivos xml que se cargaran al iniciar el servidor OpenERP con la opcin "-update=modulo". Las rutas de los archivos debe ser relativas al directorio donde est el mdulo. installable: acepta valores true o false y determina si el mdulo es instalable o no. active: acepta valores true o false y determina los si el mdulo sera instalado cuando se cree la base de datos (por defecto false)
Mapeador ORM
El mapeador se encuentra en la carpeta bin/osv, es una tcnica de
programacin para convertir datos entre el sistema de tipos utilizado en un lenguaje de programacin 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 bsicas (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 teora, todo el SQL debera estar aqu...) osv.py: Instancia los objetos expression.py : permite evaluar expresiones complejas para dominios de datos (AND, OR, etc.)
Objetos (modelo)
Todos los datos de OpenERP son accesibles a travs de "objetos". Por ejemplo, existe un objeto "res.partner" para acceder a la informacin
float
parmetro opcional digits
Ex: 'rate': fields.float('Relative Change rate', digits=(12,6))
char
parmetro size
Ex: 'zip': fields.char('Zip', size=24),
_type = 'integer_big'
.... type_dict = { fields.boolean: 'bool', fields.integer: 'int4', fields.integer_big: 'int8', ....
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)
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: informacin de contexto select : Permite definir si el campo se utilizar en los formularios de bsqueda de registros states: permite definir el valor de los dems atributos dependiendo del valor de la columna 'state'.
Objetos: boolean
Ejemplo tpico: campo 'active'. Si el campo 'active' existe para un objeto por defecto las bsquedas filtrarn solamente los registros activos. Si
base/res/partner/partner.py: base/res/partner/partner.py:
Objetos: integer
Adems de los usos habituales de los enteros se utiliza tambin en campos como 'sequence'. Es una convencin dentro de la aplicacin usar un campo llamado 'sequence' para ordenar los registros.
Objetos: reference
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 sera una referencia a la factura nmero 7.
El campo se muestra como 2: un desplegable con los objetos a enlazar y un campo para seleccionarlo. (Ver ejemplo)
Objetos: char
Son cadenas de texto. El campo 'name' es normalmente de tipo char. (Es un campo semiobligatorio por lo que podemos encontrar definiciones en prcticamente todas las clases).
Objetos: text
Objetos: float
Numricos de punto flotante En la definicin se pueden especificar los dgitos Se traduce en la base de datos por:
Ejemplo: en account/account_move_line.py
date: fecha (sin hora) datetime: almacena fecha y hora time: hora (apenas utilizado)
AAAA-MM-DD HH:MM:SS
Objetos: binary
base64
Objetos: selection
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: many2one
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 aplicacin automticamente genera en la base de datos la clave fornea, pero NO crea un ndice sobre esa clave Si el campo en cuestin lleva un select, esto es, prevemos que vamos a utilizarlo en bsquedas, la aplicacin genera un ndice sobre dicho campo
Objetos: one2many
Es la visin inversa de la relacin anterior Es posible definir la relacin en un sentido y no en el otro. La nica consecuencia es que programticamente 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:many2many
Permite crear relaciones muchos a muchos En la base de datos se utiliza una tabla intermedia (normalmente
Objetos: function
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 funcin en una
Existe la posibilidad de definir varios campos funcionales con la opcin multi . De esta manera, se pueden calcular varios simultneamente. 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: related
Campos relacionados (derivan de los campos funcionales) En versiones antiguas, no era sencillo mostrar campos
Ejemplo: Un campo de alerta en clientes. Con este tipo de campos es posible acceder y mostrar esos campos alojados en otras tablas.
Objetos: serialized
Utiliza el mtodo repr() de Python para serializar los objetos por defecto, pero puede ser reemplazado por otro mtodo mediante el parmetro serialize_func
Objetos: property
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 administracin), estas estn representadas como campos de tipo referencia.
Cuando se lee una propiedad el programa devuelve la propiedad adjunta a la instancia del objeto que se est leyendo.
class orm_template(object) / class orm(orm_template) Las clases que albergan los objetos con los que normalmente
Todos los datos del ERP son accesibles a travs de "objetos". Por
La principal consecuencia de ste hecho es que todos los mtodos de los objetos tienen un parmetro comn: el
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
Principales mtodos:
_auto_init: se ejecuta automticamente al cargar el objeto. En algunos casos se sobreescribe para aadir la creacin de ndices adicionales. (Ej: stock/stock.py) check_recursion: Se utiliza en estructuras arbreas para prevenir ciclos infinitos. Si la estructura la hemos creado a mano tambin podemos utilizar el mtodo pasndole como argumento parent el nombre del campo padre Browse: Se utiliza continuamente. Devuelve un conjunto de objetos navegables de una clase. Copy: Es el mtodo 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 mtodo. Ejemplo: account.move.line (al crear un apunte contable) default_get: Devuelve los valores por defecto establecidos por un usuario, etc. Ejemplo de utilizacin: account.move.line
Principales mtodos:
distinct_field_get: Devuelve todos los distintos valores introducidos en un campo. Se utiliza normalmete para autocompletar campos (es automtico). fields_get: Devuelve los campos pertenecientes a un objeto. Ejemplo de utilizacin: si fuesemos a escribir nuestra propia aplicacin cliente utilizaramos este mtodo remotamente para obtener los campos y sus tipos. Hay un ejemplo de manipulacin de este mtodo en base/res/partner/partner.py en la definicin de los bancos. export_data / import_data: Son los mtodos utilizados en la importacin / exportacin de datos desde el cliente. El hecho de que sean mtodos de clase nos permite sobreescribirlos, en caso necesario, para los objetos que queramos. (No hay un slo caso en todo el repositorio, pero es posible hacerlo) fields_view_get: Devuelve la vista correspondiente a un objeto (en su contexto). Es el mtodo que entre otras cosas se encarga de la aplicacin de las herencias en las vistas. Ejemplo de manipulacin: en stock/product.py o en ir/ir_model.py (ver ste ltimo en funcionamiento)
Principales mtodos:
name_get: Es un mtodo trivial que devuelve el valor del campo name o el especificado en _rec_name. Ejemplo de utilizacin: Las categoras de producto. name_search: Define la bsqueda a travs del nombre de un objeto. Ejemplo de utilizacin: bsqueda de productos. _parent_store_compute: Para la optimizacin de determinadas consultas en la base de datos de estructuras arbreas es preciso calcular para cada nodo sus ramas izquierda y derecha. Es este mtodo el encargado de realizar el clculo. Ejemplo de utilizacin: este tipo de estructuras se utilizan actualmente con las cuentas contables y las localizaciones de almacn. (enlace) perm_read: Permite consultar los permisos sobre un objeto y los datos de creacin y ltima modificacin. Este mtodo es a veces conveniente ya que los campos internos (create_uid, create_date, etc.) son accesibles directamente slo si los hemos redeclarado (en _columns). Con este mtodo podemos acceder a leerlos sin necesidad de dicha declaracin
Principales mtodos:
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 ms lento y nos permite realizar lo mismo con una sintaxis ms clara. search_count: Devuelve el nmero de registros como resultado de una bsqueda. search : Es otro de los mtodos muy utilizados. Devuelve una lista de ids que cumplen con una serie de requisitos. Ejemplo de utilizacin: 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 pestaa, dependiendo del contexto. Write: Es el mtodo que se utiliza habitualmente para escribir valores en un objeto
states
Uso: establecer parmetros dependiendo del estado Sintaxis: {'nombre_estado': lista_atributos, ...}
Ejemplo:
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'),
Ejemplo:
Ejemplo:
Parmetros opcionales:
ondelete = cascade
-
Ejemplo:
obj es el otro objeto relacionado rel es el nombre de la tabla que hace la relacin id1 e id2 son los nombres de los campos en la tabla de relacin Ejemplo:
'category_id':
fields.many2many( res.partner.category', 'res_partner_category_rel', 'partner_id', 'category_id', 'Categories'),
Seleccin dinmica:
<field name="name">Project Task</field> <field name="object">project.task</field>
Ejemplo _defaults = {
Objetos: restricciones
_constraints = [
(_constraint_sum, 'Error: el resultado debera ser < 1000.', ['name'])
} _defaults = {
'manuf_warranty': lambda *a: False,
custom_material()
Ejemplo:
Ver product.product y product.template
_table
_rec_name
_order
self.pool.get('nombre.objeto')
Ejemplo:
Acceso a travs de Netservice (en el servidor pero desde fuera de los objetos)
Acceso XML-RPC
create
def create(self, cr, uid, vals, context={}) devuelve el id def search(self, cr, uid, args, offset=0, limit=80)
search
devuelve lista de ids def read(self, cr, uid, ids, fields=None, context={}) devuelve lista de diccionarios: [{'nombre_campo': valor}]
read
write
devuelve True def unlink(self, cr, uid, ids) devuelve True def browse(self, cr, uid, ids, offset=0, limit=2000) Ejemplo:
unlink
browse
name_get
def name_get(self, cr, uid, ids, context={}) Devuelve
name_search
Vistas
Vistas sirven para definir como mostrar los objetos. tienes que saber que la interfaz de usuario de OpenERP es dinmica. Esto quiere decir que no esta descrita estticamente por algn cdigo, pero es dinmicamente 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
Vistas: principios
Acciones
Items de Men
Vistas: sintaxis
Como los otros ficheros XML (usan las etiquetas record) objeto que almacena vistas = ir.ui.view
<openerp>
<data>
<record model=ir.ui.view id=...>
...
</record>
</data>
</openerp>
<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>
Vista: ejemplo
<form string="Company">
</form>
</field>
</record>
Menus y acciones
<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>
Seguridad de objetos
Es importante definir permisos de acceso a los objetos de openERP para que puedan acceder a ellos otros usuarios que no sean administradores. Para ello es necesario definir politicas de seguridad a los mdulos que se definiran, tal y como hemos visto en la estructura del mdulo, 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 siguientes columnas: Id: Indica el identificador de esa lnea 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 mdulo que lo crea. Si lo hiciesemos desde otro mdulo se llamara con: base.model_res_partner (Pertenece al mdulo base) Group_id:id: Identificador del grupo de usuarios para el cual se estn estableciendo los permisos. Ej: base.group_partner_manager
Seguridad de objetos
ir_model_access.csv: Perm_read: Indica si al grupo definido le est permitida la lectura sobre ese 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.
Seguridad de objetos
Archivo modulo_security.xml: En este archivo se define la creacin de grupos, reglas de registros y los permisos de un grupo sobre los mens. Creacin de grupos:
<record model="res.groups" id="group_system"> <field name="name">Administrator / Configuration</field> </record>
Seguridad de objetos
Archivo modulo_security.xml: En este archivo se define la creacin de grupos, reglas de registros y los permisos de un grupo sobre los mens. Creacin de Reglas: Sirven para crear dominios especificos sobre los grupos que las tienen definidas. En el ejemplo se crear una regla para que los 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>
Seguridad de objetos
Archivo modulo_security.xml: En este archivo se define la creacin de grupos, reglas de registros y los permisos de un grupo sobre los mens. Asignacin de reglas a grupos: A la hora de crear un grupo podemos asignarle las reglas definidas anteriormente:
<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>
Ejercicio prctico