Guide des Calculs de Facturation
Ce document décrit les règles de calcul utilisées dans le système de facturation, incluant les calculs de TVA, remises, totaux, et les règles d'arrondi.
Date de création : 2024-12-19
Objectif : Documenter précisément les règles de calcul pour assurer la cohérence entre frontend et backend
Table des matières
- Vue d'ensemble
- Précision des Calculs
- Calcul des Totaux
- Gestion des Remises
- Calcul de la TVA
- Règles d'Arrondi
- Exemples de Calcul
Vue d'ensemble
Le système utilise une approche à double précision pour tous les calculs financiers :
- Wrapper
Money: Utilisedecimal.jspour éviter les erreurs de précision des nombres flottants JavaScript - Calculs par ligne : Chaque ligne d'article est calculée indépendamment
- Agrégation : Les totaux sont calculés par agrégation des lignes
- Arrondi au centime : Tous les montants sont arrondis au centime près (2 décimales)
Précision des Calculs
Classe Money
La classe Money encapsule tous les calculs monétaires :
import { Money } from "./billing/domain/money";
// Création depuis un nombre
const amount = Money.fromNumber(100.5); // 100.50 EUR
// Création depuis des centimes (pour éviter les erreurs de précision)
const amount = Money.fromCents(10050); // 100.50 EUR
// Opérations arithmétiques
const total = amount1.add(amount2);
const difference = amount1.subtract(amount2);
const multiplied = amount.multiply(1.2); // 20% d'augmentation
const divided = amount.divide(2);
Avantages
- Précision : Évite les erreurs de calcul dues aux nombres flottants (ex:
0.1 + 0.2 !== 0.3) - Arrondi cohérent : Tous les montants sont arrondis au centime
- Type-safety : TypeScript garantit l'utilisation correcte
Calcul des Totaux
Flux de Calcul
-
Pour chaque ligne d'article :
- Calcul du sous-total HT avec remise (si applicable)
- Calcul de la TVA sur le sous-total HT
- Calcul du sous-total TTC
-
Agrégation :
- Total HT = somme des sous-totaux HT
- Total TVA = somme des montants de TVA
- Total TTC = somme des sous-totaux TTC
Service InvoiceTotalsService
Le service centralise tous les calculs :
import { InvoiceTotalsService } from "./billing/calculations/invoice-totals.service";
const totalsResult = totalsService.calculateTotals(items, "EUR");
// Résultat :
// {
// totals: {
// subtotal_ht: Money,
// total_tva: Money,
// total_ttc: Money,
// currency: "EUR"
// },
// taxBreakdown: [
// { rate: 20, base_ht: Money, amount_tva: Money }
// ]
// }
Gestion des Remises
Types de Remises
-
Remise en pourcentage (
discount_percentage)- Appliquée sur le prix unitaire HT
- Exemple :
discount_percentage: 10→ 10% de remise
-
Remise fixe HT (
discount_type: 'FIXED_WITHOUT_TAX')- Montant fixe en HT
- Exemple :
discount_amount: 50→ 50 EUR HT de remise
-
Remise fixe TTC (
discount_type: 'FIXED_WITH_TAX')- Montant fixe en TTC
- Le montant HT est calculé en retirant la TVA
Calcul de la Remise
// Remise en pourcentage
const priceAfterDiscount = priceWithoutTax.multiply(
1 - discountPercentage / 100
);
// Remise fixe HT
const priceAfterDiscount = priceWithoutTax.subtract(discountAmount);
// Remise fixe TTC
const discountHT = discountAmount.divide(1 + vatPercentage / 100);
const priceAfterDiscount = priceWithoutTax.subtract(discountHT);
Calcul de la TVA
Taux de TVA
Les taux de TVA sont définis par ligne d'article :
- TVA standard : 20% (France)
- TVA réduite : 5.5% ou 10% (selon le type de bien/service)
- TVA 0% : Exonération
- TVA intracommunautaire : 0% (B2B UE, avec numéro TVA)
Calcul
// TVA = Sous-total HT × (Taux TVA / 100)
const vatAmount = subtotalHT.multiply(vatPercentage / 100);
// Total TTC = Sous-total HT + TVA
const totalTTC = subtotalHT.add(vatAmount);
Détail par Taux
Le système calcule automatiquement un détail des montants de TVA par taux :
// Exemple avec 2 taux différents :
// - 20% sur 100 EUR HT → 20 EUR TVA
// - 5.5% sur 50 EUR HT → 2.75 EUR TVA
// Total : 150 EUR HT, 22.75 EUR TVA, 172.75 EUR TTC
taxBreakdown: [
{ rate: 20, base_ht: 100.0, amount_tva: 20.0 },
{ rate: 5.5, base_ht: 50.0, amount_tva: 2.75 },
];
Règles d'Arrondi
Principe Général
Tous les montants sont arrondis au centime près (2 décimales).
Règle d'Arrondi
- Arrondi bancaire : Arrondi à la valeur paire la plus proche en cas d'égalité (IEEE 754)
- Précision : 2 décimales pour les montants, 2 décimales pour les pourcentages
Exemples
// Arrondi au centime
Money.fromNumber(100.125).round(); // 100.13 (arrondi vers le haut)
Money.fromNumber(100.124).round(); // 100.12 (arrondi vers le bas)
Money.fromNumber(100.125).round(); // 100.12 si arrondi bancaire (valeur paire)
Calcul par Ligne vs Global
Approche actuelle : Calcul par ligne puis agrégation
- ✅ Avantage : Cohérence avec les lignes individuelles
- ✅ Précision : Chaque ligne est précise
- ⚠️ Note : De légères différences peuvent apparaître si on arrondit d'abord puis qu'on agrège
Exemples de Calcul
Exemple 1 : Facture Simple avec TVA 20%
Ligne 1 :
- Prix unitaire HT : 100.00 EUR
- Quantité : 2
- TVA : 20%
Calcul :
Sous-total HT = 100.00 × 2 = 200.00 EUR
TVA = 200.00 × 20% = 40.00 EUR
Sous-total TTC = 200.00 + 40.00 = 240.00 EUR
Totaux :
- Total HT : 200.00 EUR
- Total TVA : 40.00 EUR
- Total TTC : 240.00 EUR
Exemple 2 : Facture avec Remise en Pourcentage
Ligne 1 :
- Prix unitaire HT : 100.00 EUR
- Quantité : 1
- Remise : 10%
- TVA : 20%
Calcul :
Prix après remise = 100.00 × (1 - 10%) = 90.00 EUR
TVA = 90.00 × 20% = 18.00 EUR
Sous-total TTC = 90.00 + 18.00 = 108.00 EUR
Exemple 3 : Facture avec Taux TVA Multiples
Ligne 1 (TVA 20%) :
- Prix unitaire HT : 100.00 EUR
- Quantité : 1
- Sous-total HT : 100.00 EUR
- TVA : 20.00 EUR
- Sous-total TTC : 120.00 EUR
Ligne 2 (TVA 5.5%) :
- Prix unitaire HT : 50.00 EUR
- Quantité : 1
- Sous-total HT : 50.00 EUR
- TVA : 2.75 EUR
- Sous-total TTC : 52.75 EUR
Totaux :
- Total HT : 150.00 EUR
- Total TVA : 22.75 EUR
- Total TTC : 172.75 EUR
Détail TVA :
TVA à 20% : 20.00 EUR (base 100.00 EUR)
TVA à 5.5% : 2.75 EUR (base 50.00 EUR)
Exemple 4 : Facture avec Remise Fixe TTC
Ligne 1 :
- Prix unitaire HT : 120.00 EUR
- Quantité : 1
- Remise fixe TTC : 20.00 EUR
- TVA : 20%
Calcul :
Prix TTC initial = 120.00 × 1.20 = 144.00 EUR
Prix TTC après remise = 144.00 - 20.00 = 124.00 EUR
Prix HT après remise = 124.00 / 1.20 = 103.33 EUR (arrondi)
TVA = 103.33 × 20% = 20.67 EUR
Vérification : 103.33 + 20.67 = 124.00 EUR ✓
Synchronisation Frontend/Backend
Les calculs doivent être identiques entre le frontend et le backend pour éviter les incohérences.
Frontend
Le frontend utilise la même logique dans frontend/src/utils/document-totals.utils.ts :
// Exemple de calcul frontend (doit correspondre au backend)
const calculateLineTotal = (item) => {
let priceHT = item.price_without_tax;
// Appliquer remise
if (item.discount_percentage > 0) {
priceHT = priceHT * (1 - item.discount_percentage / 100);
} else if (item.discount_amount) {
// ... logique remise fixe
}
// Calculer TVA
const vatAmount = priceHT * (item.vat_percentage / 100);
// Total TTC
const totalTTC = priceHT + vatAmount;
return { priceHT, vatAmount, totalTTC };
};
Validation
Lors de la création/modification d'une facture :
- Le frontend calcule les totaux
- Le backend recalcule et valide
- Si différence, le backend utilise ses calculs (source de vérité)
Bonnes Pratiques
- Toujours utiliser
Moneypour les calculs monétaires - Ne jamais utiliser
Number()directement pour les montants - Arrondir au centime avant d'afficher ou stocker
- Vérifier la cohérence entre frontend et backend
- Documenter les exceptions (ex: remises spéciales)
Références
backend/src/billing/domain/money.ts- ClasseMoneybackend/src/billing/calculations/invoice-totals.service.ts- Service de calculsfrontend/src/utils/document-totals.utils.ts- Calculs frontend