Rendre votre ERP "intelligent". Automatisation ODOO

C'est la touche finale qui va rendre votre ERP "intelligent". 


Au lieu que vos gestionnaires fassent tout à la main, Odoo va travailler en arrière-plan pour maintenir la cohérence des données envoyées par l'app React.

Dans Odoo Studio, cela se passe dans le menu "Automatisations" (ou "Actions Automatisées").

Voici les 5 Automatisations Prioritaires à implémenter pour votre projet Synergia.

1. Le "Nettoyeur de Nom" (Data Quality)

Objectif : React envoie Prénom et Nom séparés. Odoo a besoin d'un champ name complet pour l'affichage.

  • Modèle : Contact (res.partner)
  • Déclencheur : À la création et à la mise à jour.
  • Champs surveillés : x_firstname, x_lastname.
  • Action à effectuer : Exécuter du code Python.

Code Python :

codePython

downloadcontent_copy

expand_less
for record in records:
    # On prend le prénom (ou vide si null) et le nom (ou vide si null)
    prenom = record.x_firstname or ''
    nom = record.x_lastname or ''
    # On concatène et on retire les espaces inutiles (.strip)
    record['name'] = f"{prenom} {nom}".strip()

2. Le "Calculateur d'Expérience" (Smart Data)

Objectif : Quand un candidat ajoute une expérience dans l'app, Odoo doit recalculer automatiquement son ancienneté totale sur sa fiche principale.

  • Modèle : Expérience Candidat (x_candidate_experience)
  • Déclencheur : À la création, mise à jour et suppression.
  • Action à effectuer : Exécuter du code Python.

Code Python :

codePython

downloadcontent_copy

expand_less
# On récupère le candidat lié à cette expérience
candidat = record.x_candidate_id

if candidat:
    # On cherche toutes ses expériences
    experiences = env['x_candidate_experience'].search([('x_candidate_id', '=', candidat.id)])
    
    total_jours = 0
    import datetime

    for exp in experiences:
        if exp.x_date_start:
            # Si "En poste", on prend la date d'aujourd'hui comme fin
            date_fin = datetime.date.today() if exp.x_is_current else exp.x_date_end
            if date_fin:
                delta = date_fin - exp.x_date_start
                total_jours += delta.days
    
    # On convertit en années (approximatif) et on écrit sur le candidat
    # (Assurez-vous d'avoir créé un champ x_total_experience_years sur res.partner)
    candidat['x_total_experience_years'] = round(total_jours / 365.25, 1)

3. Le "Validateur de Profil" (Workflow)

Objectif : Si un document passe au statut "Validé", vérifier si le dossier est complet. Si oui, passer le candidat en "Profil Vérifié" automatiquement.

  • Modèle : Documents de Conformité (x_compliance_document)
  • Déclencheur : À la mise à jour.
  • Champs surveillés : x_validation_status.
  • Domaine (Filtre) : Appliquer uniquement si x_validation_status = valid.
  • Action à effectuer : Exécuter du code Python.

Code Python :

codePython

downloadcontent_copy

expand_less
candidat = record.x_partner_id

# Liste des types de documents obligatoires pour Synergia
types_obligatoires = ['id_card', 'diploma', 'rpps', 'kbis']

# On cherche tous les docs validés de ce candidat
docs_valides = env['x_compliance_document'].search([
    ('x_partner_id', '=', candidat.id),
    ('x_validation_status', '=', 'valid')
])

# On récupère la liste des types qu'il a déjà validés
types_valides = [doc.x_document_type for doc in docs_valides]

# On vérifie si TOUS les obligatoires sont présents dans les valides
dossier_complet = all(type_doc in types_valides for type_doc in types_obligatoires)

if dossier_complet:
    # On change le statut du candidat (créez ce champ sur res.partner)
    candidat['x_onboarding_stage'] = 'validated'
    # Optionnel : Envoyer un email de félicitations

4. L'Alerte "Document Expiré" (Compliance)

