Dolibarr avancé : ETL avec intégrations modernes

Comment exploiter la puissance d’un ERP/CRM léger comme Dolibarr pour des flux de données automatisés, scalables et compatibles avec les architectures cloud‑native.


1. Introduction

Dolibarr est un ERP/CRM open‑source très léger, idéal pour les PME ou les départements qui souhaitent une solution « tout‑en‑un » sans complexité.
Cependant, dans les environnements modernes, il est souvent nécessaire d’alimenter d’autres outils (BI, data‑warehouse, plateformes de marketing, systèmes de paiement, etc.) via des ETL (Extract‑Transform‑Load).

Cet article décrit comment déployer des pipelines ETL avancés à partir de Dolibarr, en s’appuyant sur des outils contemporains : API REST, connecteurs Kafka, sauvegardes dans un data‑lake, orchestration serverless, et gouvernance des données (metadata‑driven).

Objectif : passer de “exporter un CSV à la main” à “orchestrer des flux de données fiables, réutilisables et gouvernés”, le tout grâce aux capacités d’extension et aux API exposées par Dolibarr.


2. Architecture de Base : Layers d’Intégration

+-------------------+        +----------------------+        +-------------------+
| Dolibarr (ERP) | API | Connecteurs Externe| ETL | Orchestration |
| (Core) +-----> (Kafka, REST, JDBC) +-----> (Airflow, Prefect) |
+-------------------+ +----------------------+ +-------------------+
| | |
v v v
+-------------------+ +----------------------+ +-------------------+
| Cloud Storage | <----> | Transformation | <----> | BI / Data Lake |
| (S3, Blob) | | (dbt, Spark) | | (PowerBI, Looker)|
+-------------------+ +----------------------+ +-------------------+

2.1. Points d’attache (entry points)

Point d’attache Méthode Cas d’usage typique
API REST native GET/POST/PUT via /dolibarr/api/index.php (v10+) Export de factures, synchronisation des contacts
Webhooks POST (payload JSON) déclenché par évènements Dolibarr Réaction en temps réel à une commande payée
Export CSV/Excel Scripts PHP ou CLI Extrait ponctuel de gros jeux de données
BD relationnelle connexion directe à MySQL/PostgreSQL Chargement massifs dans un entrepôt cloud
Messages Kafka Connecteur Debezium → Kafka topic Streaming change‑data‑capture (CDC)


3. Extraction (E)

3.1. Exemple : Exporter les factures avec l’API REST

curl -X GET "https://example.com/dolibarr/api/index.php?module=admin&route=commande&filter='{\"status\": \"paid\"}' \
-H "Authorization: Bearer $TOKEN"

  • Gestion de l’authentification

    • Token d’accès : généré dans Configuration > Sécurité > Token API.
    • Rate‑limit : header X-RateLimit-Limit à gérer côté client.
    • Paginations : paramètres range ou limit/offset à itérer jusqu’à épuisement.

  • Bibliothèques recommandées

    • python-requests + pytest pour les tests unitaires.
    • apify-client pour orchestration serverless (AWS Lambda, Azure Functions).

3.2. Streaming changelog via Debezium + Kafka

{
"name": "dolibarr-connector",
"config": {
"connector.class":"io.debezium.connector.mysql.MySqlConnector",
"tasks.max":"1",
"database.hostname":"db.dolibarr.local",
"database.port":"3306",
"database.user":"dolibarr_user",
"database.password":"****",
"database.server.id":"184054",
"database.server.name":"dolibarr_cdc",
"database.whitelist":"llx_commande,llx_facture,llx_client",
"snapshot.mode":"when_needed",
"include.column.names":"true"
}
}

  • Avantages : aucune requête supplémentaire sur Dolibarr, latence quasi‑temps réel, décodage des modifications à la volée.
  • Tip : ajouter un schema registry (Confluent) pour garder les messages sérialisés en Avro/Protobuf et éviter les ruptures de version.

3.3. Export direct depuis la base

SELECT 
c.id as client_id,
f.id as facture_id,
f.facture_date,
f.total_ht,
f.status
FROM llx_facture f
JOIN llx_client c ON f.id_client = c.id
WHERE f.facture_date >= CURRENT_DATE - INTERVAL 30 DAY;

  • Export vers S3 : utilisation de SELECT ... INTO OUTFILE '/tmp/factures_$(date +%F).csv' puis aws s3 cp.
  • Optimisation : créer une vue matérialisée vw_factures_recentes pré‑indexée pour accélérer les scans.


