Owl Odoo
Integración de Odoo con Owl
Arquitectura Avanzada y Estrategias de Desarrollo Experto en el Framework OWL para Odoo
1. Fundamentos Arquitectónicos y Evolución del Frontend en Odoo
La transformación tecnológica de la interfaz de usuario de Odoo ha culminado en la adopción integral del Odoo Web Library (OWL), un framework que no solo moderniza la experiencia de desarrollo, sino que redefiniendo la arquitectura subyacente del ERP. Para aspirar a un nivel de maestría técnica en Odoo 17 y 18, es imperativo trascender la comprensión superficial de la sintaxis y adentrarse en los principios de diseño que motivaron su creación. OWL se presenta como un framework de interfaz de usuario “pequeño” (menos de 20kb comprimido) pero extremadamente robusto, diseñado específicamente por Odoo S.A. para satisfacer las necesidades únicas de modularidad y extensibilidad que un ERP demanda.1
A diferencia de las versiones anteriores que dependían de una amalgama de Widgets basados en Backbone.js y jQuery, OWL introduce un paradigma declarativo basado en componentes. Este cambio no es meramente estético; representa una evolución hacia un sistema reactivo de grano fino, inspirado en las mejores prácticas de React y Vue, pero ejecutado con una visión centrada en la integración con el ecosistema de Odoo.1 La arquitectura de OWL se basa en clases ES6 y plantillas XML (QWeb), utilizando un DOM virtual subyacente para optimizar el renderizado, integrándose de manera nativa con hooks y soportando renderizado asíncrono.1
1.1. Filosofía de Diseño y Comparativa Tecnológica
El análisis de la documentación técnica revela que la decisión de construir un framework propio en lugar de adoptar React o Vue se basa en la necesidad crítica de integración con el sistema de plantillas QWeb y el mecanismo de herencia de vistas de Odoo. Las plantillas en OWL no son simples archivos JSX compilados; son definiciones XML que pueden ser almacenadas en base de datos, heredadas y modificadas dinámicamente mediante XPaths antes de ser compiladas en el navegador.3 Esta capacidad es fundamental para la modularidad de Odoo, permitiendo que un módulo de terceros altere la interfaz de una aplicación core sin tocar el código fuente original.
| Característica | React / Vue | Odoo OWL | Implicación para el Experto |
|---|---|---|---|
| Definición de Vistas | JSX / Single File Components | XML (QWeb) | Permite herencia y modificación vía XPath desde otros módulos. |
| Toolchain | Webpack / Vite (Node.js) | Integrado en Assets de Odoo | No requiere compilación compleja externa; carga dinámica de assets.3 |
| Estado | useState / ref / Vuex | useState / reactive / Stores | Reactividad basada en Proxies optimizada para el ciclo de vida de Odoo. |
| Ciclo de Vida | Hooks (useEffect) | Hooks Específicos (onWillStart, etc.) | Control granular sobre la asincronía y la interacción con el DOM. |
1.2. El Ecosistema de Archivos y Estructura de Componentes
Para desarrollar componentes mantenibles y escalables, la práctica estándar dictamina una separación estricta de responsabilidades. Aunque técnicamente es posible definir plantillas “inline” usando el helper xml, un desarrollo experto requiere la definición de plantillas en archivos XML separados. Esto no solo facilita la lectura, sino que es un requisito técnico indispensable para que el sistema de traducciones de Odoo funcione, ya que las cadenas de texto dentro de archivos JS son más complejas de gestionar en el flujo de internacionalización.4
La estructura canónica de un componente experto en Odoo reside en tres archivos ubicados en el mismo directorio:
- Lógica (JavaScript): Define la clase del componente, su estado y comportamiento.
- Presentación (XML): Contiene la estructura del DOM y las directivas QWeb.
- Estilo (SCSS): Define las reglas visuales encapsuladas o específicas del componente.4
Esta tríada se integra en el sistema a través del archivo de manifiesto (__manifest__.py), donde se deben declarar en el bundle web.assets_backend para asegurar su carga correcta en el cliente web.5
2. Ingeniería de Componentes: Ciclo de Vida y Configuración
La unidad atómica de la interfaz en Odoo es el componente. Entender su ciclo de vida y cómo se instancia es la barrera que separa al desarrollador junior del arquitecto de soluciones. En OWL, los componentes son clases, pero su instanciación y configuración siguen patrones estrictos para garantizar la compatibilidad con el sistema de reactividad.
2.1. El Método setup() frente al Constructor
Un error crítico y común en desarrolladores que migran desde otros entornos es el uso del constructor para inicializar la lógica del componente. La documentación oficial y las mejores prácticas son enfáticas: no se debe utilizar el constructor. En su lugar, OWL proporciona el método setup(), el cual se invoca inmediatamente después de la creación de la instancia.4
El razonamiento técnico detrás de esta restricción es la capacidad de “parchear” (patching) componentes. En JavaScript, los constructores de clases no pueden ser sobrescritos o extendidos fácilmente mediante mixins o utilidades de parcheo sin romper la cadena de prototipos o invocar super de manera compleja. El método setup(), al ser una función estándar de la clase, permite una extensión limpia y es el lugar designado para inicializar hooks, estado y servicios.4
Implementación Correcta de setup():
/** @odoo-module **/
import { Component, useState, onWillStart } from "@odoo/owl";
export class ExpertComponent extends Component {
static template = "my_module.ExpertComponent"; // Referencia al ID del XML
setup() {
// Inicialización del estado reactivo
this.state = useState({ counter: 0, data: null });
// Uso de Hooks de ciclo de vida
onWillStart(async () => {
this.state.data = await this.fetchInitialData();
});
}
}
2.2. Hooks del Ciclo de Vida: Control Temporal Preciso
El control del flujo de ejecución en componentes asíncronos es vital. OWL expone una serie de hooks que permiten inyectar lógica en momentos precisos de la existencia del componente. El análisis de estos hooks revela su importancia para el rendimiento y la gestión de recursos.1
- onWillStart: Este hook es fundamental para la gestión de asincronía inicial. Se ejecuta antes de que el componente se renderice por primera vez. Si la función pasada a onWillStart retorna una promesa, el renderizado del componente se detiene hasta que dicha promesa se resuelva. Esto es crítico para asegurar que los datos necesarios (por ejemplo, configuraciones cargadas desde el servidor) estén disponibles antes de pintar la interfaz, evitando el parpadeo de interfaces vacías.5
- onMounted: Se dispara una vez que el componente ha sido renderizado e insertado en el DOM. Este es el único momento seguro para interactuar con elementos del DOM nativo, inicializar librerías de terceros (como Chart.js o editores de texto externos) o añadir listeners globales que requieran la presencia física de los elementos.5
- onWillUpdateProps: Permite reaccionar ante cambios en las propiedades recibidas desde el padre. Es esencial para componentes que deben recalcular su estado interno o realizar nuevas peticiones al servidor cuando sus inputs cambian.5
- onWillUnmount y onWillDestroy: Estos hooks son la defensa principal contra las fugas de memoria. Cualquier listener manual añadido al window o document, así como cualquier intervalo (setInterval), debe ser limpiado explícitamente en estos hooks. Ignorar esto en una aplicación SPA como Odoo (donde el usuario no recarga la página frecuentemente) puede llevar a una degradación severa del rendimiento del navegador.5
2.3. Gestión de Props y Validación
La robustez de un componente aumenta significativamente mediante la validación de sus propiedades (Props). OWL permite definir un esquema estático props en la clase del componente. Esto no solo sirve como documentación viva del contrato del componente, sino que activa validaciones en tiempo de ejecución durante el modo de desarrollo, alertando sobre tipos incorrectos o propiedades faltantes.7
static props = {
title: { type: String, optional: false },
count: { type: Number, optional: true, default: 0 },
slots: { type: Object, optional: true }, // Validación de slots
};
La validación estricta de props es una marca de código de calidad en el ecosistema Odoo, previniendo errores silenciosos que son difíciles de depurar en producción.
3. El Motor de Reactividad: Proxies y Estado
El corazón de la interactividad en OWL es su sistema de reactividad. A diferencia de frameworks antiguos que requerían llamadas manuales para actualizar la vista, OWL utiliza Proxies de JavaScript para interceptar lecturas y escrituras en el estado, programando actualizaciones de la interfaz de manera automática y eficiente.
3.1. useState vs. reactive: Matices Técnicos
Aunque ambos mecanismos generan objetos reactivos, su uso y alcance son distintos y su correcta aplicación es crucial para la arquitectura de la aplicación.
- useState: Este hook vincula el objeto reactivo directamente al componente que lo invoca. Cuando una propiedad del estado cambia, OWL sabe que este componente específico debe ser re-renderizado. Es la herramienta estándar para el estado local de la interfaz (ej. visibilidad de un modal, valor de un input).1
- Mecanismo: useState envuelve el objeto en un Proxy y registra el componente actual como un “observador”.
- reactive: Crea un objeto reactivo “desvinculado”. Por sí solo, modificar un objeto reactive no causará que ningún componente se actualice. Para que surta efecto en la UI, un componente debe leer este objeto dentro de su flujo de renderizado o a través de un useState. reactive es la base para construir Stores o servicios de estado global que son compartidos entre múltiples componentes.7
3.2. Problemas Comunes de Reactividad y Soluciones
Un desafío recurrente en el desarrollo avanzado es la pérdida de reactividad o la falta de re-renderizado en estructuras de datos anidadas o cuando se utilizan objetos reactivos fuera del contexto de un componente.
- Renderizado Profundo: En versiones modernas de OWL (Odoo 17+), el renderizado no es profundo por defecto. Si una prop cambia en una propiedad anidada, el componente hijo podría no enterarse a menos que esa prop sea en sí misma reactiva y el hijo la esté observando. OWL gestiona esto re-observando objetos reactivos pasados como props, pero el desarrollador debe evitar desestructurar props reactivas en variables primitivas locales, ya que esto rompe el enlace con el Proxy.11
- markRaw y toRaw: Existen situaciones donde no deseamos que un objeto sea reactivo, por ejemplo, al almacenar una instancia compleja de una librería externa o un objeto grande y estático. markRaw previene que OWL convierta el objeto en un Proxy, optimizando el rendimiento. Inversamente, toRaw permite extraer el objeto original de un Proxy, útil para operaciones de depuración o comparaciones estrictas.5
4. QWeb Avanzado: Directivas y Templating Dinámico
El motor de plantillas QWeb es el puente entre la lógica JavaScript y la representación DOM. OWL enriquece QWeb con directivas específicas que permiten una manipulación del DOM virtual altamente eficiente.
4.1. Directivas Estructurales y Claves (t-key)
Las directivas de control de flujo como t-if y t-foreach son fundamentales. Sin embargo, el uso de t-foreach en OWL introduce un requisito estricto: la directiva t-key.
La directiva t-key no es opcional para el desarrollo profesional. Permite al algoritmo de reconciliación de OWL identificar de manera única cada nodo en una lista. Si no se provee, o si se usa un índice simple en una lista que cambia de orden, OWL destruirá y recreará los componentes en lugar de moverlos, perdiendo el estado interno (como el foco de un input o texto no guardado). La práctica experta exige usar identificadores únicos y estables, como los IDs de base de datos (t-key=“record.id”).13
4.2. Binding Bidireccional con t-model
Para simplificar la gestión de formularios, OWL ofrece t-model. Esta directiva crea una vinculación bidireccional (two-way binding) entre un input del formulario y una variable del estado.
- Sintaxis:
<input t-model="state.value" /> - Funcionamiento: Equivale a establecer
valuecon el estado y escuchar el eventoinputpara actualizar el estado. - Modificadores: Se pueden usar modificadores como
.lazypara actualizar el estado en el eventochangeen lugar deinput, optimizando el rendimiento en campos de texto largos.13
4.3. El Poder de los Slots
Los Slots son la herramienta definitiva para la reutilización de componentes, permitiendo diseñar componentes “contenedor” que no conocen de antemano su contenido.
- Slots Nombrados: Permiten inyectar contenido en áreas específicas de un componente padre. Se definen en el hijo con
<t t-slot="header"/>y se pueblan desde el padre con<t t-set-slot="header">... content...</t>. Esto es esencial para componentes de layout como Card o Layout.14 - Scopes de Slots (t-slot-scope): Esta es una técnica avanzada donde el componente hijo pasa datos de vuelta al template que se inyecta en el slot. Es crucial para componentes iteradores, como una tabla de datos genérica que renderiza filas, pero permite al usuario de la tabla definir cómo se ve cada celda.
- Ejemplo Conceptual: El componente
Tableitera sobrerowsy exponerowvíat-slot-scope. El padre usa<Table><t t-set-slot="row" t-slot-scope="scope"><span t-esc="scope.row.name"/></t></Table>. Esto invierte el control del renderizado, otorgando máxima flexibilidad.14
- Ejemplo Conceptual: El componente
- Slots Dinámicos: OWL permite determinar qué slot renderizar en tiempo de ejecución mediante interpolación:
<t t-slot="{{currentSlotName}}" />. Esto se utiliza en sistemas de pestañas dinámicas o wizards condicionales.16
4.4. Referencias al DOM (t-ref)
A pesar de la naturaleza declarativa de OWL, a veces es inevitable acceder al DOM real (por ejemplo, para enfocar un input o medir un elemento). La directiva t-ref junto con el hook useRef proporciona este acceso.
- Ciclo de Vida de la Referencia: Es vital entender que this.miRef.el será null hasta que el componente esté montado (onMounted). Intentar acceder a la referencia en setup() o onWillStart resultará en errores.
- Referencias a Componentes: t-ref también puede referenciar instancias de componentes hijos, permitiendo llamar métodos públicos del hijo desde el padre, aunque este patrón debe usarse con precaución para no acoplar excesivamente los componentes.17
5. El Sistema de Registros y Servicios: La Columna Vertebral de Odoo
Odoo opera sobre una arquitectura modular donde las funcionalidades están desacopladas. El mecanismo que permite esta interacción fluida es el sistema de Registros (Registry) y Servicios. Un experto en Odoo no hardcodea dependencias; las solicita al entorno.
5.1. Registros: Extensibilidad Modular
El objeto registry importado de @web/core/registry actúa como un diccionario global categorizado donde los módulos registran sus componentes y utilidades.
| Categoría de Registro | Uso Experto | Referencia |
|---|---|---|
| fields | Registro de widgets para campos de formulario (ej. Char, Many2One). Clave para crear visualizaciones de datos personalizadas. | 19 |
| views | Registro de tipos de vistas completos (ej. una nueva vista map o grid). Permite definir la arquitectura MVC completa (Controller, Renderer, Model). | 21 |
| actions | Registro de “Client Actions”. Permite crear aplicaciones completas dentro de Odoo que toman control total del área de trabajo (ej. Dashboards, Kioscos). | 6 |
| systray | Elementos de la barra de menú superior (notificaciones, menú de usuario). Ideal para widgets globales siempre visibles. | 23 |
| services | Lógica de negocio transversal compartida (RPC, Notificaciones, Bus). | 24 |
| main_components | Componentes de alto nivel que persisten sobre la interfaz (ej. gestores de diálogos). | 25 |
5.2. Servicios Esenciales del Núcleo (useService)
Los servicios son singletons accesibles en cualquier componente a través del hook useService. El dominio de estos servicios es obligatorio para interactuar con el backend y la interfaz del usuario.24
Servicio orm y rpc
Aunque rpc permite realizar llamadas JSON-RPC crudas, el servicio orm es la abstracción preferida para interactuar con modelos de datos. Proporciona métodos como call, search, create, write, manejando automáticamente contextos y sesiones.
- Uso Experto: const orm = useService(“orm”); const data = await orm.searchRead(“res.partner”, domain, [“name”, “email”]);. Esto es más limpio y semántico que construir llamadas rpc manuales.24
Servicio action
Permite manipular el flujo de la aplicación ejecutando acciones de ventana, cerrando diálogos o refrescando la vista actual. Es el mecanismo para navegar entre vistas programáticamente: action.doAction(“account.action_invoice_tree”).6
Servicio bus: Comunicación Real-Time
Para aplicaciones que requieren actualizaciones en tiempo real (como chats o monitores de estado), el servicio bus conecta el frontend con el bus de eventos de Odoo (basado en Longpolling o WebSockets).
- Implementación: Se debe usar el hook useBus para suscribirse a eventos. Este hook gestiona automáticamente la limpieza del listener al desmontar el componente, previniendo fugas de memoria críticas en aplicaciones de larga ejecución.28
Servicio notification
Permite mostrar feedback al usuario mediante “toasts” o alertas no intrusivas. Es vital para mejorar la UX tras operaciones asíncronas.31
6. Personalización Avanzada: Patching y Widgets
Una de las capacidades más potentes de Odoo es modificar el comportamiento de módulos existentes (incluso del núcleo) sin alterar su código fuente. En el mundo JS/OWL, esto se logra mediante el sistema de Patching.
6.1. La Utilidad patch
La función patch (@web/core/utils/patch) permite “inyectar” o sobrescribir métodos de una clase componente existente. Esto es análogo a la herencia de modelos en Python (_inherit).
Patrón de Patching Experto:
import { patch } from "@web/core/utils/patch";
import { OrderWidget } from "@point_of_sale/app/generic_components/order_widget/order_widget";
patch(OrderWidget.prototype, {
// Sobrescribir setup para añadir nuevo estado
setup() {
super.setup();
console.log("OrderWidget extendido");
this.customState = useState({ extraInfo: "activo" });
},
// Sobrescribir un getter o método
get totalQuantity() {
const originalTotal = super.totalQuantity;
return originalTotal + (this.customState.extraValue || 0);
}
});
Este mecanismo es esencial para personalizar componentes complejos como los del Punto de Venta o las vistas Web sin reescribirlos desde cero.32
6.2. Creación de Widgets de Campo Personalizados
Los “Field Widgets” controlan cómo se renderiza un campo específico en una vista Form o Tree. Crear uno implica registrar un componente en la categoría fields.
- Definición: El componente debe aceptar props estándar (StandardFieldProps) que incluyen el valor, el registro (record) y si es de solo lectura.
- Registro: Se añade al registro fields.
- Uso: En el XML de la vista, se invoca con
<field name="mi_campo" widget="mi_widget_custom" />.
Un caso de uso avanzado sería un widget que renderice un gráfico interactivo en lugar de un simple número, utilizandochart.jsdentro del hookonMounteddel widget.19
7. Arquitectura del Punto de Venta (PoS): Un Caso Especial
El Punto de Venta de Odoo merece una distinción especial. Es una Single Page Application (SPA) que debe funcionar sin conexión a internet (Offline-First). Su arquitectura difiere del resto del cliente web.
7.1. Mecanismo Offline y Sincronización de Datos
El PoS carga una copia masiva de datos críticos (productos, clientes, tarifas) al iniciar la sesión. Estos datos se almacenan en el navegador, utilizando IndexedDB para manejar grandes volúmenes (cientos de miles de registros) que exceden la capacidad de LocalStorage.35
- Modelos JS Espejo: El PoS reimplementa la lógica de negocio de Python en JavaScript (modelos PosGlobalState, Order, Orderline). Esto permite, por ejemplo, calcular impuestos complejos y totales de venta sin realizar ninguna llamada al servidor.
- Cola de Sincronización: Cuando se crea una orden offline, se guarda localmente y se marca como “no sincronizada”. Un proceso en segundo plano intenta enviar estas órdenes al backend tan pronto como se restablece la conexión. El icono de Wi-Fi en la interfaz indica visualmente el estado de esta cola (rojo para desconectado/pendiente, verde para sincronizado).35
7.2. Carga de Datos y Personalización
Para añadir nuevos campos o modelos a la carga inicial del PoS, no basta con añadirlos a la vista. Se debe intervenir en el proceso de carga:
- En Python: Extender el modelo pos.session y el método _pos_ui_models_to_load para incluir nuevos modelos. Para campos en modelos existentes, se utiliza pos.config o métodos específicos de carga de campos.38
- En JS: Los datos cargados se inyectan en los modelos JS correspondientes. Si se crea un nuevo modelo JS, se debe registrar para que el sistema sepa cómo poblarlo con los datos recibidos.
7.3. Personalización de Pantallas (Screens)
Las pantallas del PoS (ProductScreen, PaymentScreen, ReceiptScreen) son componentes OWL. Para modificarlos, se utiliza intensivamente el patching o la herencia de plantillas QWeb (t-inherit). Un caso común es modificar el recibo impreso: esto se hace alterando la plantilla XML OrderReceipt, la cual tiene acceso al objeto order y sus líneas.32
8. Estrategias de Testing y Aseguramiento de Calidad
El desarrollo experto no está completo sin una estrategia de pruebas sólida. Odoo proporciona herramientas específicas para probar código frontend.
8.1. Pruebas Unitarias con QUnit
Odoo utiliza QUnit para las pruebas de componentes JS. Estas pruebas se ejecutan en un entorno controlado (navegador real o headless) y permiten verificar la lógica de interacción y renderizado.41
Helpers de Testing
Para facilitar las pruebas, Odoo expone helpers poderosos en web.test_utils:
- makeTestFixture(): Crea un elemento DOM limpio para montar el componente bajo prueba.
- click(el): Simula un clic de usuario, asegurando que el elemento sea visible y esté habilitado.
- nextTick(): Una función asíncrona crítica que espera a que el ciclo de renderizado de OWL se complete. Dado que OWL actualiza el DOM de forma asíncrona, después de cambiar un estado o simular un clic, siempre se debe hacer await nextTick() antes de asertar el resultado en el DOM.43
- Mocking de RPC: Las pruebas unitarias no deben depender de un backend real. Los helpers permiten “mockear” las llamadas rpc y orm, definiendo respuestas simuladas para métodos como search_read o call.41
Ejemplo de Test Experto:
QUnit.test("Counter incrementa al hacer clic", async function (assert) {
const fixture = makeTestFixture();
await mount(Counter, { target: fixture });
assert.strictEqual(fixture.querySelector(".count").innerText, "0");
await click(fixture.querySelector("button.increment"));
await nextTick(); // Esperar renderizado
assert.strictEqual(fixture.querySelector(".count").innerText, "1");
});
9. Depuración, Profiling y Rendimiento
La optimización del rendimiento es el paso final hacia la maestría.
9.1. OWL DevTools
La extensión de navegador “OWL DevTools” es indispensable para el desarrollador. Permite inspeccionar el árbol de componentes OWL en vivo, ver el estado interno (state) y las propiedades (props) de cada componente, y visualizar las dependencias reactivas. Esto permite diagnosticar por qué un componente no se actualiza (falta de suscripción reactiva) o por qué se actualiza demasiado (renderizado innecesario).44
9.2. Profiling de Código
Odoo 17 y 18 incluyen herramientas de profiling avanzadas que integran Speedscope.
- Modo de Actuación: Se puede activar el profiler desde la interfaz de depuración o programáticamente.
- Análisis: Permite ver “Flamegraphs” que combinan la ejecución de JavaScript en el cliente con las consultas SQL y el código Python en el servidor. Esto ofrece una visión holística del rendimiento de una acción del usuario, permitiendo identificar si la lentitud proviene de una consulta SQL ineficiente, un bucle en Python o un renderizado pesado en JS.45
- Chrome Performance Panel: Para problemas puramente de frontend (FPS bajos, bloqueos del hilo principal), el panel “Performance” de Chrome DevTools sigue siendo la herramienta estándar para analizar el scripting y el layout del navegador.47
10. Conclusión
Convertirse en un experto en Odoo con OWL implica dominar una arquitectura sofisticada que combina la reactividad moderna con la modularidad clásica de un ERP. Desde la correcta implementación del ciclo de vida con setup() y la gestión precisa del estado con useState, hasta la manipulación avanzada del registro y la personalización mediante patching, cada herramienta tiene un propósito específico en el ecosistema.
La verdadera maestría se demuestra no solo escribiendo código que funciona, sino diseñando componentes que son eficientes (gracias al entendimiento del Virtual DOM y t-key), mantenibles (siguiendo la estructura de archivos y validación de props) y robustos (asegurados por pruebas QUnit y limpios de fugas de memoria). Con la adopción total de OWL en Odoo 17 y 18, incluyendo el Punto de Venta y el Website, estas habilidades son ahora el estándar de oro para el desarrollo técnico en la plataforma.
Works cited
- odoo/owl: OWL: A web framework for structured, dynamic and maintainable applications - GitHub, accessed December 18, 2025, https://github.com/odoo/owl
- javascript in Odoo 18, accessed December 18, 2025, https://www.odoo.com/forum/help-1/javascript-in-odoo-18-264634
- OWL Framework, accessed December 18, 2025, https://odoo.github.io/owl/
- Owl components — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/19.0/developer/reference/frontend/owl_components.html
- Owl components — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/17.0/developer/reference/frontend/owl_components.html
- How to Configure Client Action in Odoo 17 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-configure-client-action-in-odoo-17
- Odoo 18 OWL JS: Key Improvements Over Odoo 17 | PySquad, accessed December 18, 2025, https://www.pysquad.com/blogs/odoo-18-owl-js-key-improvements-over-odoo-17
- Resolving Owl Lifecycle Errors While Editing Odoo 17.0 CE Websites - Medium, accessed December 18, 2025, https://medium.com/@python-javascript-php-html-css/resolving-owl-lifecycle-errors-while-editing-odoo-17-0-ce-websites-62d64140aa55
- Chapter 1: Owl components — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/19.0/developer/tutorials/discover_js_framework/01_owl_components.html
- Data Binding and Reactivity in Owl.js and Odoo - PySquad, accessed December 18, 2025, https://www.pysquad.com/blogs/data-binding-and-reactivity-in-owljs-odoo-17
- owl/doc/reference/reactivity.md at master · odoo/owl - GitHub, accessed December 18, 2025, https://github.com/odoo/owl/blob/master/doc/reference/reactivity.md
- Fixing OWL Component Not Re-rendering in Odoo 17 Frontend Public Web(QWeb), accessed December 18, 2025, https://adhon-rizky.medium.com/fixing-owl-component-not-re-rendering-in-odoo-17-frontend-public-web-qweb-25b5b7977954
- An Overview of Qweb Templates & Operations in Odoo 17, accessed December 18, 2025, https://www.cybrosys.com/blog/an-overview-of-qweb-templates-and-operations-in-odoo-17
- How to Use Owl Slots in Odoo 17 - Odoo Slides | PPTX - Slideshare, accessed December 18, 2025, https://www.slideshare.net/slideshow/how-to-use-owl-slots-in-odoo-17-odoo-slides/279781636
- owl/doc/reference/slots.md at master · odoo/owl - GitHub, accessed December 18, 2025, https://github.com/odoo/owl/blob/master/doc/reference/slots.md
- How to Use Owl Slots in Odoo 17, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-use-owl-slots-in-odoo-17
- owl/doc/reference/refs.md at master · odoo/owl - GitHub, accessed December 18, 2025, https://github.com/odoo/owl/blob/master/doc/reference/refs.md
- How to use t-ref and useRef in OWL in Odoo 17 | PPTX - Slideshare, accessed December 18, 2025, https://www.slideshare.net/slideshow/how-to-use-t-ref-and-useref-in-owl-in-odoo-17/273396593
- How to Create a Widget in Odoo 17 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-create-a-widget-in-odoo-17
- HOW TO CREATE A FIELD WIDGET IN ODOO - Technaureus, accessed December 18, 2025, https://www.technaureus.com/blog-detail/create-field-widget-in-odoo
- How to Create a New View Type in Odoo 17 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-create-a-new-view-type-in-odoo-17
- Customize a view type — Odoo 17.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/17.0/th/developer/howtos/javascript_view.html
- How to Create Custom Hooks in Odoo 19 OWL - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-create-custom-hooks-in-odoo-19-owl
- RPC Call | Odoo 17 Development Book - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/odoo/odoo-books/odoo-17-development/pos/rpc-call/
- [v15] POS OWL framework Abstract Concepts - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/v15-pos-owl-framework-abstract-concepts-204025
- Calling an action from js (owl) - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/calling-an-action-from-js-owl-198984
- Error when using orm with useService in Odoo 17, accessed December 18, 2025, https://www.odoo.com/forum/help-1/error-when-using-orm-with-useservice-in-odoo-17-238594
- Owl Hooks in Odoo 18: A Beginner’s Guide - Technaureus, accessed December 18, 2025, https://www.technaureus.com/blog-detail/owl-hooks-in-odoo-18
- How to Setup Real-time Communication in Odoo: Using Bus Service, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-setup-real-time-communication-in-odoo-using-bus-service
- Using useBus hook in Odoo 17, accessed December 18, 2025, https://www.odoo.com/forum/help-1/using-usebus-hook-in-odoo-17-251318
- How to Implement OWL Notification Service in Odoo 17 | by Walter White - Medium, accessed December 18, 2025, https://medium.com/cybrosys/how-to-implement-owl-notification-service-in-odoo-17-54ec40406f2d
- How To Patch Existing OWL Component in Odoo 17 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-patch-existing-owl-component-in-odoo-17
- Using patch to override props (OWL) - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/using-patch-to-override-props-owl-257024
- How to Create a Custom Field Type in Odoo 17 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-create-a-custom-field-type-in-odoo-17
- What’s the mechanism of POS offline? - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/whats-the-mechanism-of-pos-offline-283217
- Offline point of sale entreprise - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/offline-point-of-sale-entreprise-291365
- How is the Point of Sale “offline mode” working? - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/how-is-the-point-of-sale-offline-mode-working-218314
- How to Load POS Session Data to POS Order in Odoo 17 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-load-pos-session-data-to-pos-order-in-odoo-17
- Custom JavaScript Not Working in POS Module in Odoo 17, accessed December 18, 2025, https://www.odoo.com/forum/help-1/custom-javascript-not-working-in-pos-module-in-odoo-17-241973
- Custom Javascript Files in POS | Odoo 17 Development Book - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/odoo/odoo-books/odoo-17-development/pos/
- QUnit Test | Odoo 17 Development Book - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/odoo/odoo-books/odoo-17-development/test-cases/qunit-test/
- How to Create & Perform a QUnit Test in the Odoo? - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/how-to-create-perform-a-qunit-test-in-the-odoo
- owl/doc/learning/how_to_test.md at master · odoo/owl - GitHub, accessed December 18, 2025, https://github.com/odoo/owl/blob/master/doc/learning/how_to_test.md
- Owl devtools - Chrome Web Store, accessed December 18, 2025, https://chromewebstore.google.com/detail/owl-devtools/ldbfanecnfeflgbmgkbmipobkmoolbjb
- Performance — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/19.0/developer/reference/backend/performance.html
- What is Code Profiling & How to Enable it in Odoo 18 - Cybrosys Technologies, accessed December 18, 2025, https://www.cybrosys.com/blog/what-is-code-profiling-and-how-to-enable-it-in-odoo-18
- Performance panel: Analyze your website’s performance | Chrome DevTools, accessed December 18, 2025, https://developer.chrome.com/docs/devtools/performance/overview