Publicidad

martes, 8 de abril de 2014

Introduccion en la Declaracion de Campos Odoo (OpenERP)

Los campos Introducción 


    Los objetos pueden contener diferentes tipos de campos. Esos tipos se pueden dividir en tres categorías: los tipos simples, tipos de relación y campos funcionales. Los tipos simples son enteros, reales, booleanos, cadenas, etc ... ; Los tipos de relación se utilizan para representar relaciones entre objetos (one2one, one2many, many2one). Campos funcionales son campos especiales porque no se almacenan en la base de datos pero calculan en tiempo real dado otros campos de la vista.

    Aquí está la cabecera del método de inicialización de cualquier campo de la clase definida en Odoo (OpenERP) (como se puede ver en el server / bin / OSV / fields.py):
def __ init__ (self, char = "Unknow", required = False, readonly = False, domain = None, context = None, priority = 0, change_default = False, size = None, onDelete = "cascade", translate = False, selection = False, ** args):
Hay un conjunto común de parámetros opcionales que están disponibles para la mayoría de los tipos de campos:

change_default: Ya sea o no el usuario puede definir valores por defecto en otros campos en función del valor de este campo. Estos valores por defecto deben ser definidos en la tabla ir.values.
help: Una descripción de cómo se debe utilizar el campo: más y más descriptivo que char . Aparecerá en la información sobre herramientas cuando se pasa el ratón sobre el campo.
ondelete: Cómo manejar las eliminaciones  en un registro relacionado. Por default encontraremos el valor "ondelete".
priority: No se utiliza?
readonly: True si el usuario no puede editar este campo, de lo contrario False .
required: True si el campo debe tener un valor antes de que el objeto puede ser salvado, de lo contrario False .
size: El tamaño del campo en la base de datos: número de caracteres o dígitos. Para los campos de tipo Char.
states: Permite anular otros parámetros para los estados específicos de este objeto. Acepta un diccionario con los nombres de los estados como claves y una lista de nombres / valores tuplas como los valores. Por ejemplo: states = {'done': [('readonly', True)]}
char: El nombre del campo como debe aparecer en una etiqueta o encabezado de la columna. Cadenas que contienen caracteres no ASCII deben utilizar objetos unicode de Python. Por ejemplo: 'test': fields.boolean (u'Testé ')
translate: True si el contenido de este campo debe ser traducido, de lo contrario False .

También hay algunos parámetros opcionales que son específicos para algunos tipos de campos:



domain:
Restricción de dominio en un campo relacional.
Valor por defecto: [].
Ejemplo: domain = [('campo', '=', valor)])
invisible:
Ocultar el valor del campo en los formularios. Por ejemplo, una contraseña.
on_change:
El valor por defecto para el on_change atributo en la vista. Esto abrirá una función en el servidor cuando los cambios en el campo en el cliente. Por ejemplo, on_change = "onchange_shop_id (shop_id)" .
related:
Se utiliza cuando un campo es una referencia a otra tabla mediante su id. Este es el nombre de la tabla para buscar el valor del campo.  Por lo general se utiliza con los tipos de campos relacionados y función.
selection:
El valor por defecto para la selección de atributos en la vista. 1 significa búsqueda básica y 2 medios de búsqueda avanzada.

Tipo de Campos 

Tipos básicos 

booleano:
Un booleano (true, false).
Sintaxis:
fields.boolean ('Nombre de campo' [, Parámetros opcionales]),
integer:
Un entero.
Sintaxis:
fields.integer ('Nombre de campo' [, Parámetros opcionales]),
float:
Un número de punto flotante.
Sintaxis:
fields.float ('Nombre de campo' [, Parámetros opcionales]),

Nota

Los dígitos parámetro opcional define la precisión y la escala del número. La escala es el número de dígitos después del punto decimal, mientras que la precisión es el número total de dígitos significativos en el número (antes y después del punto decimal). Si los dígitos parámetro no está presente, el número será un número de punto flotante de doble precisión. Advertencia: estos números en coma flotante son inexactas (no cualquier valor puede ser convertido a su representación binaria) y esto puede dar lugar a errores de redondeo. Siempre se debe utilizar el parámetro dígitos para cantidades monetarias.
Ejemplo:
«Nombre Campo »: fields.float (
    "Tasa cambio relativo",
    digits = (12,6) [,
    Parámetros opcionales]),

