Calcul de nos indicateurs financiers
Pour chaque chiffre : ce qu'il mesure, sa formule, les modèles Odoo lus, le périmètre, la convention retenue et ses limites connues.
Pourquoi cette page existe#
Un expert-comptable qui relit nos chiffres ne demande pas si l'outil est joli. Il demande d'où vient le montant, sur quelle période, avec quelle convention, et ce qui n'est pas dedans. Sans ces réponses, il ne peut pas accorder sa confiance, donc il ne la donne pas. Cette page est là pour qu'il n'ait rien à deviner, et elle est publique : pas besoin de compte pour la lire.
Ce qui garantit qu'elle est à jour#
Ces définitions ne sont pas rédigées à côté du produit, elles vivent dans le code qui calcule. Un contrôle automatique refuse toute modification du calcul d'un indicateur qui ne serait pas accompagnée de sa définition, un second refuse que cette page s'écarte des définitions, et un troisième refuse une définition sans sa traduction. Une documentation non gardée est fausse en trois mois ; celle-ci ne peut pas l'être sans bloquer la livraison.
Deux conséquences qu'il vaut mieux dire :
- Le périmètre d'un chiffre est mesuré, pas déclaré. Quand UpBoard annonce « écritures comptabilisées du 1er au 13 octobre, 1 240 lignes lues », ces valeurs viennent des lectures réellement exécutées dans votre Odoo, pas d'une phrase écrite à la main.
- Seules les écritures comptabilisées sont lues, sauf une exception signalée comme telle : la marge par produit, qui lit des commandes confirmées et n'est donc pas une lecture comptable.
Les trois règles qui gouvernent les périodes#
Elles valent pour tous les indicateurs datés, et ce sont celles qui se trompent le plus silencieusement ailleurs.
- L'appartenance à une période suit la date comptable de l'écriture, jamais sa date de création ou de dernière modification technique. Pour les créances et les dettes, c'est la date d'échéance qui compte, puisque c'est le retard qui est mesuré.
- Les cumuls partent de l'ouverture de votre exercice comptable, pas du 1er janvier. Si votre exercice se clôture le 30 juin, le comparatif avec l'année précédente et les versements anticipés à l'impôt des sociétés suivent cet exercice.
- L'état de vos comptes est lu dans Odoo. Un mois antérieur à votre date d'arrêté est annoncé définitif ; un mois ouvert annonce son jour et la date d'arrêté. Si UpBoard ne peut pas lire cette date, il dit que le statut est inconnu, et jamais que la période est ouverte.
Ce qu'UpBoard ne couvre pas en finance#
Dit franchement, parce qu'un trou découvert seul coûte plus cher qu'un trou annoncé :
- la clôture avec écritures : UpBoard ne passe aucune écriture de régularisation et ne verrouille aucune période ;
- les immobilisations : aucun suivi ni plan d'amortissement. Seule une anomalie est détectée, les biens non amortis ;
- le réel contre le budget : aucune comparaison budgétaire ;
- les notes de frais : ni validation, ni remboursement.
Si votre Odoo contient des données sur l'un de ces sujets, UpBoard vous le dit plutôt que de laisser croire que ses chiffres les englobent.
Le référentiel#
Score de santé compta
Score composite 0-100 et grade A-F- Aucune lecture propre : agrège les sorties de O02 à O19.
- Un axe sans donnée exploitable n'est pas noté : le score est alors annoncé partiel, avec les axes non notés. Ne jamais lire un score partiel comme une note complète.
- Un domaine Odoo absent chez le client est exclu de la moyenne plutôt que noté 100 : zéro anomalie faute de module ne vaut pas « tout va bien ».
Trésorerie disponible et autonomie
Solde de trésorerie, burn rate, runway- `account.move.line.balance` sur les comptes de liquidité
- `account.account` pour identifier ces comptes
- Lignes de crédit non tirées, découverts autorisés.
- Aucune écriture de trésorerie trouvée ne donne pas un solde de 0 mais un solde **inconnu** : un faux zéro se lirait comme une faillite.
- Le runway n'est rendu que si le burn rate est positif.
Prévisionnel de trésorerie 30, 60, 90 jours
Projection d'encaissements et décaissements probabilisés- `account.move.amount_residual` et `invoice_date_due` (clients et fournisseurs)
- Solde de départ : mêmes comptes que O02
- Factures non encore émises, commandes non facturées, salaires et échéances fiscales à venir qui ne sont pas des écritures.
- Les taux de recouvrement sont des hypothèses fixes, pas un historique du client : un payeur systématiquement en retard est traité comme les autres.
- Les sorties récurrentes hors comptabilité (salaires, loyers non encore comptabilisés) ne sont pas projetées, donc le solde projeté est plutôt optimiste.
Alertes de trésorerie
Franchissements de seuil sur le solde et le runway- Aucune lecture propre : lit les sorties de O02 et O03.
- Solde inconnu : aucune alerte de trésorerie n'est émise, plutôt qu'une alerte rassurante ou alarmiste sur un chiffre absent.
Rapprochement bancaire
Lignes bancaires non rapprochées et correspondances proposées- `account.bank.statement.line` non rapprochées
- `account.move` ouvertes (`amount_residual`) pour la mise en correspondance
- Les listes sont plafonnées (2 000 lignes lues) : sur une base très volumineuse, le compte affiché est un plancher, et la troncature est dite.
- Un paiement groupé couvrant plusieurs factures n'est pas rapproché.
Position nette de trésorerie
Trésorerie nette des dettes court terme, quick ratio- Trésorerie : mêmes comptes que O02
- `account.move.amount_residual` des factures fournisseurs ouvertes
- Dettes financières à plus d'un an, provisions.
- Le quick ratio n'est pas rendu quand il n'y a aucune dette court terme : une division par zéro ne vaut pas « ratio excellent ».
Balance âgée clients
Aging des créances par tranche d'ancienneté- `account.move` clientes ouvertes : `amount_residual`, `invoice_date_due`
- `res.partner` pour le nom du client
- Factures en brouillon, avoirs non imputés.
- Un litige commercial en cours n'est pas distingué d'un simple retard de paiement : les deux apparaissent comme une créance échue.
Risque de crédit par client
Score de défaut 0-100 et encours exposé- `account.move` clientes et `account.payment` (historique)
- `res.partner` (ancienneté de la relation)
- Aucune donnée externe (solvabilité publiée, défaut déclaré) n'entre dans le score : il ne lit que l'historique présent dans Odoo.
- Un client récent sans historique obtient un score peu informatif.
Délai moyen d'encaissement
DSO (days sales outstanding), méthode countback- `account.move` clientes : `invoice_date`, `invoice_date_due`, `amount_residual`
- `account.payment` pour les dates de règlement
- Un mois de facturation exceptionnel déforme le DSO de la période suivante, countback comprise.
- Le DSO par client sur 180 jours n'est pas comparable au DSO global sur 365 jours : ne pas les mettre côte à côte sans le dire.
Clients à relancer
File de relance priorisée, niveau et canal- `account.move` clientes échues
- `mail.message` pour savoir ce qui a déjà été envoyé
- `res.partner` pour le canal disponible
- Un dossier relancé depuis moins de sept jours et resté sans réponse n'est pas re-signalé : utile contre le harcèlement, mais le dossier disparaît temporairement de la file.
- Une réponse arrivée depuis la boîte d'un employé plutôt que l'adresse du client peut ne pas être vue.
Promesses de paiement
Suivi des engagements client, tenus et rompus- `mail.message` sur les factures (l'engagement est un échange, pas un champ)
- `account.move.amount_residual` et `invoice_date_due` (le paiement attendu)
- Un engagement pris par téléphone et non consigné dans Odoo est invisible : l'indicateur ne mesure que ce qui a été écrit.
Balance âgée fournisseurs
Aging des dettes par tranche d'ancienneté- `account.move` fournisseurs ouvertes : `amount_residual`, `invoice_date_due`
- `res.partner` pour le fournisseur
- Factures en brouillon, notes de crédit non imputées.
- Un escompte de règlement anticipé disponible n'est pas signalé ici.
Délai moyen de paiement
DPO (days payable outstanding)- `account.move` fournisseurs et `account.move.line` (lettrage)
- Le repère sectoriel affiché est indicatif et interne, ce n'est pas une statistique officielle.
- Un paiement partiel étalé donne un délai moyen peu représentatif.
Date de paiement conseillée
Arbitrage trésorerie contre relation fournisseur- `account.move` fournisseurs ouvertes : `invoice_date_due`, `amount_residual`
- Les conditions de paiement négociées hors Odoo, et l'escompte, ne sont pas connus de l'indicateur.
TVA prévisionnelle
Solde de TVA de la période en cours et anomalies de codes- `account.move.line` sur les comptes de TVA : `balance`
- `res.company` pour la périodicité déclarative
- `ir.module.module` pour vérifier la localisation belge
- Écritures en brouillon, donc une TVA non encore comptabilisée.
- Ce n'est pas une déclaration : aucun report, aucun prorata de déduction, aucun régime particulier n'est appliqué.
- Un solde calculé en cours de période n'est pas le solde final.
Échéances fiscales
Calendrier à 90 jours (TVA, ISOC, listing intracommunautaire)- Catalogue belge interne, daté par le code
- `res.company` pour l'exercice comptable et le numéro d'entreprise
- Catalogue belge seulement, et tenu à la main : une date légale qui change demande une mise à jour du code.
- Sans numéro d'entreprise lisible sur la société, les échéances société sont affichées par défaut plutôt que tues.
- Ce calendrier ne remplace pas celui du mandataire fiscal.
Compte de résultat du mois
P&L mensuel avec charges récurrentes attendues- `account.move.line.balance` et `account.account.code`
- Les charges récurrentes attendues sont une **estimation** fondée sur les trois mois précédents, pas une écriture : elles sont affichées à part et ne doivent pas être recopiées dans une déclaration.
- Un mois en cours n'est pas un mois clos, quelle que soit la présentation.
Comparatif avec l'année précédente
Cumul d'exercice contre même période de l'exercice précédent- `account.move.line.balance` et `account.account.code`
- Un écart de périmètre entre les deux exercices (acquisition, changement de plan comptable) n'est pas détecté : la comparaison est faite sur les comptes tels qu'ils sont.
- Si l'un des deux bouts tombe dans une période non arrêtée, le cumul est annoncé non définitif.
Marge par produit et par client
Marge brute estimée sur commandes confirmées- `sale.order.line` des commandes confirmées (`state in sale, done`)
- `purchase.order.line` des six derniers mois (`state in purchase, done`)
- `product.product.standard_price`
- Devis non confirmés, commandes annulées.
- Le coût est un **prix de revient estimé**, pas un coût de revient comptable : frais de port, remises fournisseur et stocks valorisés différemment ne sont pas repris. Un produit « vendu à perte » ici est un signal à vérifier, pas une conclusion comptable.
- Un produit jamais acheté sur les six derniers mois garde son prix de revient de fiche, qui peut être obsolète.
- Les lignes sans produit (frais saisis à la main) sont hors marge.
Un chiffre vous paraît faux ?#
Deux cas, et ils se traitent différemment. Si le chiffre ne correspond pas à la définition ci-dessus, c'est un bug : écrivez-nous à info@upboard.ai avec l'indicateur concerné. Si le chiffre correspond à la définition mais pas à votre attente, c'est une convention à discuter, et c'est une conversation que nous prenons volontiers : ces choix sont documentés précisément pour pouvoir être contestés.