(Guide pratique pour automatiser l’extraction, la transformation et le chargement des données lors d’une migration ou d’une mise à jour de votre instance Dolibarr)
1. Pourquoi l’ETL est indispensable lors d’une mise à niveau de Dolibarr
| Situation | Risque sans ETL | Bénéfice avec ETL |
|---|---|---|
| Migration d’une version 0.x → 12.x | perte de données, champs incompatibles,orfrois de duplication | transfert fiable, validation des mappings, traçabilité |
| Intégration d’une nouvelle boutique / site multi‑entreprises | duplication manuelle, erreurs de saisie | automatisation du flux d’alimentation des modèles (clients, produits, comptes) |
| Synchronisation avec d’autres ERP ou CRM | divergence des référentiels | flux bidirectionnel, réconciliation automatisée |
L’ETL (Extract‑Transform‑Load) désigne le processus qui extrait les données d’une source, les transforme (nettoyage, agrégation, mapping), puis les charge dans une cible (une nouvelle base Dolibarr ou un référentiel externe).
Dans le contexte d’une mise à niveau, l’ETL garantit :
- La cohérence entre les anciens et les nouveaux schémas de données.
- La reproductibilité du processus (script, job planifié, CI).
- La traçabilité (logs, historique des changements).
2. Principes de base d’un ETL dédié à Dolibarr| Étape | Description | Outils/Technologies couramment utilisés |
|——|————-|—————————————|
| Extraction (E) | Extraction des tables essentielles (e.g. llx, llx_product, llx_categorie, llx_user) depuis l’instance source. | – Scripts PHP (Dolibarr SDK)
– SQL natif (SELECT ... FROM llx_…)
– dump-sql ou mysqldump |
| Transformation (T) | Nettoyage, mapping des anciens codes (status, type) avec les nouveaux, agrégation de données (ex : fusion de sous‑commandes), génération de clés JSON ou CSV compatibles avec le format attendu par la cible. | – PHPUnit pour valider les règles
– Symfony Console (commandes)
– Pandas (Python) ou pandas‑flavor pour volumineux
– Scripts SQL (stories, fonctions) |
| Chargement (L) | Insertion dans la base cible (nouvelle version ou instance). L’insertion doit respecter les contraintes (PRIMARY KEY, NOT NULL, triggers) et activer les hooks Dolibarr. | – php dolibarr.php move (outil interne)
– Doctrine DBAL / Doctrine ORM
– INSERT … VALUES via script batch ou script Python avec pymysql |
3. Étapes concrètes pour un upgrade standard> À retenir : Avant de lancer le ETL, créez toujours un dump complet de la base source et testez le processus sur une base de sandbox.
3.1. Scoop (extraction)
# Export de tous les modules nécessaires (exemple : clients, devis, factures, articles)
mysqldump -u root -p mydb \
llx_categorie llx_client llx_command llx_facture \
llx_product llx_product_category llx_sales;
Le dump se retrouve sous forme de fichiers .sql ou de CSV (via le module CSV Export de Dolibarr).
3.2. Transformation – Mapping des champs
Exemple 1 : Passages de status 0/1 à confirmed / cancelled
| Ancien champ | Ancien valeur | Nouvelle valeur | Règle de transformation |
|---|---|---|---|
status (int) |
0 |
0 → draft |
if($old==0) $new='draft'; else $new='confirmed'; |
status (int) |
1 |
1 → cancelled |
if($old==1) $new='cancelled'; |
Exemple 2 : Conversion de dates (format YYYY-MM-DD → YYYY-MM-DD HH:MM:SS)
// Avant$dateOld = $row['date'];
// Après
$dt = new DateTime($dateOld);
$dateNew = $dt->format('Y-m-d H:i:s');
Exemple 3 : Normalisation des codes produits
UPDATE llx_productSET sku = REPLACE(sku, 'OLD_', 'P_')
WHERE sku LIKE 'OLD_%';
3.3. Chargement – Insertion dans la nouvelle base« `php
// Exemple d’une commande artisanale via le SDK
use Dolibarr\Core\ injector\ Dolibarr;
Dolibarr::getInstance()->useDb();
$newOrder = new \Dolibarr\Order($db);
$newOrder->date = $dateNew;
$newOrder->status = $newStatus;
$newOrder->total = $row[‘total’];
$newOrder->client_update($clientId, $db); // Met à jour/Déjà créé le client
foreach ($items as $item) {
$newLine = new \Dolibarr\Line( »);
$newLine->fk_product = $item[‘fk_product’];
$newLine->qty = $item[‘qty’];
$newLine->price = $item[‘unit_price’];
$newLine->add(); // ajoute à la commande
}
$newOrder->add(); // sauvegarde
> **Astuce** : Encapsulez le tout dans une **commande Symfony CLI** (`php bin/console app:upgrade-dolibarr`) afin de pouvoir lancer, stopper ou ré‑exercuter le flux via le scheduler.
---
## 4. Exemples concrets d’ETL « real‑world »
### 4.1. Migration multi‑site vers une architecture "Societe/Multisite"
**Contexte**
- 12 boutiques matérielles, chaque boutique possède son propre jeu de produits.
- Installation d’une plateforme centrale (Dolibarr 12 avec multi‑societe).
**ETL à mettre en œuvre**
| Étape | Action | Code snippet (PHP) |
|------|--------|--------------------|
| **E** | Extraction de chaque `llx_entity` (fichier `entities` de chaque boutique). | ```php $db = new \Dolibarr\db('host','user','pwd','db'); $res = $db->query('SELECT * FROM '.$prefix.'entity');``` |
| **T** | Transformations : <br>• Normaliser la clé `entity` → `soc_id` (auto‑increment) <br>• Convertir les sites `currency` en un même champ `currency` ou `default_currency`. | ```php $entityId = $row['id']; $socId = $newIndexMap[$entityId]; $currency = $row['currency'];``` |
| **L** | Chargement dans la base centrale avec `soc_id` approprié, création des comptes clients associés. | ```php $soc = new \Dolibarr\Societe($db); $soc->fetch($socId); $soc->createFromArray([...]);``` |
**Résultat** :
- < 2 % de données en doublon après le mapping.
- Un script **batch** exécutable via `cron` toutes les 24 h pour synchroniser de nouvelles modifications.
---
### 4.2. Migration d’un module *Purchase* → *Procurement* avec champs additionnels
**Avant (v9)**
- Table `llx_product` (SKU, label, price)
- `llx_supplier` (nom, adresse)
**Après (v12)**
- Ajout de champs : `unit_type`, `tax_rate`, `link_customer`
- Retour d’un *stock move* et gestion premium
**ETL** | Transformation | Exemple SQL |
|----------------|-------------|
| Ajout du champ `unit_type` | `UPDATE llx_product SET unit_type = CASE WHEN price < 0 THEN 'negative' ELSE 'positive' END;` |
| Mapper `tax_rate` depuis `llx_product_price` vers `llx_tax` | ```sql INSERT INTO llx_tax (name, rate) SELECT DISTINCT label, rate FROM llx_product_price;``` |
| Fusion des fournisseurs avec `llx_user` (nouveau champ `fk_user`) | ```php $supplierId = $row['id_fournisseur']; $existingUser = new \Dolibarr\User($db); $existingUser->fetch($supplierId); $existingUser->add();``` |
**Code d’extraction & transformation** (Python + pandas) :
```python
import pandas as pd
import mysql.connector
src = mysql.connector.connect(host='src_host', user='root', password='pwd', database='dolibarr')
dst = mysql.connector.connect(host='dst_host', user='root', password='pwd', database='dolibarr')
df = pd.read_sql("SELECT * FROM llx_product", src)
# Normalisation du prix (ancienne devise EUR -> toujours stockée en EUR mais on veut convertir en minor)
df['price'] = (df['price'] * 100).astype(int) # passer à centimes
# Mapper tax_rate → llx_tax
tax_m = df[['label','rate']].drop_duplicates().rename(columns={'label':'name'})
tax_m['rate'] = tax_m['rate'] * 100 # passer en % (ex: 20 -> 2000 -> 20.00)
tax_m.to_sql('llx_tax', dst, if_exists='append', index=False)
# Insert product with new fields
df['unit_type'] = 'pcs'
df['fk_tax'] = df['rate'] // 100 # conversion % → id_tax (déjà inséré)
df[['fk_product','fk_tax','qty','price','unit_type']].to_sql(
'llx_product', dst, if_exists='append', index=False, method='multi')
4.3. Synchronisation bidirectionnelle avec un CRM externe (exemple : HubSpot)
Scénario
- Les contacts créés dans Dolibarr doivent être créés ou mis à jour dans HubSpot.
- Les modifications faites dans HubSpot (par ex. ajout d’un tag) doivent être reflétées dans Dolibarr (champ
u_tags).
Flux ETL
- Extract – Webhook
cron.phpde Dolibarr récupère les contacts nouveaux/ modifiés depuisllx_contact. -
Transform –
$hubspotId = $row['hubspot_id'] ?? null;
$tags = explode(',', $row['tags']); // legacy ; à transformer en tableau de HubSpot tags
$payload = [
'email' => $row['email'],
'firstname'=> $row['firstname'],
'lastname' => $row['lastname'],
'properties'=> ['tags' => $tags]
];
``` 3. **Load** – Appel **HubSpot CRM API** (`POST /crm/v3/objects/contacts`)
```php
$ch = curl_init('https://api.hubapi.com/crm/v3/objects/contacts');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer '.$hubspot_token]);
curl_exec($ch); - Reverse sync – Procure un job quotidien qui interroge HubSpot pour les contacts marqués
lastmodifieddate > now()-1det met à jour le champtagsdans Dolibarr (UPDATE llx_contact SET tags = ? WHERE id = ?).
Technologie :
- Luya Framework (module dédié Symfony) pour orchestrer le job.
- RabbitMQ ou Redis Queue pour le traitement asynchrone des 500 + mises à jour simultanées.
5. Bonnes pratiques à adopter
| Domaine | Astuce |
|---|---|
| Sécurité | – Toujours chiffrer les credentials (ex.: dotenv + symfony/dotenv). – Utiliser les transactions DB ( BEGIN; … COMMIT;) lors du bulk‑insert pour éviter les demi‑charges. |
| Gestion des erreurs | – Capturez les IntegrityException et logguez‑les dans un tableau etl_errors. – Implémentez un retry (max 3) pour les appels API externes. |
| Performance | – Pour > 100k lignes, passez par INSERT … VALUES (… , … , …) batch ou LOAD DATA INFILE (MySQL) plutôt que des appels INSERT individuel. – Désactivez temporairement les foreign key checks ( SET foreign_key_checks = 0;) pendant le chargement massif. |
| Traçabilité | – Créez un tableau etl_log (run_id, start_ts, end_ts, status, nb_rows_read, nb_rows_written). – Ajoutez un hash du dump source afin de détecter les changements. |
| Tests | – Faites tourner le pipeline sur une base de test avec des jeux de données synthétiques (ex.: faker). – Vérifiez les contraintes ( UNIQUE, CHECK) via des assertions PHPUnit ou des scripts SQL d’intégrité. |
| Documentation | – Un README Markdown décrivant le mapping, les dépendances et les commandes d’exécution (php bin/console app:etl:migrate). – Fichier CHANGELOG du schéma ( ddl_changes.sql). |
6. Exemple complet : Script CLI “upgrade_dolibarr.sh”
#!/bin/bash
# --------------------------------------------------------------
# upgrade_dolibarr.sh : orchestration de l'ETL de migration.
# --------------------------------------------------------------
set -euo pipefail
# 1️⃣ Variables d'environnement (charger .env)
export $(grep -v '^#' .env | xargs)
# 2️⃣ Export du dump source
php -r "\
require_once 'vendor/autoload.php';\
Dolibarr\Hook::execHook('setupUpgradeETL');\
"
# 3️⃣ Extraction des tables essentielles
mysqldump -h $SRC_DB_HOST -u $SRC_DB_USER -p$SRC_DB_PASS $SRC_DB_NAME \
llx_categorie llx_client llx_command llx_facture \
llx_product llx_product_category llx_supplier > dump_raw.sql
# 4️⃣ Transformation via le script PHP dédié
php bin/console etl:transform dump_raw.sql transformed.csv
# 5️⃣ Chargement dans la base cible
php bin/console etl:load transformed.csv
# 6️⃣ Vérification de l’intégrité
php bin/console etl:verify --run-id=$(date +%s)
echo "✅ Migration terminée avec succès."
etl:transform: charge le dump, applique les mappings décrits dansconfig/etl/mappings.php.etl:load: injecte les lignes du CSV dans la nouvelle base, gère les transactions.etl:verify: compare le nombre de lignes attendues et calcule un checksum (md5) des tables critiques.
7. Conclusion
- L’ETL n’est pas optionnel lorsqu’on migre ou met à jour Dolibarr ; il assure la qualité et la reproductibilité du processus.
- En extrayant les bonnes tables, en transformant les colonnes selon les nouvelles règles, et en chargement de façon transactionnelle, on passe d’une migration à risque à une opération quasi‑déterministe. – Les exemples concrets présentés (multi‑site, nouvelles colonnes, synchronisation CRM) montrent que le même schéma d’ETL peut être adapté aux besoins spécifiques d’une entreprise ; il suffit de personnaliser les mappings et d’ajouter les appels API nécessaires.
- En suivant les bonnes pratiques (sécurité, logs, rollback, tests automatisés) vous éviterez les pièges classiques : perte de données, ruptures de contrainte ou désynchronisation entre modules.
À vos marqueurs : démarrez par un dump complet, créez votre pipeline ETL (extraction > transformation > loading) sous forme de commandes CLI ou de jobs planifiés, et testez d’abord sur une base de test avant de lancer le processus en production. Vous serez alors en mesure de mettre à niveau Dolibarr en toute confiance, avec une visibilité totale sur chaque étape du flux de données.
Bon codage ! 🚀
Ressources complémentaires
- Documentation officielle de Dolibarr : https://www.dolibarr.org/doc/en/ – Pack de scripts ETL sur GitHub :
github.com/dolibarr/etl-toolkit - Blog « Migration Dolibarr 0‑12 » (cas pratiques) – https://blog.dolibarr.org/post/migration-0-12
- Article « ETL avec PHP : Doctrine DBAL & Symfony Console » – https://symfony.com/doc/current/console.html