char:
Una cadena de longitud limitada. El parámetro tamaño requerido determina su tamaño.
Sintaxis:
fields.char (
        'Nombre de campo',
        size = n [,
        Parámetros opcionales]), donde #'' n'' es un número entero.
Ejemplo:
"Ciudad": fields.char ('Nombre de la ciudad', size = 30, required = True),
text:
Un campo de texto sin límite de longitud.
Sintaxis:
fields.text ('Nombre de campo' [, Parámetros opcionales]),
date:
A la fecha.
Sintaxis:
fields.date ('Nombre de campo' [, Parámetros opcionales]),
datetime:
Permite almacenar la fecha y la hora del día en el mismo campo.
Sintaxis:
fields.datetime ('Nombre de campo' [, Parámetros opcionales]),
binary:
Una cadena binaria
selection:
Un campo que permite al usuario hacer una selección entre varios valores predefinidos.
Sintaxis:
fields.selection ((('n', 'Sin confirmar'), ('c', 'Confirmado')),
                   'Nombre de campo' [, Parámetros opcionales]),
Nota
Formato del parámetro de selección: tupla de tuplas de cadenas de la forma:
(( 'key_or_value' ,  'string_to_display' ),  ...  )
Nota
Usted puede especificar la función que devolverá la tupla. Ejemplo
def  _get_selection ( auto ,  cr ,  uid ,  context = None ): 
    return  ( 
       ( 'choice1' ,  'Esta es la opción 1' ), 
       ( 'choice2' ,  'Esta es la opción 2' ))

_columns  =  { 
   'sel'  :  fields. selection ( 
       _get_selection , 
       '¿Qué quieres? " ) 
}
Ejemplo
El uso de campos de relación many2one con la selección . En los campos de definiciones agregan:
...,
'Mi_elemento': fields.many2one (
        'modelo.relacion',
        'Título',
        selección = _sel_func),
...,
Y luego definir el _sel_func así (pero antes de las definiciones campos):
def _sel_func(self, cr, uid, context=None):
    obj = self.pool.get('modulo.relacion')
    ids = obj.search(cr, uid, [])
    res = obj.read(cr, uid, ids, ['name', 'id'], context)
    res = [(r['id'], r['name']) for r in res]
    return res

Tipos relacionales 

one2one:
Un campo one2one expresa un uno: a: una relación entre dos objetos. Se ha quedado en desuso. Utilice many2one lugar.
Sintaxis:
fields.one2one ( 'other.object.name' ,  'Nombre de campo' )
many2one:
Associates este objeto a un objeto primario a través de este campo. Por ejemplo, un empleado del Departamento pertenece haría muchos a uno. es decir, muchos empleados pertenecen a un departamento
Sintaxis:
fields.many2one (
        'other.object.name',
        'Nombre de campo',
        parámetros opcionales)
Parámetros opcionales:
  • onDelete: ¿Qué debe suceder cuando el recurso de este campo se apunta a eliminar.
    • Valor predefinido: "cascade", "set default"

    • required: true
  • readonly: True
  • select: True - (crea un índice en el campo de clave externa)
Ejemplo
"Comercial": fields.many2one (
        'res.users',
        "Comercial",
        onDelete = "cascade"),
one2many:
TODO
Sintaxis:
fields.one2many (
        'Other.object.name',
        'Campo Identificación relación - campo_id ",
        'Nombre del campo',
        parámetro opcional)
Parámetros opcionales:
  • invisible: True / False
  • readonly: True / False
Ejemplo
'Dirección': fields.one2many (
        'res.partner.address',
        'partner_id',
        "Contactos"),
many2many:
TODO
Sintaxis:
campos . many2many ( 'other.object.name' , 
                 'tabla_relacion_modelox_modeloy' , 
                 'actual.object.id' , 
                 'other.object.id' , 
                 'Nombre de campo' )
Dónde:
  • other.object.name es el otro objeto que pertenece a la relación
  • objeto de relación es la mesa que hace que el enlace
  • actual.object.id y other.object.id son los nombres de los campos »utilizados en la tabla de relación
Ejemplo:
'Category_ids':
   fields.many2many (
    'res.partner.category',
    'res_partner_category_rel',
    'partner_id',
    'category_id',
    'Categorías'),
Para que sea bidireccional (= crear un campo en el otro objeto):
 
      
      
         
            
            objeto ' , 
            'actual.object.id' , 
            'other.object.id' , 
            'Other Nombre del campo' ), 
    } 
