Aller au contenu principal
Automatisation · n8n et Odoo

n8n et Odoo : ce qu'un flux automatise et ce qui exige un module

n8n convient à ce qui se passe autour d'Odoo ; ce qui change l'état de l'activité à l'intérieur demande un module. La frontière, avec le JSON-RPC en premier et des réponses réelles d'un laboratoire avec Odoo 19 et n8n 2.30.6.

Tableau de bord d'Odoo : là où atterrissent les enregistrements créés par un flux n8n et où l'on vérifie qu'ils sont bien passés

n8n convient à ce qui se passe autour d'Odoo : récupérer un formulaire externe, prévenir un chat, monter un rapport quotidien. Ce qui change l'état de l'activité à l'intérieur (prix, réservations de stock, validations de bons de livraison, rapprochement de paiements) demande un module. La frontière se voit en exécutant les deux contre un vrai Odoo : cet article est tiré d'un laboratoire propre avec Odoo 19.0-20260630 et n8n 2.30.6.

Idée clé : un flux qui appelle l'API d'Odoo n'exécute pas son interface. Il peut recevoir un 200 avec un assistant à l'intérieur et croire avoir validé un bon de livraison qui reste ouvert.

Comment n8n parle à Odoo : quatre chemins, pas un seul

  • XML-RPC : /xmlrpc/2/common pour s'authentifier et /xmlrpc/2/object pour execute_kw. Celui de la documentation.
  • JSON-RPC : un POST /jsonrpc avec service, method et args. Le même service en JSON.
  • Session web : /web/session/authenticate et /web/dataset/call_kw avec le cookie. Ce que fait votre navigateur.
  • L'API JSON-2, uniquement dans Odoo 19 : POST /json/2/<modelo>/<método> avec Authorization: bearer <clave API> et X-Odoo-Database. Sans session : les arguments sont des champs nommés, context compris.

Les trois premiers continuent de fonctionner en 19, mais le serveur avertit dans le log : « The /xmlrpc, /xmlrpc/2 and /jsonrpc endpoints are deprecated in Odoo 19 and scheduled for removal in Odoo 22 ». Un nouveau flux contre un 19 devrait passer par /json/2 ; s'il sert aussi 17 et 18, par la session.

# Sesion + call_kw: funciona igual en 17, 18 y 19.
POST /web/session/authenticate
 {"params":{"db":"lab","login":"n8n_bot2","password":"..."}}
-> 200 {"result":{"uid":6,"server_version":"19.0-20260630"}}   # + cookie

POST /web/dataset/call_kw          # con esa cookie
 {"params":{"model":"crm.lead","method":"create",
            "args":[{"name":"Lead web","type":"lead"}],
            "kwargs":{"context":{"lang":"es_ES"}}}}
-> 200 {"result": 10}

# Clave API en la cabecera, sin sesion: solo Odoo 19.
POST /json/2/crm.lead/create
Authorization: bearer <clave>     X-Odoo-Database: lab
 {"vals_list":[{"name":"Lead via /json/2 (API key)"}]}
-> 200 [9]

# Sin cabecera -> 401 "User not authenticated, use an API Key with a
#                 Bearer Authorization header."
# Metodo privado -> 403 "Private methods (such as
#                 'crm.lead._compute_display_name') cannot be called remotely." 

Le nœud Odoo de n8n 2.30.6 choisit pour vous selon l'identifiant : celui à clé API passe par /json/2 ; le classique passe par /jsonrpc avec execute, positionnel, qui n'accepte pas kwargs et ne peut pas transmettre de contexte. L'identifiant à clé API prévient en outre qu'il requiert « Odoo 19+ and a Custom pricing plan ».

Le nœud HTTP Request, tel qu'il est resté

Remarquez où la clé n'est pas : le corps ne contient que des données et l'en-tête Authorization est posé par un identifiant n8n, chiffré et renouvelé à part.

// Lineas del nodo real, copiadas de `n8n export:workflow`.
"type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2,
"url": "http://odoo:8069/json/2/crm.lead/create",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": { "parameters": [
    { "name": "X-Odoo-Database", "value": "lab" } ] },
"jsonBody": "={{ JSON.stringify({ vals_list: [{ name: 'Web: ' + $json.body.empresa, contact_name: $json.body.nombre, email_from: $json.body.email, description: $json.body.mensaje, type: 'lead' }] }) }}",
"credentials": { "httpHeaderAuth": { "name": "Odoo lab - API key (header)" } }
// La clave no esta aqui: la pone esa credencial.