Objectif : Vérifier tous les jours si un document expire bientôt (ex: Assurance, CNI) et notifier l'infirmier.

  • Modèle : Documents de Conformité (x_compliance_document)
  • Déclencheur : Action Planifiée (Cron) - Fréquence : 1 jour.
  • Action à effectuer : Envoyer un email.

Configuration sans code :

  1. Dans Studio, filtrez les enregistrements : Date expiration est dans 30 jours ET Statut = Validé.
  2. Action : "Envoyer un email".
  3. Choisissez un modèle d'email (Template) qui dit : "Bonjour, votre document {{object.x_document_type}} va expirer le {{object.x_expiration_date}}. Merci de le mettre à jour sur l'application."

5. Notification Admin "Nouveau Inscrit" (Réactivité)



Objectif : Alerter l'équipe Synergia quand quelqu'un finit son inscription via l'App.

  • Modèle : Contact (res.partner)
  • Déclencheur : À la mise à jour.
  • Champs surveillés : x_onboarding_stage.
  • Domaine : x_onboarding_stage = profile_filled (ou le statut qui correspond à la fin du wizard React).
  • Action à effectuer : Ajouter un abonné ou Créer une activité.

Configuration sans code :

  1. Action : Créer une activité.
  2. Type d'activité : À faire.
  3. Résumé : Nouveau candidat à vérifier.
  4. Assigné à : Utilisateur spécifique (ex: Responsable Recrutement).
  5. Description : "Le candidat {{object.name}} vient de finaliser son inscription. Merci de vérifier ses documents."

Récapitulatif pour l'intégration


PrioritéNomTypePourquoi ?
🔥 HauteNettoyeur de NomPythonÉvite d'avoir des factures sans nom.
🔥 HauteValidateur ProfilPythonAutomatise le passage "En attente" -> "Validé". Gain de temps énorme.
⚡ MoyenneNotif AdminStandardPour ne rater aucun nouveau lead.
⚡ MoyenneCalcul ExpériencePythonPour pouvoir filtrer "Infirmiers > 5 ans exp".
🛡️ BasseAlerte ExpirationCronPour la conformité légale sur le long terme.

6- Validateur Profil

C'est une excellente décision. C'est l'automatisation qui a le plus fort retour sur investissement (ROI) car elle évite à votre équipe de vérifier manuellement chaque dossier 10 fois par jour.

Voici le code Python prêt à l'emploi et la procédure d'installation pas à pas.

Prérequis (Noms techniques)

Assurez-vous que vous avez bien ces noms de champs (ou adaptez le code) :

  1. Modèle Document : x_compliance_document
    • Champ Type : x_document_type (valeurs: id_card, diploma, rpps, etc.)
    • Champ Statut : x_validation_status (valeur validée : valid)
    • Lien Candidat : x_partner_id
  2. Modèle Contact (res.partner) :
    • Champ Étape : x_onboarding_stage (valeur cible : validated)

🛠️ Configuration dans Odoo Studio

  1. Allez sur le modèle Documents de Conformité (x_compliance_document).
  2. Cliquez sur le bouton Automatisations > Nouveau.
  3. Configurez comme suit :
    • Nom : Validation Automatique Candidat
    • Modèle : Documents de Conformité
    • Déclencheur : À la mise à jour
    • Champs surveillés : Statut (x_validation_status)
    • Domaine (Filtre) : ["x_validation_status", "=", "valid"]
      • (Cela signifie : ne lance ce code QUE si le document vient de passer à "Validé")
    • Action à effectuer : Exécuter du code Python

🐍 Le Code Python

Copiez-collez ce bloc dans l'éditeur de code d'Odoo :

codePython

downloadcontent_copy

expand_less
# 1. Récupérer le candidat lié au document qu'on vient de valider
candidat = record.x_partner_id

# Sécurité : Si le document n'est pas lié à un candidat, on ne fait rien
if not candidat:
    action = {'type': 'ir.actions.act_window_close'} # Stop propre