other_object_name2 ()
Ejemplo:
class res_partner_category2(osv.osv):
    _inherit = 'res.partner.category'
    _columns = {
        'partner_ids': fields.many2many(
            'res.partner',
            'res_partner_category_rel',
            'category_id',
            'partner_id',
            'Partners'),
    }
res_partner_category2()
related:
A veces es necesario hacer referencia a la relación de una relación. Por ejemplo, supongamos que usted tiene objetos: Ciudad -> Estado -> País, y tiene que referirse al país de una ciudad, se puede definir un campo de la siguiente manera en el objeto City:
'Country_id': fields.related (
    'state_id',
    'country_id',
    type = "many2one",
    relation = "res.country",
    string = "País",
    store = False)
Dónde:
  • El primer conjunto de parámetros son de la cadena de campos de referencia a seguir, con el campo deseado en el extremo.
  • type es el tipo de campo que se desea.
  • Use relation si el campo deseado sigue siendo una especie de referencia. relación es la tabla para buscar esa referencia pulg

Los campos funcionales 

Un campo funcional es un campo cuyo valor se calcula por una función (en lugar de ser almacenado en la base de datos).
Parámetros:
fnct, arg = None, fnct_inv = None, fnct_inv_arg = None, type = "float",fnct_search = None, obj = None, method = False, store = False, multi = False
donde
  • fnct es la función o el método que va a calcular el valor del campo. Debe de haber sido declarada antes de declarar el ámbito funcional.
  • fnct_inv es la función o método que le permitirá escribir valores en ese campo.
  • tipo es el nombre del tipo de campo devuelto por la función. Puede ser cualquier nombre de tipo de campo, excepto la función.
  • fnct_search le permite definir el comportamiento de búsqueda en ese campo.
  • method si el campo se calcula mediante un método (de un objeto) o una función global
  • almacenar Si desea almacenar campo en la base de datos o no. El valor predeterminado es False.
  • multi es un nombre de grupo. Todos los campos con el mismo varios parámetros se calculan en una sola llamada de función.

fnct parámetro 

Si el method es cierto que la firma del método debe ser:
def fnct (self, cr, uid, ids, field_name, arg, context):
de lo contrario (si se trata de una función global), su firma debe ser:
def fnct (cr, table, ids, field_name, arg, context):
De cualquier manera, debe devolver un diccionario de valores de la forma {id'_1_ ': value'_1_', id'_2_ ': value'_2_', ...}.
Los valores del diccionario devuelto deben ser del tipo especificado por el argumento de tipo en la declaración del campo.
Si multi se ha establecido, field_name se sustituye por field_names : una lista de los nombres de los campos que deben ser calculados. Cada valor en el diccionario devuelto es también un diccionario de nombre del campo de valor. Por ejemplo, si los campos "Nombre" y "edad" están basados ​​en la vital_statistics función, el valor de retorno de vital_statistics podría tener este aspecto cuando ids es [1, 2, 5] :
{
    1: {'nombre': 'Bob', "edad": 23},
    2: {"nombre": "Sally," edad ", 19},
    5: {"nombre": "Ed", "edad": 62}
}

parámetro fnct_inv 

Si el método es cierto, la firma del método debe ser:
def fnct (self, cr, uid, ids, field_name, FIELD_VALUE, arg, context):
de lo contrario (si se trata de una función global), que debe ser:
def fnct (cr, table, ids, field_name, FIELD_VALUE, arg, context):

parámetro fnct_search 

Si el method es True, la firma del método debe ser:
def fnct (self, cr, uid, obj, name, args, contexto):
de lo contrario (si se trata de una función global), que debe ser:
def fnct (cr, uid, obj, name, args, contexto):
El valor de retorno es una lista que contiene las tuplas de 3 partes que se utilizan en función de la búsqueda:
return  [( 'id' , 'in' , [ 1 , 
3 , 5 ])]
obj es el mismo que 1 mismo , y el nombre recibe el nombre de campo. args es una lista de tuplas 3-parte que contiene criterios de búsqueda para este campo, a pesar de la función de búsqueda puede activarse por separado para cada tupla.

Ejemplo 

Supongamos que creamos un objeto de contrato, que es:
class hr_contract(osv.osv):
    _name = 'hr.contract'
    _description = 'Contract'
    _columns = {
        'name' : fields.char('Contract Name', size=30, required=True),
        'employee_id' : fields.many2one('hr.employee', 'Employee', required=True),
        'function' : fields.many2one('res.partner.function', 'Function'),
    }
hr_contract()
Si queremos añadir un campo que recupera la función de un empleado por mirar de su contrato actual, se utiliza un campo funcional. El hr_employee objeto se hereda de esta manera:
 
      
      
      
      
            
          
            
            
            
            
            Función ' ) 
    } 
