Audit mesuré sur saas~19.4+e le 25 juillet 2026. Bundle analysé, tests runtime, captures. Chaque chiffre est traçable.
Depuis quelques mois, une phrase revient dans les réunions d'avant-projet : « Odoo va faire l'offline, vos applications ne serviront plus ». Elle mérite mieux qu'une réponse commerciale. On a donc testé.
Odoo 19.4 embarque un vrai moteur hors connexion. C'est nouveau et il faut le reconnaître. Ce moteur ne couvre pas le travail de terrain, pour six raisons mesurables qui ne relèvent pas du bug.
Ce qui existe, et qu'il faut arrêter de nier
Le service @web/core/offline/offline_service est enregistré par défaut dans la 19.4, actif sans configuration.
| Brique | État | Détail |
|---|---|---|
| Détection de perte réseau | ConnectionLostError, événements online/offline, polling à backoff exponentiel | |
| Stockage local | IndexedDB, valeurs chiffrées en AES-GCM | |
| File d'écritures | table orm-to-sync, rejeu séquentiel, verrou navigator.locks | |
| Indicateur utilisateur | systray « Working offline », « Syncing », « Sync issues » | |
| Édition et sauvegarde hors connexion | testé, web_save mis en file puis rejoué |
Vous perdez le réseau dix minutes, votre onglet reste ouvert, vous corrigez deux champs sur une fiche déjà affichée : ça marche, et ça rend service à un utilisateur de bureau.
L'offline-first commence ailleurs, et l'écart se mesure sur six points.
Les 6 points de rupture
1. Quatre méthodes ORM seulement sont rejouables
La liste est exhaustive, extraite de l'énumération STATUS du systray et du modèle record.js :
web_save → créé / modifié
unlink → supprimé
action_archive → archivé
action_unarchive → désarchivé
Aucun appel de méthode métier n'est mis en file d'attente. C'est la cause du point suivant.
2. Tout bouton métier est désactivé hors connexion
Le mécanisme fonctionne en liste blanche : button:not([data-available-offline]) est grisé. Tout ce qui n'est pas explicitement marqué comme sûr hors connexion devient inactif.
On a compté les occurrences du marqueur data-available-offline dans l'intégralité du bundle 19.4 : 112 occurrences, toutes dans le chrome web générique (pagination, barre de navigation, dialogues, sélecteur de date, recherche) et dans Discuss. Modules métier : zéro. Ni stock, ni timesheet, ni projet, ni qualité, ni maintenance, ni vente.
23 rouges = boutons désactivés hors connexion, dont Valider, Signer, Imprimer, Code-barres, Mettre en colis et Joindre un fichier.
Traduction terrain : hors connexion, un magasinier peut modifier un champ. Il ne peut pas valider son opération.
3. Photos, signatures et pièces jointes : aucun support
Recherche d'occurrences du mot offline et de ConnectionLostError dans les modules concernés :
| Module | offline | ConnectionLostError |
|---|---|---|
file_upload_service | 0 | 0 |
name_and_signature | 0 | 0 |
image_field | 0 | 0 |
binary_field | 0 | 0 |
file_input | 0 | 0 |
Pas de photo d'intervention, pas de signature client, pas de pièce jointe. Sur un rapport d'intervention, ce sont les éléments qui font foi devant un client ou un assureur.
4. Hors connexion, vous n'avez accès qu'à ce que vous avez déjà ouvert
La fonction _populateVisited() reconstruit la surface disponible à partir des écrans réellement ouverts pendant la session en ligne. Il n'existe aucun mécanisme pour provisionner un jeu de données avant de partir.
| Action hors connexion | État | Résultat |
|---|---|---|
| Rouvrir une fiche déjà consultée | fonctionne | |
| Ouvrir une fiche de la liste jamais consultée | rien ne se passe, ni formulaire, ni erreur, ni notification | |
| Ouvrir une action jamais chargée | ConnectionLostError | |
| Appliquer un filtre différent de celui utilisé en ligne | « There is no data to display offline for the given filters » |
Le deuxième cas est le plus problématique. L'échec est silencieux. L'utilisateur clique, rien ne bouge, il ne comprend pas pourquoi son application ne réagit pas. En formation, c'est ce comportement qui produit le plus d'appels au support.
5. L'application ne redémarre pas hors connexion
Test : application en état hors connexion, rechargement de la page.
GET /odoo/action-845 200 ← coquille HTML du service worker
GET /web/assets/…/web.assets_web.min.js 200 ← bundle depuis le cache HTTP
GET /web/webclient/load_menus ERR_INTERNET_DISCONNECTED
GET /web/webclient/translations?hash=… ERR_INTERNET_DISCONNECTED ← bloquant
Le chargement des traductions est une dépendance dure et non mise en cache du démarrage des services. Résultat mesuré : document.body.innerText vide. Page blanche.
Les écritures en attente survivent dans IndexedDB, on l'a vérifié. Mais elles restent inaccessibles jusqu'au retour du réseau.
Traduction terrain : le technicien qui ferme puis rouvre son application sur un chantier sans réseau obtient un écran blanc, avec son travail enfermé dedans.
Cause structurelle : le fichier /web/service-worker.js de la 19.4 est strictement identique à celui de la 19.0. Même taille, diff vide. Aucune évolution du service worker sur quatre releases SaaS.
6. Aucune détection de conflit, et un écrasement silencieux
C'est le point le plus grave, et le plus facile à reproduire. Test à deux utilisateurs sur le même enregistrement :
Il saisit sa valeur et sauvegarde. L'écriture part en file d'attente.
Il saisit une autre valeur sur le même champ et sauvegarde.
La file se rejoue. La saisie du dispatcher disparaît.
Ce qu'on observe à t2 : aucun dialogue de conflit, aucune notification, aucune erreur en file, aucun indicateur dans le systray.
La saisie du dispatcher est détruite sans laisser de trace. web_save exécute un write() nu : pas de contrôle de version, pas de verrou optimiste, pas de comparaison de write_date. Le dernier à synchroniser gagne, y compris quand sa donnée est la plus ancienne.
Corollaire trouvé dans la boucle de synchronisation : une écriture qui échoue est replanifiée avec un marqueur d'erreur, mais la boucle filtre ensuite les entrées portant ce marqueur. Une écriture en erreur n'est donc plus jamais retentée. Elle reste parquée en « Sync issues », à ressaisir à la main.
La synthèse opposable
| Capacité terrain | Odoo 19.4 |
|---|---|
| Éditer un champ sur une fiche déjà ouverte | |
| Supprimer ou archiver hors connexion | |
| Resynchroniser au retour du réseau | |
| Valider une opération métier hors connexion | |
| Prendre une photo | |
| Faire signer le client | |
| Ouvrir une fiche non pré-visitée | |
| Provisionner la tournée du jour | |
| Redémarrer l'application hors connexion | |
| Détecter un conflit d'édition | |
| Rejouer une écriture en erreur | |
| Synchroniser application fermée |
Le volet mobile, souvent confondu avec le sujet
Le responsive fonctionne. En 390 × 844, aucun débordement horizontal, le mode isSmall s'active correctement. Ce n'est pas le problème.
Un client web de 3,58 Mo sur un réseau de chantier, avec 92 % des cibles tactiles trop petites pour un opérateur ganté : ça se paie en minutes perdues à chaque prise de poste.
Et l'IA ?
Le bundle 19.4 contient 83 modules @ai/*. Occurrences du mot offline dans l'ensemble de ces modules : zéro. Occurrences d'IndexedDB : zéro. Les endpoints appelés sont tous serveur, relayés vers un fournisseur externe.
Sans réseau, aucune fonction IA. S'ajoute la question de la souveraineté : photos et transcriptions vocales quittent l'appareil et l'entreprise.
Pourquoi ce n'est pas un bug qui sera corrigé en v20
L'erreur symétrique serait de parier qu'Odoo n'y arrivera jamais. Odoo sait faire de l'offline sérieux, et le Point de Vente le prouve : environ 1 375 lignes de moteur dédié, avec son propre service de données, sa couche IndexedDB et ses modèles relationnels.
Mais ce moteur est entièrement sur mesure pour un seul domaine, construit sur une décennie, et non réutilisable par le client web générique.
Les six points ci-dessus ne sont pas des correctifs de release. Ce sont des problèmes d'architecture distribuée : résolution de conflit, provisionnement de jeux de données, file d'attente de fichiers binaires, rejeu de méthodes métier arbitraires, démarrage sans réseau. Chacun demande un choix produit lourd, sur une surface qui n'est pas le cœur de marché d'Odoo. C'est aussi ce qui sépare une application mobile Odoo sur mesure d'un client web mis en cache.
Odoo comble le cas du bureau avec un réseau instable. Il ne comble pas le cas du terrain sans réseau. Et quand il s'en approchera, ce sera domaine par domaine, comme pour le Point de Vente, pas d'un coup pour tous les workflows.
Un signal va dans ce sens : depuis la 19.2, l'application Field Service est supprimée et fusionnée dans Planning. Les priorités bougent sur la planification, pas sur le terrain déconnecté.
Ce que ça change pour une équipe qui travaille vraiment sans réseau
Chez une PME belge de SAV industriel de 15 techniciens, le passage à une application terrain conçue hors connexion depuis le départ a produit des écarts mesurés sur les six premiers mois.
Délai de facturation
Erreurs de saisie
Satisfaction des techniciens, sur 5
Ces écarts tiennent à des capacités qu'aucune des six ruptures ci-dessus ne permet : valider une intervention sans réseau, y attacher photo et signature, retrouver son travail après avoir redémarré l'application dans un sous-sol. C'est ce que couvre ASKA Field Service.
Vérifiez par vous-même, et redatez
Cet audit porte sur saas~19.4+e au 25 juillet 2026. Odoo publie une version SaaS toutes les six semaines environ. Il périme.
La méthode est reproductible en une trentaine de minutes : comparer /web/service-worker.js avec la version précédente, chercher data-available-offline et offline_service dans le bundle web.assets_web.min.js, activer le mode hors connexion puis recharger la page, et tester un conflit d'édition à deux onglets.
Si vous refaites le test sur une version plus récente et que les résultats diffèrent, écrivez-nous. On mettra l'audit à jour et on le dira.
Vous avez des équipes qui travaillent sans réseau et une échéance de conformité au 1er janvier 2027 ?
On regarde ensemble, en 20 minutes, ce que votre dispositif actuel enregistre hors connexion et ce qui manquerait au regard de l'obligation d'enregistrement du temps de travail. Sans présentation commerciale.
Prendre rendez-vousFAQ
Odoo 19.4 fonctionne-t-il hors ligne ?
En partie. Un moteur hors connexion existe depuis la 19.4 et permet d'éditer, supprimer ou archiver un enregistrement déjà ouvert, puis de resynchroniser au retour du réseau. Il ne permet pas de valider une opération métier, d'ajouter une photo ou une signature, d'ouvrir une fiche non visitée, ni de redémarrer l'application sans réseau.
Quelle différence entre le mode hors connexion d'Odoo et une application offline-first ?
Le mode d'Odoo met en cache ce qui a déjà été affiché et rejoue quatre méthodes ORM. Une application offline-first utilise une base locale comme source de vérité, provisionne ses données à l'avance, gère les fichiers binaires et arbitre les conflits d'édition. La première approche couvre un réseau instable, la seconde couvre l'absence de réseau.
Que se passe-t-il si deux personnes modifient la même donnée, l'une hors connexion ?
Sur Odoo 19.4, la dernière synchronisation écrase la précédente sans avertissement, y compris si sa donnée est plus ancienne. Le test est reproductible en deux onglets.
Odoo 20 va-t-il régler le problème ?
Probablement pas d'un coup. Les points bloquants relèvent de l'architecture distribuée, pas du correctif. Le précédent du Point de Vente suggère une résolution domaine par domaine, sur plusieurs années.
À lire aussi : Application mobile Odoo : PWA, native ou sur mesure, le guide pour décider.