Desarrollo

Owl Odoo

Integración de Odoo con Owl

Owl Odoo

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ísticaReact / VueOdoo OWLImplicación para el Experto
Definición de VistasJSX / Single File ComponentsXML (QWeb)Permite herencia y modificación vía XPath desde otros módulos.
ToolchainWebpack / Vite (Node.js)Integrado en Assets de OdooNo requiere compilación compleja externa; carga dinámica de assets.3
EstadouseState / ref / VuexuseState / reactive / StoresReactividad basada en Proxies optimizada para el ciclo de vida de Odoo.
Ciclo de VidaHooks (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:

  1. Lógica (JavaScript): Define la clase del componente, su estado y comportamiento.
  2. Presentación (XML): Contiene la estructura del DOM y las directivas QWeb.
  3. 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 value con el estado y escuchar el evento input para actualizar el estado.
  • Modificadores: Se pueden usar modificadores como .lazy para actualizar el estado en el evento change en lugar de input, 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 Table itera sobre rows y expone row vía t-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
  • 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 RegistroUso ExpertoReferencia
fieldsRegistro de widgets para campos de formulario (ej. Char, Many2One). Clave para crear visualizaciones de datos personalizadas.19
viewsRegistro de tipos de vistas completos (ej. una nueva vista map o grid). Permite definir la arquitectura MVC completa (Controller, Renderer, Model).21
actionsRegistro de “Client Actions”. Permite crear aplicaciones completas dentro de Odoo que toman control total del área de trabajo (ej. Dashboards, Kioscos).6
systrayElementos de la barra de menú superior (notificaciones, menú de usuario). Ideal para widgets globales siempre visibles.23
servicesLógica de negocio transversal compartida (RPC, Notificaciones, Bus).24
main_componentsComponentes 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.

  1. Definición: El componente debe aceptar props estándar (StandardFieldProps) que incluyen el valor, el registro (record) y si es de solo lectura.
  2. Registro: Se añade al registro fields.
  3. 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, utilizando chart.js dentro del hook onMounted del 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

  1. odoo/owl: OWL: A web framework for structured, dynamic and maintainable applications - GitHub, accessed December 18, 2025, https://github.com/odoo/owl
  2. javascript in Odoo 18, accessed December 18, 2025, https://www.odoo.com/forum/help-1/javascript-in-odoo-18-264634
  3. OWL Framework, accessed December 18, 2025, https://odoo.github.io/owl/
  4. Owl components — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/19.0/developer/reference/frontend/owl_components.html
  5. Owl components — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/17.0/developer/reference/frontend/owl_components.html
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  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
  18. 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
  19. 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
  20. HOW TO CREATE A FIELD WIDGET IN ODOO - Technaureus, accessed December 18, 2025, https://www.technaureus.com/blog-detail/create-field-widget-in-odoo
  21. 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
  22. 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
  23. 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
  24. 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/
  25. [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
  26. 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
  27. 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
  28. 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
  29. 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
  30. Using useBus hook in Odoo 17, accessed December 18, 2025, https://www.odoo.com/forum/help-1/using-usebus-hook-in-odoo-17-251318
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. Offline point of sale entreprise - Odoo, accessed December 18, 2025, https://www.odoo.com/forum/help-1/offline-point-of-sale-entreprise-291365
  37. 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
  38. 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
  39. 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
  40. 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/
  41. 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/
  42. 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
  43. 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
  44. Owl devtools - Chrome Web Store, accessed December 18, 2025, https://chromewebstore.google.com/detail/owl-devtools/ldbfanecnfeflgbmgkbmipobkmoolbjb
  45. Performance — Odoo 19.0 documentation, accessed December 18, 2025, https://www.odoo.com/documentation/19.0/developer/reference/backend/performance.html
  46. 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
  47. Performance panel: Analyze your website’s performance | Chrome DevTools, accessed December 18, 2025, https://developer.chrome.com/docs/devtools/performance/overview