Agent gériatre B) le moteur de scoring > Où inscrire ça dans Odoo ?
1️⃣ Où inscrire ça dans Odoo ?
Je te conseille un modèle dédié “Entretien gériatrique” relié au patient.
🔹 Modèle principal
- Nom modèle technique : x_synergia_geriatrie_entretien
- Module de base : Contacts (et éventuellement CRM / Helpdesk si tu veux des tickets)
-
Relations clés :
- patient_id → res.partner (le senior)
- responsable_id → res.users ou res.partner (pharmacien / infirmier / coordinateur)
- un entretien = un JSON “figé” + scores
Tu pourras ensuite voir :
- onglet “Gériatrie” sur la fiche contact ODOO (patient)
- liste des entretiens gériatriques par patient
- filtres : niveau de risque, alertes actives, etc.
2️⃣ Mapping JSON → Odoo (Odoo Studio)
a) JSON de départ
{ "profil": { "age": 82, "habitat": "seul", "aidant": true }, "scores": { "autonomie": 55, "cognitif": 40, "chute": 80, "nutrition": 60, "moral": 65 }, "fragilite_globale": 68, "niveau_risque": "élevé", "alertes": ["chute", "isolement", "oubli traitement"], "recommandations": [ "aménagement salle de bain", "visite infirmière", "bilan gériatrique", "appel de suivi hebdomadaire" ] }
b) Champs à créer dans x_synergia_geriatrie_entretien
| JSON path | Champ Odoo | Type Odoo | Commentaire |
|---|---|---|---|
| profil.age | x_age | Integer | Âge au moment de l’entretien (snapshot) |
| profil.habitat | x_habitat | Selection | Valeurs : seul, conjoint, famille, institution… |
| profil.aidant | x_has_aidant | Boolean | “Aidant identifié (oui/non)” |
| (lié patient) | x_patient_id | Many2one res.partner | Le senior concerné |
| (évaluateur) | x_responsable_id | Many2one res.users ou res.partner | Pharmacien / infirmier / coordinateur |
| scores.autonomie | x_score_autonomie | Integer | 0–100 |
| scores.cognitif | x_score_cognitif | Integer | 0–100 |
| scores.chute | x_score_chute | Integer | 0–100 |
| scores.nutrition | x_score_nutrition | Integer | 0–100 |
| scores.moral | x_score_moral | Integer | 0–100 |
| fragilite_globale | x_fragilite_globale | Integer | Score global 0–100 |
| niveau_risque | x_niveau_risque | Selection | faible / modéré / élevé |
| alertes (liste) | x_alertes_json | Text | Stocker la liste JSON brute (facile côté API) |
| recommandations (liste) | x_recommandations_text | Text (multiligne) | Reco lisibles pour humain |
| (trace brute entretien) | x_raw_payload_json | Text | Optionnel : stocker tout le JSON d’origine |
| (date entretien) | x_date_entretien | Datetime | Pour l’historique / tri |
| (canal : voix / texte) | x_canal | Selection | voix / texte / mixte |
Simple & Odoo Online-friendly : on garde les listes (alertes, recommandations) en TEXT/JSON. Tu pourras les normaliser en modèles dédiés plus tard si besoin (tags, etc.).
c) Mise en forme dans l’interface
Avec Odoo Studio :
-
Vue formulaire “Entretien gériatrique”
- En haut : patient, date, niveau de risque (badge coloré)
- Bloc “Scores” avec jauges ou au moins champs numériques
- Bloc “Alertes” (zone texte + tags visuels)
- Bloc “Recommandations” (multi-ligne, lisible pour le pharmacien / infirmier)
-
Vue liste :
- Colonnes : Patient, Date, Niveau_risque, Score global, Nb d’alertes
- Filtre rapide : Risque élevé uniquement
-
Sur fiche Contact (patient) :
- Onglet “Synergia Senior / Gériatrie”
- Smart button : “Entretiens gériatriques (N)”
3️⃣ Organisation avec n8n : le bot dans la boucle
🧩 Idée générale
- Le bot / WebApp collecte l’entretien (voix/texte).
- Le moteur d’IA + scoring produit le JSON ci-dessus.
- n8n reçoit ce JSON → le transforme → l’injecte dans Odoo via API.
-
n8n peut ensuite :
- créer des activités / tâches,
- déclencher notifications,
- alimenter des dashboards.
🔁 Flow n8n type
Node 1 – Webhook “Entretien gériatrique terminé”
- Type : Webhook
- Méthode : POST
- Reçoit un body ≈ ton JSON :
{ "patient_external_id": "PAT-000123", "entretien": { "profil": {...}, "scores": {...}, "fragilite_globale": 68, "niveau_risque": "élevé", "alertes": [...], "recommandations": [...] } }
Node 2 – Function (mapping vers Odoo)
En JS dans n8n, tu prépares le payload pour Odoo :
const body = items[0].json.entretien; const patientExtId = items[0].json.patient_external_id; // Exemple : on suppose que patient_external_id = ref dans res.partner return [{ json: { model: "x_synergia_geriatrie_entretien", values: { x_patient_id: { ref: patientExtId }, // ou un id numérique résolu avant x_age: body.profil.age, x_habitat: body.profil.habitat, x_has_aidant: body.profil.aidant, x_score_autonomie: body.scores.autonomie, x_score_cognitif: body.scores.cognitif, x_score_chute: body.scores.chute, x_score_nutrition: body.scores.nutrition, x_score_moral: body.scores.moral, x_fragilite_globale: body.fragilite_globale, x_niveau_risque: body.niveau_risque, x_alertes_json: JSON.stringify(body.alertes || []), x_recommandations_text: (body.recommandations || []).join("\n"), x_raw_payload_json: JSON.stringify(body), x_date_entretien: new Date().toISOString(), x_canal: items[0].json.canal || "texte" } } }];
(À adapter selon ta stratégie d’identification patient : id direct, ref, email, etc.)
Node 3 – HTTP Request → Odoo /web/dataset/call_kw
- Méthode : POST
- URL : https://ton_instance.odoo.com/web/dataset/call_kw
- Body JSON (exemple) :
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "x_synergia_geriatrie_entretien", "method": "create", "args": [ { "x_patient_id": 123, "x_age": 82, "x_habitat": "seul", "x_has_aidant": true, "x_score_autonomie": 55, "x_score_cognitif": 40, "x_score_chute": 80, "x_score_nutrition": 60, "x_score_moral": 65, "x_fragilite_globale": 68, "x_niveau_risque": "élevé", "x_alertes_json": "[\"chute\",\"isolement\"]", "x_recommandations_text": "aménagement salle de bain\nvisite infirmière", "x_raw_payload_json": "{...}", "x_date_entretien": "2025-11-27T14:00:00", "x_canal": "voix" } ], "kwargs": {} } }
Auth : session Odoo ou token API (selon ce que tu mets en place).
Dans n8n : soit en Basic Auth si reverse proxy, soit cookie de session, soit Bearer si tu as un module d’API.
Node 4 – Règles et notifications
Tu peux enchaîner avec :
-
IF node : si fragilite_globale >= 67 ou niveau_risque == "élevé"
- Node : envoyer un email au pharmacien
- Node : créer une Activité sur le patient dans Odoo (modèle mail.activity)
- Node : ping sur un canal Slack / Teams “Risque élevé détecté”
4️⃣ En résumé (stratégie)
- Odoo Studio
- Créer x_synergia_geriatrie_entretien
- Ajouter tous les champs du JSON (profil, scores, fragilité, alertes, recos, raw JSON)
- Lier au patient (Many2one res.partner)
- Ajouter un onglet “Gériatrie” sur la fiche patient
-
n8n
- Webhook ← reçoit le JSON de ton agent IA
- Function → mappe vers values Odoo
- HTTP Request → create dans x_synergia_geriatrie_entretien
- IF → déclenche des actions (email, activité, etc.)
-
Bot
- Continue à faire la conversation, scoring, etc.
- n8n devient la colonne vertébrale d’intégration entre ton bot et Odoo.
ANNEXES
A1- tableau complet des champs Odoo Studio “prêt à créer” (nom technique, label FR, type, aide),
Parfait, on passe en mode Odoo Studio ready 🧩
Voici le tableau complet des champs à créer pour le modèle x_synergia_geriatrie_entretien, couvrant tout ton JSON + ce qu’il faut pour travailler confortablement dans Odoo.
💡 Tu pourras regrouper ces champs en onglets “Profil”, “Scores”, “Alertes & recommandations”, “Technique” dans la vue formulaire.
🧱 Modèle Odoo
- Nom technique du modèle : x_synergia_geriatrie_entretien
- Nom affiché : Entretien gériatrique
- Base : module Contacts (lié à res.partner)
📋 Tableau des champs Odoo Studio
| Section | Label FR | Nom technique | Type Odoo | Requis | Valeurs / Domaine | Aide (tooltip) |
|---|---|---|---|---|---|---|
| 🔗 Identification / liens | Intitulé de l’entretien | x_name | Texte (Char) | Non | – | Titre court de l’entretien (ex. “Entretien gériatrique de novembre 2025”). |
| 🔗 Identification / liens | Patient | x_patient_id | Many2one → res.partner | Oui | Domain : contact de type “personne” | Patient concerné par cet entretien. |
| 🔗 Identification / liens | Responsable Synergia | x_responsable_id | Many2one → res.users ou res.partner | Non | – | Professionnel ayant conduit ou validé l’entretien (pharmacien, infirmier, coordinateur…). |
| 🔗 Identification / liens | Date de l’entretien | x_date_entretien | Datetime | Oui | – | Date et heure de réalisation de l’entretien. |
| 🔗 Identification / liens | Canal d’entrée | x_canal | Sélection | Non | voix, texte, mixte | Canal principal utilisé par le patient (voix / texte). |
| 👤 Profil | Âge au moment de l’entretien | x_age | Entier (Integer) | Non | – | Âge du patient au moment de l’entretien (photo instantanée). |
| 👤 Profil | Habitat | x_habitat | Sélection | Non | seul, conjoint, famille, institution, autre | Situation de vie principale du patient. |
| 👤 Profil | Aidant identifié | x_has_aidant | Booléen | Non | – | Cocher si un aidant (proche, voisin, professionnel) est identifié. |
| 📊 Scores | Score autonomie | x_score_autonomie | Entier | Non | 0–100 | Score 0–100 calculé à partir des réponses sur les activités de la vie quotidienne. |
| 📊 Scores | Score cognitif | x_score_cognitif | Entier | Non | 0–100 | Score 0–100 estimant le risque de troubles cognitifs. |
| 📊 Scores | Score risque de chute | x_score_chute | Entier | Non | 0–100 | Score 0–100 pour le risque de chute (chutes, peur de tomber, blessures…). |
| 📊 Scores | Score nutrition | x_score_nutrition | Entier | Non | 0–100 | Score 0–100 relatif au risque de dénutrition / hydratation insuffisante. |
| 📊 Scores | Score moral / psycho-social | x_score_moral | Entier | Non | 0–100 | Score 0–100 sur l’isolement, le moral, la perte d’intérêt. |
| 📊 Scores | Score global de fragilité | x_fragilite_globale | Entier | Non | 0–100 | Score global agrégé de fragilité gériatrique. |
| 📊 Scores | Niveau de risque global | x_niveau_risque | Sélection | Non | faible, modere, eleve | Catégorie globale : faible / modéré / élevé (dérivée du score global). |
| 🚨 Alertes & recommandations | Alertes (JSON brut) | x_alertes_json | Texte (Text) | Non | – | Liste JSON des alertes générées par l’IA (ex. ["chute","isolement","oubli traitement"]). |
| 🚨 Alertes & recommandations | Alertes (lecture humaine) | x_alertes_label | Texte (Text) ou Char | Non | – | Version lisible des alertes (ex. “Risque de chute ; Isolement ; Oubli de traitement”). |
| 🚨 Alertes & recommandations | Recommandations (texte) | x_recommandations_text | Texte (Text, multi-ligne) | Non | – | Synthèse des recommandations : aménagement, visites, bilans, appels de suivi… |
| 🛠 Technique / audit | Payload JSON brut | x_raw_payload_json | Texte (Text) | Non | – | JSON complet renvoyé par le moteur d’IA (pour audit ou recalcul). |
| 🛠 Technique / audit | Référence externe (entretien bot) | x_external_ref | Texte (Char) | Non | – | Identifiant de l’entretien côté WebApp / bot / n8n (trace technique, corrélation). |
🧭 Comment les utiliser dans Odoo Studio (concrètement)
-
Créer le modèle
- Ouvrir Contacts → Studio → Nouveau modèle → “Entretien gériatrique”
- Nom technique : x_synergia_geriatrie_entretien
-
Créer les champs selon le tableau
- Respecter les noms techniques (colonne Nom technique)
- Utiliser les types indiqués
- Pour les sélections, saisir exactement les valeurs proposées (clé technique en minuscules, sans accent de préférence).
-
Lier au patient
- Champ x_patient_id (Many2one → Contact)
- Dans la fiche Contact : ajouter un smart button “Entretiens gériatriques” et/ou un onglet “Gériatrie” qui liste les enregistrements de x_synergia_geriatrie_entretien.
-
Préparer l’injection via n8n / API
-
Ton flow n8n fera un create sur x_synergia_geriatrie_entretien en mappant le JSON :
- profil.age → x_age
- scores.autonomie → x_score_autonomie
- etc. (champ par champ, le mapping est 1:1 grâce à ce tableau).
-
Ton flow n8n fera un create sur x_synergia_geriatrie_entretien en mappant le JSON :
A2- exemple de flow n8n écrit “node par node” que tu peux reconstituer.
Parfait, on passe en mode n8n architecte 🧠⚙️
Je te propose un flow complet ultra simple :
- le bot envoie le JSON d’entretien →
- n8n le reçoit →
- crée l’enregistrement x_synergia_geriatrie_entretien dans Odoo →
- envoie une alerte si risque élevé.
Je pars sur le cas le plus simple et robuste :
👉 le front / bot envoie déjà patient_id (id Odoo) dans le POST.
🔁 Flow n8n : “Synergia – Enregistrement entretien gériatrique dans Odoo”
🌐 Node 1 – Webhook “Entretien gériatrique terminé”
- Type : Webhook
- Nom : Webhook – Entretien gériatrique
- Méthode : POST
- Path : /synergia/geriatrie/entretien
-
Response :
- Mode : On Received
- Body : application/json
- Réponse basique : { "status": "received" }
Body attendu (exemple) côté bot
{ "patient_id": 123, // ID Odoo du patient (res.partner) "canal": "voix", // "voix" | "texte" | "mixte" "entretien": { "profil": { "age": 82, "habitat": "seul", "aidant": true }, "scores": { "autonomie": 55, "cognitif": 40, "chute": 80, "nutrition": 60, "moral": 65 }, "fragilite_globale": 68, "niveau_risque": "élevé", "alertes": ["chute", "isolement", "oubli traitement"], "recommandations": [ "aménagement salle de bain", "visite infirmière", "bilan gériatrique", "appel de suivi hebdomadaire" ] } }
🧮 Node 2 – Function “Build Odoo Payload”
- Type : Function
- Nom : Build Odoo Payload
Ce node transforme le JSON d’entrée en un payload Odoo propre pour call_kw.
Code
const input = items[0].json; const patientId = input.patient_id; const canal = input.canal || "texte"; const body = input.entretien || {}; const profil = body.profil || {}; const scores = body.scores || {}; const alertes = body.alertes || []; const recommandations = body.recommandations || []; return [ { json: { jsonrpc: "2.0", method: "call", params: { model: "x_synergia_geriatrie_entretien", method: "create", args: [ { x_patient_id: patientId, x_age: profil.age || null, x_habitat: profil.habitat || null, x_has_aidant: !!profil.aidant, x_score_autonomie: scores.autonomie ?? null, x_score_cognitif: scores.cognitif ?? null, x_score_chute: scores.chute ?? null, x_score_nutrition: scores.nutrition ?? null, x_score_moral: scores.moral ?? null, x_fragilite_globale: body.fragilite_globale ?? null, x_niveau_risque: body.niveau_risque || null, x_alertes_json: JSON.stringify(alertes), x_alertes_label: alertes.join(" ; "), x_recommandations_text: recommandations.join("\n"), x_raw_payload_json: JSON.stringify(body), x_date_entretien: new Date().toISOString(), x_canal: canal, // Optionnel : titre lisible x_name: `Entretien gériatrique – patient #${patientId}` } ], kwargs: {} } } } ];
👉 Après ce node, items[0].json est directement le body JSON à envoyer à Odoo sur /web/dataset/call_kw.
🧷 Node 3 – HTTP Request “Odoo – Create Entretien”
🧷 Node 3 – HTTP Request “Odoo – Create Entretien”
- Type : HTTP Request
- Nom : Odoo – Create Entretien
- Méthode : POST
- URL : https://TON_INSTANCE.odoo.com/web/dataset/call_kw
Authentification
Selon ton setup :
- soit Basic Auth (proxy devant Odoo),
- soit API Key / Bearer en Header,
- soit cookie de session si tu sais le gérer dans n8n.
Exemple simple (Headers) :
- Header : Content-Type: application/json
- Header : X-Api-Key: TON_TOKEN (si tu as un module API)
Body
- Content Type : JSON
- Body : {{ JSON.stringify($json) }}
Le $json ici est exactement celui généré dans le node précédent.
Réponse Odoo
En général :
{ "jsonrpc": "2.0", "id": null, "result": 456 // ID de l'entretien créé }
Tu peux récupérer entretien_id = $json.result dans le node suivant.
🚨 Node 4 – IF “High Risk ?”
🚨 Node 4 – IF “High Risk ?”
- Type : IF
- Nom : IF – Risque élevé ?
On veut déclencher des actions si risque fort.
Comme le JSON original est sur le Webhook, on a deux options :
- soit on rebranche le Webhook sur l’IF via un second output,
- soit on passe les infos utiles via meta (simplifions).
Le plus simple : on branche l’IF juste après le Webhook, en parallèle du Flow “Odoo”.
Configuration de l’IF
-
Condition 1 :
- Value 1 : {{$json.entretien.fragilite_globale}}
- Operation : larger
- Value 2 : 66
- OU
-
Condition 2 :
- Value 1 : {{$json.entretien.niveau_risque}}
- Operation : equal
- Value 2 : élevé
Tu peux cocher “Combine” → Any (au moins une des conditions vraie).
✉️ Node 5 (branche TRUE) – Notification (ex: Email)
5a – Email “Alerte gériatrique”
- Type : Email
- Nom : Email – Alerte risque élevé
-
Config :
- To : adresse du pharmacien / coordinateur, ou liste.
- Subject : Alerte Synergia – Risque gériatrique élevé
- Body (HTML ou texte) :
Un entretien gériatrique signale un niveau de risque élevé. Patient ID Odoo : {{ $json.patient_id }} Score global de fragilité : {{ $json.entretien.fragilite_globale }} Niveau de risque : {{ $json.entretien.niveau_risque }} Alertes : {{ $json.entretien.alertes.join(", ") }} Recommandations proposées : {{ $json.entretien.recommandations.join("\n") }}
5b – (option) HTTP Request “Odoo – Créer activité”
Si tu veux aussi créer une activité de suivi sur le patient :
- Type : HTTP Request
- Nom : Odoo – Create Activity
- URL : https://TON_INSTANCE.odoo.com/web/dataset/call_kw
- Body (exemple, modèle mail.activity) :
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "mail.activity", "method": "create", "args": [ { "res_model": "res.partner", "res_id": {{ $json.patient_id }}, "activity_type_id": 1, "summary": "Suivi gériatrique – risque élevé", "note": "Un entretien gériatrique a détecté un risque élevé.\nScore global : " + {{ $json.entretien.fragilite_globale }} + "\nAlertes : " + {{ $json.entretien.alertes.join(", ") }} } ], "kwargs": {} } }
(tu adapteras activity_type_id en fonction de ta config Odoo)
🧱 Vue d’ensemble du flow
-
Webhook – Entretien gériatrique
↳ reçoit le JSON depuis ton bot. -
[Branche A]
2.1. Build Odoo Payload
2.2. Odoo – Create Entretien -
[Branche B] (en parallèle)
3.1. IF – Risque élevé ?
3.2. Si vrai → Email – Alerte risque élevé (+ optionnel Odoo – Create Activity)
flow mais dans le cas où tu ne connais PAS patient_id et tu dois d’abord faire un search_read sur res.partner à partir d’un external_ref ou d’un email.
Parfait, on passe à la version “réaliste” : tu ne connais pas patient_id, tu as juste une référence externe (ex. external_ref) ou un email.
On va faire :
- Webhook reçoit le JSON (avec patient_external_ref ou patient_email)
- n8n fait un search_read sur res.partner pour trouver le patient
- récupère id
- crée l’x_synergia_geriatrie_entretien dans Odoo
- en parallèle : IF risque élevé → alertes
🧩 0. Payload côté bot (entrante)
On suppose que ton bot envoie un truc du genre :
{ "patient_external_ref": "PAT-000123", // ou null "patient_email": "jeanne.dupont@example.com", // fallback "canal": "voix", "entretien": { "profil": { "age": 82, "habitat": "seul", "aidant": true }, "scores": { "autonomie": 55, "cognitif": 40, "chute": 80, "nutrition": 60, "moral": 65 }, "fragilite_globale": 68, "niveau_risque": "élevé", "alertes": ["chute", "isolement", "oubli traitement"], "recommandations": [ "aménagement salle de bain", "visite infirmière", "bilan gériatrique", "appel de suivi hebdomadaire" ] } }
👉 Pas de patient_id ici.
🌐 Node 1 – Webhook “Entretien gériatrique”
Identique au flow précédent, sauf que le body n’a plus patient_id.
On garde le même path : /synergia/geriatrie/entretien.
🔍 Node 2 – Function “Build Search Patient Query”
On prépare le domain pour search_read Odoo sur res.partner.
- Type : Function
- Nom : Build Patient Search Query
Code
const input = items[0].json; const externalRef = input.patient_external_ref || null; const email = input.patient_email || null; if (!externalRef && !email) { throw new Error("Aucun identifiant patient fourni (external_ref ou email manquant)."); } // On prépare le domain pour Odoo let domain; if (externalRef) { // Suppose qu'on utilise un champ x_external_ref sur res.partner domain = [["x_external_ref", "=", externalRef]]; } else { domain = [["email", "=", email]]; } return [ { json: { domain, original: input // on garde le payload original pour la suite } } ];
🧵 Node 3 – HTTP Request “Odoo – search_read Patient”
- Type : HTTP Request
- Nom : Odoo – search_read Patient
- Méthode : POST
- URL : https://TON_INSTANCE.odoo.com/web/dataset/call_kw
- Headers : Content-Type: application/json (+ auth comme d’habitude)
Body (JSON)
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "res.partner", "method": "search_read", "args": [ {{ $json.domain }}, ["id", "name", "email", "x_external_ref"] ], "kwargs": { "limit": 2 } } }
Dans n8n, tu écris le body comme :
return JSON.stringify({ jsonrpc: "2.0", method: "call", params: { model: "res.partner", method: "search_read", args: [ $json.domain, ["id", "name", "email", "x_external_ref"] ], kwargs: { limit: 2 } } });
⚠️ limit: 2 permet de détecter les doublons (0, 1 ou >1 résultats).
✅ Node 4 – Function “Extract Patient ID”
On récupère le résultat de search_read et on gère les cas :
- 0 résultat → erreur / log / pas d’insertion
- 1 résultat → ok
-
1 résultat → au choix : prendre le 1er ou lever une alerte
- Type : Function
- Nom : Extract Patient ID
Code
// items[0].json contient la réponse d'Odoo const res = items[0].json; const result = res.result || []; if (!Array.isArray(result)) { throw new Error("Réponse Odoo inattendue sur search_read"); } if (result.length === 0) { throw new Error("Aucun patient trouvé pour ce critère (external_ref / email)."); } if (result.length > 1) { // Selon stratégie : ici on prend le premier, mais tu peux aussi throw // throw new Error("Plusieurs patients trouvés, ambiguïté."); console.warn("Plusieurs patients trouvés, premier utilisé."); } const patient = result[0]; const patientId = patient.id; // On récupère aussi le payload original du Webhook. // Astuce : on le passait dans "original" depuis le node 2. // Donc on doit l’avoir dans un autre branchement… // Simplifions : on va supposer que tu rebranches le Webhook sur ce node // via un Merge node. Je te donne la version “après Merge” : // Ici, on va supposer que tu merges "search_read" avec "originalPayload" plus loin. // Donc ce node ne garde que patientId pour l'instant. return [ { json: { patient_id: patientId, patient_name: patient.name, patient_email: patient.email, patient_external_ref: patient.x_external_ref || null } } ];
👉 Pour être propre, on va utiliser un Merge Node ensuite pour fusionner :
- le patient_id trouvé
- le payload original d’entretien reçu au Webhook
🔗 Node 5 – Merge “Patient + Entretien”
On a 2 branches qui remontent ici :
- Branche A : depuis le Webhook (payload original)
- Branche B : depuis Extract Patient ID (patient info)
- Type : Merge
- Mode : Merge by Index (simple, un seul item dans chaque branche)
- Nom : Merge – Patient + Entretien
Résultat attendu :
{ "patient_id": 123, "patient_name": "Jeanne Dupont", "patient_email": "jeanne.dupont@example.com", "patient_external_ref": "PAT-000123", "entretien": { ... }, "canal": "voix" }
Tu peux y arriver en branchant :
- Sortie du Webhook → Input 1 du Merge
- Sortie du node “Extract Patient ID” → Input 2 du Merge
🧮 Node 6 – Function “Build Odoo Entretien Payload”
C’est l’équivalent du Build Odoo Payload d’avant, mais sur la base du JSON fusionné.
- Type : Function
- Nom : Build Odoo Entretien Payload
Code
const input = items[0].json; const patientId = input.patient_id; const canal = input.canal || "texte"; const body = input.entretien || {}; const profil = body.profil || {}; const scores = body.scores || {}; const alertes = body.alertes || []; const recommandations = body.recommandations || []; return [ { json: { jsonrpc: "2.0", method: "call", params: { model: "x_synergia_geriatrie_entretien", method: "create", args: [ { x_patient_id: patientId, x_age: profil.age || null, x_habitat: profil.habitat || null, x_has_aidant: !!profil.aidant, x_score_autonomie: scores.autonomie ?? null, x_score_cognitif: scores.cognitif ?? null, x_score_chute: scores.chute ?? null, x_score_nutrition: scores.nutrition ?? null, x_score_moral: scores.moral ?? null, x_fragilite_globale: body.fragilite_globale ?? null, x_niveau_risque: body.niveau_risque || null, x_alertes_json: JSON.stringify(alertes), x_alertes_label: alertes.join(" ; "), x_recommandations_text: recommandations.join("\n"), x_raw_payload_json: JSON.stringify(body), x_date_entretien: new Date().toISOString(), x_canal: canal, x_name: `Entretien gériatrique – ${input.patient_name || ("patient #" + patientId)}` } ], kwargs: {} } } } ];
🧷 Node 7 – HTTP Request “Odoo – Create Entretien”
Identique à avant :
- Type : HTTP Request
- Nom : Odoo – Create Entretien
- Méthode : POST
- URL : https://TON_INSTANCE.odoo.com/web/dataset/call_kw
- Body : {{ JSON.stringify($json) }}
- Headers : Content-Type: application/json + auth
🚨 Branche risque élevé : IF + Email (en parallèle)
Comme précédemment, tu peux faire :
- Sortie du Merge ou du Webhook → IF – Risque élevé ?
- Puis Email – Alerte gériatrique + éventuellement Odoo – Create Activity
Node IF – “Risque élevé ?”
- Type : IF
- Nom : IF – Risque élevé ?
Conditions :
-
{{$json.entretien.fragilite_globale}} > 66
OU - {{$json.entretien.niveau_risque}} equal élevé
Node Email – “Alerte risque élevé”
Exemple de corps :
Alerte Synergia : risque gériatrique élevé détecté. Patient externe : {{ $json.patient_external_ref || 'N/A' }} Email patient : {{ $json.patient_email || 'N/A' }} Score global de fragilité : {{ $json.entretien.fragilite_globale }} Niveau de risque : {{ $json.entretien.niveau_risque }} Alertes : {{ $json.entretien.alertes.join(", ") }} Merci de vérifier la situation et de planifier un suivi.
🧱 Résumé des nodes dans l’ordre logique
- Webhook – Entretien gériatrique
- Function – Build Patient Search Query
- HTTP – Odoo search_read Patient
- Function – Extract Patient ID
- Merge – Patient + Entretien
- Function – Build Odoo Entretien Payload
- HTTP – Odoo Create Entretien
En parallèle depuis le Webhook ou le Merge :
- IF – Risque élevé ?
- Email – Alerte (+ optionnel : HTTP – Odoo Create Activity)
ANNEXE
Décrire les champs res.partner à prévoir (ex. x_external_ref, “type patient”, etc.),
Excellent choix — la qualité de votre modèle res.partner conditionne toute la robustesse du système (reconnaissance patient, historique, IA, RGPD, interopérabilité).
Voici donc le modèle patient Odoo idéal pour Synergia Senior : minimal mais structurant.
🧩 res.partner — Champs à prévoir dans Odoo Studio
(Fiche patient enrichie — base de tout le système gériatrique)
🎯 Objectifs du modèle
Votre fiche Contact devient :
- une identité patient stable,
- une clé d’interopérabilité avec vos apps (bot, web, téléphone),
- un point d’ancrage pour les entretiens, scores, alertes,
- une base RGPD propre.
✅ Champs obligatoires (fondation technique)
| Label FR | Nom technique | Type Odoo | Requis | Utilité |
|---|---|---|---|---|
| Identifiant externe patient | x_external_ref | Char | ✅ | ID unique venant du bot / mobile / système externe |
| Type de contact | x_contact_type | Selection | ✅ | patient, aidant, professionnel, etablissement |
| Consentement entretien IA | x_consent_ai | Boolean | ✅ | Autorisation légale entretien IA |
| Autorisation stockage données | x_consent_data | Boolean | ✅ | RGPD : accord stockage |
| Date consentement | x_consent_date | Datetime | ✅ | Trace légale |
| Canal préféré | x_preferred_channel | Selection | Non | voix, sms, email, whatsapp, app |
| Langue préférée | x_language | Selection | Non | fr, mg, en, etc. |
🧬 Identity & démographie
| Label FR | Nom technique | Type Odoo | Commentaire |
|---|---|---|---|
| Date de naissance | birthdate_date | Date | Champ standard Odoo |
| Sexe | x_gender | Selection | homme, femme, autre |
| Situation familiale | x_family_status | Selection | seul, couple, famille, institution |
| Nationalité | x_nationality | Char | Optionnel |
| Langue maternelle | x_native_language | Char | Utile pour API voix |
🏠 Habitat & contexte de vie
| Label FR | Nom technique | Type |
|---|---|---|
| Type d’habitat | x_housing_type | Selection |
| Présence d’escaliers | x_has_stairs | Boolean |
| Type de logement | x_home_type | Selection |
| Vit seul | x_living_alone | Boolean |
| Vit en zone isolée | x_geo_isolated | Boolean |
❤️ Santé & dépendance (haut niveau)
| Label FR | Nom technique | Type |
|---|---|---|
| Affection de longue durée (ALD) | x_has_ald | Boolean |
| Niveau de dépendance | x_dependency_level | Selection (autonome, fragile, dependent) |
| Mobilité | x_mobility_level | Selection |
| Troubles cognitifs connus | x_known_cognitive_issue | Boolean |
| Chutes récentes | x_recent_falls | Boolean |
⚠️ Ces champs sont déclaratifs, pas médicaux (conformité réglementaire).
👪 Aidants & entourage
| Label FR | Nom technique | Type |
|---|---|---|
| Aidant principal | x_main_caregiver_id | Many2one → res.partner |
| Type de relation | x_caregiver_relation | Selection |
| Présence d’aidant | x_has_caregiver | Boolean |
| Aidant épuisé (signalé) | x_caregiver_burnout | Boolean |
🔗 Interopérabilité & systèmes
| Label FR | Nom technique | Type |
|---|---|---|
| Compte bot lié | x_bot_account_id | Char |
| ID téléphone système | x_telephony_id | Char |
| Origine des données | x_data_source | Selection (bot, pharmacie, infirmier, web, import) |
| Dernier entretien IA | x_last_ai_interview | Datetime |
| Score dernière fragilité | x_last_fragility_score | Integer |
| Niveau dernier risque | x_last_risk_level | Selection |
🔐 Conformité RGPD & audit
| Label FR | Nom technique | Type |
|---|---|---|
| Traitement autorisé | x_data_processing_ok | Boolean |
| ACL niveau | x_access_level | Selection |
| Date dernière mise à jour données | x_last_data_update | Datetime |
| Source du dernier consentement | x_consent_source | Selection |
✅ Champs minimum viables (MVP)
Si tu veux démarrer vite et propre, crée d’abord ces 10 champs essentiels :
| Champ | Nom technique |
|---|---|
| ID externe | x_external_ref |
| Type contact | x_contact_type |
| Consentement IA | x_consent_ai |
| Consentement data | x_consent_data |
| Date consentement | x_consent_date |
| Canal préféré | x_preferred_channel |
| Langue | x_language |
| Aidant présent | x_has_caregiver |
| Dernier score | x_last_fragility_score |
| Dernier risque | x_last_risk_level |
🔁 Chauffage automatique via n8n
Après chaque entretien gériatrique, n8n pourra :
Mettre à jour res.partner automatiquement :
write res.partner: x_last_ai_interview = now() x_last_fragility_score = fragilite_globale x_last_risk_level = niveau_risque
Et éventuellement :
si risque élevé: x_dependency_level = "fragile"
✅ Vision cible
Avec ces champs :
- Odoo devient votre DMP patient senior (mini dossier médico-social),
- n8n devient votre orchestrateur,
- l’IA devient votre capteur humain.
Si vous voulez, je peux maintenant vous livrer :
✅ le mapping JSON → res.partner write prêt pour n8n
✅ les vues Odoo Studio recommandées (onglet “Synergia Senior”)
✅ le schéma global architecture Synergia Senior (bot → n8n → Odoo)
✅ un module prédictif basé sur l’évolution des scores
Dis-moi ce que tu veux prendre ensuite 👇
Faire un “mini schéma JSON-RPC Odoo global” pour toute la chaîne (bot → n8n → Odoo),
Parfait, on va faire un “mini schéma contractuel” de tout le pipeline, côté JSON & JSON-RPC Odoo.
Je te le découpe en 4 blocs :
- Contrat bot → n8n (Webhook)
- Appels JSON-RPC Odoo : res.partner.search_read
- Appels JSON-RPC Odoo : x_synergia_geriatrie_entretien.create
- Appels JSON-RPC Odoo : res.partner.write (mise à jour patient)
1️⃣ Contrat bot → n8n (Webhook)
1.1. URL Webhook n8n
POST https://ton-n8n.com/webhook/synergia/geriatrie/entretien Content-Type: application/json
1.2. Body JSON attendu
{ "patient_external_ref": "PAT-000123", // option 1 (préférée) "patient_email": "jeanne.dupont@example.com", // option 2 (fallback) "canal": "voix", // "voix" | "texte" | "mixte" "entretien": { "profil": { "age": 82, "habitat": "seul", "aidant": true }, "scores": { "autonomie": 55, "cognitif": 40, "chute": 80, "nutrition": 60, "moral": 65 }, "fragilite_globale": 68, "niveau_risque": "élevé", "alertes": ["chute", "isolement", "oubli traitement"], "recommandations": [ "aménagement salle de bain", "visite infirmière", "bilan gériatrique", "appel de suivi hebdomadaire" ] } }
👉 n8n reçoit toujours ce format.
Ensuite il décide :
- trouver le patient dans Odoo
- créer l’entretien
- éventuellement mettre à jour res.partner.
2️⃣ JSON-RPC Odoo – res.partner.search_read
Objectif : retrouver patient_id à partir de x_external_ref ou email.
2.1. URL & headers
POST https://ton-instance.odoo.com/web/dataset/call_kw Content-Type: application/json ( + Auth : selon ton setup )
2.2. search_read par x_external_ref
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "res.partner", "method": "search_read", "args": [ [["x_external_ref", "=", "PAT-000123"]], ["id", "name", "email", "x_external_ref"] ], "kwargs": { "limit": 2 } } }
2.3. search_read par email (fallback)
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "res.partner", "method": "search_read", "args": [ [["email", "=", "jeanne.dupont@example.com"]], ["id", "name", "email", "x_external_ref"] ], "kwargs": { "limit": 2 } } }
2.4. Réponse attendue
{ "jsonrpc": "2.0", "id": null, "result": [ { "id": 123, "name": "Jeanne Dupont", "email": "jeanne.dupont@example.com", "x_external_ref": "PAT-000123" } ] }
👉 n8n extrait patient_id = result[0].id.
3️⃣ JSON-RPC Odoo – x_synergia_geriatrie_entretien.create
Objectif : créer un enregistrement d’entretien avec les champs Studio que tu as définis.
3.1. URL & headers
Toujours :
POST https://ton-instance.odoo.com/web/dataset/call_kw Content-Type: application/json
3.2. Payload type (après mapping n8n)
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "x_synergia_geriatrie_entretien", "method": "create", "args": [ { "x_patient_id": 123, "x_age": 82, "x_habitat": "seul", "x_has_aidant": true, "x_score_autonomie": 55, "x_score_cognitif": 40, "x_score_chute": 80, "x_score_nutrition": 60, "x_score_moral": 65, "x_fragilite_globale": 68, "x_niveau_risque": "élevé", "x_alertes_json": "[\"chute\",\"isolement\",\"oubli traitement\"]", "x_alertes_label": "chute ; isolement ; oubli traitement", "x_recommandations_text": "aménagement salle de bain\nvisite infirmière\nbilan gériatrique\nappel de suivi hebdomadaire", "x_raw_payload_json": "{... JSON complet de entretien ...}", "x_date_entretien": "2025-11-27T14:25:00", "x_canal": "voix", "x_name": "Entretien gériatrique – Jeanne Dupont" } ], "kwargs": {} } }
3.3. Réponse attendue
{ "jsonrpc": "2.0", "id": null, "result": 456 }
👉 456 = id de l’entretien créé (utile si tu veux le réutiliser juste après).
4️⃣ JSON-RPC Odoo – res.partner.write (mise à jour du patient)
Objectif : garder sur la fiche patient une vue synthétique du dernier entretien.
Exemple : mettre à jour :
- x_last_ai_interview
- x_last_fragility_score
- x_last_risk_level
4.1. Payload write
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "res.partner", "method": "write", "args": [ [123], { "x_last_ai_interview": "2025-11-27T14:25:00", "x_last_fragility_score": 68, "x_last_risk_level": "élevé" } ], "kwargs": {} } }
4.2. Réponse attendue
{ "jsonrpc": "2.0", "id": null, "result": true }
5️⃣ Vue synthétique de la chaîne (contrat global)
5.1. Résumé “du point de vue de chaque acteur”
| Acteur | Envoie | Reçoit |
|---|---|---|
| Bot | JSON “Entretien” → Webhook n8n | 200 OK simple ({"status":"received"}) |
| n8n | JSON-RPC search_read / create / write → Odoo | JSON-RPC result |
| Odoo | N/A | reçoit les call_kw et retourne les result |
5.2. Pipeline complet (texte)
-
Bot → n8n
- POST /webhook/synergia/geriatrie/entretien
- Body = JSON d’entretien (profil + scores + alertes + recommandations)
-
n8n → Odoo #1 (res.partner.search_read)
- JSON-RPC model: "res.partner", method: "search_read"
- Domain = par x_external_ref puis fallback par email
-
n8n
- extrait patient_id
- fusionne avec l’entretien
- construit args[0] pour le create du modèle x_synergia_geriatrie_entretien
-
n8n → Odoo #2 (x_synergia_geriatrie_entretien.create)
- JSON-RPC model: "x_synergia_geriatrie_entretien", method: "create"
-
n8n → Odoo #3 (optionnel)
- res.partner.write pour mettre à jour x_last_ai_interview, x_last_fragility_score, x_last_risk_level
-
Branche alerte
-
si fragilite_globale >= 67 ou niveau_risque = "élevé"
→ Email / Slack / activité Odoo (autres call_kw possibles).
-
si fragilite_globale >= 67 ou niveau_risque = "élevé"
tableau récap des 3 appels JSON-RPC (colonnes : Use Case / model / method / args / kwargs),
Voici le tableau récapitulatif clair et prêt à l’emploi des 3 appels JSON-RPC Odoo utilisés dans votre chaîne bot → n8n → Odoo.
Format volontairement simple pour être collé dans Notion / Excel / documentation projet.
📋 Tableau récapitulatif — Appels JSON-RPC Odoo (Synergia Senior)
| Use case | Model | Method | Args | Kwargs |
|---|---|---|---|---|
| 🔍 Rechercher le patient par identifiant externe | res.partner | search_read | [[["x_external_ref","=","PAT-000123"]], ["id","name","email","x_external_ref"]] | {"limit":2} |
| 🔍 Rechercher le patient par email (fallback) | res.partner | search_read | [[["email","=","jeanne.dupont@example.com"]], ["id","name","email","x_external_ref"]] | {"limit":2} |
| 📝 Créer l’entretien gériatrique | x_synergia_geriatrie_entretien | create | [{"x_patient_id":123,"x_age":82,"x_habitat":"seul","x_has_aidant":true,"x_score_autonomie":55,"x_score_cognitif":40,"x_score_chute":80,"x_score_nutrition":60,"x_score_moral":65,"x_fragilite_globale":68,"x_niveau_risque":"élevé","x_alertes_json":"[\"chute\",\"isolement\"]","x_alertes_label":"chute ; isolement","x_recommandations_text":"aménagement salle de bain\nvisite infirmière","x_raw_payload_json":"{...}","x_date_entretien":"2025-11-27T14:25:00","x_canal":"voix","x_name":"Entretien gériatrique – Jeanne Dupont"}] | {} |
| 🔄 Mettre à jour la synthèse sur le patient | res.partner | write | [[123], {"x_last_ai_interview":"2025-11-27T14:25:00","x_last_fragility_score":68,"x_last_risk_level":"élevé"}] | {} |
✅ Comment lire le tableau
🔹 Use Case
Le scénario métier : chercher un patient, créer un entretien, mettre à jour son profil.
🔹 Model
Le modèle Odoo impacté :
- res.partner → fiche patient
- x_synergia_geriatrie_entretien → table personnalisée Odoo Studio
🔹 Method
Méthodes standard JSON-RPC Odoo :
- search_read → lire
- create → créer
- write → modifier
🔹 Args
Transmis tel quel dans params.args :
"args": [ ...arguments... ]
🔹 Kwargs
Options supplémentaires (limit, context, etc.) :
"kwargs": { "limit": 2 }
✅ Utilisation directe dans n8n
Dans chaque node HTTP Request :
URL Odoo
https://TON_INSTANCE.odoo.com/web/dataset/call_kw
Body générique
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "...", "method": "...", "args": [...], "kwargs": {...} } }
Tu adaptes simplement les blocs model, method, args, kwargs à partir du tableau.
✅ un flow n8n export JSON prêt à importer
Les grandes histoires ont une personnalité. Envisagez de raconter une belle histoire qui donne de la personnalité. Écrire une histoire avec de la personnalité pour des clients potentiels aidera à établir un lien relationnel. Cela se traduit par de petites spécificités comme le choix des mots ou des phrases. Écrivez de votre point de vue, pas de l'expérience de quelqu'un d'autre.
Les grandes histoires sont pour tout le monde, même lorsqu'elles ne sont écrites que pour une seule personne. Si vous essayez d'écrire en pensant à un public large et général, votre histoire sonnera fausse et manquera d'émotion. Personne ne sera intéressé. Ecrire pour une personne en particulier signifie que si c'est authentique pour l'un, c'est authentique pour le reste.
voici un workflow n8n export JSON prêt à coller dans n8n (Menu → Import from file / clipboard → Paste JSON).
✅ À adapter :
- ODDO_BASE_URL (URL de ton Odoo Online)
- Auth des deux nodes HTTP (ajouter tes credentials dans n8n)
- Adresses email dans le node Email
{ "name": "Synergia – Entretien gériatrique → Odoo", "nodes": [ { "id": "WebhookGeriatrie", "name": "Webhook – Entretien gériatrique", "type": "n8n-nodes-base.webhook", "typeVersion": 1, "position": [260, 300], "parameters": { "path": "synergia/geriatrie/entretien", "httpMethod": "POST", "responseMode": "onReceived", "responseData": "custom", "responseBody": "{\"status\":\"received\"}", "options": { "rawBody": false } }, "webhookId": "synergia-geriatrie-entretien" }, { "id": "BuildSearchQuery", "name": "Build Patient Search Query", "type": "n8n-nodes-base.function", "typeVersion": 1, "position": [540, 180], "parameters": { "functionCode": "const input = items[0].json;\n\nconst externalRef = input.patient_external_ref || null;\nconst email = input.patient_email || null;\n\nif (!externalRef && !email) {\n throw new Error(\"Aucun identifiant patient fourni (external_ref ou email manquant).\");\n}\n\nlet domain;\nif (externalRef) {\n domain = [[\"x_external_ref\", \"=\", externalRef]];\n} else {\n domain = [[\"email\", \"=\", email]];\n}\n\nreturn [{ json: { domain } }];" } }, { "id": "OdooSearchPatient", "name": "Odoo – search_read Patient", "type": "n8n-nodes-base.httpRequest", "typeVersion": 1, "position": [820, 180], "parameters": { "url": "https://ODDO_BASE_URL/web/dataset/call_kw", "method": "POST", "authentication": "none", "jsonParameters": true, "options": {}, "bodyParametersJson": "={\n \"jsonrpc\": \"2.0\",\n \"method\": \"call\",\n \"params\": {\n \"model\": \"res.partner\",\n \"method\": \"search_read\",\n \"args\": [\n $json.domain,\n [\"id\", \"name\", \"email\", \"x_external_ref\"]\n ],\n \"kwargs\": {\n \"limit\": 2\n }\n }\n}" } }, { "id": "ExtractPatientId", "name": "Extract Patient ID", "type": "n8n-nodes-base.function", "typeVersion": 1, "position": [1100, 180], "parameters": { "functionCode": "const res = items[0].json;\nconst result = res.result || [];\n\nif (!Array.isArray(result)) {\n throw new Error(\"Réponse Odoo inattendue sur search_read\");\n}\n\nif (result.length === 0) {\n throw new Error(\"Aucun patient trouvé pour ce critère (external_ref / email).\");\n}\n\nif (result.length > 1) {\n // selon ta politique, tu peux throw ici\n console.warn(\"Plusieurs patients trouvés, premier utilisé.\");\n}\n\nconst patient = result[0];\n\nreturn [{\n json: {\n patient_id: patient.id,\n patient_name: patient.name,\n patient_email: patient.email,\n patient_external_ref: patient.x_external_ref || null\n }\n}];" } }, { "id": "MergePatientEntretien", "name": "Merge – Patient + Entretien", "type": "n8n-nodes-base.merge", "typeVersion": 1, "position": [1380, 300], "parameters": { "mode": "mergeByIndex", "join": "inner" } }, { "id": "BuildEntretienPayload", "name": "Build Odoo Entretien Payload", "type": "n8n-nodes-base.function", "typeVersion": 1, "position": [1660, 300], "parameters": { "functionCode": "const input = items[0].json;\n\nconst patientId = input.patient_id;\nconst canal = input.canal || \"texte\";\nconst body = input.entretien || {};\n\nconst profil = body.profil || {};\nconst scores = body.scores || {};\n\nconst alertes = body.alertes || [];\nconst recommandations = body.recommandations || [];\n\nreturn [{\n json: {\n jsonrpc: \"2.0\",\n method: \"call\",\n params: {\n model: \"x_synergia_geriatrie_entretien\",\n method: \"create\",\n args: [\n {\n x_patient_id: patientId,\n x_age: profil.age || null,\n x_habitat: profil.habitat || null,\n x_has_aidant: !!profil.aidant,\n\n x_score_autonomie: scores.autonomie ?? null,\n x_score_cognitif: scores.cognitif ?? null,\n x_score_chute: scores.chute ?? null,\n x_score_nutrition: scores.nutrition ?? null,\n x_score_moral: scores.moral ?? null,\n\n x_fragilite_globale: body.fragilite_globale ?? null,\n x_niveau_risque: body.niveau_risque || null,\n\n x_alertes_json: JSON.stringify(alertes),\n x_alertes_label: alertes.join(\" ; \"),\n x_recommandations_text: recommandations.join(\"\\n\"),\n\n x_raw_payload_json: JSON.stringify(body),\n x_date_entretien: new Date().toISOString(),\n x_canal: canal,\n\n x_name: `Entretien gériatrique – ${input.patient_name || (\"patient #\" + patientId)}`\n }\n ],\n kwargs: {}\n }\n }\n}];" } }, { "id": "OdooCreateEntretien", "name": "Odoo – Create Entretien", "type": "n8n-nodes-base.httpRequest", "typeVersion": 1, "position": [1940, 300], "parameters": { "url": "https://ODDO_BASE_URL/web/dataset/call_kw", "method": "POST", "authentication": "none", "jsonParameters": true, "bodyParametersJson": "={{$json}}", "options": {} } }, { "id": "BuildPartnerWrite", "name": "Build Partner Write Payload", "type": "n8n-nodes-base.function", "typeVersion": 1, "position": [1660, 520], "parameters": { "functionCode": "const input = items[0].json;\n\nconst patientId = input.patient_id;\nconst body = input.entretien || {};\n\nreturn [{\n json: {\n jsonrpc: \"2.0\",\n method: \"call\",\n params: {\n model: \"res.partner\",\n method: \"write\",\n args: [\n [patientId],\n {\n x_last_ai_interview: new Date().toISOString(),\n x_last_fragility_score: body.fragilite_globale ?? null,\n x_last_risk_level: body.niveau_risque || null\n }\n ],\n kwargs: {}\n }\n }\n}];" } }, { "id": "OdooUpdatePartner", "name": "Odoo – Update Patient", "type": "n8n-nodes-base.httpRequest", "typeVersion": 1, "position": [1940, 520], "parameters": { "url": "https://ODDO_BASE_URL/web/dataset/call_kw", "method": "POST", "authentication": "none", "jsonParameters": true, "bodyParametersJson": "={{$json}}", "options": {} } }, { "id": "IFRiskHigh", "name": "IF – Risque élevé ?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [540, 460], "parameters": { "conditions": { "number": [ { "value1": "={{$json.entretien.fragilite_globale}}", "operation": "larger", "value2": 66 } ], "string": [ { "value1": "={{$json.entretien.niveau_risque}}", "operation": "equal", "value2": "élevé" } ] }, "combineOperation": "any" } }, { "id": "EmailAlert", "name": "Email – Alerte gériatrique", "type": "n8n-nodes-base.emailSend", "typeVersion": 1, "position": [820, 460], "parameters": { "fromEmail": "", "toEmail": "pharmacien@example.com", "subject": "Synergia – Alerte risque gériatrique élevé", "text": "Alerte Synergia : risque gériatrique élevé détecté.\n\nPatient externe : {{$json.patient_external_ref || 'N/A'}}\nEmail patient : {{$json.patient_email || 'N/A'}}\n\nScore global de fragilité : {{$json.entretien.fragilite_globale}}\nNiveau de risque : {{$json.entretien.niveau_risque}}\nAlertes : {{($json.entretien.alertes || []).join(', ')}}\n\nMerci de vérifier la situation et de planifier un suivi." } } ], "connections": { "Webhook – Entretien gériatrique": { "main": [ [ { "node": "Build Patient Search Query", "type": "main", "index": 0 }, { "node": "IF – Risque élevé ?", "type": "main", "index": 0 }, { "node": "Merge – Patient + Entretien", "type": "main", "index": 0 } ] ] }, "Build Patient Search Query": { "main": [ [ { "node": "Odoo – search_read Patient", "type": "main", "index": 0 } ] ] }, "Odoo – search_read Patient": { "main": [ [ { "node": "Extract Patient ID", "type": "main", "index": 0 } ] ] }, "Extract Patient ID": { "main": [ [ { "node": "Merge – Patient + Entretien", "type": "main", "index": 1 } ] ] }, "Merge – Patient + Entretien": { "main": [ [ { "node": "Build Odoo Entretien Payload", "type": "main", "index": 0 }, { "node": "Build Partner Write Payload", "type": "main", "index": 0 } ] ] }, "Build Odoo Entretien Payload": { "main": [ [ { "node": "Odoo – Create Entretien", "type": "main", "index": 0 } ] ] }, "Build Partner Write Payload": { "main": [ [ { "node": "Odoo – Update Patient", "type": "main", "index": 0 } ] ] }, "IF – Risque élevé ?": { "main": [ [ { "node": "Email – Alerte gériatrique", "type": "main", "index": 0 } ], [] ] } }, "active": false, "versionId": "synergia-geriatrie-v1", "settings": {}, "tags": [] }
Pour l’utiliser
- Dans n8n : Workflows → Import → Paste JSON → colle tout.
- Remplace https://ODDO_BASE_URL par l’URL réelle de ton Odoo Online.
- Sur les nodes HTTP, ajoute tes credentials (API key / Basic Auth / cookie, selon ton setup).
- Mets un vrai email dans le node Email – Alerte gériatrique.
Les grandes histoires ont une personnalité. Envisagez de raconter une belle histoire qui donne de la personnalité. Écrire une histoire avec de la personnalité pour des clients potentiels aidera à établir un lien relationnel. Cela se traduit par de petites spécificités comme le choix des mots ou des phrases. Écrivez de votre point de vue, pas de l'expérience de quelqu'un d'autre.
Les grandes histoires sont pour tout le monde, même lorsqu'elles ne sont écrites que pour une seule personne. Si vous essayez d'écrire en pensant à un public large et général, votre histoire sonnera fausse et manquera d'émotion. Personne ne sera intéressé. Ecrire pour une personne en particulier signifie que si c'est authentique pour l'un, c'est authentique pour le reste.