Przejdź do głównej treści
Automatyzacja · n8n i Odoo

n8n i Odoo: co zautomatyzować przepływem, a co wymaga modułu

n8n sprawdza się przy tym, co dzieje się wokół Odoo; to, co zmienia stan biznesu wewnątrz, wymaga modułu. Granica, z JSON-RPC na pierwszym miejscu i rzeczywistymi odpowiedziami z laboratorium z Odoo 19 i n8n 2.30.6.

Panel Odoo: tu trafiają rekordy tworzone przez przepływ n8n i tu sprawdza się, czy powstały poprawnie

n8n służy do tego, co dzieje się wokół Odoo: odebrać zewnętrzny formularz, powiadomić czat, przygotować dzienny raport. To, co zmienia stan biznesu wewnątrz (ceny, rezerwacje zapasów, zatwierdzanie dostaw, uzgadnianie płatności), wymaga modułu. Granicę widać dopiero po uruchomieniu obu rozwiązań na prawdziwym Odoo: ten artykuł powstał w naszym laboratorium z Odoo 19.0-20260630 i n8n 2.30.6.

Kluczowa myśl: przepływ wywołujący API Odoo nie uruchamia jego interfejsu. Może dostać 200 z kreatorem w środku i uznać, że zatwierdził dostawę, która nadal jest otwarta.

Jak n8n rozmawia z Odoo: cztery drogi, nie jedna

  • XML-RPC: /xmlrpc/2/common do uwierzytelnienia i /xmlrpc/2/object dla execute_kw. Ten z dokumentacji.
  • JSON-RPC: POST /jsonrpc z service, method i args. Ta sama usługa w JSON.
  • Sesja webowa: /web/session/authenticate i /web/dataset/call_kw z ciasteczkiem. To, co robi Twoja przeglądarka.
  • API JSON-2, tylko w Odoo 19: POST /json/2/<modelo>/<método> z Authorization: bearer <clave API> i X-Odoo-Database. Bez sesji: argumenty idą jako pola nazwane, context też.

Pierwsze trzy nadal działają w 19, ale serwer ostrzega w logu: „The /xmlrpc, /xmlrpc/2 and /jsonrpc endpoints are deprecated in Odoo 19 and scheduled for removal in Odoo 22”. Nowy przepływ do Odoo 19 powinien korzystać z /json/2; jeśli obsługuje też 17 i 18, z sesji.

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

Węzeł Odoo w n8n 2.30.6 wybiera za Ciebie w zależności od poświadczeń: ten z kluczem API korzysta z /json/2; klasyczny korzysta z /jsonrpc z execute, pozycyjnym, który nie przyjmuje kwargs i nie może przekazać kontekstu. Poświadczenie z kluczem API ostrzega ponadto, że wymaga „Odoo 19+ and a Custom pricing plan”.

Węzeł HTTP Request, dokładnie tak, jak został

Zwróć uwagę, gdzie nie ma klucza: treść zawiera tylko dane, a nagłówek Authorization ustawia poświadczenie n8n, które jest szyfrowane i rotowane osobno.

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

Przepływ nie loguje się też jako administrator, lecz jako użytkownik techniczny z minimalnymi grupami i limitem, jaki Odoo 19 nakłada na jego klucz:

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

Ten limit 90 dni to data, w której Twój przepływ przestanie działać bez udziału kogokolwiek. Zapisz ją w dniu utworzenia klucza.

Pięć automatyzacji, które mieszczą się w przepływie

Wszystkie łączy jedno: fakt już się wydarzył, a przepływ tylko przenosi go w inne miejsce.

PrzypadekWyzwalaczWywołanie Odoo
Lead z zewnętrznego formularzaWebhook n8ncrm.lead / create
Powiadomienie na czacie po zatwierdzeniu dostawyAutomatyzacja Odoo z akcją webhookaBrak: Odoo wypycha dane
Kontakty do narzędzia marketingowegoHarmonogram, co nocres.partner / search_read według write_date
Alert o niskim stanie magazynowymHarmonogram, co ranoproduct.product / search_read z qty_available
Dzienny raport dla zarząduHarmonogramread_group na sale.order

Drugi przypadek ma drobny druk. Akcja webhooka wysyła _model, _id i nazwę akcji, a działa zgodnie z zasadą „wyślij i zapomnij”: POST trwający sekundę, bez ponowienia. W wersji 19 wychodzi po commit; w 17 i 18 odbywa się wewnątrz transakcji, więc wolny n8n opóźnia użytkownika.

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

Pięć, które nie, i dokładny powód

  1. Obliczanie cen lub rabatów. Odoo liczy je z cennika; jeśli przepływ liczy je na zewnątrz, po zmianie cennika są dwie prawdy.
  2. Rezerwowanie zapasów dla wielu kanałów. Odoo rozstrzyga wyścig wewnątrz transakcji; przepływ, który osobno czyta, decyduje i zapisuje, sprzeda więcej, niż jest.
  3. Uzgadnianie płatności. Dopasowanie i zaksięgowanie idą razem: jeśli jedno dzieje się na zewnątrz, a drugie wewnątrz, przerwa w sieci zostawia pół uzgodnienia.
  4. To, co ktoś będzie audytował. Historia n8n to nie chatter: „kto to zmienił i dlaczego?” sprawdza się w dokumencie.
  5. To, co zależy od pola zmieniającego się między wersjami. Sprawdziliśmy to, zapisując w Odoo 19 to, co działało w 18.

