Publicidad

lunes, 6 de enero de 2014

Campos Funcionales con OpenERP

En OpenERP un campo funcional es un campo cuyo valor no sera definido por el usuario sino el resultado de una funcion (estos campos no se guardan en base de datos ). En ocasiones, para aumentar la velocidad de consulta de OpenERP y facilitar las búsquedas, los campos funcionales también pueden ser guardados en la base de datos aunque siempre son calculados/actualizados por una o varias funciones y no por el usuario
.
La estructura de un campo funcional es la Siguiente:
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,...)

Donde:

    • type es el tipo de campo devuelto por la función. Puede ser cualquiera excepto function. 
    • method indica si el campo se calcula mediante un método (de un objeto) o una función global. 
    • store y multi son mecanismos de optimización, para guardar los valores de los campos funcionales en la base de datos (store=True) aunque se seguirán calculando mediante una función Python o para calcular varios campos funcionales a la vez con el atributo multi. 
   •fnct es la función o método que calculará el valor del campo. Es un parámetro obligatorio. Debe haberse declarado antes de declarar el campo funcional.

Si method es verdadero (True), la signatura del método debe ser:

def fnct(self, cr, uid, ids, nombre_campo, arg, context)
en otro caso (si se trata de una función 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 parámetro type de la declaración del campo. 
   •fnct_inv es la función o método que permitirá escribir valores en ese campo. Si method es verdadero (True), la signatura del método debe ser:
def fnct(self, cr, uid, ids, nombre_campo, valor_campo, arg, context)
en otro caso (si se trata de una función global), su signatura debe ser:
def fnct(cr, table, ids, nombre_campo, valor_campo, arg, context)
   •fnct_search permite definir el comportamiento de las búsquedas en ese campo. Si method es verdadero (True), la signatura del método debe ser:
def fnct(self, cr, uid, obj, name, args)
en otro caso (si se trata de una función global), su signatura debe ser:
def fnct(cr, uid, obj, name, args)

 

Ejemplo de un campo funcional

Supongamos que creamos un objeto contract (contrato) cuya definición es:


from osv import osv, fields

class almacen_almacen (osv.osv):   

   def calculate_price(self, cr, uid, ids, field_name, arg, context=None):
      records = self.browse(cr, uid, ids)
      res = {}
      for r in records:
         res[r.id] = r.cost * r.quantity
         print "RESULTADO", res
      return res

   _name = 'almacen.almacen'
   _columns = {
   'code' : fields.char     ('Codigo', 10, required = True),
   'name' : fields.integer  ('Nombre del Producto', required = True),
   'description' : fields.char     ('Descripción',60),
   'tipe_selection' : fields.selection([ ('1','Linea Blanca y Electronica'), ('2','Articulos Consumo Diario'), ('3','Otro'), ],'Tipo de artículo', required = True),
   'cost': fields.float('Costo', digits=(3,2)),
   'quantity': fields.integer('Cantidad'),
   'calculate_price' : fields.function (calculate_price, type = 'float', string = 'Total a Pagar'),
   }
almacen_almacen()

 En el ejemplo anterior obtendremos el total a pagar de un cliente en una compra simple de un almacen X, como podemos observar el campo calculado define como primer argumento el nombre de la función con la cual obtendremos el resultado, y en la misma función seria la formula con la cual obtendremos el resultado del campo.

Nota:
En la función mando un print que no se mostrara en OpenERP sino solamente en la terminal donde este ejecutándose nuestro servidor.
No se olviden Comentar....

13 comentarios:

  1. muy interesante como le aria para la suma de dos campos y el resultado lo muestre en un tercer campo
    por ejemplo campo1+campo2=campo3restultado

    ResponderEliminar
  2. Francisco eso lo harias exactamente asi como lo dices con codigo python y entras a la base con object:
    def _campo3(self, cr, uid, ids, field_name, arg, context=None):
    result = {}
    for line in self.browse(cr, uid, ids, context=context):
    result[line.id] = ( line.campo1 + line.campo2 )
    return result

    Yo necesito es sumar solo los primeros 5 campos de un dashboard o campo one2many
    Asi lo he ido Haciendo tirame un cable agradecido:D
    suma_5_campos = sum([v.datos_a_extraer for v in class_master.one2many_ids])

    Creo que si le coloco range o le coloco ,5 al final deberia funcionar :D, a ver si luego verifico
    Mas adelante creo que necesitare los cmpos del mes pero esa es otra historia :_D

    ResponderEliminar
  3. realizarte una consulta por este medio ya que me urge solucionar este problemita que tengo con el report Qweb en openerp, ya que tienes bastante experiencia en esto. Lo que ya hice es un listado general de compras. sería más bien mostrar las cabeceras de ventas del día. para realizar la sumatoria necesitaré una funcion.
    ejemplo:

    Nº Compra Proveedor Fecha Monto Imponible Impuesto Total con Impuesto
    PO001 XXX 100.000 10.000 110.000
    PO002 YYY 200.000 20.000 220.000

    Lo que no me sale y no consigo hacer es lo siguiente la sumatoria de la columnas del monto imponible y el total del con impuesto. lo que quedaría de la sgte forma.

    Nº compra Cliente Fecha Monto Imponible Impuesto Total con Impuesto
    PO001 XXX 100.000 10.000 110.000
    PO002 YYY 200.000 20.000 220.000

    totales: 300.000 330.000

    si pudieras ayudarme a solucionar este problema. desde ya muchas gracias por su atención.

    ResponderEliminar
  4. mi caso es que tengo presupuesto lineadeproducto y product
    en linea de producto tengo la cantidad de producto y el producto seleccionado, y en el presupuesto tengo el total
    tengo que recorrer las linesas de producto y multiplicar la cantidad por el precio del producto, como podria hacerlo.

    Muchas gracias

    ResponderEliminar
  5. Buenas, buena explicación, una pregunta, se podría obtener de un campo relacional el objeto y de este mismo obtener un campo de la clase? por ejemplo, si tengo una clase "contabbilidad" que tiene un campo relacional "contrato", este contrato tiene un campo precio, quiero obtenerlo en contabilidad, se podría hacer??
    muchas gracias de antemano,

    ResponderEliminar
    Respuestas
    1. Que tal Grabriel,

      Los campos relacion te permiten obtener datos de n cantidad de relaciones en el ejemplo que me explicas el resultado seria algo como esto:

      'precio': fields.related('contrato','precio', type="float", string="Precio"),

      No es necesario utilizar una funcion.

      Sl2

      Eliminar
  6. Buen dia por favor que tengo en este codigo que aun no logro resultado en el formulario xml

    class pickup(models.Model):
    _name = 'pickup'
    _description = u'Clase pickup'
    _rec_name = 'by'

    def calculate_price(self, cr, uid, ids, field_name, arg, context=None):
    # records = self.browse(cr, uid, get_count, context): #DECLARANDOD DENTRO DEL RECORDS EL SELF.BROWSE
    # res = {} #DECLARANDO LA VARIABLE VACIA
    for r in self.browse(cr, uid,ids, context=None):
    # OTRA FORMA DE REALIZAR LA SUMA records.mapped(lambda res =r.by2+r.by3)
    resu[r.id]= (r.by2 + r.by3)
    return resu

    @api.one
    @api.depends('resu')
    def extras(self):
    self.by = self.resu

    solo necesito una simple suma y me me muestre el resultado en el fields.Float en este caso se llama by, el servidor odoo me muestra el formulario pero no me muestra mas nada

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Juan usa algo como:

      class pickup(models.Model):
      _name = 'pickup'
      _description = u'Clase pickup'
      _rec_name = 'by'

      by = fields.float('By', compute='_compute_by')
      @api.one
      def _compute_by(self):
      self.by = self.by2 + self.by3

      Estructura el codigo, ya que lo escribi aqui mismo.

      Nota: en tu modelo deben existir los campos by2 y by3 si no esto no funcionara.

      Saludos

      Eliminar
    3. Muy agradecido German muchas gracias por el aporte, practicándolo logre resolver mi problema ahora creé muchas funciones las cuales realizan sumas, multiplicaciones y divisiones las cuales se van ejecutando de acuerdo al selectio al cual le asigne la función en este caso mi modulo fue de un conversor de unidades, tengo otra duda para ver si pudieras orientarme:
      - Requiero colocar un usuario logueado en odoo que por defecto salga automáticamente el nombre de este en todas las ventanas pues es el que estará ejecutando acciones en ese sistema.
      - En una ventana requiero traerme montos float que fueron calculados en otra ventana para realizar una nueva operaciones con estos.
      En que funciones me podria yo enfocar para generar estos resultados con odoo v8 para investigar para guiarme logrando asi poder ejecutar lo que quiero hacer. mis agradecimientos de antemano.

      Eliminar
  7. Buenas tardes, si me pueden ayudar con la siguiente consulta:

    Tengo los siguientes campos:

    “rec” Fecha automática del sistema
    “toma” Campo tipo fecha (se ingresa)
    “edad” capo tipo entero (se ingresa)
    “falla” Este campo es una fecha que se calcula cumpliendo la siguiente condición:
    “falla” = si “falla” es < “rec” entonces “falla”= “rec” si no “falla”= “toma” + “edad”

    ResponderEliminar
  8. Buenas noches, espero me puedan ayudar con lo siguiente:
    Tengo un modelo y en un field quiero poner una lista de valores que no esta relacionado con el modelo actual, estaba intentando hacerlo mediante un campo calculado, pero nose que tipo de campo debería ponerlo, o nose de que forma lo puedo hacer. Este campo es para que luego se imprima en un tree dentro de un form en la vista.

    Muchas gracias por su ayuda

    ResponderEliminar