Se rendre au contenu

Modifier le nom d'un modèle de projet à la validation d'un devis : l'article pratique pour Odoo 19

Comment automatiser le renommage d'un projet et de son dossier Documents dès la confirmation d'un bon de commande, sans module spécifique.
11 mai 2026 par
Régis GEROMEGNACE

Vous cherchez à modifier le nom d'un modèle de projet à la validation d'un devis ? Cet article vous explique, pas à pas, comment automatiser cette opération dans Odoo 19 Enterprise sans développer le moindre module spécifique. À la clé : un projet et un dossier Documents renommés automatiquement selon vos règles de nommage, dès que la commande client est confirmée.

Pourquoi modifier le nom d'un modèle de projet à la validation d'un devis ?

Dans Odoo, lorsqu'un produit de type service est paramétré avec l'option « Créer à la commande = Projet & Tâche », la confirmation d'un devis déclenche automatiquement la création d'un projet à partir d'un modèle de projet prédéfini. Très pratique… sauf que le projet hérite par défaut du nom du modèle ou de celui de la commande, ce qui rend rapidement la liste des projets illisible quand le volume d'affaires grandit.

Pour un intégrateur ERP, un bureau d'études ou toute structure qui gère ses prestations en mode projet, il devient vite indispensable de retrouver d'un coup d'œil :

  • le numéro du devis à l'origine du projet ;
  • l'opportunité commerciale rattachée (côté CRM), si elle existe ;
  • à défaut, le nom du client.

C'est précisément l'objectif de cet article : mettre en place une règle d'automatisation native qui réécrit le nom du projet et celui du dossier Documents associé selon un format normalisé, à chaque validation de devis.

Le cas concret traité dans cet article

