Saltar al contenido
Volver al blog
3 min de lectura

Por qué tu módulo se rompe en cada actualización de Odoo

La causa casi nunca es Odoo. Es la forma en que se escribió el módulo. Tres patrones que garantizan que tu desarrollo sobreviva el siguiente upgrade.

ArquitecturaOdooBuenas prácticas

Cada vez que sale una versión nueva de Odoo se repite la misma escena: alguien actualiza en staging, la mitad de los módulos a medida truena, y el proveedor que los escribió cotiza otra vez casi lo mismo que costó construirlos.

Después de siete años arreglando ese desastre —a veces el nuestro— podemos decirlo sin rodeos: el problema casi nunca es Odoo. Es que el módulo se escribió apostando a que el core nunca cambiaría.

1. Nunca modifiques el core

El pecado original. Alguien necesita cambiar el comportamiento de stock.picking, abre el archivo de Odoo, edita el método y se va a dormir tranquilo. Funciona perfecto — hasta que git pull de la siguiente versión sobrescribe el archivo y el cambio desaparece sin dejar rastro.

Odoo tiene un sistema de herencia precisamente para esto:

from odoo import models, api

class StockPicking(models.Model):
    _inherit = 'stock.picking'

    def action_confirm(self):
        # super() primero: el comportamiento estándar sigue vivo
        result = super().action_confirm()
        self._millora_validar_tarimas()
        return result

La diferencia práctica: cuando Odoo 19 cambie action_confirm, tu código sigue llamando a super() y hereda la mejora en lugar de pelearse con ella.

2. Trata los campos calculados como contratos, no como atajos

Un compute sin depends correcto es una bomba de tiempo. Funciona en tu prueba porque el registro se recalcula por casualidad, y falla en producción cuando el ORM decide que no hace falta recalcular.

cantidad_disponible = fields.Float(
    compute='_compute_cantidad_disponible',
    store=True,   # si lo vas a filtrar o agrupar, tiene que estar almacenado
)

@api.depends('move_ids.state', 'move_ids.product_uom_qty')
def _compute_cantidad_disponible(self):
    for picking in self:
        picking.cantidad_disponible = sum(
            move.product_uom_qty
            for move in picking.move_ids
            if move.state != 'cancel'
        )

Regla que aplicamos sin excepción: si el campo se usa en un filtro, un group by o un reporte, va almacenado y con depends explícito. Si no, no pasa la revisión de código.

3. Las vistas se extienden con xpath, no se reemplazan

Reemplazar una vista completa es la versión gráfica de modificar el core. Funciona, y te deja fuera de todas las mejoras de UI que venga después.

<record id="view_picking_form_millora" model="ir.ui.view">
    <field name="inherit_id" ref="stock.view_picking_form"/>
    <field name="arch" type="xml">
        <xpath expr="//field[@name='partner_id']" position="after">
            <field name="tarima_id"/>
        </xpath>
    </field>
</record>

Si el xpath deja de encontrar su ancla en una versión nueva, Odoo falla al instalar con un mensaje claro. Eso es una ventaja: te enteras en staging, en dos minutos, en lugar de descubrirlo tres semanas después porque un usuario reportó que "ya no aparece el campo".

Lo que esto significa a la hora de contratar

Cuando evalúes a un proveedor de desarrollo Odoo, pregunta tres cosas:

  1. ¿Modificas archivos del core en algún caso? (La respuesta correcta es no.)
  2. ¿Cómo pruebas el módulo antes de entregarlo? (Debe existir un staging con los datos del cliente.)
  3. ¿Qué pasa cuando salga la siguiente versión de Odoo? (Debe haber una respuesta concreta, no "lo vemos cuando llegue".)

Si las tres respuestas son vagas, el precio que te están cotizando no es el precio real: es el primer pago de varios.


En nuestro catálogo cada desarrollo se prueba contra las versiones que decimos soportar, de Odoo 16 a 19. Y si necesitas algo que no está ahí, puedes contratar horas sin pasar por tres juntas de descubrimiento.