You are on page 1of 60

Introduccin Tcnica

Junio - 2014
Contenido
Estructura de mdulos
ORM
Tipos de campos
Mtodos estndares
Vistas
Herencia
Reportes
Ejercicios
Estructura de mdulos
En OpenERP todos los mdulos se encuentran en la carpeta C:\Archivos de
Programa\OpenERP 7 (o numero de versin)\Server\server\openerp\addons .
Para crear nuevos mdulos se debe ir dentro de la carpeta addons y crear una
nueva carpeta con el nombre del nuevo modulo. Dicho nombre no puede contener
maysculas ni espacios, por lo que si es un nombre de varias palabras debe
estar escrito de la siguiente manera: modulo_nombre
La estructura de un modulo completo es la siguiente:
addons/
modulo_nombre/ # La carpeta del modulo
demo/ # Datos pre cargados a la BD para el demo y la unidad de testeo
i18n/ # Archivos de traduccin
report/ # Definicin de reportes
security/ # Declaracin de grupos y derechos de acceso
wizard/ # Definicin de los wizards
workflow/ # Definicin de los flujos de trabajo
__init__.py # Paquete Python de inicializacin (requerido)
__openerp__.py # Declaracin del modulo (requerido)
modulo_nombre.py # Clases Python, objetos del modulo
modulo_nombre_view.xml # La vista del modulo con los forms, trees, menus
El archivo __init__.py es aquel que se encarga de inicializar el modulo. Para este
caso el contenido de este archivo seria:
# -*- encoding: utf-8 -*-
import modulo_nombre
Es muy importante prestar atencin al cdigo de arriba ya que ese cdigo es lo que
hace que los archivos Python se lean correctamente y OpenERP no de errores al
leerlos.
El archivo __openerp__.py es aquel que contiene un nico diccionario
conteniendo el nombre del modulo, su descripcin, sus dependencias, sus vistas,
demos y datos. Para nuestro caso este archivo se vera de la siguiente manera:
# -*- encoding: utf-8 -*-
{
'name' : Nombre del Modulo',
'version' : '1.0',
'author' : 'OpenERP',
'description' : Descripcion del Modulo',
'category': Categoria del Modulo',
'website': 'http://www.openerp.com',
'depends' : ['base'], # lista de dependencias, sin estas no se inicia el modulo
'data' : [ # vistas y datos del modulo
'security/groups.xml', # siempre carguen los grupos primero!
'security/ir.model.access.csv', # cargar los derechos de acceso despues de los grupos
'workflow/workflow.xml',
'wizard/wizard.xml',
'report/report.xml',
modulo_nombre_view.xml
],
'demo': ['demo/demo.xml'], # Datos del demo (para testeo de la unidad)
"active": False,
"installable": True,
"certificate" : "",
}
El archivo modulo_nombre.py define los objetos que componen un modulo en
la vista y en la base de datos, estos objetos tienen atributos predeterminados los
cuales son usados e interpretados por Open ERP.
Atributos predeterminados:
_columns: Este atributo es requerido, en el se definen los campos que se crean en la tabla de la base de
datos y las vistas
_constraints: Permite establecer restricciones a un campo de un objeto
_sql_constraints: Permite establecer restricciones SQL a un campo de un objeto
_defaults: Establece valores predeterminados para un campo
_inherit: Establece la herencia entre los objetos
_name: Este atributo es requerido y pone nombre al objeto creado
_order: Este atributo es usado como resultado de una bsqueda y lectura de mtodos
_rec_name: Nombre del campo que se usa para recursos de bsqueda
El archivo modulo_nombre_view.xml contiene la vista del modulo. En OpenERP se
dividen en tres principales; las tree, las formy las graphic. Las vistas describen como es
mostrado cada objeto y como y donde es dibujado cada campo de nuestro objeto.
La definicin de la vista contiene tres tipos de tag:
- <record> un tags con el atributo model=ir.ui.view, que contiene la definicion de la vista
- <record> un tags con el atributo model=ir.actions.act_window, que contiene el tipo de
accin perteneciente a esa vista
- <menuitem> un tags que crea la entrada en el menu y el vinculo de la accin.
La estructura de bsica de una vista consta del siguiente formato:
<?xml version="1.0"?>
<openerp>
<data>
[view definitions]
</data>
</openerp>
ORM
ORM (Object Relational Mapping)
Para todos aquellos que no conozcan el significado de las siglas ORM (Object Relational
Mapping), diremos que es una tcnica de programacin para convertir datos entre el lenguaje
de programacin orientado a objetos utilizado y el sistema de base de datos relacional
utilizado en el desarrollo de nuestra aplicacin.
Actualmente, las bases de datos relacionales solo pueden guardar datos primitivos, por lo que
no podemos guardar objetos que vayamos creando en nuestra aplicacin, sino que lo que
hacemos es convertir los datos del objeto en datos primitivos que si podremos almacenar en
las tablas correspondientes de nuestras bases de datos. Si luego necesitamos ese objeto en
alguna parte de nuestra aplicacin, debemos de recuperar los datos primitivos de la base de
datos y volver a construir el objeto.
El mapeo objeto-relacional lo que nos ayudar ser precisamente a eso, a olvidarnos
completamente de como convertir los objetos en datos primitivos para almacenarlos y
viceversa.
Para ver el efecto que tiene el ORM en nuestro cdigo al momento de declarar un nuevo
objeto en OpenERP, debajo se encuentra la declaracin de los objetos de nuestro modulo
modulo_nombre en el archivo modulo_nombre.py.
# -*- encoding: utf-8 -*-
from osv import osv, fields
class objeto_modulo_nombre(osv.osv):
_name = objeto.modulo.nombre'
_columns = {
'name': fields.char('Title', size=64, required=True, translate=True),
'state': fields.selection([('draft','Draft'),
('confirmed','Confirmed')],'State',required=True,readonly=True),
'description': fields.text('Description', readonly=True,
states={'draft': [('readonly', False)]} )
}
_defaults = {
'active': True,
'state': 'draft',
}
def _check_name(self,cr,uid,ids):
for idea in self.browse(cr, uid, ids):
if 'spam' in idea.name: return False
return True
_sql_constraints = [('name_uniq','unique(name)', 'Ideas must be unique!')]
_constraints = [(_check_name, 'Please avoid spam in ideas !', ['name'])]
objeto_modulo_nombre()
Tipos de campos
Los objetos en Open ERP contienen campos los cuales permiten introducir datos en la base de
datos, estos campos van definidos en el atributo _columns. Hay tres tipos de campos, los
bsicos, los relacionales y los funcionales. Los bsicos solos sirven para introducir datos
bsicos, los relacionales (many2one, one2many, many2many) permiten establecer relaciones
entre los objetos y los funcionales no se guardan en la base de datos y son calculados al vuelo
como funciones Python.
Campos simples principales:
- Boleano (True, False): fields.boolean(Nombre' [, Parametors Opcionales]),
- Integer: fields.integer('Nombre' [, Parametors Opcionales]),
- Float: fields.float('Nombre' [, Parametors Opcionales]),
- Char: fields.char(Nombre', size=n [, Parametors Opcionales]),
- Date: fields.date(Nombre' [, Parametors Opcionales]),
- Selection: fields.selection((('n',No confirmado'), ('c','Confirmado')),Nombre' [,
Parametors Opcionales]),
Existen otros campos como Text, Datetime y Binary tambin.
Campos relacionales principales:
- Many2one: Asocia este objeto con un objeto padre en una relacin muchos a uno, por
ejemplo, de muchas marcas de autos existe una que pertenece a un vehculo en particular.
fields.many2one(nombre.otro.objeto', Nombre', parametro opcional)
- One2many: Este campo expresa una relacin uno a muchos entre dos objetos, este
campo es obsoleto utilizando una relacin many2one. Se utiliza en tablas.
fields.one2one('nombre.otro.objeto', Nombre')
fields.one2many('nombre.otro.objeto', id del campo relacional', Nombre',
parametro opcional)
- Many2many: Es una relacin bilateral entre dos objetos.
fields.many2many( nombre.otro.objeto', objetorelacional', id.objeto.actual',
id.otro.objeto', Nombre')
Campos funcionales principales:
- Function: fields.function(fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type="float,
fnct_search=None, obj=None, method=False, store=False,
multi=False,...)
- type es el tipo de campo devuelto por la funcin. Puede ser cualquiera excepto function.
- method indica si el campo se calcula mediante un mtodo (de un objeto) o una funcin global.
- store y multi son mecanismos de optimizacin, para guardar los valores de los campos funcionales en la base de datos
(store=True) aunque se seguirn calculando mediante una funcin Python o para calcular varios campos funcionales a la vez
con el atributo multi.
- fnct es la funcin o mtodo que calcular el valor del campo. Es un parmetro obligatorio. Debe haberse declarado antes de
declarar el campo funcional.
Si method es verdadero (True), la signatura del mtodo debe ser:
def fnct(self, cr, uid, ids, nombre_campo, arg, context)
en otro caso (si se trata de una funcin global), su signatura debe ser:
def fnct(cr, tabla, ids, nombre_campo, arg, context)
De cualquier manera, debe devolver un diccionario de valores de la forma {id'_1_': valor'_1_',id'_2_': valor'_2_',...}.
Los valores del diccionario devuelto deben ser del tipo indicado en el parmetro type de la declaracin del campo.
- fnct_inv es la funcin o mtodo que permitir escribir valores en ese campo. Si method es
verdadero (True), la signatura del mtodo debe ser:
def fnct(self, cr, uid, ids, nombre_campo, valor_campo, arg, context)
en otro caso (si se trata de una funcin global), su signatura debe ser:
def fnct(cr, table, ids, nombre_campo, valor_campo, arg, context)
- fnct_search permite definir el comportamiento de las bsquedas en ese campo. Si method es
verdadero (True), la signatura del mtodo debe ser:
def fnct(self, cr, uid, obj, name, args)
en otro caso (si se trata de una funcin global), su signatura debe ser:
def fnct(cr, uid, obj, name, args)
Tambin existen otros dos campos llamados related y property. Por referencias acerca de
estos se puede ir a la direccin web:
https://doc.openerp.com/6.0/developer/2_5_Objects_Fields_Methods/field_type
Mtodos estndares
OpenERP tiene definido una cantidad considerable de mtodos que son muy tiles al
momento de desarrollar nuevos mdulos. Estos mtodos tienen definido de que manera se le
tienen que pasar los datos y de que forma devuelven los mismos. Para acceder a la
informacin especifica de cada mtodo perteneciente a OpenERP se recomienda acceder a
https://doc.openerp.com/6.0/developer/2_5_Objects_Fields_Methods/methods/ en donde
podrn encontrar todos o casi todos los mtodos y la informacin detallada de cada uno.
Mtodos principales:
- Mtodo crear: create (cr, uid, values, context=None)
Crea un nuevo registro con los valores especificados. Parmetros especficos:
values: Diccionario con los valores de los campos para el nuevo registro.
Devuelve el id del registro creado. Puede generar los siguientes errores:
AccessError: Si el usuario no tiene permisos de escritura en el objeto solicitado, o si el usuario intenta
ignorar las reglas de acceso para crear el objeto solicitado.
ValidateError: Si el usuario intenta introducir un valor invlido para un campo que no est en la
seleccin.
UserError: Si se crease un bucle en una estructura de objetos jerrquica como resultado de la operacin
(como establecer un objeto como su propio padre).
- Mtodo buscar: search(cr, uid, args, offset=0, limit=None, order=None, context=None, count=False)
Busca registros basndose en el dominio de bsqueda. Parmetros especficos:
offset: Nmero de registros a omitir. Opcional. Por defecto 0.
limit: Nmero mximo de registros a devolver. 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: Debe ser un nombre vlido del campo de un modelo de un objeto, posiblemente
siguiendo las relaciones many2one, usando la notacin de punto. Por ejemplo partner_id.country es
un valor vlido.
operator: Debe ser una cadena con un operador de comparacin vlido de esta lista: =, !=, >, >=, <,<=,
like, ilike, in, not in, child_of, parent_left, parent_right. El significado de muchos de estos operadores es
obvio. El operador child_of buscar registros que son hijos o descendientes de un registro dado, de acuerdo
al significado de dicho modelo.
value: Debe ser un valor vlido con que comparar los valores del campo field_name, dependiendo de su
tipo.
El criterio del dominio puede ser una combinacin que use 3 operadores lgicos que pueden aadirse entre
tuplas:
'&': Y lgico. Por defecto.
'|': O lgico.
'!': No lgico o negacin.
Para mostrar todos los registros, se debe pasar una lista vaca.
Devuelve una lista de ids (lista de nmeros enteros) de los registros que coinciden con el criterio.
Posibles errores:
AccessError: Si el usuario no tiene permisos de lectura en el objeto solicitado.
- Mtodo browse: browse (cr, uid, ids, context=None)
Obtiene registros como objetos permitiendo utilizar la notacin de puntos para explorar los campos y las
relaciones.
Devuelve un objeto (si ids es un entero) o lista de objetos (si ids es una lista de enteros) solicitados.
Es un mtodo muy potente, pues permite consultar con facilidad campos relacionados de forma encadenada
a partir de un objeto.
- Mtodo leer: read (cr, uid, ids, fields=None, context=None)
Obtiene una lista de los valores de los campos fields de los registros ids. Tiene los siguientes parmetros:
fields: Lista de campos.
Esto me devuelve un diccionario con el nombre y valor de los campos solicitados algo como:
{'list_price': 5500.00, 'default_code': 'CLHTC1'}
- Mtodo modificar: write(cr, uid, ids, values, context=None)
Actualiza los registros con los ids dados con los valores de los campos dados. Parmetros especficos:
values: Diccionario con los valores de los campos a modificar. El tipo de los valores de campo que se
pasan para los campos relacionales es especfico.
Devuelve True.
Posibles errores:
AccessError: Si el usuario no tiene permisos de escritura en el objeto solicitado, o si intenta soslayar las
reglas de escritura del objeto solicitado.
ValidateError: Si el usuario intenta entrar un valor invlido en un campo que no est en la seleccin.
UserError: Si se crease un bucle en una estructura de objetos jerrquica como resultado de la operacin
(como es establecer un objeto como su propio padre).
- Mtodo copiar: copy (cr, uid, id, defaults=None, context=None)
Duplica el registro con el id propuesto actualizndolo con los valores por defecto. Parmetros:
defaults: Diccionario de valores de campo para cambiar antes de guardar el objeto duplicado.
Devuelve True.
- Mtodo eliminar: unlink(cr, uid, ids, context=None)
Borra los registros con los ids dados. Devuelve True. Posibles errores:
AccessError: Si el usuario no tiene permisos de escritura en el objeto solicitado, o si intenta soslayar las
reglas de borrado del objeto solicitado.
UserError: Si el registro es una propiedad por defecto para otros registros.
- Mtodo desplegar nombre: name_get(cr, user, ids, context=None)
Devuelve el valor a mostrar (el texto que ve el usuario) para los registros con los ids dados.
Devuelve una lista con tuplas (id, texto_a_mostrar) para los registros con los ids dados.
- Mtodo buscar nombre: name_search(cr, user, name='', args=None, operator='ilike',
context=None, limit=100)
Busca registros que tengan un nombre como el dado en name y cumplan la comparacin del operador
operator.
Parametros:
args (lista) dominio de bsqueda opcional (como en el mtodo search())
operator (cadena) operador de comparacin para la bsqueda como ilike o =
limit (entero) numero mximo opcional de registro a devolver
Devuelve una lista con tuplas (id, texto_a_mostrar) con los ids de los registros devuelvos y sus respectivos
nombres.
Vistas
Las vistas en OpenERP se dividen en seis tipos; las tree, las form, las graphic, las kanban, las Grantt y las
search view. Dentro de las vistas tambin se definen los menus y las acciones o actions.
Elementos de diseo dentro de las vistas:
Existen varios elementos de diseo que nos permiten personalizar las vistas formy tree de los objetos
creados.
Notebook: Permite distribuir los campos de la vista en diferentes tabs que van definidos por
paginas, ejemplo:
<notebook colspan="4">....</notebook>
Page: Define una nueva pgina para el notebook, ejemplo:
<page string="Order Line"> ... </page>:
El atributo string define el nombre de la pagina
Separator: Agrega una lnea de separacin en el formato, ejemplo:
<separator string="Links" colspan="4"/>
El atributo string define la etiqueta del separador y el atributo colspan define su tamao
Group: Permite crear grupos de varias columnas, ejemplo:
<group col="3" colspan="2">
<field name="invoiced" select="2"/>
<button colspan="1" name="make_invoice" states="confirmed"
string="Make Invoice type="object"/>
</group>
Parmetros para crear grupos:
colspan: numero de columnas para usar
rowspan: numero de filas para expandir o no el grupo
col: numero de columnas proporcionas (a su hijo)
string: (opcional) Si se establece, un marco ser dibujado alrededor del grupo con una etiqueta de
texto conteniendo el valor de string.
Atributos para los campos (field) dentro de la vista
select=1: Esta marca proporciona un criterio de bsqueda para la vista rbol, este criterio es un campo
del objeto. Cuando su valor es 1 significa que es un criterio.
colspan=4:El numero de columnas por las que se puede extender un campo
readonly=1: Establece un widget como solo lectura
invisible=True: Oculta el campo y su etiqueta
password=True: Reemplaza la entrada de un campo con un smbolo
string=: Cambia la etiqueta de un campo. Tambin es usado como parmetro de bsqueda por la vista
rbol.
domain: puede restringir un dominio
Ejemplo: domain=[(partner_id,=,partner_id)]
widget: puede cambiar un widget.
Ejemplo: widget=one2many_list
Tambin puede ser: one2one_list, one2many_list, many2one_list, many2many, url, email, image,
float_time, reference
Vistas Form
Distribuyen los campos en una forma o ventana siguiendo ciertos criterios y personalizaciones.
Los campos son distribuidos usando las siguientes reglas:
Cada campo es precedido por una etiqueta con su nombre
Los capos son puestos de izquierda a derecha, de acuerdo al orden con que son declarados en
el archivo xml
El formato siempre esta divido en cuatro espacios ocupados por dos campos con sus
respectivas etiquetas, sin embargo un campo puede usar varias columnas como es el caso de de
un campo de relacin one2many. Tambin se puede realizar la operacin inversa, tomar varias
columnas y dividirlas en varias columnas.
Vistas Arbol o Tree:
Las vistas rbol son usadas como modo de listado la cual nos permete realizar bsquedas en la
pantalla. Esta vista es simple y solo tiene algunas opciones de diseo.
Diseo de vista con un Formdeclarado:
<?xml version="1.0"?>
<openerp>
<data>
<record id="vista_pelicula_form" model="ir.ui.view">
<field name="name">motion.pelicula.form</field>
<field name="model">motion.pelicula</field>
<field name="type">form</field>
<field name="arch" type="xml">
<formstring="Peliculas">
<group col="2" colspan="2">
<separator string="Informacion Secundaria" colspan="2"/>
<field name="fecha"/>
<field name="costo"/>
<field name="numero"/>
<field name="costo_a"/>
</group>
<notebook colspan="4">
<page string="Notas">
<field colspan="4" nolabel="1" name="notas"/>
</page>
</notebook>
</form>
</field>
</record>
</data>
</openerp>
Diseo de vista con un Tree declarado:
<?xml version="1.0"?>
<openerp>
<data>
<record id="vista_peliculas_arbol" model="ir.ui.view">
<field name="name">motion.pelicula.tree</field>
<field name="model">motion.pelicula</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Peliculas">
<field name="nombre"/>
<field name="codigo"/>
<field name="nombre_d"/>
</tree>
</field>
</record>
</data>
</openerp>
Diseo de vista con un Formdeclarado y un Tree adentro usando widgets:
<?xml version="1.0"?>
<openerp>
<data>
<record id="vista_peliculas_arbol" model="ir.ui.view">
<field name="name">motion.pelicula.tree</field>
<field name="model">motion.pelicula</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<field name=ids widget=one2many_list>
<tree>
<field name="nombre"/>
<field name="codigo"/>
<field name="nombre_d"/>
</tree>
</field>
</field>
</record>
</data>
</openerp>
Acciones:
Las acciones determinan el comportamiento del sistema en respuesta a las acciones de usuario,
las tipos de acciones son:
Window: Abren una nueva ventana
Report: Imprimen un reporte
CustomReport: Personaliza los reportes
Wizard: Iniciar un Wizard
Execute: Ejecutar un mtodo del lado del servidor
Group: Rene algunas acciones en un grupo
A continuacin se construye una nueva accin para la vista formy tree del objeto
motion.pelicula que creara la entrada para el formulario.
Acciones Form:
<?xml version="1.0"?>
<openerp>
<data>
<record id="abrir_vista_nueva_pelicula" model="ir.actions.act_window">
<field name="name">Nueva pelicula</field>
<field name="res_model">motion.pelicula</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
</record>
</data>
</openerp>
Acciones Tree:
<?xml version="1.0"?>
<openerp>
<data>
<record id="abrir_vista_peliculas_arbol" model="ir.actions.act_window">
<field name="name">Todas las peliculas</field>
<field name="res_model">motion.pelicula</field>
<field name="view_type">tree</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="vista_peliculas_arbol"/>
<field name="domain">[]</field>
</record>
</data>
</openerp>
Menus:
Los mens en Open ERP poseen las siguientes caractersticas:
Id: Todos los mens necesitan un id para poder ser identificados por Open ERP dentro de la
tabla de items
Name: Especifica la posicin jerrquica y el nombre del men o entrada
Action: Identifica la accin asociada al men (este campo no es obligatorio)
Icon: Especifica el icono que ser utilizado por el men
Los iconos disponibles son : STOCK_ABOUT, STOCK_ADD, STOCK_APPLY, STOCK_BOLD,
STOCK_CANCEL, STOCK_CDROM, STOCK_CLEAR, STOCK_CLOSE,
STOCK_COLOR_PICKER, STOCK_CONNECT.
Groups: Especifica los grupos que pueden ver el men
Sintaxis men principal:
<?xml version="1.0"?>
<openerp>
<data>
<menuitemicon="STOCK_MEDIA_PLAY"
id="menu_raiz_motion"
name="Motion Peliculas"/>
</data>
</openerp>
Sintaxis sub-menus :
<?xml version="1.0"?>
<openerp>
<data>
<menuitemid="menu_motion_reporte name="Reportes parent="motion.menu_raiz_motion"/>
<menuitemid="menu_motion_peli name="Peliculas parent=motion.men_raz_motion/>
</data>
</openerp>
Herencia
Herencia de objetos
En OpenERP existen tres tipos de herencia, herencia por prototipo, por extensin y por
delegacin (herencia mltiple), todas son completamente diferentes y constituyen una gran
herramienta para el desarrollo de los mdulos en OpenERP.
En la herencia por prototipo y por extensin se debe agregar el siguiente atributo:
_inherit='object.name'
Donde object.name es el objeto del cual se hereda.
Herencia por extensin
Al igual que en programacin orientada a objetos en las nuevas clases creadas heredan los
atributos y los mtodos de la superclase padre, sin embargo la diferencia radica en que el
objeto afectado es el padre y no el hijo, ejemplo:
Ejemplo herencia por extensin:
class res_partner(osv.osv):
_name = 'res.partner'
_inherit="res.partner"
_columns = {
'codEmpresaCliente': fields.integer('Codigo Empresa Cliente',size=4),
'nit': fields.char('NIT',size=10),
'ciudades_cod_dane_ciudad': fields.integer('Codigo de Ciudades',size=3),
'tel1': fields.char('Telefono 1',size=16),
'tel2': fields.char('Telefono 2',size=16),
'cel': fields.char('Celular',size=16),
'email': fields.char('Email',size=100),
'fax': fields.char('FAX',size=100),
'direccion': fields.char('Direccion',size=200),
'autoretenedor': fields.boolean('Autoretenedor'),
'granContribuyente': fields.boolean('Gran Contribuyente'),
'diponibilidad': fields.boolean('Disponibilidad'),
'es_empleado': fields.boolean('Es Empleado'),
}
res_partner()
Es importante apreciar que el campo _name tiene el mismo valor que el campo _inherit, sin embargo
el nombre general de la clase puede ser dife-rente o igual a la clase original sin afectar el resultado de la
operacin (heren-cia). Con la herencia establecida se especifica que los nuevos campos del atributo
_columns creados en la nueva clase podrn ser vistos en las vistas formy tree de la clase original
(superclase), En el ejemplo todos los campos sern agregados a la superclase, cabe resaltar que para que
los campos sean visibles en la vista se debe heredar la vista de la superclase en el archivo <modulo_view>.
xml y agregar estos campos.
Herencia por prototipo
En este tipo de herencia la diferencia radica en que la nueva clase copia todos los atributos y
mtodos de su padre (superclase), ejemplo:
class other_material(osv.osv):
_name = 'other.material'
_inherit = 'network.material'
_columns = {
'manuf_warranty': fields.boolean('Manufacturer warranty?'),
}
_defaults = {
'manuf_warranty': lambda *a: False,
}
other_material()
En este ejemplo el campo _inherit y _name son diferentes debido a que la tabla (el objeto
nuevo) es el que est operando y no su padre, por lo tanto sus atributos y mtodos no sern
reconocidos en las vistas de la superclase.
Herencia por delegacin
La herencia por delegacin es parecida a la herencia mltiple de c++, en este caso el objeto
heredad de mltiples tablas, la tcnica cosiste en agregar una columna a la tabla al objeto
heredado. Estas columnas guardaran una clave foranea (id de otra tabla). Ejemplo:
class tiny_object(osv.osv)
_name = 'tiny.object'
_table = 'tiny_object'
_inherits = {
'tiny.object_a': 'object_a_id',
'tiny.object_b': 'object_b_id',
... ,
'tiny.object_n': 'object_n_id'
}
(...)
Los valores object_a_id, object_b_id, object_n_id son de tipo string y determina el
titulo de las columnas las cuales son las claves forneas de tiny.object_a, tiny.object_n
que son guardadas. El objeto tiny.object hereda todos las columnas y mtodos de los n
objectos tiny.object_a, tiny.object_n.
Herencia de vistas
Cuando se crean objetos heredades a veces es necesario modificar la vista del objeto
por lo tanto es necesario heredar tambin la vista de la superclase, as se puede
agregar, quitar o modificar los campos que se deseen.
Es posible anexar o editar el contenido de un tag. Los tags tienen algunos atributos
que permiten especificar la posicin en la cual se desean hacer modificaciones, en el
siguiente ejemplo se agrega una pgina a la vista res.partner.form en el modulo
base.
Se pueden utilizar los siguientes valores para indicar la posicin:
inside (default): Este valor indica que se anexara un tag dentro.
after: Se agrega un contenido despus del tag
before: Se agregara un contenido despus del tag
replace: Se remplazara el contenido de un tag
Ejemplo herencia de vistas:
<record model="ir.ui.view" id="view_partner_form">
<field name="name">res.partner.form.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Relations">
<field name="relation_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
</field>
</record>
En algunos casos un mismo campo (id) es usado en el mismo <record> por lo que al momento de llamarlo
de la manera que se especifica arriba OpenERP dar un error debido a que no sabe a cual de todos esos
campos iguales tiene que efectuar el cambio. Para estos casos existe el uso del <xpath> al cual se le debe
poner la direccin exacta del campo y de esta forma OpenERP sabr cual de todos estos campos va a ser el
que ser modificado.
Para ello debemos ir a la vista original (padre) y ubicarnos en el <record> que estamos heredando. Luego,
debemos seguir el camino de tags hasta llegar al campo que deseamos modificar. Ejemplo:
Ejemplo herencia de vistas usando xpath:
<record model="ir.ui.view" id="view_partner_form">
<field name="name">res.partner.form.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<xpath expr="/form/sheet/notebook/page/field[@name='line_cr_ids']/tree/field[@name='amount_original']"
position="after">
<field name="relation_ids" colspan="4" nolabel="1"/>
</xpath>
</field>
</record>
Ejercicios
Crear nuevo modulo
Dentro de la carpeta OpenERP7\Server\server\openerp\addons\ cada
subcarpeta es un modulo.
Dentro de cada modulo por lo menos existen los siguientes archivos
__init__.py, __openerp__.py, modulo.py y modulo_view.xml
__init__.py: Aqui se importan todos los archivos y directorios que
contienen codigo python, ste archivo hace que OPENERP reconozca al
directorio o capeta modulo como un mdulo.
__openerp__.py: Contiene un diccionario en Python para agregar
las descripciones del mdulo, como autor, versin, etc.
modulo.py: Aqu escribiremos el cdigo Python que permitir agregar
o modificar las funcionalidades de OPENERP, este archivo ser
importado en __init__.py, como veremos mas abajo.
modulo_view.xml: Aqu vamos agregar los codigos XML
que permitir la vista del Mdulo en OPENERP, en nombre debe de
terminar en _view.xml por convencion.
Modificacin de Pantallas
Proceso
Crear un nuevo modulo
Crear un directorio y los 4 primeros archivos
Heredar elementos a modificar
Seleccionar que elementos queremos modificar, tomar el
modulo y modificarlos
En el modulo.py
Se puede o no utilizar el mismo nombre de la clase a heredar
Utilizar _inherit
En el modulo.xml
Definir de quien queremos heredar
<field name='inherit_id' ref='base.view_partner_form'/>
Agregar el campo
<field name="website" position="after"> <!-- after: despues del campo sitio
web -->
<field name="rut"/> <!-- llamamos al campo rut con el
atributo name de field -->
</field>
Agregar nuevos objetos.
Ej: Uy_localizacion
Agregar validaciones en los
campos
Las validaciones se agregan como funciones dentro de la
clase que estamos trabajando.
Es decir en el modulo.py agregamos una funcion. Por
ejemplo en este caso que el rut tenga mas de 5 digitos
Luego agregamos la sentencia para que realice el
chequeo
_constraints=[(funcion,valor en falso,[campo])]
def _check_rut(self,cr,uid,ids,context=None):
for registro in self.browse(cr,uid,ids,context=context):
rut=registro.rut
if len(registro.rut) >= 5:
return True
else:
return False
_constraints = [(_check_rut,"El valor ingresado en RUT debe tener mas de 5
digitos",['rut'] )]
Hacer visible o no un campo
La definicin de si un campo es visible o
no se realiza en la vista, es decir en el
modulo.xml
Para ello luego del objeto colocamos la
funcin de validacin
En nuestro caso solo vamos a hacer
visible el campo rut si el partner es una
empresa
<field name="rut" attrs="{'invisible': [('is_company','=',
False)]}"/>
Cargar un campo cuando se
modifica otro
OpenERP permite la ejecucin de eventos luego de que se actualiza
cualquier campo. Esto se hace mediante el evento Onchange que se
define en la vista.
<field name="account_analytic_id"
on_change="dist_prod_ori_change(product_id,account_analytic_id)"/>
En este caso si cambia el campo account_analytic_id entonces invoco
la funcion dist_prod_ori_change.
Esta funcion tiene que estar dentro del objeto (es decir en el codigo
pyton
def dist_prod_ori_change(self,cr,uid,ids,product,proyecto):
#el objetivo de esta funcion es buscar en la factura el monto del producto, proyecto que estamos colocando
v={}
if proyecto:
v['price_subtotal']=2000
return {'value':v}
En este caso coloca 2000 en el campo price_subtotal que es un cambo
del mismo objeto
Ejercicio 1
1. Para comenzar tener instalado el mdulo de proyectos y de RRHH (para que aparezca los
departamentos esto se ve en RRHH/configuracin/departamentos )
2. Crear un objeto "x_oficinas_q" solo con un campo
a. x_oficinas_q tipo Char 20
b. Crear una opcin de men dentro de configuracin/configuracin para este nuevo objeto
3. En la pantalla de proyectos habra que agregar los siguientes campos
a. x_area del tipo many2one al objeto "hr.department"
b. x_cod_proy del tipo char de 11 posiciones
c. x_oficina del tipo many2one que mire el objeto x_oficinas_q
4. Habra que dejar la pantalla tipo la siguiente (en amarillo los nuevos campos)
Ejercicio 1
Ejercicio 2
1. Tiene que estar instalado el modulo de invoice y payment
2. Cuando vas a hacer una factura de cliente hay un campo de fecha que podes poner cualquier fecha.
3. El objetivo es que la fecha sea de este mes. Es decir que salga un mensaje de error cuando le ponen
una fecha de un mes diferente al actual.
4. Yo lo hara utilizando el mtodo on_change en la vista. Es decir agregando en la vista (el xml) que
cuando salga del campo ejecute una validacin.
5. Por ejemplo en este caso un campo verifica que exista el proyecto. El raise es el que ejecuta el
mensaje para desplegar en la pantalla
a. En la vista
<field name="product_id" on_change="dist_prod_ori_change(product_id,parent.id)"/>
b. En la clase
def dist_prod_ori_change(self,cr,uid,ids,producto,factura):
#controlo que el producto este entre los productos de la factura
v={}
if producto:
cr.execute('select count(*) as cantidad fromaccount_invoice_line where invoice_id=%s and
product_id=%s', (factura,producto))
valor=0
for r in cr.fetchall():
valor = r[0]
if valor==0:
raise osv.except_osv(('Warning!'), ('Elija otro producto, el elegido no esta en la factura')
return {'value':v}
Ejercicio 3
1. Tiene que estar instalado el modulo de facturacin y pagos
2. Agregar una solapa ms que sea distribucin
4. En esa solapa agregar un campo que dependa de la factura (un campo one2many)
(https://doc.openerp.com/6.0/developer/2_5_Objects_Fields_Methods/field_type/)
5. Y la tabla asociada llmala account_invoice_distribucion y que tenga los siguientes campos
'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the invoice."),
'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True),
'product_id': fields.many2one('product.product', 'Producto Actual', ondelete='set null', select=True),
'price_subtotal': fields.float('Importe total', digits_compute= dp.get_precision('Product Unit of Measure'),
required=True),
'account_analytic_id': fields.many2one('account.analytic.account', 'Proyecto Actual'),
'account_analytic_id_destino': fields.many2one('account.analytic.account', 'Proyecto Destino'),
'product_id_destino': fields.many2one('product.product', 'Producto Destino', ondelete='set null', select=True),
'cantidad_distr': fields.float('Importe a distribuir', digits_compute= dp.get_precision('Product Unit of Measure'),
required=True),
'por_distr': fields.float('Porcentage a distribuir (%)', digits_compute= dp.get_precision('Discount')),
'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company',
store=True, readonly=True),
'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
6. Agrega en la vista distribucin
7. Luego agrega los siguientes controles cuando agrego una lnea
a. El producto actual 'product tiene que estar en las lneas de esta factura.
i. Yo lo hara con un evento on_change
ii. Ten en cuenta que en la vista cuando estas llamando al evento podes
pasar tambin referencias al padre. En este caso parent.id seria el id de factura.
b. El proyecto y producto actual ('account_analytic_id') tambin tiene que estar en las lneas de la
factura.
Ejercicio 4
1. Crear asientos analticos por cada lnea que ests haciendo.
2. Esto implica en el momento de grabar la lnea de distribucin que se grabe tambin la lnea de
contabilidad analtica. Esto es la tabla account.analytic.line
3. Es importante ver que cuando se graba una transaccin se ejecuta uno de los siguientes eventos
a. create si se esta grabando un registro nuevo, o en nuestro caso una lnea de distribucin
nueva
b. write si se esta actualizando un registro.
4. Para hace esto yo creara un evento create y un evento write dentro de la clase
account_invoice_distribucion
5. En este evento sacara los datos y grabaria el account.analytic.line
6. Hay que grabar 2 lneas
a. Una que resta la cantidad en el proyecto origen
b. Uno que suma la cantidad en el proyecto destino.
Este es un ejemplo de como grabar
account_analytic_line = self.pool.get('account.analytic.line')
data = {
'move_id': v_move_id,
'product_uom_id': 1,
'product_id': vals['product_id'],
'general_account_id': v_general_account_id,
'journal_id':v_journal_id,
'code': '',
'ref': 'distribucion',
'currency_id': v_currency_id,
'amount_currency': -1*vals['cantidad_distr'],
'amount': -1*v_amount_currency,
'name': 'prueba',
'account_id': vals['account_analytic_id']
}
if data['move_id']:
account_analytic_line.create(cr, uid, data, context)
Donde v_move_id es el id del asiento contable. Esta en la tabla de invoice en el campo move_id
product_id es el producto origen en el primer asiento y en producto destino en el segundo
general_account_id es la cuenta contable. Esta en la tabla account_move_line filtrando por el
move_id y el producto y el proyecto. Recordad que proyecto y cuenta analtica es lo mismo.
journal_id es el campo journal_id de la factura
ref: hay que cambiarlo para que guarde la lnea el id de la lnea de distribucin. Esto lo vamos a usar en
el write para saber que tenemos que modificar.
Currency_id es la moneda de la factura
Amount_currency_ es el valor que viene en la lnea de distribucin.
Amount es el valor pero en moneda contable. Dentro de la clase res.currency hay una funcin (se
llama compute) que hace el calculo para el cambio de valor a la moneda
Account_id es el proyecto origen.
Ejercicio 5
1. . En contabilidad/diarios hay que crear un diario que se llame resguardo. Cdigo RESG, tipo efectivo,
moneda (NO COLOCAR MONEDA), cuenta de dbito predeterminada (elegir cualquiera)
2. Haz una factura para un cliente y contabilzala
3. Luego ve a pagos del cliente y agrega un pago para el cliente. Al elegir el cliente en facturas van a
aparecer todas las facturas que no estn pagas, con el id de apunte contable y los montos en moneda
nacional
4. Ahora bien el cambio radica en
a. Si el mtodo de pago es resguardo el valor que se presente sea el valor el 10% de la factura
(Este porcentaje va a cambiar pero eso lo hacemos despus)
b. Si el mtodo de pago es diferente a resguardo entonces es el 90% de la factura.
El modulo a extender es account_voucher. Se recomienda prestar atencin a los mtodos
onchange_amount y onchange_partner_id.