Le besoin de départ est le suivant : sur une instance Odoo 19 Enterprise SaaS, un produit nommé « Calculs LiDAR » est paramétré en service avec création automatique d'un projet et d'une tâche, basé sur un modèle de projet. La règle de renommage souhaitée est :

  • [Numéro du devis] - [Nom de l'opportunité] si une opportunité est rattachée au devis ;
  • [Numéro du devis] - [Nom du client] si aucune opportunité n'est rattachée.

Cette même chaîne doit également renommer le dossier généré dans le module Documents et lié au projet, pour garantir la cohérence entre les deux modules.

Première approche : automatisation sur le bon de commande (et ses limites)

L'intuition la plus naturelle consiste à déclencher l'automatisation sur le modèle sale.order au passage à l'état confirmé, puis à rechercher les projets liés via le champ sale_order_id du modèle project.project.

Configuration de la règle (approche initiale)

  • Modèle : Bon de commande (sale.order)
  • Déclencheur : Lors de la mise à jour
  • Champ déclencheur : state
  • Domaine avant la mise à jour : [('state', '!=', 'sale')]
  • Domaine après la mise à jour : [('state', '=', 'sale')]
  • Action : Exécuter du code Python

Code Python initial

for order in records:
    if order.opportunity_id:
        new_name = f"{order.name} - {order.opportunity_id.name}"
    else:
        new_name = f"{order.name} - {order.partner_id.name}"

    projects = env['project.project'].search([
        ('sale_order_id', '=', order.id)
    ])
    for project in projects:
        project.name = new_name
        if project.documents_folder_id:
            project.documents_folder_id.name = new_name

Cette approche semble logique, mais elle se heurte à deux obstacles techniques qu'il est utile de connaître pour gagner du temps.

Problème n°1 : l'erreur « forbidden opcode STORE_ATTR »

Au moment d'enregistrer la règle, Odoo refuse le code et affiche une erreur de validation contenant la mention STORE_ATTR. La cause est connue : les automatisations Odoo s'exécutent dans un environnement Python restreint nommé safe_eval, qui interdit certaines opérations bytecode pour des raisons de sécurité — dont l'affectation directe d'attribut sur un objet, c'est-à-dire toute écriture du type objet.champ = valeur.

La parade consiste à passer par la méthode ORM write(), qui est un appel de méthode et non une affectation d'attribut, donc parfaitement autorisé. Au passage, on remplace les f-strings par un formatage classique avec l'opérateur %, plus sûr dans le contexte de safe_eval.

Code corrigé

for order in records:
    if order.opportunity_id:
        new_name = "%s - %s" % (order.name, order.opportunity_id.name)
    else:
        new_name = "%s - %s" % (order.name, order.partner_id.name)

    projects = env['project.project'].search([
        ('sale_order_id', '=', order.id)
    ])
    if projects:
        projects.write({'name': new_name})
        folders = projects.mapped('documents_folder_id')
        if folders:
            folders.write({'name': new_name})

Problème n°2 : le projet n'est pas encore créé au moment de l'exécution

Une fois la règle enregistrée et le devis validé, on constate que… rien ne se passe. Le projet est bien créé, mais il conserve son nom d'origine. Pourquoi ?

Parce que l'automatisation déclenchée sur le passage à l'état sale s'exécute à l'intérieur de la même transaction que la confirmation de la commande. Or, c'est cette même transaction qui crée le projet via le mécanisme « Créer à la commande ». Au moment où notre code Python s'exécute, le projet n'est pas encore visible pour la recherche : le search() retourne un recordset vide.

Conclusion : l'approche basée sur sale.order est structurellement inadaptée à ce besoin précis. Il faut inverser la logique.

La solution qui fonctionne : automatisation sur le modèle projet

Plutôt que d'écouter la confirmation de la commande, on va écouter la création du projet lui-même, puis remonter vers la commande client à l'origine de cette création. Cette approche garantit que le projet existe au moment où le code s'exécute, et que tous ses champs de liaison sont déjà renseignés.

Configuration de la règle (solution finale)

  • Modèle : Projet (project.project)
  • Déclencheur : À la création
  • Action : Exécuter du code Python

Code Python final

for project in records:
    order = project.sale_order_id
    if not order:
        if project.sale_line_id:
            order = project.sale_line_id.order_id
    if not order:
        continue

    if order.opportunity_id:
        new_name = "%s - %s" % (order.name, order.opportunity_id.name)
    else:
        new_name = "%s - %s" % (order.name, order.partner_id.name)

    project.write({'name': new_name})

    if project.documents_folder_id:
        project.documents_folder_id.write({'name': new_name})

Pourquoi cette version est plus robuste

  • Aucun problème de timing : le code s'exécute exactement quand le projet vient d'être créé, donc tous les liens vers la commande sont déjà en place.
  • Double tentative de remontée : via sale_order_id ou, à défaut, via sale_line_id.order_id. On couvre ainsi les différents cas de liaison entre projet et vente.
  • Compatible avec les projets manuels : si un projet est créé sans rattachement à une commande, le continue évite toute erreur.
  • Compatible Documents optionnel : le renommage du dossier est conditionné par sa présence effective, donc la règle fonctionne aussi si le modèle de projet n'active pas l'option Documents.

Les deux leçons à retenir de cet article

Au-delà de ce cas particulier, deux principes méritent d'être gardés en tête pour toute automatisation Odoo similaire :

  1. Comprendre les limites de safe_eval : dans les automatisations Odoo, utilisez toujours les méthodes ORM (write(), create(), unlink()) plutôt que l'affectation directe d'attribut. Préférez le formatage % ou .format() aux f-strings.
  2. Bien choisir le modèle déclencheur : quand le traitement doit s'appliquer à un enregistrement créé en cascade par une autre action (typiquement un projet généré lors de la confirmation d'une commande), il est plus fiable d'écouter la création de l'enregistrement cible que l'événement amont. Cela évite les problèmes de timing au sein d'une même transaction.

Conclusion

Modifier le nom d'un modèle de projet à la validation d'un devis dans Odoo 19 est tout à fait réalisable sans module spécifique, à condition de bien choisir le point d'ancrage de l'automatisation. En déclenchant la règle à la création du projet plutôt qu'à la confirmation de la commande, on obtient un comportement fiable, prévisible et facile à maintenir.

Ce type d'optimisation paraît mineur, mais sur le long terme, il fluidifie considérablement le travail au quotidien : les chefs de projet retrouvent leurs affaires en un clin d'œil, et la cohérence entre les modules Ventes, Projet, CRM et Documents est maintenue automatiquement.

Vous avez un projet d'intégration Odoo ou un cas d'usage similaire à automatiser ? Stellarius, partenaire officiel Odoo depuis janvier 2024, accompagne les entreprises dans la mise en œuvre et l'optimisation de leur ERP. Contactez-nous pour échanger sur votre projet.

Pour en savoir plus sur les automatisations Odoo