Saltar para o conteúdo principal
Automação · n8n e Odoo

n8n e Odoo: o que automatizar com um fluxo e o que exige um módulo

O n8n serve para o que acontece em redor do Odoo; o que altera o estado do negócio lá dentro pede um módulo. A fronteira, com o JSON-RPC à frente e respostas reais de um laboratório com Odoo 19 e n8n 2.30.6.

Painel do Odoo: onde acabam os registos que cria um fluxo do n8n e onde se audita se correram bem

O n8n serve para o que acontece em redor do Odoo: recolher um formulário externo, avisar um chat, montar um relatório diário. O que altera o estado de negócio lá dentro (preços, reservas de stock, validações de operação de stock, reconciliação de pagamentos) pede um módulo. A fronteira vê-se ao executar as duas coisas contra um Odoo a sério: este artigo nasce de um laboratório próprio com Odoo 19.0-20260630 e n8n 2.30.6.

Ideia-chave: um fluxo que chama a API do Odoo não executa a sua interface. Pode receber um 200 com um assistente lá dentro e julgar que validou uma operação de stock que continua aberta.

Como o n8n fala com o Odoo: quatro caminhos, não um

  • XML-RPC: /xmlrpc/2/common para autenticar e /xmlrpc/2/object para execute_kw. O da documentação.
  • JSON-RPC: um POST /jsonrpc com service, method e args. O mesmo serviço em JSON.
  • Sessão web: /web/session/authenticate e /web/dataset/call_kw com o cookie. O que faz o seu navegador.
  • A API JSON-2, só no Odoo 19: POST /json/2/<modelo>/<método> com Authorization: bearer <clave API> e X-Odoo-Database. Sem sessão: os argumentos vão como campos com nome, context incluído.

Os três primeiros continuam a funcionar na 19, mas o servidor avisa no log: «The /xmlrpc, /xmlrpc/2 and /jsonrpc endpoints are deprecated in Odoo 19 and scheduled for removal in Odoo 22». Um fluxo novo contra uma 19 deveria ir por /json/2; se serve também a 17 e 18, pela sessão.

# 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." 

O nó Odoo do n8n 2.30.6 escolhe por si conforme a credencial: a de chave API vai por /json/2; a clássica vai por /jsonrpc com execute, posicional, que não aceita kwargs e não pode passar contexto. A credencial de chave API avisa ainda de que requer «Odoo 19+ and a Custom pricing plan».

O nó HTTP Request, tal como ficou

Repare onde não está a chave: o corpo só leva dados e o cabeçalho Authorization é posto por uma credencial do n8n, que se cifra e se roda à parte.

// 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.

O fluxo também não entra como administrador, mas como utilizador técnico com os grupos certos e o limite que o Odoo 19 põe à sua chave:

# 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"

Esse limite de 90 dias é a data em que o seu fluxo deixará de funcionar sem que ninguém lhe toque. Anote-a no dia em que cria a chave.

Cinco automatizações que cabem num fluxo

Todas partilham o mesmo: o facto já ocorreu e o fluxo apenas o move de sítio.

CasoDisparadorChamada ao Odoo
Lead a partir de um formulário externoWebhook do n8ncrm.lead / create
Aviso ao chat ao validar uma operação de stockAutomatização do Odoo com ação de webhookNenhuma: o Odoo empurra
Contactos para uma ferramenta de marketingAgendado, todas as noitesres.partner / search_read por write_date
Alerta de stock baixoAgendado, todas as manhãsproduct.product / search_read de qty_available
Relatório diário para a direçãoAgendadoread_group sobre sale.order

O segundo caso tem letra pequena. A ação de webhook envia _model, _id e o nome da ação, e é «lançar e esquecer»: um POST de um segundo, sem nova tentativa. Na 19 sai depois do commit; na 17 e 18 vai dentro da transação, pelo que um n8n lento atrasa o utilizador.

# 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.

Cinco que não, e o motivo exato

  1. Calcular preços ou descontos. O Odoo calcula-os a partir da tarifa; se o fluxo os calcula fora, ao mudar a tarifa há duas verdades.
  2. Reservar stock para vários canais. O Odoo resolve a corrida dentro de uma transação; um fluxo que lê, decide e escreve em separado vende em excesso.
  3. Reconciliar pagamentos. Emparelhar e lançar andam juntos: se um se faz fora e o outro dentro, um corte de rede deixa meia reconciliação.
  4. O que alguém vá auditar. O histórico do n8n não é o chatter: «quem alterou isto e porquê?» responde-se no documento.
  5. O que dependa de um campo que muda entre versões. Comprovámo-lo escrevendo no Odoo 19 o que funcionava na 18.