# 2. LISTE DES DOCUMENTS OBLIGATOIRES
# Mettez ici les codes techniques exacts de votre champ Selection (x_document_type)
# Exemple : CNI, Diplôme et RPPS sont requis pour tout le monde.
docs_requis = ['id_card', 'diploma', 'rpps']

# (Optionnel) Ajout conditionnel : Si c'est une société, il faut le KBIS
# Adaptez 'societe' et 'kbis' selon vos vrais codes
# if candidat.x_freelance_status == 'societe':
#     docs_requis.append('kbis')

# 3. Interroger la base de données
# On cherche TOUS les documents de ce candidat qui sont DÉJÀ validés
docs_valides_db = env['x_compliance_document'].search([
    ('x_partner_id', '=', candidat.id),
    ('x_validation_status', '=', 'valid')
])

# 4. Extraire les types qu'on a trouvés
# On crée une liste simple des types (ex: ['id_card', 'diploma'])
types_trouves = [doc.x_document_type for doc in docs_valides_db]

# 5. Vérification Logique
# On vérifie si CHAQUE document requis est présent dans les types trouvés
# La fonction all() renvoie True seulement si tout est présent
dossier_complet = all(requis in types_trouves for requis in docs_requis)

# 6. Action Finale
if dossier_complet:
    # Si le candidat n'est pas déjà validé, on le valide
    if candidat.x_onboarding_stage != 'validated':
        candidat['x_onboarding_stage'] = 'validated'
        
        # Le petit plus : On écrit un message dans le "Chatter" (l'historique) du candidat
        candidat.message_post(
            body="✅ <b>Automation System :</b> Tous les documents obligatoires sont validés. Profil activé."
        )

🔍 Comment tester que ça marche ?

  1. Prenez un candidat de test (ex: "Jean Test").
  2. Mettez son statut à "Nouveau" ou "Profil rempli".
  3. Ajoutez-lui les 3 documents obligatoires (ex: CNI, Diplôme, RPPS).
  4. Laissez-les en brouillon.
  5. Passez les documents à "Validé" un par un.
  6. Au moment où vous validez le dernier document manquant :
    • Allez voir la fiche de "Jean Test".
    • Son statut doit être passé automatiquement à "Validé".
    • Vous devriez voir le message de confirmation dans son historique de discussion.

.

7- Nettoyeur de Nom

C'est l'automatisation de base, indispensable pour que vos factures, emails et recherches dans Odoo soient propres. Sans cela, vous aurez des fiches contacts vides ou mal nommées.

Voici la procédure exacte et le code.