4. Transformation (T)

4.1. Normalisation des types de données

Champ Source Type Dolibarr Transformation recommandée
date DATE Convertir en ISO‑8601 UTC (2025-10-31T14:20:00Z)
montant DECIMAL(12,2) Multiplier par 100 pour passer en centimes avant d’ingérer dans un data‑warehouse (Snowflake/Redshift)
status "paid" | "unpaid" Mapper vers enum PAID|PENDING|OVERDUE

4.2. Enrichissement (lookup)

  • Client → Segment Marketing : jointure avec un table dim_segment stockée dans Snowflake.
  • Produit → Prix Currency : enrichir avec taux de change du jour (API ExchageRate).

Extrait d’un script d’enrichissement (Python + dbt) :

import dbt.utils
import pandas as pd
def enrich_factures(df: pd.DataFrame) -> pd.DataFrame:
# Lookup segment
df['segment'] = df['client_id'].map(segment_map)
# Rate‑currency
df['price_usd'] = (df['total_ht'] * exchange_rate_usd(df['currency'])).round(2)
return df

Astuce dbt : créez un model stg_factures_rawfct_factures_enrichi qui regroupe toutes les transformations structurées.

4.3. Nettoyage et déduplication

  • Déduplication : créez une clé composite (facture_id, client_id).
  • Gestion des doublons : utilisez DROP DUPLICATES dans SparkSQL ou GROUP BY + MAX(updated_at) en SQL.


5. Chargement (L)

5.1. Chargement Batch vers un Data‑Lake (S3 + Glue)

aws s3 cp factures_2025-10-31.parquet s3://my-bucket/datalake/factures/

  • Glue Crawler : déclenché par l’événement ObjectCreated:*.parquet pour mettre à jour le Glue Data Catalog.
  • Partitionnement : structure s3://bucket/datalake/factures/year=2025/month=10/.

5.2. Chargement en temps réel (Kafka → Snowflake)

COPY INTO snowflake_table
FROM 'kafka://my_topic?wait_for=5s'
FILE_FORMAT = (TYPE = PARQUET);

  • Source : Connecteur Snowflake Kafka Connector (confluent) ou Kafka Connect avec sink Snowflake.
  • Mode exactement‑une‑fois : configurer isolation.level=read_committed et transactional.id pour éviter les pertes de données.

5.3. Chargement vers un Data‑Warehouse (Snowflake/BigQuery)

INSERT INTO dw.factures
SELECT * FROM staging.factures_enriched;

  • Chargement incrémental : utilisez la colonne updated_at pour ne charger que les lignes modifiées depuis la dernière exécution.


6. Orchestration Moderne

Orchestrateur Pourquoi le choisir pour Dolibarr ?
Apache Airflow DAGs explicites, UI riche, opérateurs natifs REST, Kafka, Snowflake.
Prefect 2.0 Architecture serverless, excellent support de dynamic mapping (batch‑per‑client).
Dagster Gouvernance des métadonnées + tests de data‑quality intégrés.
Dagger (CI/CD‑native) Déploiement « Infrastructure as Code » via Docker + GitOps.

Exemple de DAG Airflow pour extraire les factures et les pousser dans S3

from airflow import DAG
from airflow.providers.http.operators.http import SimpleHttpOperator
from airflow.providers.amazon.aws.operators.s3 import S3CreateObjectOperator
from airflow.utils.dates import days_ago
default_args = {
'owner': 'dolibarr_etl',
'retries': 2,
'retry_delay': timedelta(minutes=5)
}
with DAG(
dag_id='dolibarr_factures_to_s3',
default_args=default_args,
schedule_interval='@daily',
start_date=days_ago(1),
catchup=False,
) as dag:
extract = SimpleHttpOperator(
method='GET',
http_conn_id='dolibarr_api',
endpoint='/index.php?module=admin&route=commande&filter={"status":"paid"}',
headers={"Authorization": "Bearer {{ var.value.dolibarr_token }}"},
response_filter=lambda response: response.json(),
log_response=True,
)
load_to_s3 = S3CreateObjectOperator(
task_id='load_to_s3',
bucket_name='dolibarr-etl',
object_name='factures_{{ ds_nodash }}.json',
data=extract.xcom_pull(key='response', task_ids='extract'),
storage_class='STANDARD',
)