hr_employee ()
Nota
tres puntos
  • tipe = 'many2one' se debe a que el campo de la función debe crear un campo many2one; función se declara como many2one en hr_contract también.
  • obj = "res.partner.function" se utiliza para indicar que el objeto que se utilizará para el campo many2one es res.partner.function.
  • Llamamos a nuestro método _get_cur_function_id porque su función es devolver un diccionario cuyas claves son identificadores de los empleados, y cuyos valores correspondientes son los identificadores de la función de esos empleados. El código de este método es:
def  _get_cur_function_id ( auto ,  cr ,  uid ,  ids ,  field_name ,  arg ,  context ): 
    for  i  in  ids : 
        # obtener el identificador de la función actual del empleado del identificador "i" 
        sql_req =  "" " 
        SELECT f.id AS id_function
        FROM hr_contract  c
          LEFT JOIN res_partner_function f ON (f.id = c.function) 
        WHERE 
          (c.employee_id = % d ) 
        "" "  %  ( i ),

        cr . execute ( sql_req ) 
        sql_res  =  cr . dictfetchone ()

        if  sql_res :  # El empleado tiene un contrato asociado 
            res [ i ]  =  sql_res [ 'id_función' ] 
        else : 
            # res [i] se debe establecer en False y no a ninguna causa de XML: RPC 
            # "no se puede calcular las referencias Ninguno, salvo allow_none es permitido " 
            res [ i ]  =  False 
    retorno  res
El identificador de la función se recupera mediante una consulta SQL. Tenga en cuenta que si la consulta no devuelve ningún resultado, el valor de sql_res ['id_función'] será Ninguno. Nos forzamos el valor False en este caso, ya que el valor XML: RPC (comunicación entre el servidor y el cliente) no permite transmitir este valor.

Parámetro Store 

Se calculará el campo y almacenar el resultado en la tabla. El campo se vuelve a calcular cuando ciertos campos se cambian en otros objetos. Se utiliza la siguiente sintaxis:
store  =  { 
    'object_name' :  ( 
            nombre_funcion , 
            [ 'field_name1' ,  'field_name2' ], 
            priority ) 
}
Se llamará a la función nombre_funcion cuando los cambios se escriben en los campos en la lista ['campo1', 'campo2'] en 'object_name' objeto.La función debe tener la siguiente firma:
def nombre_funcion (self, cr, uid, ids, context = None):
Cuando identificadores serán los identificadores de registros de la tabla del otro objeto que han cambiado los valores en los campos observados.La función debe devolver una lista de los identificadores de los registros de su propia tabla que debe tener el campo vuelve a calcular. Dicha lista se enviará como un parámetro para la función principal del campo.
He aquí un ejemplo del módulo de afiliación:
'membership_state' : 
    fields.function( 
        _membership_state , 
        method = True , 
        string = 'Composición actual'),
        
        
        
               
              
             
                      
                
                
        

Campos Property (Propiedad) 

Declarar una propiedad

Una propiedad es un campo especial: fields.property.
{
 "Lista de precios " ,method = True , view_load = True , 
 group_name = "propiedades Lista de Precios" ) 
    }
Entonces usted tiene que crear el valor por defecto en un archivo XML para esta propiedad.:
<record model="ir.property" id="property_product_pricelist">
    <field name="name">property_product_pricelist</field>
    <field name="fields_id" search="[('model','=','res.partner'),
      ('name','=','property_product_pricelist')]"/>
    <field name="value" eval="'product.pricelist,'+str(list0)"/>
</record>


Si el valor por defecto apunta a un recurso de otro módulo, puede usar la función de árbitro de esta manera:
<field name="value" eval="'product.pricelist,'+str(ref('module.data_id'))"/>

Property en Vistas Form.

Para agregar propiedades en las formas, sólo hay que poner la etiqueta <properties/> en su formulario. Esto agregará automáticamente todos los campos de propiedades que están relacionados con este objeto. El sistema agregará propiedades en función de sus derechos. (Algunas personas serán capaces de cambiar una propiedad específica, otros no).
Las propiedades se muestran en la sección, dependiendo del atributo nombre_grupo. (Se representa en el cliente como una etiqueta separador).

¿Cómo funciona esto?