O caso que melhor o resume: validar uma operação de stock a partir de um fluxo. Preparámos uma de 10 unidades com 4 reservadas e chamámos button_validate, o mesmo que o botão.

# 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, sem erro, e uma operação de stock em assigned. Para o n8n o passo saiu verde; para o armazém, a encomenda não saiu. Um módulo reconhece o assistente e deixa-o registado no documento: a mesma fronteira que em Odoo 19 face aos conectores de middleware.

E os campos que mudam de nome entre versões, o que parte um fluxo estável depois de uma migração:

# 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

Mantemos o mesmo código no Odoo 19, 18 e 17 em 105 módulos publicados: estas diferenças paga-as o módulo, não o cliente. É também o limite do Odoo Studio quando o processo deixa de ser um campo e passa a ser uma regra.

Os quatro erros que vemos sempre

  1. O ciclo. Uma automatização avisa o n8n ao mudar um campo, o fluxo escreve no Odoo e o que foi escrito volta a disparar a automatização. Corta-se com uma condição no disparador.
  2. A credencial em texto simples. Nem no corpo do nó nem num nó de código: numa credencial do n8n, com um utilizador técnico de grupos mínimos.
  3. Sem idempotência. Um webhook repetido do outro lado cria o registo outra vez: três POST idênticos ao nosso fluxo deram três leads.
  4. Sem nova tentativa a sério. Um nó não volta a tentar a menos que ative Retry On Fail, e o motor limita as tentativas a cinco e a espera a cinco segundos. Sobra para um chat; não para uma transportadora: o nosso módulo de Correos Express volta a tentar aos 5, 15, 30, 60, 120 e 240 minutos.

A solução não é do n8n, é de desenho: guarde no Odoo a referência externa e verifique-a antes de criar. Num módulo é uma restrição única na base de dados; num fluxo, uma leitura prévia com janela de corrida.

Quando um fluxo se converte em módulo

O fluxo é uma forma barata de descobrir se o processo merece existir. O sinal de que ficou curto é um destes seis:

  • Escreve um campo que o Odoo calcula por conta própria.
  • Duas escritas têm de ocorrer juntas ou não ocorrer.
  • Alguém vai auditar dentro do Odoo o que aconteceu e quando.
  • O processo tem de sobreviver à próxima migração.
  • É preciso poder repetir a chamada sem duplicar nada.
  • O utilizador precisa de voltar a tentar a partir do próprio documento.

Chegado esse ponto não se deita fora o fluxo: leva-se para o módulo a parte que toca o estado de negócio e o n8n fica com a periferia. Passa-se o mesmo em automatizar tarefas administrativas e na integração com a Signaturit.

Resumo: se o fluxo falha e o único efeito é alguém não receber um aviso, o n8n serve. Se falha e o armazém ou o livro de faturas ficam num estado que ninguém sabe ler, isso era um módulo.

Perguntas frequentes

Posso passar o idioma ou a empresa na chamada?

Pelos três caminhos modernos sim: kwargs.context em call_kw e em execute_kw, e um campo context em /json/2 (um país sai «Spain» com en_US e «España» com es_ES). Não pode com a credencial clássica, que chama execute, posicional.

Onde guardo a chave API e quanto dura?

Numa credencial do n8n, nunca no corpo do nó. No Odoo 19 a chave de um utilizador não administrador precisa de caducidade, e o limite fixa-o o grupo: 90 dias para um utilizador interno.

O meu fluxo parte-se ao migrar do Odoo 18 para o 19?

Depende dos campos em que toque, e não avisa: res.users.groups_id passou a group_ids e stock.move.name, obrigatório na 17 e 18, não existe na 19. Teste os seus fluxos contra uma cópia.

Ligações úteis dentro da FlexigoTech

Serviços de engenharia OdooImplementação e desenvolvimento sobre OdooDesenvolvimento à medidaQuando é preciso um móduloUm conector do Odoo para o seu softwarePara partners tecnológicosSoluções por necessidadeOrdenado por problema, não por móduloOdoo 19 face aos conectores de middlewareA mesma fronteira, um nível acimaO que é o Odoo Studio e como funcionaO outro «sem código» e os seus limitesAutomatizar tarefas administrativasAutomação dentro do ERPAssinatura eletrónica no Odoo com a SignaturitOutro caso em que o fluxo fica curto

O que fazemos sobre isto

Automação com OperariaO que faz, capturas, versões e preço.

Tem fluxos do n8n contra o Odoo e já não sabe quais aguentam?

Revemo-los, dizemos-lhe quais ficam como estão e quais há que levar para um módulo, e fazemos o módulo se for preciso. Escreva para comercial@flexigobe.com ou ligue para o +34 616 809 504.

Falar com um engenheiro