Un beau rapport ne répare pas un chiffre flou

J’ai longtemps pensé qu’un rapport contesté cachait forcément une mauvaise requête. Plus je regarde le reporting, plus je découvre une possibilité encore plus tannante : la requête peut être exacte et le chiffre quand même répondre à la mauvaise question.

Prenons un exemple inventé. Un rapport affiche 1,2 million de dollars de ventes. Une autre personne arrive avec 1,1 million. Le premier total utilise la date de commande et inclut les taxes; le second utilise la date de facture, retire les retours et exclut les taxes. Les deux calculs peuvent être techniquement justes. Le mot « ventes » cachait plusieurs définitions.

Je commence donc par fixer le grain : ce que représente une ligne avant l’agrégation. Une ligne de commande, une facture, une ligne de facture ou un paiement ne se regroupent pas de la même façon. Si une facture contient cinq lignes et deux paiements, joindre les trois tables directement peut produire dix rangées et doubler les montants.

Pour un indicateur de ventes nettes facturées, une définition courte pourrait être :

Grain       : ligne de facture
Date        : date de comptabilisation de la facture
Montant     : sous-total hors taxes - remises
Retours     : notes de crédit soustraites à leur date de comptabilisation
Exclusions  : factures brouillon et annulées
Devise      : dollars canadiens selon le taux enregistré à la transaction
Fraîcheur   : chargement chaque nuit, heure de coupe affichée

La requête devient alors vérifiable :

SELECT SUM(lf.SousTotal - lf.Remise) -
       COALESCE(SUM(nc.Montant), 0) AS VentesNettes
FROM Facture f
JOIN LigneFacture lf ON lf.IdFacture = f.IdFacture
LEFT JOIN NoteCredit nc ON nc.IdLigneFacture = lf.IdLigneFacture
WHERE f.Statut = 'COMPTABILISEE'
  AND f.DateComptable >= '2004-02-01'
  AND f.DateComptable <  '2004-03-01'

Même cet exemple doit surveiller la cardinalité si plusieurs notes de crédit existent ou si d’autres tables sont jointes. J’agrège les branches séparément et je compare quelques factures manuellement. Les contraintes de statut et de date doivent correspondre aux règles écrites, pas seulement aux colonnes dont le nom semble bon.

Un entrepôt de reporting peut simplifier la lecture. Un processus ETL extrait les changements des systèmes, transforme codes et devises, puis charge une table de faits reliée à des dimensions comme date, client et produit. Les rapports ne frappent plus directement la base transactionnelle. En échange, l’ETL introduit un délai et une autre possibilité d’erreur.

Je veux donc des contrôles à chaque chargement :

  1. nombre de documents extraits par statut;
  2. somme source avant transformation;
  3. nombre de rangées rejetées et raison;
  4. somme chargée dans la table de faits;
  5. heure de la dernière donnée source incluse;
  6. différence expliquée entre source et destination.

Une exécution « réussie » avec 5 % de lignes rejetées n’est pas un succès. Le rapport devrait afficher sa fraîcheur et signaler un chargement incomplet. Il faut aussi pouvoir rejouer un lot sans doubler les faits, avec une clé source stable ou une zone de staging vidée par lot.

La sécurité suit les données, pas le graphique. Un rapport de ventes par vendeur peut être général, tandis qu’un détail de marge ou de salaire exige un autre rôle. Exporter vers Excel crée une nouvelle copie hors du contrôle du serveur; le bouton d’export et les colonnes disponibles doivent respecter les permissions.

Avant de choisir la couleur d’un graphique, je vais demander la définition, le grain, la source et l’heure de coupe. Puis je réconcilie un mois complet avec le système responsable et je garde cinq cas limites : retour, annulation, livraison partielle, changement de devise et transaction tardive. Un dashboard devient utile quand son chiffre peut être reconstruit, pas simplement quand il s’affiche vite.