← Retour aux travaux
2022 · Marketplace B2B · plateforme Odoo

MySpecialist

Plateforme SaaS belge qui met en relation des clients avec des prestataires indépendants vérifiés, en Belgique et en Suisse. Reprise en 2022 sous forme d'une couche Symfony branchée sur Odoo 8 — rebâtie en Django propre sur Odoo 16, et tenue depuis par les mêmes trois ingénieurs.

Rôle
Implémentation full-stack · architecture · QA · DevOps
Durée
Depuis 2022, en cours
Équipe
3 ingénieurs
VISUEL DE PROJET · PLACEHOLDER
FIG. 01
Contexte

MySpecialist est une plateforme SaaS belge qui met en relation des clients ayant besoin d'un travail spécialisé avec des prestataires indépendants vérifiés, en Belgique et en Suisse. Elle couvre l'ensemble du cycle — demandes de devis entrantes, matching et acceptation prestataire, planification, facturation, e-facturation Peppol, suivi de satisfaction — en trois langues (FR / NL / EN) et sur deux marchés, à partir d'une seule base de code.

Engagés en 2022 pour reprendre la plateforme de bout en bout, nous avons hérité d'une couche Symfony accumulée au rythme des livraisons rapides — formulaires faits main, pas de suite de tests, couche d'outils internes mélangée à la logique métier — branchée sur une instance Odoo 8 vieille de cinq versions majeures. La première phase de la mission a été un sauvetage : la couche Symfony a été rebâtie en une app Django propre, et le côté Odoo a été migré de la version 8 à la version 16 via un pipeline ETL sur mesure — clients, commandes, factures, fils de discussion, déplacés schéma par schéma et validés contre l'ancienne base avant bascule.

C'est ce qui sert de fondation à chaque fonctionnalité livrée depuis 2023. Quatre ans et plus de mille trois cents commits plus tard, nous sommes toujours l'équipe d'ingénierie derrière la plateforme — les mêmes trois personnes, la même base de code, et une politique de déploiement qui n'a pas produit d'incident destructeur.

Les parties intéressantes ne sont pas où l'on s'y attend pour un marketplace. Elles vivent dans les coutures : la loi belge sur la e-facturation, la double propriété avec pool client partagé, un pipeline CRM qui ne doit s'auto-avancer que lorsque trois portes booléennes passent toutes au vert, et un module EDI d'Odoo 19 qu'il a fallu retraduire avec soin dans les idiomes d'Odoo 16.

Périmètre

Ce que nous avons bâti.

myspecialist_base01

Menus fondateurs, dépendances principales, branchement l10n_be.

myspecialist_sale02

~20 modèles : workflows prescripteurs, commissions, leads CRM, portail, promos, témoignages.

myspecialist_peppol03

EDI Peppol : signature, envoi, réception des factures — backport depuis Odoo 19.

myspecialist_localities04

Hiérarchie pays / régions / villes en FR / EN / NL.

myspecialist_lang05

Standardisation des langues actives — en_BE et en_CH remplacent en_US / fr_FR, avec migration des traductions.

myspecialist_sms06

Notifications Pushbullet, configuration SMS, modèles de messages.

myspecialist_brevo_sync07

Sync unidirectionnel Odoo → Brevo avec normalisation E.164 et cron de rattrapage nocturne.

myspecialist_cdn08

Gestion des URLs CDN pour les assets statiques.

myspecialist_press09

Gestion des communiqués de presse.

myspecialist_project_pictures10

Galeries de projets.

s3_backup11

Sauvegardes de base de données vers AWS S3.

Application Django12

Reconstruite à partir de la base Symfony héritée (2022). Partage la base Postgres d'Odoo ; porte les outils et flux qui s'installent mieux hors d'Odoo.

Approche

À quoi ressemble le travail, en 4 pièces.

01

Modèle métier & pipeline CRM

Traduction du marketplace bilatéral dans le CRM d'Odoo : prescripteurs, prestataires, pool partagé MySpecialist, modèle de propriété client indépendante. Un pipeline d'opportunités à neuf étapes qui s'avance automatiquement quand ses portes de qualification passent toutes au vert, avec des règles d'accès par groupe qui isolent ce que le staff, les prescripteurs et les indépendants voient.

02

Peppol & conformité belge

Backport du module account_peppol d'Odoo 19 vers Odoo 16 — authentification proxy, gestion des paires de clés RSA-2048, documents sortants par lots, validation XML Helger avec mise en cache SHA-256 des résultats. Overrides EAS propres à la Belgique pour que l'EndpointID dans le XML corresponde au champ receiver côté API. Les factures bloquées ont un bouton de revalidation ; les enregistrements obsolètes notifient l'équipe au lieu d'être archivés silencieusement.

