Se rendre au contenu

Automatiser les relances clients pour un dossier ARDDA avec Odoo 19

Guide pratique - Odoo 19
9 avril 2026 par
Régis GEROMEGNACE

La constitution d'un dossier ARDDA en Guadeloupe (Aide à la Restructuration et au Développement des entreprises) implique la collecte de nombreux justificatifs auprès des clients. Sans système de relance, le suivi devient vite chronophage et sujet à l'oubli. Bonne nouvelle : Odoo 19 Enterprise offre tous les outils nécessaires pour automatiser ce processus de A à Z.

Dans cet article, nous vous expliquons pas à pas comment il est possible de mettre en place, une automatisation de relance par e-mail qui détecte les sous-dossiers vides dans la GED d'Odoo et notifie automatiquement le client concerné — en précisant exactement quels documents sont manquants.

1. Contexte : le dossier ARDDA dans Odoo

Le dispositif ARDDA accompagne les entreprises dans leurs démarches de restructuration ou de développement. Sa constitution nécessite la transmission de nombreux documents répartis en plusieurs catégories : pièces d'identité, documents fiscaux et prévisionnels financiers.

Dans Odoo, nous avons modélisé ce besoin autour d'un produit dédié « Prestation dossier ARDDA ». Lorsqu'un devis contenant ce produit est validé, Odoo crée automatiquement :

  • Un projet basé sur le modèle « MODELE ARDDA »
  • Une arborescence de dossiers dans la GED (module Documents Enterprise) reproduisant exactement la structure du dossier
Dossier GEDDocuments attendus
MODELE ARDDA (racine)Dossier racine lié au projet Odoo
01-IdentitéPièce d'identité du dirigeant, extrait Kbis, statuts
02-FiscalitéLiasses fiscales, bilans comptables, avis d'imposition
03-PrévisionnelBusiness plan, projections financières sur 3 ans

Le défi : s'assurer que les clients déposent bien leurs documents dans chaque sous-dossier, sans avoir à vérifier manuellement chaque projet. C'est précisément ce que résout l'automatisation présentée dans cet article.

2. Architecture de la solution

La solution repose sur quatre composants qui s'articulent ainsi :

1. Champs personnalisés (Studio) — Deux champs ajoutés sur le modèle Projet : un booléen d'incomplétude et un champ texte listant les sous-dossiers vides.

2. Action serveur (Python) — Script qui parcourt la GED du projet et met à jour les champs personnalisés.

3. Action planifiée (Cron) — Déclencheur hebdomadaire qui appelle l'action serveur et envoie les e-mails de rappel.

4. Modèle d'e-mail — Template personnalisé affichant dynamiquement la liste des documents manquants.

3. Prérequis et modules nécessaires

Module OdooRôle dans la solution
Documents (Enterprise)GED et arborescence des dossiers clients
VenteCréation du projet à la validation du devis
ProjetModèle portant les champs personnalisés
Studio (Enterprise)Ajout de champs sans développement
AutomatisationsAction serveur et cron hebdomadaire
E-mailEnvoi du rappel personnalisé au client