Przypadek, który najlepiej to podsumowuje: zatwierdzenie dostawy z przepływu. Przygotowaliśmy dostawę na 10 sztuk z 4 zarezerwowanymi i wywołaliśmy button_validate, czyli to samo, co przycisk.

# 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, bez błędu, i dostawa w assigned. Dla n8n krok wyszedł na zielono; dla magazynu zamówienie nie wyszło. Moduł rozpoznaje kreator i zapisuje to w dokumencie: ta sama granica co w Odoo 19 a konektory middleware.

A pola, które zmieniają nazwę między wersjami, czyli to, co psuje stabilny przepływ po migracji:

# 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

Utrzymujemy ten sam kod w Odoo 19, 18 i 17 w 105 opublikowanych modułach: te różnice pokrywa moduł, nie klient. To także granica Odoo Studio, gdy proces przestaje być polem i staje się regułą.

Cztery błędy, które widzimy zawsze

  1. Pętla. Automatyzacja powiadamia n8n o zmianie pola, przepływ zapisuje w Odoo, a zapis ponownie ją uruchamia. Przerywa się to warunkiem w wyzwalaczu.
  2. Poświadczenie jawnym tekstem. Ani w treści węzła, ani w węźle z kodem: w poświadczeniu n8n, z użytkownikiem technicznym o minimalnych grupach.
  3. Brak idempotencji. Webhook ponowiony po drugiej stronie tworzy rekord jeszcze raz: trzy identyczne POST do naszego przepływu dały trzy leady.
  4. Brak prawdziwego ponowienia. Węzeł nie ponawia, dopóki nie włączysz Retry On Fail, a silnik ogranicza próby do pięciu i oczekiwanie do pięciu sekund. Wystarcza dla czatu, nie dla przewoźnika: nasz moduł Correos Express ponawia po 5, 15, 30, 60, 120 i 240 minutach.

Rozwiązanie nie leży w n8n, lecz w projekcie: zapisz w Odoo zewnętrzny odnośnik i sprawdź go przed utworzeniem. W module to unikalne ograniczenie w bazie danych; w przepływie wcześniejszy odczyt z oknem wyścigu.

Kiedy przepływ staje się modułem

Przepływ to tani sposób, by odkryć, czy proces zasługuje na istnienie. Sygnałem, że okazał się za ciasny, jest jeden z tych sześciu:

  • Zapisuje pole, które Odoo oblicza samo.
  • Dwa zapisy muszą wydarzyć się razem albo wcale.
  • Ktoś będzie audytować w Odoo, co się stało i kiedy.
  • Proces musi przetrwać następną migrację.
  • Wywołanie trzeba móc powtórzyć bez duplikowania czegokolwiek.
  • Użytkownik musi móc ponowić próbę z samego dokumentu.

W tym momencie nie wyrzuca się przepływu: do modułu przenosi się część dotykającą stanu biznesu, a n8n zostaje na brzegu. Tak samo jest przy automatyzacji zadań administracyjnych i w integracji z Signaturit.

Podsumowanie: jeśli przepływ padnie i jedyną konsekwencją jest to, że ktoś nie dostanie powiadomienia, n8n wystarczy. Jeśli padnie, a magazyn lub rejestr faktur zostaną w stanie, którego nikt nie umie odczytać, to był przypadek na moduł.

Najczęstsze pytania

Czy mogę przekazać język lub firmę w wywołaniu?

Trzema nowoczesnymi drogami tak: kwargs.context w call_kw i w execute_kw, a pole context w /json/2 (kraj wychodzi jako „Spain” z en_US i „España” z es_ES). Nie da się tego klasycznym poświadczeniem, które wywołuje execute, pozycyjne.

Gdzie przechowywać klucz API i jak długo działa?

W poświadczeniu n8n, nigdy w treści węzła. W Odoo 19 klucz użytkownika niebędącego administratorem wymaga daty wygaśnięcia, a limit ustala grupa: 90 dni dla użytkownika wewnętrznego.

Czy mój przepływ przestanie działać po migracji z Odoo 18 do 19?

To zależy od pól, których dotyka, i nie ostrzega: res.users.groups_id zmieniło się w group_ids i stock.move.name, obowiązkowe w 17 i 18, nie istnieje w 19. Przetestuj swoje przepływy na kopii.

Przydatne linki w FlexigoTech

Usługi inżynieryjne OdooWdrożenie i rozwój na OdooRozwój na zamówienieGdy potrzebny jest modułKonektor Odoo dla Twojego oprogramowaniaDla partnerów technologicznychRozwiązania według potrzebyUporządkowane według problemu, nie modułuOdoo 19 a konektory middlewareTa sama granica, poziom wyżejCzym jest Odoo Studio i jak działaDrugie „no-code” i jego graniceAutomatyzacja zadań administracyjnychAutomatyzacja wewnątrz ERPPodpis elektroniczny w Odoo z SignaturitKolejny przypadek, w którym przepływ nie wystarcza

Co robimy w tym temacie

Automatyzacja z OperariąCo robi, zrzuty ekranu, wersje i cena.

Masz przepływy n8n działające z Odoo i nie wiesz już, które wytrzymają?

Przeglądamy je, mówimy, które zostają jak są, a które trzeba przenieść do modułu, i tworzymy moduł, jeśli trzeba. Napisz na comercial@flexigobe.com lub zadzwoń pod numer +34 616 809 504.

Porozmawiaj z inżynierem