7. Gouvernance & Qualité des Données

Aspect Action concrète
Catalogue de métadonnées Utilisez DataHub ou Amundsen pour enregistrer les tables Dolibarr → transformations → cibles.
Tests de data‑quality dbt data_quality tests (not_null, unique, accepted_values) exécutés à chaque run Airflow.
Audits de sécurité Masquez les champs sensibles (numéro de compte bancaire) via Dynamic Data Masking avant le transfert.
Versionnage des pipelines Stockez les DAG/Airflow/prefixes dans un repo Git ; versionnez les schémas SQL (Flyway) et les modèles dbt.


8. Bonnes Pratiques Spécifiques à Dolibarr

Pratique Description Impact
Ne jamais toucher la base en production Utilisez toujours une replication read‑only (ou un dump filtré) pour les extractions. Garantit la continuité du service ERP.
Limiter la taille du payload Découpez les réponses > 10 Mo en chunks (pagination + stream). Réduit les time‑outs API et le risque de MemoryError côté client.
Garder la logique métier hors du script ETL Utilisez les hooks et modules de Dolibarr (ex : llx_facture, llx_client) uniquement pour la lecture, jamais pour modifier les données dans le pipeline. Évite les effets de bord inattendus (ordres modifiés, stocks incohérents).
Cache des référentiels Mise en cache locale (Redis / Memcached) des listes de prix ou de devis pour limiter les appels API redondants. Diminution du temps de transformation.
Gestion des conflits de langues Si votre instance est multilingue, normalisez les libellés en français (ou langue de référence) avant le chargement. Simplifie l’analyse BI.


9. Cas d’Usage Avancé : Pipeline « Zero‑Code » avec Prefect Cloud

  1. Déclencheur : Webhook Dolibarr →Prefect Serverless → crée un flow facture_paid.
  2. Extract : prefect.http.client → appel /api/factures?status=paid&since=2025-10-30.
  3. Transform : Utilisation de Pydantic pour valider le schéma, puis conversion en Parquet via pyarrow.
  4. Load : prefect.AWSS3BucketWrite → écriture dans s3://dolibarr-pipeline/factures/YYYY/MM/DD/.
  5. Notify : Slack webhook + création d’un ticket JIRA si le nombre de lignes est > 10 000 (détection d’anomalie).

from prefect import flow, task
import pydantic_models as pm
@task
def fetch_factures():
resp = requests.get(
"https://erp.example.com/api/factures",
headers={"Authorization": f"Bearer {os.getenv('DOLIBARR_TOKEN')}"},
params={"status":"paid", "date_from":"2025-10-01"},
)
resp.raise_for_status()
return resp.json()
@task
def to_parquet(data: List[dict]):
df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['facture_date']).dt.strftime("%Y-%m-%d")
return df.to_parquet('s3://my-bucket/datalake/factures/', engine='pyarrow', compression='snappy')
@flow(name="dolibarr-facture-etl")
def facture_etl():
raw = fetch_factures()
to_parquet(raw)
if __name__ == "__main__":
facture_etl()

Ce flux peut être déclenché chaque jour via le schedule de Prefect Cloud, sans serveur dédié.


10. Conclusion

Dolibarr ne se limite pas à un simple ERP « lightweight ». En exploitant :

  • ses API REST et webhooks pour l’extraction fine‑grained,
  • les connecteurs change‑data‑capture (Debezium/Kafka) pour le streaming,
  • des pipelines de transformation modernes (dbt, PySpark, Python + Pydantic),
  • une orchestration serverless ou DAG‑based (Airflow, Prefect, Dagster),
  • une gouvernance centralisée (DataHub, tests dbt, audits de sécurité),

on obtient un ETL avancé, scalable et gouverné qui s’intègre parfaitement aux architectures cloud‑native.

Le mot de la fin : la clé du succès réside dans la séparation stricte des responsabilités (extraction → transformation → chargement), la détection proactive des changements dans Dolibarr (pas de modifications directes en prod), et l’utilisation d’outils déclaratifs et versionnés pour que chaque flux soit reproductible, auditable et prêt à évoluer avec les besoins métier futurs.

Bon ETL ! 🚀


Sources & références supplémentaires


Auteur :
[Nom du Consultant] – Architecte Data & Engineer ETL spécialisé Dolibarr, certifié Snowflake & AWS Glue.
Date : 2 novembre 2025.

Publications similaires