Le flux n'entre pas non plus en administrateur, mais en utilisateur technique avec juste les bons groupes et le plafond qu'Odoo 19 impose à sa clé :

# Usuario tecnico nuevo (solo grupo de usuario interno):
POST /json/2/crm.lead/create
-> 403 "No puede crear informes 'Lead' (crm.lead) ...
            - Sales/Administrator
            - Sales/User: Own Documents Only"
# Tras anadirle sales_team.group_sale_salesman:  -> 200

# Su clave API tampoco dura lo que uno quiera:
_generate(..., +200 dias) -> "No puede exceder 90.0 dias."
_generate(..., sin fecha) -> "La clave API debe tener una
                              fecha de vencimiento"

Ce plafond de 90 jours est la date à laquelle votre flux cessera de fonctionner sans que personne n'y touche. Notez-la le jour où vous créez la clé.

Cinq automatisations qui tiennent dans un flux

Elles ont toutes le même point commun : le fait a déjà eu lieu et le flux ne fait que le déplacer.

CasDéclencheurAppel à Odoo
Lead depuis un formulaire externeWebhook n8ncrm.lead / create
Alerte au chat à la validation d'un bon de livraisonAutomatisation Odoo avec action de webhookAucun : Odoo pousse
Contacts vers un outil de marketingPlanifié, chaque nuitres.partner / search_read par write_date
Alerte de stock basPlanifié, chaque matinproduct.product / search_read de qty_available
Rapport quotidien à la directionPlanifiéread_group sur sale.order

Le deuxième cas a ses petites lignes. L'action de webhook envoie _model, _id et le nom de l'action, et c'est du « lancer et oublier » : un POST d'une seconde, sans nouvelle tentative. En 19 il part après le commit ; en 17 et 18 il est dans la transaction, donc un n8n lent fait attendre l'utilisateur.

# Accion de servidor state='webhook' al crear un lead.
INFO    Webhook call to http://n8n:5678/webhook/odoo-lead
INFO    Webhook call to http://n8n:5678/webhook/odoo-lead - succeeded

# Apuntando a un flujo borrado (el lead se crea igual):
WARNING Webhook call failed: 404 Client Error: Not Found for url:
        http://n8n:5678/webhook/flujo-borrado
WARNING Webhook call timed out after 1s - it may or may not have failed.

Cinq qui non, et la raison exacte

  1. Calculer des prix ou des remises. Odoo les calcule à partir du tarif ; si le flux les calcule à l'extérieur, quand le tarif change il y a deux vérités.
  2. Réserver du stock pour plusieurs canaux. Odoo résout la course dans une transaction ; un flux qui lit, décide et écrit séparément vend en trop.
  3. Rapprocher des paiements. Apparier et comptabiliser vont ensemble : si l'un se fait dehors et l'autre dedans, une coupure réseau laisse un demi-rapprochement.
  4. Ce que quelqu'un va auditer. L'historique de n8n n'est pas le chatter : « qui a changé ça et pourquoi ? » se répond dans le document.
  5. Ce qui dépend d'un champ qui change entre versions. Nous l'avons vérifié en écrivant dans Odoo 19 ce qui fonctionnait en 18.

Le cas qui résume le mieux : valider un bon de livraison depuis un flux. Nous en avons préparé un de 10 unités avec 4 réservées et appelé button_validate, comme le fait le bouton.

# WH/OUT/00003: 10 pedidas, 4 reservadas.
POST /web/dataset/call_kw
 {"model":"stock.picking","method":"button_validate","args":[[2]]}
-> 200 {"result": {"name": "¿Crear entrega parcial?",
                   "type": "ir.actions.act_window",
                   "res_model": "stock.backorder.confirmation", ...}}

read -> [{"name":"WH/OUT/00003","state":"assigned"}]   # sigue abierto

HTTP 200, sans erreur, et un bon de livraison en assigned. Pour n8n l'étape est passée au vert ; pour l'entrepôt, la commande n'est pas partie. Un module reconnaît l'assistant et le consigne dans le document : la même frontière que dans Odoo 19 face aux connecteurs de middleware.

Et les champs qui changent de nom entre versions, ce qui casse un flux stable après une migration :

# Odoo 19, escribiendo lo que funcionaba en 17 y 18:
res.users write {"groups_id": [[4, 1]]}
-> "Invalid field 'groups_id' in 'res.users'"     # en 19 se llama group_ids

stock.move create {"name": "Latiguillo", "product_id": 1, ...}
-> "Invalid field 'name' in 'stock.move'"         # en 17 y 18 era obligatorio

