Introducción
Si has pasado tiempo trabajando con Odoo, probablemente te hayas encontrado con campos que calculan su valor automáticamente. Un campo computado almacenado lleva esto un paso más allá: calcula el valor y lo guarda directamente en la base de datos.
Esta distinción importa más de lo que podría parecer a primera vista. Un campo que solo se calcula al vuelo no puede ser buscado, filtrado, agrupado o exportado de manera eficiente. Un campo computado almacenado puede. Se comporta como una columna de base de datos normal mientras sigue siendo impulsado por la lógica que defines.
Esta guía cubre todo lo que necesitas saber sobre los campos computados almacenados en Odoo: cómo funcionan dentro del modelo de datos de Odoo, cómo crearlos utilizando Odoo Studio o Python, casos de uso empresarial reales y los errores más comunes que debes evitar.
¿Qué es un campo computado almacenado en Odoo?
En el ORM de Odoo, cada campo en un modelo contiene un pedazo de datos. La mayoría de los campos almacenan lo que el usuario introduce manualmente. Un campo computado es diferente: su valor es generado por una función de Python en lugar de ser introducido por un usuario.
Un campo computado almacenado es simplemente un campo computado con store=True. Cuando sus dependencias cambian, Odoo ejecuta la función de cálculo y escribe el resultado en la columna de la base de datos. El valor está disponible como cualquier otro campo.
En Python, el patrón básico se ve así:
total_amount = fields.Float(
string='Total Amount',
compute='_compute_total_amount',
store=True,
)
@api.depends('quantity', 'unit_price')
def _compute_total_amount(self):
for record in self:
record.total_amount = record.quantity * record.unit_price
El parámetro store=True es lo que separa un campo computado almacenado de un campo computado regular. Sin él, el valor se recalcula cada vez que se lee el campo, pero nunca se persiste en la base de datos.
En la interfaz de Odoo, un campo computado almacenado se ve exactamente como cualquier otro campo. Los usuarios lo ven en formularios, vistas de lista e informes. Pueden filtrar por él, agrupar registros usando este campo e incluirlo en exportaciones. No hay un indicador visual que muestre que el valor es computado en lugar de ingresado.
Campos Computados Almacenados vs No Almacenados
Entender esta diferencia es esencial para cualquier trabajo de desarrollo en Odoo:
- Campo computado no almacenado: Calculado al vuelo cuando se lee. No se puede usar en filtros, búsqueda o agrupación. Más ligero en almacenamiento pero no disponible para consultas en la base de datos.
- Campo computado almacenado: Calculado cuando cambian las dependencias y guardado en la base de datos. Buscable, filtrable, exportable. Ocupa espacio en la base de datos como cualquier columna regular.
La elección entre los dos no se trata de cuál es mejor en general. Depende de para qué necesitas el campo. Si solo lo muestras en un solo formulario, el no almacenado está bien. Si necesitas filtrar, ordenar o agregar por él, usa el almacenado.
Cómo funciona el campo
Cuando defines un campo computado almacenado en Odoo, el ORM establece disparadores de recomputación automáticos basados en los campos listados en el decorador @api.depends().
Cada vez que alguno de esos campos dependientes cambia en un registro, Odoo marca ese registro como necesitando recomputación. Se ejecuta el método de cálculo y el resultado se escribe de nuevo en la columna de la base de datos para ese campo.
El Ciclo de Recomputación
Aquí está lo que sucede paso a paso:
- Un usuario o un proceso automatizado cambia un campo que está listado en
@api.depends(). - Odoo detecta el cambio e identifica todos los registros que dependen de este campo.
- Se llama al método de cálculo para esos registros.
- El valor calculado se escribe en la columna de la base de datos.
- El campo ahora está disponible para búsqueda, filtrado y exportación con el valor actualizado.
En la mayoría de los casos, esta recomputación ocurre inmediatamente dentro de la misma transacción. Para operaciones por lotes grandes, Odoo puede diferir algunas recomputaciones y procesarlas en segundo plano.
Dependencias a Través de Modelos Relacionados
El decorador @api.depends() admite rutas con puntos para acceder a campos en modelos relacionados. Por ejemplo:
@api.depends('partner_id.country_id.name')
def _compute_country_name(self):
for record in self:
record.country_name = record.partner_id.country_id.name or ''
En este caso, Odoo rastrea cambios en partner_id, country_id y name a través de modelos. Si el nombre del país cambia en un socio, todos los registros relacionados se recomputan automáticamente. Este es uno de los aspectos más poderosos del marco de Odoo.
Impacto en la Base de Datos
Debido a que el campo se almacena, Odoo crea una columna real en la tabla de la base de datos PostgreSQL. Esto significa que el campo participa directamente en las consultas SQL. Las búsquedas y filtros en campos computados almacenados son rápidos y eficientes, al igual que las búsquedas en campos regulares.
Casos de uso empresarial
Los campos computados almacenados aparecen en todas las áreas de Odoo. Aquí hay cinco ejemplos prácticos de flujos de trabajo empresariales reales.
1. Ventas: Porcentaje de Margen en Líneas de Pedido
Un equipo de ventas quiere ver el porcentaje de margen en cada línea de pedido sin abrir una calculadora. Un campo computado almacenado toma el precio unitario y el precio de costo, calcula el margen y lo almacena en la línea. El gerente de ventas puede filtrar pedidos por porcentaje de margen, encontrar líneas no rentables al instante y agrupar por bandas de margen en vistas de pivote.
2. CRM: Días Sin Actividad en un Lead
Un campo computado almacenado en el modelo de lead de CRM puede rastrear cuántos días han pasado desde la última actividad programada. Combina esto con una acción programada que desencadena la recomputación cada mañana, y tu equipo de ventas puede filtrar leads por umbral de inactividad. No se requiere seguimiento manual.
3. Inventario: Cantidad Neta Disponible
Para productos con reglas de stock complejas, un campo computado almacenado puede contener un valor pre-calculado como la cantidad en mano menos la cantidad reservada. Dado que el valor está almacenado, los gerentes de producto pueden ordenar y filtrar la lista de productos por disponibilidad sin que Odoo realice cálculos complejos de stock en vivo para cada fila en pantalla.
4. Contabilidad: Conteo de Facturas Vencidas por Cliente
En el modelo de cliente, un campo computado almacenado puede contar cuántas facturas están actualmente vencidas. Cuando el equipo de contabilidad abre la lista de contactos, puede ordenar a los clientes por conteo de facturas vencidas con un solo clic. Esto solo es posible porque el conteo está almacenado en la base de datos en lugar de ser calculado sobre la marcha para cada fila.
5. Fabricación: Duración Total Estimada del Trabajo
En una lista de materiales, un campo computado almacenado puede sumar la duración estimada a través de todas las operaciones del centro de trabajo adjuntas al BOM. Los planificadores de producción pueden filtrar y ordenar los BOM por tiempo total de trabajo, lo cual es útil para la planificación de capacidad y programación. Cada vez que se añade o modifica una operación, el total se actualiza automáticamente.
Creando o personalizando el campo
Hay dos maneras principales de crear campos computados almacenados en Odoo: usando Odoo Studio para casos simples, o escribiendo código Python en un módulo personalizado para tener control total.
Usando Odoo Studio
Odoo Studio te permite añadir campos computados sin escribir ningún código. Cuando creas un nuevo campo de tipo Entero, Flotante o Monetario en Studio, puedes habilitar una opción de fórmula que acepta una expresión similar a Python. Studio maneja el seguimiento de dependencias en segundo plano.
Los campos computados de Studio son una buena opción cuando la lógica es una expresión aritmética simple entre campos en el mismo registro. Son fáciles de configurar y no requieren un entorno de desarrollo. Sin embargo, tienen límites reales. Si tu lógica implica campos de modelos relacionados, ramas condicionales o agregación a través de registros secundarios, Studio no será suficiente. Necesitarás un módulo personalizado.
Esta es una distinción importante al planificar tu personalización de Odoo: Studio es rápido para casos sencillos, pero Python te da total flexibilidad cuando la lógica se vuelve compleja.
Usando un Módulo Personalizado de Python
Para cualquier cosa más allá de fórmulas básicas, defines el campo en Python dentro de un módulo Odoo personalizado. Aquí hay un ejemplo concreto que añade un campo de porcentaje de margen a las líneas de pedido de venta:
from odoo import models, fields, api
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
x_margin_pct = fields.Float(
string='Margen %',
compute='_compute_margin_pct',
store=True,
digits=(5, 2),
)
@api.depends('price_unit', 'purchase_price')
def _compute_margin_pct(self):
for line in self:
if line.price_unit:
line.x_margin_pct = (
(line.price_unit - line.purchase_price) / line.price_unit
) * 100
else:
line.x_margin_pct = 0.0
Cuando este módulo está instalado, Odoo crea la columna x_margin_pct en la base de datos, ejecuta el método de cálculo para todos los registros existentes y comienza a rastrear cambios en price_unit y purchase_price a partir de ese momento.
El prefijo de campo x_ es la convención para campos personalizados en Odoo para evitar conflictos con los campos centrales. Esta es una práctica estándar en desarrollo de Odoo.
Haciendo un Campo Computado Almacenado Editable
Por defecto, los campos calculados son de solo lectura. Si deseas que los usuarios puedan anular manualmente el valor calculado, puedes definir un método inverse junto a tu método de cálculo. El método inverso se ejecuta cuando un usuario escribe directamente en el campo y puede actualizar los campos fuente en consecuencia. Este patrón es útil para campos donde el valor calculado es un buen valor predeterminado, pero a veces necesita una anulación manual.
Campos de Odoo Studio y la API XML-RPC
Para equipos que gestionan campos de base de datos de Odoo a través de la API XML-RPC, puedes crear campos estándar a través del modelo ir.model.fields. Sin embargo, para campos calculados almacenados con lógica personalizada en Python, el método de cálculo en sí debe residir en el código del lado del servidor. El enfoque de la API funciona bien para aprovisionar campos simples como parte de implementaciones automatizadas, pero la lógica detrás de un campo calculado siempre requiere un módulo personalizado instalado en el servidor.
Mejores prácticas
Aquí están las prácticas que siguen los consultores experimentados de Odoo al trabajar con campos calculados almacenados.
Declara todas las dependencias con precisión
El decorador @api.depends() debe listar cada campo que tu método de cálculo lee. Si olvidas uno, el campo no se actualizará cuando esa dependencia cambie. Revisa tu método de cálculo línea por línea y asegúrate de que cada acceso a un campo esté listado en el decorador.
Mantén los métodos de cálculo rápidos
Tu método de cálculo se ejecuta en cada registro que se ve afectado por un cambio de dependencia. En una instancia de Odoo ocupada, esto puede significar miles de registros a la vez. Evita las consultas a la base de datos dentro de los métodos de cálculo siempre que sea posible. Si necesitas acceder a datos relacionados, utiliza los campos que ya están cargados en lugar de ejecutar búsquedas adicionales.
Usa store=True solo cuando lo necesites
Los campos almacenados consumen espacio en la base de datos y desencadenan operaciones de escritura en cada recomputación. Si solo necesitas mostrar el campo en una vista de formulario y nunca filtrar o agrupar por él, un campo calculado no almacenado es la opción más ligera. Toma esta decisión deliberadamente en lugar de optar por almacenado para todo.
Maneja los casos límite en el método de cálculo
Siempre ten en cuenta los valores vacíos o faltantes dentro de tu método de cálculo. La división por cero, los registros relacionados faltantes y los valores nulos son causas comunes de errores silenciosos en campos calculados. Agrega verificaciones explícitas y establece valores predeterminados seguros cuando el cálculo normal no pueda continuar.
Plan para la Recomputación Inicial en Tablas Grandes
Cuando instalas un módulo que añade un nuevo campo computado almacenado, Odoo lo recomputa para cada registro existente en la tabla. En una tabla con cientos de miles de filas, esto puede llevar una cantidad significativa de tiempo. Prueba tu migración primero en un entorno de pruebas y planifica un posible tiempo de inactividad o procesamiento en segundo plano al desplegar en producción.
Evita Dependencias Circulares
Si el campo A depende del campo B y el campo B depende del campo A, Odoo generará un error cuando se cargue el módulo. Diseña las dependencias de tus campos computados para que fluyan en una sola dirección.
Errores comunes
Olvidar store=True
Este es el error más común. El campo se muestra correctamente en la vista de formulario, así que todo parece estar bien durante las pruebas. Luego, alguien intenta añadirlo como un filtro o incluirlo en un informe, y no funciona. Antes de escribir cualquier lógica de cálculo, decide de antemano si necesitas que el campo sea buscable. Si es así, añade store=True desde el principio.
Falta de una Dependencia en @api.depends
Si tu método de cálculo lee partner_id.country_id pero tu decorador solo lista partner_id, el campo no se actualizará cuando el país cambie en el registro del socio. Rastrear el camino completo de cada acceso al campo en tu método y listar cada paso explícitamente en el decorador.
Errores Silenciosos en el Método de Cálculo
Si tu método de cálculo genera una excepción para un registro, Odoo omite silenciosamente la recomputación para ese registro y mantiene el valor almacenado anterior. El error puede aparecer en los registros del servidor, pero nada se muestra al usuario. Esto puede llevar a valores obsoletos o incorrectos que son difíciles de rastrear. Siempre prueba tu método de cálculo contra registros que tengan datos faltantes o inusuales.
Degradación del Rendimiento en Grandes Conjuntos de Datos
Un método de cálculo que funciona bien durante el desarrollo puede convertirse en un serio cuello de botella en producción si la tabla crece a decenas de miles de registros. Presta atención a cuántas consultas a la base de datos dispara tu método de cálculo por registro. Una sola consulta adicional por registro multiplicada por diez mil registros son diez mil consultas para una sola operación de guardado.
Uso de sudo() dentro de métodos de cálculo
Llamar a sudo() dentro de un método de cálculo para eludir los derechos de acceso es un riesgo de seguridad. Si el valor calculado expone datos que el usuario actual no debería ver, devolverlo a través de un método de cálculo derrota el modelo de permisos de Odoo. Utiliza sudo() dentro de los métodos de cálculo solo cuando hayas pensado deliberadamente en las implicaciones de seguridad.
Esperando recomputación inmediata en todos los contextos
En la mayoría de las operaciones interactivas, la recomputación es sincrónica. Pero durante importaciones por lotes, trabajos en segundo plano o ciertas operaciones de ORM con banderas de contexto, Odoo puede diferir la recomputación. No construyas lógica de negocio que asuma que el valor almacenado siempre está actualizado en el momento exacto en que se escribe un registro. Verifica el comportamiento en el contexto específico donde se utilizará tu campo.
Conclusión
Los campos computados almacenados son una de las herramientas más útiles disponibles al construir o extender Odoo. Te permiten automatizar cálculos, mantener tus datos consistentes y hacer que los registros sean buscables y exportables sin ningún trabajo manual por parte de tus usuarios.
Los puntos clave a recordar:
- Usa
store=Truecuando necesites que el campo sea buscable, filtrable o exportable. - Siempre declara todas las dependencias en
@api.depends(), incluyendo rutas entre modelos. - Mantén los métodos de cálculo rápidos y maneja los casos extremos explícitamente.
- Para fórmulas simples, Odoo Studio es una opción rápida. Para cualquier cosa más compleja, escribe en Python.
- Planifica la recomputación inicial al desplegar en producción en tablas grandes.
Ya sea que estés construyendo un nuevo módulo personalizado, extendiendo un modelo existente de Odoo, o explorando tipos de campo de Odoo por primera vez, los campos computados almacenados valen la pena entenderlos a fondo. Se sitúan en la intersección del ORM de Odoo, la capa de base de datos y tu lógica de negocio.
¿Necesita ayuda con su implementación de Odoo?
Dasolo ayuda a las empresas a implementar, personalizar y optimizar Odoo en una amplia gama de necesidades empresariales. Ya sea que necesite agregar campos calculados a su modelo de datos, construir informes impulsados por valores calculados, o llevar su desarrollo de Odoo más allá, nuestro equipo tiene la experiencia para ayudar.
Póngase en contacto con nosotros si necesita apoyo con su proyecto de Odoo. Estamos encantados de hablar sobre su caso de uso y encontrar el enfoque adecuado para su negocio.