03

Tests, environnements, déploiement

Suites Playwright découpées par marché (BE / CH) et par tier (office / prod), plus un pipeline end-to-end couvrant devis → facture → paiement → satisfaction. Une politique à deux environnements — chaque push sur staging déclenche un déploiement office et une mise à jour de module via XML-RPC ; les déploiements prod sont manuels et explicites. Archivage des effets de bord côté tests pour qu'ils ne fuient jamais de mail.

04

Sauvetage, migration, longévité

La première phase a été un sauvetage — la couche Symfony rebâtie en Django propre, le côté Odoo migré de 8 à 16 via un pipeline ETL sur mesure. Depuis, la plateforme a tenu sa forme sur onze modules, deux marchés, trois langues et un socle Odoo 16 stable. Les décisions d'architecture sont écrites dans CLAUDE.md — n'importe lequel d'entre nous reprend là où un autre s'est arrêté.

Choix techniques

Les solutions dont nous sommes le plus fiers.

01

Symfony spaghetti → port Django propre

La première année de la mission a été surtout un sauvetage. La base Symfony s'était accumulée au rythme des livraisons rapides — formulaires faits main, pas de tests, couche d'outils internes enchevêtrée à la logique métier. Nous l'avons rebâtie en une app Django partageant la base Postgres d'Odoo : frontières ORM nettes, vraie suite de tests, la même équipe étend désormais une fonctionnalité en jours au lieu de semaines.

02

Migration Odoo 8 → 16 par ETL

La plateforme tournait initialement sur Odoo 8 — cinq versions majeures en retard. Nous avons écrit un pipeline ETL sur mesure pour faire passer clients, commandes, factures et fils de discussion vers Odoo 16, en remappant les schémas au fil des changements de modèles. Chaque lot était validé contre l'ancienne base avant bascule. L'ère Odoo 16 a démarré en 2023, sans perte de donnée.

03

Backport Peppol, Odoo 19 → 16

Ré-implémentation d'account_peppol contre l'ancien wizard d'envoi (account.invoice.send au lieu d'account.move.send en Odoo 19). Le XML est généré au posting via account_edi_ubl_cii._ubl_cii_post_invoice puis explicitement régénéré avant ré-envoi, l'attachment stocké pouvant dériver. Les tests mockent le proxy via une fixture commune.

04

Override EAS pour les partenaires belges

Le core d'Odoo 16 livre COUNTRY_EAS['BE'] = 9925, mais les partenaires Peppol belges utilisent en réalité l'EAS 0208. Override d'account.edi.xml.ubl_bis3._get_partner_party_vals pour que l'EndpointID du XML corresponde au champ receiver côté API — sans ce fix, le proxy renvoie l'erreur 103 et rien ne part.

05

Dédup des comptes bancaires en entrée

Le _import_retrieve_and_fill_partner_bank_details d'Odoo 16 sanitize son input mais cherche res.partner.bank par acc_number brut, percutant la contrainte d'unicité quand le compte stocké a un formatage du type 'BE55 7350 7167 8944'. Override pour chercher par sanitized_acc_number, avec clean_context pour rester aligné sur le core.

06

Prévention de récursion via threading.local

Les appels Peppol sortants passent par un proxy Odoo qui peut être appelé par Odoo lui-même. Les requêtes sont enveloppées dans des flags threading.local() — un appel proxy à l'intérieur d'un appel proxy court-circuite au lieu de récursionner sous charge.

07

Revalidation des factures bloquées

Quand une facture se bloque en cours de flow Peppol, un bouton action_revalidate_peppol_xml régénère l'attachment, ré-exécute la validation Helger et poste le résultat dans le chatter via account.edi.common._check_xml_ecosio. L'équipe voit ce qui a foiré et ce qui a été tenté, dans le document lui-même.

08

Politique de déploiement à deux environnements

Office (staging) et prod suivent des règles opposées : chaque push staging est suivi d'un déploiement office et d'une mise à jour de module ; les déploiements prod n'ont lieu que sur demande humaine explicite. Quatre ans plus tard, aucun incident destructeur causé par un déploiement, sur l'un ou l'autre environnement.

Résultats

Quelques chiffres, en formes brutes.

11
Modules Odoo personnalisés
BE · CH
Marchés en production
FR · NL · EN
Langues, une seule base
4+ ans
Même équipe, même base de code

Stack
Odoo 16PythonPostgreSQLDjangoPeppolPlaywrightDockerNginxAWS S3GitHub Actions

Un projet qui mérite ce niveau de soin ?

Démarrer une conversation