Nous maintenons le même code sur Odoo 19, 18 et 17 dans 105 modules publiés : ces différences sont à la charge du module, pas du client. C'est aussi la limite d'Odoo Studio quand le processus cesse d'être un champ et devient une règle.

Les quatre erreurs que nous voyons toujours

  1. La boucle. Une automatisation prévient n8n lors du changement d'un champ, le flux écrit dans Odoo et ce qu'il écrit la redéclenche. On la coupe avec une condition dans le déclencheur.
  2. L'identifiant en clair. Ni dans le corps du nœud ni dans un nœud de code : dans un identifiant n8n, avec un utilisateur technique aux groupes minimaux.
  3. Sans idempotence. Un webhook relancé de l'autre côté crée à nouveau l'enregistrement : trois POST identiques vers notre flux ont donné trois leads.
  4. Sans vraie nouvelle tentative. Un nœud ne réessaie que si vous activez Retry On Fail, et le moteur limite les essais à cinq et l'attente à cinq secondes. Suffisant pour un chat ; pas pour un transporteur : notre module Correos Express réessaie à 5, 15, 30, 60, 120 et 240 minutes.

La solution n'est pas dans n8n, elle est dans la conception : conservez dans Odoo la référence externe et vérifiez-la avant de créer. Dans un module c'est une contrainte unique en base de données ; dans un flux, une lecture préalable avec fenêtre de course.

Quand un flux devient un module

Le flux est une façon peu coûteuse de découvrir si le processus mérite d'exister. Le signe qu'il est devenu trop juste est l'un de ces six :

  • Il écrit un champ qu'Odoo calcule lui-même.
  • Deux écritures doivent avoir lieu ensemble ou pas du tout.
  • Quelqu'un auditera dans Odoo ce qui s'est passé et quand.
  • Le processus doit survivre à la prochaine migration.
  • Il faut pouvoir répéter l'appel sans rien dupliquer.
  • L'utilisateur a besoin de réessayer depuis le document lui-même.

À ce stade on ne jette pas le flux : on porte dans le module la partie qui touche l'état de l'activité et n8n garde la périphérie. C'est pareil pour automatiser les tâches administratives et pour l'intégration avec Signaturit.

Résumé : si le flux tombe et que la seule conséquence est que quelqu'un ne reçoit pas une alerte, n8n suffit. S'il tombe et que l'entrepôt ou le livre de factures se retrouvent dans un état que personne ne sait lire, c'était un module.

Questions fréquentes

Puis-je passer la langue ou la société dans l'appel ?

Par les trois chemins modernes oui : kwargs.context dans call_kw et dans execute_kw, et un champ context dans /json/2 (un pays sort « Spain » avec en_US et « España » avec es_ES). Pas avec l'identifiant classique, qui appelle execute, positionnel.

Où conserver la clé API et combien de temps dure-t-elle ?

Dans un identifiant n8n, jamais dans le corps du nœud. Dans Odoo 19 la clé d'un utilisateur non administrateur nécessite une expiration, et le plafond est fixé par le groupe : 90 jours pour un utilisateur interne.

Mon flux casse-t-il en migrant d'Odoo 18 à 19 ?

Cela dépend des champs touchés, et il n'y a pas d'avertissement : res.users.groups_id est passé à group_ids et stock.move.name, obligatoire en 17 et 18, n'existe pas en 19. Testez vos flux contre une copie.

Liens utiles dans FlexigoTech

Services d'ingénierie OdooMise en place et développement sur OdooDéveloppement sur mesureQuand il faut un moduleUn connecteur Odoo pour votre logicielPour les partenaires technologiquesSolutions par besoinClassées par problème, pas par moduleOdoo 19 face aux connecteurs de middlewareLa même frontière, un niveau au-dessusQu'est-ce qu'Odoo Studio et comment fonctionne-t-ilL'autre « sans code » et ses limitesAutomatiser les tâches administrativesAutomatisation à l'intérieur de l'ERPSignature électronique dans Odoo avec SignaturitUn autre cas où le flux est trop juste

Ce que nous faisons à ce sujet

Automatisation avec OperariaCe qu'il fait, captures, versions et prix.

Vous avez des flux n8n contre Odoo et vous ne savez plus lesquels tiennent ?

Nous les examinons, nous vous disons lesquels restent tels quels et lesquels il faut porter dans un module, et nous réalisons le module si besoin. Écrivez à comercial@flexigobe.com ou appelez le +34 616 809 504.

Parler à un ingénieur