🛠️ Configuration dans Odoo Studio


  1. Allez sur l'application Contacts.
  2. Ouvrez Studio (l'icône clé à molette).
  3. Cliquez sur Automatisations (menu gauche ou haut) > Nouveau.
  4. Configurez comme suit :
    • Nom : Calcul Automatique du Nom Complet
    • Modèle : Contact (res.partner)
    • Déclencheur : À la création et à la mise à jour
    • Champs surveillés : Sélectionnez vos deux champs : x_firstname (Prénom) et x_lastname (Nom)
      • Astuce : Il faut maintenir Ctrl ou Cmd pour en sélectionner plusieurs, ou les ajouter l'un après l'autre.
    • Action à effectuer : Exécuter du code Python

🐍 Le Code Python

Copiez ce code. Il gère les majuscules automatiquement et évite les erreurs si un champ est vide.

codePython

downloadcontent_copy

expand_less
for record in records:
    # 1. Récupération sécurisée (évite le crash si le champ est vide)
    # .strip() retire les espaces accidentels avant/après
    prenom = (record.x_firstname or '').strip()
    nom = (record.x_lastname or '').strip()

    # 2. Mise en forme (Optionnel : Joli formatage)
    # Met la première lettre en majuscule (Jean)
    prenom_format = prenom.title()
    # Met tout le nom en majuscule (DUPONT) - Standard administratif français
    nom_format = nom.upper()

    # 3. Concaténation
    # On assemble. Si l'un est vide, .strip() à la fin nettoiera les espaces en trop.
    nom_complet = f"{prenom_format} {nom_format}"

    # 4. Écriture dans le champ standard Odoo
    record['name'] = nom_complet.strip()

🔎 Ce que fait ce code (Exemple)

Saisie React (x_firstname)Saisie React (x_lastname)Résultat Odoo (name)
"jean""lauret"Jean LAURET
"MARIE ""curie"Marie CURIE
"" (vide)"Dupont"DUPONT
"Thomas""" (vide)Thomas

⚠️ Point d'attention pour l'API React

Puisque Odoo calcule le nom automatiquement, votre développeur React ne doit pas envoyer le champ name lors de la création du contact.

Payload JSON correct à envoyer :

codeJSON

downloadcontent_copy

expand_less
{
  "x_firstname": "Jean",
  "x_lastname": "Valjean",
  "email": "jean@test.com"
  // PAS de champ "name", Odoo s'en occupe !
}

Si React envoie aussi le champ name, il risque d'écraser le calcul ou de créer un conflit. Laissez Odoo faire le travail.

8- Notif admin 


C'est une excellente pratique. Plutôt que d'envoyer un email qui risque de se perdre, nous allons utiliser le système d'Activités Odoo (le petit réveil en haut à droite).

Cela créera une tâche "À faire" pour votre responsable recrutement dès qu'un candidat termine son inscription sur l'app React.

Voici comment configurer cela sans une seule ligne de code (Standard).

🛠️ Configuration dans Odoo Studio

  1. Allez sur l'application Contacts.
  2. Ouvrez Studio (l'icône clé à molette).
  3. Cliquez sur Automatisations > Nouveau.
  4. Configurez les paramètres généraux :
    • Nom : Notif Nouveau Candidat Inscrit
    • Modèle : Contact (res.partner)
    • Déclencheur : À la mise à jour
    • Champs surveillés : x_onboarding_stage (Étape d'inscription)

1. Le Filtre (Quand déclencher ?)

Nous ne voulons pas une alerte à chaque modification, mais uniquement quand l'inscription est finie.

  • Dans la section "Appliquer sur" (ou Domaine), cliquez sur "Modifier le domaine".
  • Ajoutez la règle suivante :
    • Étape d'inscription est égal à Profil Rempli (ou la valeur technique que votre React envoie à la fin, ex: profile_filled).
    • Optionnel mais conseillé : Ajoutez Est un candidat est vrai.

2. L'Action (Quoi faire ?)

  • Type d'action : Créer une activité
  • Type d'activité : À faire (ou Appel, ou Email selon votre process)
  • Résumé : Nouveau candidat à valider
  • Assigné à : Choisissez l'utilisateur responsable (ex: "Responsable RH" ou vous-même).
  • Date d'échéance : Date de lancement + 0 jours (Pour que ce soit urgent/aujourd'hui).
  • Note :
    Vous pouvez écrire un petit texte qui apparaîtra dans la tâche, par exemple :
    "Un nouveau candidat vient de finaliser son inscription via l'application mobile. Merci de vérifier ses documents et de valider son profil."

🔎 Résultat pour l'utilisateur Odoo

Dès que votre App React enverra la donnée :

{ "x_onboarding_stage": "profile_filled" }

  1. Une pastille verte/rouge apparaîtra sur l'icône "Horloge" en haut à droite de l'écran du recruteur.
  2. Dans la liste des activités, il verra : "Jean Dupont : Nouveau candidat à valider".
  3. Il pourra cliquer dessus pour ouvrir la fiche, vérifier les infos, et cliquer sur "Marquer comme fait".

C'est simple, standard, et rien ne passe à travers les mailles du filet !

9- Calcul d'expérience 

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.

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.

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.