⚠️ Important : Cette solution nécessite Odoo 19 Enterprise. Les modules Documents et Studio ne sont pas disponibles en version Community. Le mode développeur doit être activé (?debug=1 dans l'URL) pour accéder aux actions serveur et aux actions planifiées.

4. Étape 1 — Préparer les champs via Studio

Avant d'écrire la moindre ligne de code, nous ajoutons deux champs personnalisés sur le modèle Projet grâce à Studio. Ces champs serviront d'intermédiaires entre l'action de détection et le modèle d'e-mail.

  1. Ouvrez un projet Odoo quelconque, puis cliquez sur l'icône Studio (crayon en haut à droite).
  2. Ajoutez un champ de type Case à cocher (Booléen) nommé techniquement x_studio_ardda_incomplete, avec le label « Dossier ARDDA incomplet ».
  3. Ajoutez un second champ de type Texte nommé x_studio_ardda_dossiers_vides, avec le label « Sous-dossiers manquants ».
  4. Sauvegardez et quittez Studio.

Ces deux champs seront alimentés automatiquement par l'action serveur décrite à l'étape suivante.

5. Étape 2 — Créer l'action serveur de détection

Rendez-vous dans Paramètres → Technique → Actions → Actions serveur. Créez une nouvelle action avec les paramètres suivants :

  • Nom : Vérification dossiers ARDDA
  • Modèle : Projet (project.project)
  • Action : Exécuter du code Python

Découverte clé : la structure GED dans Odoo 19

En Odoo 19 Enterprise, les dossiers et les fichiers partagent le même modèle ORM : documents.document. La distinction se fait via le champ type (valeur 'folder' pour un dossier). Les sous-dossiers sont des enfants via le champ folder_id(relation auto-référentielle). La liaison avec le projet Odoo se fait via le champ project_ids.

Collez le code suivant dans le champ « Code » de l'action serveur :

def log(niveau, message):
    env['ir.logging'].sudo().create({
        'name': 'odoo.ardda.check',
        'type': 'server',
        'level': niveau,
        'dbname': env.cr.dbname,
        'message': message,
        'path': 'action_serveur',
        'func': 'ardda_check',
        'line': '0',
    })

for project in records:
    log('INFO', '=== ARDDA CHECK - Projet : [%s] ===' % project.name)

    # Recherche du dossier racine GED lié au projet
    dossier_racine = env['documents.document'].search([
        ('project_ids', 'in', [project.id]),
        ('type', '=', 'folder'),
    ])

    if not dossier_racine:
        log('WARNING', '!! Aucun dossier GED trouvé pour [%s]' % project.name)
        continue

    sous_dossiers_requis = ['01-Identité', '02-Fiscalité', '03-Prévisionnel']
    dossiers_vides = []

    for nom in sous_dossiers_requis:
        sous_dossier = env['documents.document'].search([
            ('folder_id', 'in', dossier_racine.ids),
            ('type', '=', 'folder'),
            ('name', 'ilike', nom),
        ])

        if not sous_dossier:
            dossiers_vides.append(nom + ' (dossier manquant)')
            continue

        nb_docs = env['documents.document'].search_count([
            ('folder_id', 'in', sous_dossier.ids),
            ('type', '!=', 'folder'),
        ])

        if nb_docs == 0:
            dossiers_vides.append(nom)
            log('WARNING', '!! %s est vide' % nom)
        else:
            log('INFO', 'OK %s : %s document(s)' % (nom, nb_docs))

    statut = len(dossiers_vides) > 0
    project.write({
        'x_studio_ardda_incomplete': statut,
        'x_studio_ardda_dossiers_vides': ', '.join(dossiers_vides),
    })
    log('INFO', '=== Fin traitement [%s] ===' % project.name)

⚠️ Contraintes du sandbox Odoo : Le moteur safe_eval interdit import logging et l'assignation directe record.champ = valeur. Utilisez toujours record.write({'champ': valeur}) pour modifier un enregistrement, et env['ir.logging'].create() pour vos logs.

6. Étape 3 — Configurer l'action planifiée

L'action planifiée est le moteur qui déclenche régulièrement la vérification et envoie les e-mails. Accédez à Paramètres → Technique → Automatisation → Actions planifiées.

Créez une nouvelle action planifiée avec ces paramètres :

  • Nom : ARDDA — Rappel dossiers incomplets
  • Fréquence : Hebdomadaire (recommandé : chaque lundi à 8h00)
  • Nombre d'appels : Illimité
def log(niveau, message):
    env['ir.logging'].sudo().create({
        'name': 'odoo.ardda.cron',
        'type': 'server',
        'level': niveau,
        'dbname': env.cr.dbname,
        'message': message,
        'path': 'cron',
        'func': 'ardda_rappel',
        'line': '0',
    })

# Vérifier que le modèle d'e-mail existe
template = env['mail.template'].search([
    ('name', '=', 'Rappel dossier ARDDA incomplet')
], limit=1)

if not template:
    raise UserError("Modèle e-mail 'Rappel dossier ARDDA incomplet' introuvable")

# Tous les projets marqués comme incomplets
projets = env['project.project'].search([
    ('x_studio_ardda_incomplete', '=', True)
])

log('INFO', '=== ARDDA CRON : %s projet(s) à relancer ===' % len(projets))

for project in projets:
    if not project.partner_id or not project.partner_id.email:
        log('WARNING', '!! [%s] sans e-mail client — ignoré' % project.name)
        continue

    dossier_racine = env['documents.document'].search([
        ('project_ids', 'in', [project.id]),
        ('type', '=', 'folder'),
    ])
    dossiers_vides = []

    for nom in ['01-Identité', '02-Fiscalité', '03-Prévisionnel']:
        sous_dossier = env['documents.document'].search([
            ('folder_id', 'in', dossier_racine.ids),
            ('type', '=', 'folder'),
            ('name', 'ilike', nom),
        ])
        if not sous_dossier:
            dossiers_vides.append(nom + ' (dossier manquant)')
            continue
        nb_docs = env['documents.document'].search_count([
            ('folder_id', 'in', sous_dossier.ids),
            ('type', '!=', 'folder'),
        ])
        if nb_docs == 0:
            dossiers_vides.append(nom)

    if dossiers_vides:
        project.write({
            'x_studio_ardda_incomplete': True,
            'x_studio_ardda_dossiers_vides': ', '.join(dossiers_vides),
        })
        template.send_mail(
            project.id,
            force_send=True,
            email_values={'email_to': project.partner_id.email}
        )
        log('INFO', 'Mail envoyé à %s' % project.partner_id.email)
    else:
        project.write({
            'x_studio_ardda_incomplete': False,
            'x_studio_ardda_dossiers_vides': '',
        })
        log('INFO', '[%s] : dossier complet, flag remis à False' % project.name)

7. Étape 4 — Créer le modèle d'e-mail

Dans E-mail → Modèles (mode debug activé), créez un nouveau modèle :

ParamètreValeur
NomRappel dossier ARDDA incomplet
Modèleproject.project
Sujet⚠️ Dossier ARDDA incomplet - {{ object.name }}

Corps du message :

<p>Bonjour {{ object.partner_id.name }},</p>

<p>Dans le cadre de votre dossier ARDDA
<strong>{{ object.name }}</strong>,
nous n'avons pas encore reçu les documents
dans les rubriques suivantes :</p>

<p><strong>{{ object.x_studio_ardda_dossiers_vides }}</strong></p>

<p>Merci de bien vouloir déposer vos documents dès que possible
afin que nous puissions traiter votre dossier dans les meilleurs délais.</p>

<p>Pour toute question, n'hésitez pas à nous contacter.</p>

<p>Cordialement,<br/>
{{ user.name }}<br/>
{{ user.company_id.name }}</p>

💡 Pourquoi éviter les boucles Jinja ? Le moteur de rendu des templates e-mail Odoo n'évalue pas le contexte Python passé via with_context() de façon fiable. En stockant la liste des dossiers manquants dans le champ texte x_studio_ardda_dossiers_vides, on utilise directement {{ object.champ }} — toujours fiable, sans boucle.

8. Contraintes techniques du sandbox Odoo à connaître

ErreurCauseSolution
STORE_ATTRAssignation directe record.champ = valUtiliser record.write({'champ': val})
IMPORT_NAMEimport logging interditUtiliser env['ir.logging'].create()
NameError __name__Dunder __name__ interditPasser la chaîne 'odoo.ardda.check'
KeyError 'documents.folder'Modèle inexistant en Odoo 19Utiliser documents.document avec type='folder'

Consulter les logs

Tous les logs sont visibles dans Paramètres → Technique → Logging (mode debug requis). Filtrez sur name = odoo.ardda.check. Sur Odoo.sh, utilisez l'onglet Logs de votre branche.

Conclusion

En combinant Studio, le module Documents, les actions serveur et les actions planifiées, Odoo 19 Enterprise permet de mettre en place une automatisation robuste de relance documentaire — sans développement spécifique ni module additionnel.

La clé de la réussite réside dans la bonne compréhension de la structure interne du module Documents (modèle auto-référentiel documents.document) et dans le respect des contraintes du sandbox Python d'Odoo.

Cette approche est généralisable à tout processus de collecte documentaire dans Odoo : dossiers de financement, onboarding client, appels d'offres, dossiers RH… Partout où un client ou un collaborateur doit déposer des fichiers dans une structure prédéfinie.


Vous souhaitez mettre en place cette automatisation?

Contactez-nous