Programacion Interactiva

Descubre una Nueva y Poderosa Herramienta.

FrameWork de Nueva Generacion

Acceso a tu Informacion desde cualquier Dispositivo con Navegador.

Enfoque en el Backend

Frontend de forma facil con Odoo y XML.

Creacion de Verticales

Creacion de nuevas Verticales Conquistando nuevos Mercados.

Tu marca aqui mismo

Llega a miles de personas.

Publicidad

viernes, 11 de diciembre de 2020

Dominios Dinámicos en Campos One2Many (Odoo 9, 10, 11, 12, 13, 14)

 Creación de un dominio dinámico para Odoo

    Una pregunta y necesidad que tuve hace poco tiempo fue agregar un dominio en una vista de árbol generada por un campo One2many, buscando información y ejemplos finalmente no encontré y lo trate de realizar por medio de JS, un total fracaso, el tiempo que tenia no ayudaba mucho y fue entonces que intente realizarlo por medio de un dominio dinámico y una emulación de botón que retornara mi objeto con el filtro dinámico.

Primero voy a ejemplificar mis 2 clases, realmente no eran como el siguiente ejemplo pero trato de que sea mas digerible para todos nosotros.


Mi Clase Linea:

class DescargaAlmacenProducto(models.Model):
    _name = 'descarga.almacen.producto'
    _description = 'Linea Descarga de Productos'
    _rec_name = 'product_id' 
    _order = 'id desc' 

    download_id = fields.Many2one('descarga.almacen', 'ID Ref')
	
	product_id = fields.Many2one('product.product', 'Nombre', required=True)

    familia_producto = fields.Char('Familia', size=128, related="product_id.familia_producto")

    product_qty = fields.Float('Cantidad', digits=(14,4))

    uom_id = fields.Many2one('product.uom', 'UdM')


Mi Clase Principal:

class DescargaAlmacen(models.Model):
    _name = 'descarga.almacen'
    _description = 'Asistente Descarga de Productos'
    _rec_name = 'sequence_name' 
    _order = 'id desc' 


    def _compute_selection_family(self):
        selection_options = [('no_one','Sin Filtro')]
        cr = self.env.cr
        context = self._context
        if 'family_complete_list_ctx' in context and context['family_complete_list_ctx']:
            family_complete_list_ctx = context['family_complete_list_ctx']
            if family_complete_list_ctx:
                for f2 in family_complete_list_ctx:
                    selection_options.append((f2,f2))

        return selection_options

    def _get_domain_func(self, ):
        context = self._context
        if 'dynamic_domain' in context and context['dynamic_domain']:
            if 'record_ids' in context and context['record_ids']:
                self_br = self.browse(context['record_ids'])[0]
                filter_familia_producto = self_br.filter_familia_producto
                if not filter_familia_producto or filter_familia_producto == 'no_one':
                    return []
                domain = [('familia_producto', '=', filter_familia_producto)]
                return domain
        return []

    filter_familia_producto = fields.Selection(selection=lambda self: self._compute_selection_family(), string="Familia", default="no_one")

    space_download_line_ids = fields.One2many('descarga.almacen.producto', 'download_id', 'Lineas de Descarga', ondelete="cascade", domain=_get_domain_func)

    sequence_name = fields.Char('Secuencia', size=128)

    #### Filtro Dinamico ######
    def refresh_filter(self):
        family_complete_list_ctx = []
        for rec in self:
            print ("## rec.space_download_line_id >>>>> ",rec.space_download_line_ids)              
            for line in rec.space_download_line_ids:
                line_familia = line.familia_producto
                if line_familia and line_familia not in family_complete_list_ctx:
                    family_complete_list_ctx.append(line_familia)
        return {
                'name': _('Descarga - Familia' % self.filter_familia_producto),
                'view_mode': 'form',
                'view_id': self.env.ref('mi_modulo.mi_vista').id,
                'res_model': 'descarga.almacen',
                'context': "{'readonly_by_pass': True, 'record_ids': %s, 'dynamic_domain': True, 'family_complete_list_ctx': %s}" % (self.ids, family_complete_list_ctx), # self.env.context
                'type': 'ir.actions.act_window',
                'res_id': self.id,
                'flags': {'initial_mode': 'edit'}
            }


El campo que utilizare para filtrar los datos es un tipo Selection:

  •  filter_familia_producto

Un dato importante es que este campo de tipo "seleccion" es calculado para solo tener los filtros de mis registros, no quisiera mostrar todos por que no traeria información.

Mi campo One2many que contiene las lineas principales de mi registro tiene por nombre:

  •  space_download-line_ids

Podemos observar que dentro de estas lineas se encuentra mi dominio dinámico:

domain=_get_domain_func

Estos datos los estoy retornando por medio del contexto en mi función refresh_filter

'context': "{'readonly_by_pass': True, 'record_ids': %s, 'dynamic_domain': True, 'family_complete_list_ctx': %s}" % (self.ids, family_complete_list_ctx), # self.env.context

Para no tener errores con mi funcion domain, dentro del contexto vuelvo a retornar las opciones calculadas en todos mis registros y los ids de estos.

Para finalizar, agregue en mi vista el campo y el boton que retornara mi objeto con los nuevos filtros:

<group >
    <group>
        <field name="filter_familia_producto" string="Filtro Familia"  />
    </group>
    <group class="oe_subtotal_footer oe_right" >
        <button string="Filtrar" icon="fa-search" name="refresh_filter" style="display: inline-block;
padding: 5px 15px;
font-size: 12px;
cursor: pointer;
text-align: center;
text-decoration: none;
outline: none;
color: #fff;
background-color: #b787aa;
border: none;
border-radius: 5px;
box-shadow: 0 5px #999;"/>
    </group>
</group>


Agregue unos estilos para dar mejor presentación y el resultado se muestra asi:



Espero sea de su ayuda.