La clase fields.property hereda de fields.function y reemplaza el método de lectura y escritura. El tipo de este campo es many2one, por lo que en la forma de una propiedad se representa como una función many2one.
Pero el valor de una propiedad se almacena en la clase ir.property / table como un registro completo. El valor almacenado es un campo de referencia de tipo (no many2one), ya que cada establecimiento puede apuntar a un objeto diferente. Si modifica los valores de las propiedades (en el menú de administración), se representan como un campo de referencia de tipo.
Cuando se lee una propiedad, el programa le da la propiedad asociado con la instancia de objeto que está leyendo. Si este objeto no tiene valor, el sistema le dará la propiedad predeterminada.
La definición de una propiedad se almacena en la clase ir.model.fields como cualquier otro campo. En la definición de la propiedad, puede agregar grupos que tienen permiso para cambiar a la propiedad.

Utilización de las propiedades o campos normales

Si desea añadir una nueva característica, tendrá que optar por aplicar como una propiedad o terreno normal. Utilice un campo normal cuando se hereda de un objeto y quiere extender este objeto. Utilice una propiedad cuando la nueva función no está relacionada con el objeto, sino a un concepto externo.
Aquí hay algunos consejos para ayudarle a elegir entre un campo normal o una propiedad:
Campos normales ampliar el objeto, la adición de más características o datos.
Una propiedad es un concepto que se adjunta a un objeto y tienen características especiales:
  • Valor diferente para la misma propiedad en función de la empresa
  • La gestión de derechos por campo
  • Es un vínculo entre los recursos (many2one)
Ejemplo 1: Cuentas por cobrar

La "Cuenta por cobrar" por defecto de pareja se implementa como una propiedad porque:
  • Este es un concepto relacionado con la tabla de cuenta y no a la pareja, por lo que es una propiedad de cuenta de que es visible en una forma pareja. Derechos tienen que ser manejados en este campo para los contables, estos no son los mismos derechos que se aplican a los objetos asociados. Así que usted tiene derechos específicos sólo para este campo de forma pareja: sólo los contadores pueden cambiar la cuenta por cobrar de un socio.
  • Este es un campo multi-empresa: la misma pareja puede tener diferentes valores de cuentas por cobrar en función de la empresa que pertenece el usuario. En un sistema multi-empresa, hay una carta cuenta por la empresa. La cuenta por cobrar de una pareja depende de la empresa que realizó el pedido de venta.
  • La cuenta por cobrar por defecto es el mismo para todos los socios y se configura desde el menú general de la propiedad (en la administración).

Nota

Una cosa interesante es que las propiedades evitan código "spaghetti". El módulo cuenta depende del módulo pareja (base). Pero se puede instalar el módulo pareja (base) sin el módulo de contabilidad. Si agrega un campo que apunta a una cuenta en el objeto de pareja, ambos objetos dependerán de los demás. Es mucho más difícil de mantener y código (por ejemplo, tratar de eliminar una tabla cuando ambas tablas están apuntando a los demás.)

Ejemplo 2: Tiempos de productos

El módulo de caducidad del producto implementa todas las demoras relacionadas con los productos: Fecha de retiro, usetime producto, ... Este módulo es muy útil para las industrias de alimentos.
En este módulo se hereda del objeto product.product y añade nuevos campos a la misma:

clase  product_product ( OSV . OSV ):

    _inherit  =  'product.product' 
    _name  =  'product.product' 
    _columns  =  {

        'Life_time' :  fields.integer ( 'Tiempo de vida del producto' ), 
        'use_time' :  fields.integer ( 'usetime producto' ), 
        'removal_time' :  fields.integer ( "tiempo de retirada del producto ' ), 
        'alert_time' :  fields.integer ( 'tiempo de alerta del producto' ), 
        }

product_product ()
Este módulo agrega campos simples al objeto product.product. No usamos las propiedades debido a que:
  • Extendemos un producto, el campo life_time es un concepto relacionado con un producto, no a otro objeto.
  • No necesitamos una gestión correcta por campo, los diferentes retardos son gestionados por las mismas personas que manejan todos los productos.

1 comentario:

  1. Germán, cuidadín al traducir de forma automática!!
    Como pongas "cataratas" en lugar de "cascade" al definir un campo, ya verás que tortazo.
    Parámetro "tienda", otra más. Es "store" y punto.
    Los campos de tipo propiedad no existen, son de tipo "property".
    En fin, hay que darle un repaso :-)
    Un saludo,
    Juan

    ResponderBorrar