Renfort technique pour intégrateurs Odoo
Vos projets Odoo ne bloquent pas sur la compta.
Ils bloquent sur la boutique, sur la caisse, sur l'étiquette de colis qui ne sort pas de l'imprimante du dépôt. C'est la partie que personne n'aime chiffrer. C'est celle que je reprends.
Le constat
Une migration se vend sur l'ERP. Elle se juge sur ce que le client touche tous les jours.
Le plan comptable est carré, les stocks sont repris, la facturation tourne. Et pourtant le client râle.
Parce que sa vendeuse scanne un article sur deux. Parce qu'une page de rayon met trois secondes à s'afficher. Parce que l'étiquette de transport ne sort pas, et que personne ne sait dire pourquoi.
Ces sujets tombent entre deux chaises. Ils demandent de connaître Odoo en profondeur et d'aimer le web, CUPS, les DNS, les feuilles de style et les files d'impression. Dans beaucoup d'agences, il n'y a personne pour les prendre.
Je fais ça, et seulement ça. En renfort de votre équipe, sous votre marque, sans jamais toucher à votre périmètre ERP.
Ce que je reprends
La boutique et le site, dans Odoo
Thème, tunnel de commande, click and collect, pages de rayon, fiches produit. SEO technique, balisage schema.org, flux produits, redirections. Dans Odoo, pas dans un WordPress posé à côté qu'il faudra synchroniser toute sa vie.
Ce qui se passe dans le dépôt
Page de préparation des commandes, étiquettes de transport qui sortent toutes seules, impression depuis le serveur vers la box IoT, files CUPS et pilotes ZPL, caisse et codes-barres. Le genre de détail qui décide si l'outil est adopté ou contourné.
L'acquisition, et des chiffres relisables
Newsletters et campagnes dans Odoo, API Conversions de Meta écrite à la main, GA4, PostHog, Search Console, IndexNow. Des mesures qu'on peut recouper et contredire, pas un tableau de bord de démonstration.
Mettre en production sans parier
Scripts de déploiement, sauvegarde avant chaque écriture, surveillance externe, chien de garde sur la prod, procédure de redémarrage qui se vérifie elle-même et sait revenir en arrière. Une boutique et une caisse sur la même instance ne pardonnent pas.
La douleur numéro un des migrations
Une migration Odoo perd les URL indexées. Celle-ci n'en a pas perdu une.
Odoo sert ses fiches produit sous /shop/... par une constante écrite en dur,
SHOP_PATH, appelée à 27 endroits du code. L'ancien site les servait à la racine
du domaine. Réécrire les adresses, c'était accepter de repartir de zéro sur Google, avec un
client qui voit son trafic s'effondrer le lendemain de la bascule et une agence sans réponse
à lui donner.
La parade n'est pas un plan de redirections : c'est un convertisseur d'URL werkzeug qui ne reconnaît que les slugs de produits publiés. Werkzeug essaie ses règles dans l'ordre, donc tout ce qui n'est pas un produit connu retombe sur le routage normal d'Odoo. Les pages de contenu, le back-office et les routes natives gardent la priorité.
Les 808 adresses indexées ont été conservées à l'identique. Il est resté 79 redirections de rubriques, toutes à zéro clic, au lieu des 887 prévues au départ.
Le périmètre a été tranché sur des données, pas au ressenti : six mois de Search Console exportés, 47 199 lignes relues. Verdict, 609 fiches produit cumulaient 281 clics quand la page d'accueil en faisait 3 857.
L'actif à protéger n'était donc pas le référencement des fiches, c'étaient les signaux locaux de la page d'accueil. Savoir ce qu'on ne doit pas protéger fait gagner autant de temps que le reste.
class EvProductSlugConverter(BaseConverter):
"""Convertisseur d'URL qui ne matche que les slugs de produits publiés."""
regex = MOTIF_SLUG
def to_python(self, value):
# lang=None est indispensable : le convertisseur tourne PENDANT le routage,
# avant qu'Odoo n'ait normalisé la langue du navigateur. Un visiteur qui
# envoie « Accept-Language: fr-FR » laisse le contexte sur fr_FR, langue non
# installée ici, et le moindre accès à l'ORM lève alors « Invalid language
# code » : HTTP 422 sur les fiches produit ET sur toutes les pages de contenu.
env = request.env(context={'lang': None})
produit = env['product.template'].sudo().search(
[('ev_url_slug', '=', value), ('is_published', '=', True)], limit=1
)
if not produit:
raise ValidationError() # werkzeug passe à la règle suivante
return produit.with_env(request.env)
Les cinq lignes de commentaire valent le code. Ce lang=None vient d'un incident
réel : un convertisseur s'exécute pendant le routage, avant qu'Odoo n'ait normalisé la langue
du navigateur. Un visiteur avec Accept-Language: fr-FR, langue non installée sur
cette instance, faisait tomber les fiches produit et toutes les pages de contenu
en HTTP 422. Ce genre de détail ne s'apprend pas dans la documentation.
Le site, en vrai
Odoo peut faire une boutique qui ne ressemble pas à Odoo.
Ce n'est pas un thème acheté. Thème sur mesure, tunnel en deux étapes, click and collect avec calendrier de retrait, tri par disponibilité réelle, pastille de rupture, données structurées complètes. Tout vit dans Odoo : un seul stock, un seul catalogue, une seule base clients.
Ce que le panier propose
Les suggestions ne se rattachent pas à la main.
Odoo sait afficher des accessoires et des alternatives, à condition que quelqu'un les associe produit par produit. Sur 926 fiches, personne ne le fait, et ce qui n'est pas fait reste vide. Ici, le bloc se calcule sur les tickets réellement encaissés, magasin compris.
- 170 règles d'affinité entre catégories, soit 85 paires tenues dans les deux sens. Chacune porte son lift et le nombre de tickets qui la soutiennent, parce qu'une règle sans son effectif ne se relit pas.
- Le nombre de tickets est le garde-fou. Une paire vue trois fois produit un lift spectaculaire et ne veut rien dire. Celle qui s'affiche sur la capture, « Jeans » vers « Pantalons », tient sur 765 tickets pour un lift de 3,03. C'est modeste et c'est solide.
- Les associations traversent les rayons. La plus forte du dossier relie « Chaussures enfants » et « Basket filles », lift 154 sur 45 tickets. La suivante relie des boucles d'oreilles à une marque de bijoux : deux catégories qu'aucun arbre produit ne rapproche tout seul.
- Le reste du panier travaille aussi. L'emballage cadeau est proposé en accessoire, et la barre annonce ce qui manque pour la livraison offerte plutôt que de laisser la cliente le calculer.
Le calcul lui-même, les cohortes et la segmentation des clientes vivent dans l'entrepôt de données et sont décrits sur la page pilotage. Ce qui est décrit ici est seulement ce que la boutique en fait : une table lue par le panier, servie depuis Odoo, sans intervention.
Le cas qui n'entre pas dans le moule
Une marque au catalogue, mais pas au panier.
Certaines maisons ne veulent pas être revendues en ligne, ou le stock est trop unique pour être promis à distance. Le réflexe est de les sortir du site. On perd alors les recherches qui portent le nom de la marque, et elles sont nombreuses.
- 138 références restent au catalogue, avec leurs fiches, leurs photos et leur disponibilité réelle. Elles sont indexables, et elles captent les recherches de marque.
- L'ajout au panier est remplacé, pas retiré. Sur ces fiches, le bouton ouvre un formulaire de demande. La cliente dit quel modèle l'intéresse, la boutique vérifie et répond.
- Le stock est unique et partagé avec le magasin. C'est la raison honnête du dispositif, et la page l'écrit : mieux vaut vérifier qu'un sac est là que l'annoncer à tort.
- La page assume d'être locale. Adresse, horaires, distance depuis Liège, et un numéro à appeler avant de se déplacer. Ce n'est pas du contenu de remplissage, c'est ce que cherche quelqu'un qui tape le nom d'une marque avec celui d'une région.
Le tunnel livré
Deux étapes, et rien qui ne serve la commande.
Le tunnel d'Odoo demande tout, tout de suite, et le compte avant la commande. Celui-ci demande l'e-mail, puis les coordonnées, puis fait payer. Voici les quatre écrans réels, dans l'ordre où la cliente les voit.
Le Click and Collect
Un calendrier qui ne se maintient nulle part.
- Les dates viennent des heures d'ouverture du magasin, déjà dans Odoo. Les jours proposés sont ceux où le magasin travaille, et les congés posés dans ce même calendrier bloquent les dates tout seuls. Rien ne se saisit deux fois, donc rien ne peut diverger.
- Jamais le jour même. La première date proposée est demain : une commande passée à 23 h ne peut pas être promise pour le matin.
- La date choisie s'écrit sur la commande, et le bon de livraison est régénéré pour la porter. La préparatrice la voit sur son écran sans aller la chercher, et le colis attend la bonne cliente le bon jour.
- Le retrait est en tête, et gratuit. C'est le seul mode de livraison qui fait revenir quelqu'un dans le magasin, et une cliente qui vient chercher un jeans en repart rarement avec le jeans seul.
- Les points de fidélité s'affichent avant le paiement : ce que la cliente a, ce qui lui manque pour cinq euros, et ce que la commande va lui rapporter. Le mécanisme existait déjà et personne ne le voyait : 2 170 clientes avaient des points et aucune page du tunnel ne le leur disait.
- Quatre moyens de paiement par un seul contrat, carte, Bancontact, Belfius et PayPal, avec la note Google affichée juste à côté. Celle qui s'affiche ici est celle que les demandes d'avis ont fait bouger.
Dans le même tunnel
L'adresse se vérifie chez bpost pendant qu'elle se tape.
Une adresse mal écrite se paie deux fois : l'étiquette part, le colis revient, et la cliente écrit au magasin. Le tunnel interroge donc bpost à la frappe et pose ses suggestions dans les champs d'Odoo, sans en ajouter un seul à l'écran.
Essayez Tapez « chaus » dans Rue, choisissez, puis tapez 8 dans Numéro. Les flèches parcourent la liste, Entrée choisit, Échap ferme. Le code postal et la ville interrogent le même niveau et se remplissent ensemble.
- Le widget officiel de bpost a été posé, puis retiré le même jour. Il ajoutait ses quatre champs au-dessus de ceux d'Odoo, avec ses libellés : la cliente voyait « code postal », « nom de rue », « numéro de maison », puis quinze centimètres plus bas « Code postal », « Rue », « Numéro ». Les mêmes informations, demandées deux fois.
- Il pesait 528 Ko d'Angular sur la page où la latence compte le plus de tout le site, et il lisait la clé d'API dans le HTML, donc elle était publique. On appelle maintenant le même service depuis le serveur : 16 Ko de JavaScript au total, et la clé ne quitte jamais la machine.
- Le contrat a été trouvé en lisant le widget, rien n'étant documenté : quatre niveaux qui s'enchaînent, localité, rue, numéro, boîte, chacun exigeant le contexte du précédent. Le paramètre s'appelle
locality, la réponse rendlocalityName, et l'en-tête estx-api-key: tout le reste répond 403 ou 400. - 220 ms de repos entre deux frappes, deux caractères minimum, six suggestions, quatre secondes de patience. En dessous de deux caractères tout le pays répond ; au-delà de quatre secondes, une suggestion arrive après que la cliente a fini de taper, donc elle ne sert plus à rien.
- Le tunnel ne dépend jamais du service. Aucun champ n'est verrouillé, aucune valeur refusée, et si bpost ne répond pas il ne se passe simplement rien. Une adresse étrangère, un lieu-dit, une rue trop neuve : tout se tape à la main. Une API qui tombe ne doit pas empêcher une vente.
- Et un interrupteur. Vider la clé dans les paramètres éteint les suggestions : le marqueur disparaît de la page, le script ne trouve rien et s'arrête. Le formulaire retrouve sa forme d'origine sans redémarrage ni mise à jour de module.
Le service de validation ne répond jamais « faux ». Il rend ce qu'il a su reconnaître, et corrige en silence : « Peron » devient « PERRON ». Le seul signal exploitable est le champ qui revient vide quand il n'a pas su placer la rue ou le numéro.
« 82 Chaussée de Mons » ne rend ni rue ni numéro. La même adresse écrite « Chaussée de Mons 82 » rend les deux. Une bonne part des adresses signalées ne sont donc pas fausses, seulement mal écrites, et se réparent sans rien demander à la cliente.
Le même service passe en revue les adresses déjà en base, celles reprises de l'ancien site comme celles saisies en magasin. On répare avant que le colis parte, pas après qu'il est revenu.
Le terrain, en vrai
Une page de préparation, écrite pour un téléphone tenu d'une main.
L'ancien site avait un outil de préparation maison, 5 292 lignes accumulées au fil des ans, qui mourait avec lui. Reconstruit en module Odoo : une route, une page autonome sans le gabarit de la boutique, aucun framework et aucune police distante. Elle s'ouvre vite sur le wifi du magasin, y compris quand il est mauvais.
Essayez Cochez une ligne : elle se barre. Cochez tout un bon et le bouton de validation apparaît, puis demande confirmation en nommant la cliente. La flèche en haut à droite remet les deux bons dans la file.
- 44 px minimum par cible tactile. En dessous, on rate la case et on coche la ligne d'à côté. Ici, ça veut dire préparer le mauvais article.
- La vignette fait 96 × 128, pas 72 × 96. C'est la photo qui fait reconnaître la pièce dans un rayon, le libellé ne sert qu'à confirmer. Trop petite, elle oblige à lire, et lire est lent.
- Le bouton photo est hors du label. Dedans, un clic sur l'image ouvrirait la galerie et cocherait la case du même geste.
- La dernière case ne valide pas. Cocher dit « j'ai la pièce en main » : fréquent, réversible. Valider expédie, crée une étiquette réelle et facture un envoi. Le bouton n'apparaît que quand tout est coché, et la confirmation nomme la cliente.
- Rechargement toutes les 30 secondes, par injection des seules cartes nouvelles. Jamais par rechargement de la page : la préparatrice a le pouce sur l'écran.
- Fenêtre de sept jours, « tout » par défaut. La base portait cinq bons prêts dont le plus vieux datait de cinq mois. Un bon oublié doit sauter aux yeux, pas se cacher derrière le bon onglet.
auth="user" ne protège rien ici : toute cliente ayant un compte est un res.users. Ce qui tient, c'est le refus des comptes partagés plus l'exigence du groupe Stock.
stock.move.line.picked et stock.move.picked sont deux champs distincts, le premier n'alimente pas le second, et button_validate ne regarde que le second.
Deux commandes préparées, zéro étiquette sortie. La recherche d'imprimante ramenait celle des étiquettes d'article, et le transporteur du bon valait in_store. Corrigé, et écrit.
L'après-vente, et la loi
La rétractation n'est pas un retour. Depuis juin, elle a son propre bouton.
Deux régimes coexistent sur une boutique belge. Ils ne se ressemblent pas, les confondre coûte cher, et un intégrateur les découvre rarement dans le cahier des charges : ils tombent à la fin, juste avant la mise en ligne.
Quatorze jours calendrier pour renoncer, sans motif, à compter du jour où la cliente reçoit le bien. Articles VI.47 à VI.53 du Code de droit économique, qui transposent la directive 2011/83/UE. Et si l'information sur ce droit n'est pas donnée dans les formes, l'article VI.48 porte le délai de quatorze jours à douze mois.
L'article 11 bis de cette même directive, inséré par la directive (UE) 2023/2673, impose une fonction de rétractation en ligne : un lien clairement identifié et disponible pendant tout le délai, un formulaire où la cliente confirme son identité et sa commande, un bouton de confirmation, et un accusé de réception sur support durable portant la date et l'heure.
| Retour commercial | Rétractation | |
|---|---|---|
| Motif | selon les conditions de la maison | aucun exigé |
| Frais de livraison aller | non remboursés | remboursés si la commande est rendue en entier |
| Forme du remboursement | avoir ou bon d'échange | le moyen de paiement d'origine |
| Délai | politique de la maison | 14 jours après la déclaration |
Cette colonne de droite n'est pas négociable, et deux textes du site la contredisaient. Les conditions générales déduisaient les frais de port dès que le total repassait sous le seuil de livraison offerte, y compris sur un retour total : sur une rétractation entière, tous les paiements reçus doivent être rendus, livraison standard comprise. Et les conditions promettaient un échange que la politique de retour refusait deux pages plus loin. Les deux ont été réalignées sur ce qui se pratique vraiment.
Ce qu'on a trouvé en ouvrant l'existant
Une page qui confirmait des demandes qu'elle n'enregistrait pas.
La page de rétractation reprise de l'ancien site affichait « veuillez remplir les informations ci-dessous », puis un volet dépliant qui annonçait « votre demande a été soumise avec succès ». Sans un seul champ de formulaire. Le formulaire n'avait pas migré, seul son habillage était passé. C'est pire qu'une page absente : la cliente lisait une confirmation pour une demande qui n'existait nulle part, et repartait rassurée.
- La date de déclaration est posée à la création et n'est jamais recalculée. C'est elle qui fait foi, c'est elle qui fait courir les quatorze jours, et aucun traitement ne doit pouvoir la déplacer.
- L'enregistrement et l'accusé horodaté sont automatiques. C'est le cœur de l'obligation légale : ça ne se confie pas à une tâche planifiée qui peut ne pas tourner.
- Le remboursement, lui, reste manuel. La loi autorise à attendre le colis ou la preuve de son envoi, et rembourser au clic ouvrirait la porte à l'abus. C'est une décision du commerçant, pas un automatisme.
- Un garde-fou quotidien pose un rappel à dix jours, pour que les quatorze ne soient jamais dépassés. Rien dans Odoo ne signale ce dépassement, et c'est pourtant lui qui coûte.
- La commande n'est trouvée que si la référence et l'e-mail concordent, et le message d'erreur est volontairement le même dans les deux cas d'échec. Sinon le formulaire devient un moyen de tester l'existence des commandes, dont les numéros se suivent.
- L'accusé ne s'efface pas après envoi. Odoo supprime par défaut certains messages une fois partis : un accusé de réception qui disparaît ne prouve plus rien, le jour où il faut prouver.
Détail qui a son importance : le lien du pied de page ne s'appelle plus « droit de rétractation » mais « renoncer au contrat ». Le texte européen veut une formule qui désigne la fonction, sans ambiguïté, pas l'intitulé d'une page d'information.
L'autre régime
Le retour commercial passe par un ticket, pas par une boîte mail.
Un formulaire public : sa commande retrouvée par référence et e-mail, les articles à rendre cochés un par un, un motif par article, et le choix entre remboursement et bon d'échange.
Trois brouillons créés d'un coup : un ticket dans l'équipe Retours, le retour de marchandise côté stock, et la note de crédit. Tout se traite depuis le ticket, remise en stock ou mise au rebut article par article, puis remboursement.
Aucune commande n'est exposée sans correspondance exacte de l'e-mail, le nombre d'essais par adresse IP est limité, et tout ce que la cliente écrit est échappé avant d'atterrir dans le ticket.
Un exemple de tuyauterie
Le flux produits, enrichi article par article.
1 557 articles servis en continu par un contrôleur Odoo. Odoo ne sait pas produire ça seul : la catégorie Google, le genre, la tranche d'âge et les images secondaires ont été déduits du catalogue et ajoutés. Voici un article, tel qu'il sort aujourd'hui.
<item>
<g:id>01-729053-604-blanc-L</g:id>
<g:item_group_id>T19092</g:item_group_id>
<title>Débardeur avec finition en maille filet - YAYA - blanc (L)</title>
<link>https://[domaine du client]/debardeur-avec-finition-en-maille-filet-yaya-blanc</link>
<g:image_link>.../product.product/37438/image_1920</g:image_link>
<g:additional_image_link>.../product.image/1116/image_1920</g:additional_image_link>
<g:additional_image_link>.../product.image/1117/image_1920</g:additional_image_link>
... cinq autres images secondaires
<g:availability>in_stock</g:availability>
<g:price>34.95 EUR</g:price>
<g:brand>YAYA</g:brand>
<g:size>L</g:size>
<g:google_product_category>212</g:google_product_category>
<g:gender>female</g:gender>
<g:age_group>adult</g:age_group>
</item> L'autre bout du même tuyau
La mesure part du serveur, pas du navigateur.
Un flux produits sert à faire de la publicité. Une publicité ne s'optimise que si les conversions remontent. Or le marqueur posé dans la page est bloqué, tronqué ou expiré chez une bonne partie des visiteurs. Ici, les événements partent d'Odoo, qui sait ce qui s'est réellement passé.
- 8 202 événements au 22 septembre 2026, tous partis, aucun en échec. Ce n'est pas un appel direct dans le code du site : chaque événement est écrit dans une table Odoo, envoyé par un traitement de fond, et garde sa réponse de Meta, son compteur de tentatives et son état. Quand l'API répond mal, ça se rejoue au lieu de disparaître.
- Chaque événement porte un identifiant partagé avec le marqueur du navigateur. C'est ce qui permet à Meta de reconnaître qu'un achat vu deux fois est le même achat. Sans lui, poser la mesure des deux côtés gonfle les chiffres au lieu de les fiabiliser.
- L'achat est déclenché par la commande, pas par l'affichage d'une page de remerciement. Une cliente qui ferme l'onglet après avoir payé est comptée comme les autres.
Les cinquante achats remontés se comparent aux cinquante-sept commandes réellement encaissées sur le même intervalle. L'écart est celui du consentement, et il se lit. C'est le but : une mesure dont on connaît la marge vaut mieux qu'une mesure dont on ignore le trou.
Les preuves
Huit choses trouvées sur un seul dossier.
Une boutique de prêt-à-porter, site public et caisse sur la même instance, migrée de la V14 à la V19. Tout ce qui suit a été mesuré avant et après, pas estimé. Aucun de ces points n'était dans le cahier des charges, et c'est exactement le problème.
13 469 références sur 23 691. La règle Lot barcodes interceptait les codes internes avant la règle Produit. Le défaut était antérieur à la migration et personne ne l'avait jamais nommé : comme une partie des articles passait, tout le monde croyait à un scanner capricieux.
Les visiteurs anonymes du site naviguaient avec les droits d'un administrateur système. Le symptôme remonté était du SEO : un sitemap de 5 759 URL pour 756 produits publiés. La cause était de la sécurité. Odoo ne filtre les produits dépubliés que pour les utilisateurs externes.
27 000 règles de prix mortes réévaluées à chaque affichage, et un champ calculé qui finissait par s'appeler lui-même. Deux causes indépendantes qui se masquaient l'une l'autre dans le profil.
wkhtmltopdf redemande ses feuilles de style à Odoo, en HTTP, sur le serveur vivant. Avec deux workers, un rendu un peu lourd les prend tous les deux et plus rien ne répond. Diagnostic, puis chien de garde qui tue les rendus qui s'éternisent.
L'e-mail « donnez-nous votre avis » de l'ancien site n'était ni dans l'outil d'envoi ni dans une extension du marché : un greffon maison, chargé sans activation, invisible dans l'administration. 281 demandes entre mai et août, 26 avis récoltés, note passée de 4,6 à 4,7. Avant de déclarer un automatisme perdu, il faut aller voir sur l'ancien serveur, il répond encore.
Un PNG envoyé dans une file ZPL. CUPS répondait fièrement completed, le pilote jetait le travail à la poubelle. Deux jours de colis étiquetés à la main avant que quelqu'un ose dire que ça ne marchait pas.
Le programme de fidélité repris de WooCommerce fonctionnait parfaitement. Aucune page du tunnel n'en soufflait mot. Le mécanisme existait déjà dans Odoo : il suffisait de l'afficher là où la cliente est identifiée et où une remise l'intéresse encore.
Après avoir compris pourquoi Odoo mettait une heure là où l'ancien outil mettait deux minutes : un seul fil de cron, et deux tâches qui ne peuvent pas se croiser. Et après avoir mesuré que l'accélérateur maison rendait l'envoi plus lent, puis l'avoir retiré.
Ce ne sont pas des anecdotes. Chacun de ces points a été écrit, daté et rangé dans une base de connaissances relisable, avec la cause, la parade et le piège à ne pas refaire. C'est ce qui reste chez vous quand je pars.
Quatre pièges que la documentation ne mentionne pas
Chacun a coûté une demi-journée. Une fois.
Ceux-là sont dans le code de l'éditeur, pas dans le mien. Ils ont un point commun : ils ne lèvent aucune erreur, ou ils la lèvent très loin de leur cause. C'est pour ça qu'ils coûtent cher la première fois, et rien du tout la deuxième.
literal_eval Les domaines des campagnes marketing sont lus avec literal_eval, pas safe_eval : ni datetime, ni context_today, ni relativedelta n'y passent. Tout calendrier doit vivre dans un champ stocké qu'un cron entretient.
marketing.campaign Une campagne aspire tout l'historique le jour où on la démarre. Sur les commandes, ça faisait 11 849 lignes reprises de l'ancien site, prêtes à recevoir un e-mail. Ce qui protège : un filtre sur l'origine web plus un plancher de date. Ne jamais élargir un domaine de campagne sans compter d'abord ce qui entrerait.
ir.qweb Odoo surveille les balises de script de ses pages de contenu et réécrit ce qu'il ne reconnaît pas. Un pixel publicitaire collé dans l'éditeur ne part jamais, et rien ne le signale. Le suivi des conversions a donc été écrit côté serveur, avec l'API dédiée.
cookie Un cookie de consentement illisible fait tomber tout le site en 500, pas seulement la barre qui le lit. Un visiteur avec un cookie corrompu ne voit plus rien, et son navigateur le lui renvoie à chaque tentative.
Ce qui reste dans le dépôt
Vingt-quatre modules, nommés par leur rôle.
Le préfixe porte le nom du client, il est masqué ici. Chacun est un module Odoo autonome, installé en production, versionné, avec ses commentaires en français et sa raison d'être écrite en tête de fichier.
Comment on travaille
Quatre règles, écrites avant de commencer.
Votre client ne me voit pas, ou il me voit sous votre nom. Au choix, et c'est le vôtre. Je ne démarche jamais un compte rencontré chez vous.
Un périmètre écrit, un prix, une date. Ce qui sort du périmètre est chiffré à part, avant d'être fait. Pas de régie qui dérive et qu'on découvre à la facture.
Du code commenté en français, des modules propres hors de vos arbres git, les scripts de déploiement et la procédure de retour arrière. Rien qui ne tourne que sur ma machine.
Je reste sur le web, le terrain et l'exploitation. La compta, les stocks, la production et la paie restent chez vous. Si un correctif doit passer par votre périmètre, je le documente et je vous le passe.
Les questions qui viennent toujours
Sept réponses, avant le premier appel.
Une migration vers Odoo fait-elle perdre le référencement ?
Pas si les adresses sont conservées. Odoo sert ses fiches produit sous /shop/... par une constante écrite en dur, appelée à 27 endroits du code. Un convertisseur d'URL werkzeug qui ne reconnaît que les slugs de produits publiés permet de garder les adresses de l'ancien site à l'identique, sans voler les URL des pages de contenu ni des routes natives. Sur le dossier de référence, les 808 adresses indexées ont été conservées et il n'est resté que 79 redirections de rubriques, toutes à zéro clic, au lieu des 887 prévues au départ.
Travaillez-vous en marque blanche pour une agence Odoo ?
Oui, c'est le mode par défaut. Le client final ne me voit pas, ou il me voit sous le nom de l'agence : c'est l'agence qui choisit. Je ne démarche jamais un compte rencontré chez vous.
Quel périmètre Odoo prenez-vous, et lequel ne prenez-vous pas ?
Je prends le site et la boutique dans Odoo, le tunnel de commande, le SEO technique et les flux produits, les outils de terrain (préparation de commandes, étiquettes de transport, impression vers box IoT, caisse et codes-barres) et l'exploitation (déploiement, surveillance, retour arrière). Je ne touche pas à la comptabilité, aux stocks, à la production ni à la paie : ce périmètre reste chez l'intégrateur.
Comment se facture une mission de renfort Odoo ?
Par lot, au forfait : un périmètre écrit, un prix et une date. Ce qui sort du périmètre est chiffré à part avant d'être réalisé. Pas de régie qui dérive et qu'on découvre à la facture.
Gérez-vous le droit de rétractation et les retours dans Odoo ?
Oui, et les deux régimes sont tenus séparés. La rétractation est une obligation légale : quatorze jours calendrier sans motif à compter de la réception du bien, articles VI.47 à VI.53 du Code de droit économique belge, et depuis le 19 juin 2026 une fonction de rétractation en ligne imposée par l'article 11 bis de la directive 2011/83/UE, inséré par la directive (UE) 2023/2673, avec accusé de réception horodaté sur support durable. Le retour commercial, lui, relève de la politique du commerçant et passe par un formulaire public qui crée le ticket, le retour de marchandise et la note de crédit en brouillon. Sur une rétractation totale, tous les paiements reçus sont remboursés, frais de livraison standard compris.
Que reste-t-il à l'agence à la fin de la mission ?
Des modules Odoo propres déposés dans un répertoire distinct de vos arbres git, du code commenté en français, les scripts de déploiement et la procédure de retour arrière, plus une base de connaissances qui documente chaque cause, chaque parade et chaque piège rencontré.
Sur quelle version d'Odoo intervenez-vous ?
Odoo 19, en production, boutique publique et point de vente sur la même instance. L'expérience de référence est une migration complète de V14 à V19, réalisée en six semaines.
Un dossier qui traîne depuis trois mois ?
Décrivez-le en cinq lignes. Je réponds sous 48 h : si c'est pour moi, ce que ça coûte et combien de temps ça prend. Si ce n'est pas pour moi, je le dis aussi, et je le dis vite.