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.


1 comentario:

  1. Hola, he tratao de utilizar un campo Many2one relacionado, tome este ejemplo que me encontré por ahí:

    deudor_id = fields.Many2one('res.partner', 'Deudor', readonly=True, required=True, states={'draft': [('readonly', False)]})

    # fiador_id = fields.Many2one('res.partner', related='deudor_id.fiador_id', string='Fiador', store=True)

    Pero cuando reinicio Odoo y actualizo el módulo me da este error:

    KeyError: 'fiador_id' - -

    El ejemplo es un Odoo 8 y estoy tratando de usarlo en Odoo 14.

    ¿Qué estaŕe haciendo mal? He buscado documentación por todo lado pero ninguna me aclara como usarlo en Odoo 14.

    Saludos cordiales...
    Francisco Javier Guillén Ramírez

    ResponderBorrar