Calculs et TVA
Étape 3 — Calculs & TVA
Tous les montants du système sont stockés en centimes (nombres entiers) pour éviter les erreurs d'arrondi des nombres à virgule. 1 000 € = 100000 cents.
L'anatomie d'une ligne de facture
Chaque ligne porte tout ce qu'il faut pour recalculer et auditer :
| Champ | Signification |
|---|---|
amountVatExcludedCents | Montant hors TVA (HT) de la ligne |
amountVatCents | Montant de TVA = HT × taux / 100 |
rateVat | Taux de TVA appliqué (ex. 21) |
quantity | Quantité |
itemRateCommission / itemRateService | Taux de commission / de service appliqués à l'item |
rateFees / fixFees / feesType | Frais proportionnels (%) / frais fixes / nature des frais (COMMISSION ou SERVICE) |
accountingCode | Le code comptable de la ligne (voir plus bas) |
Et au niveau de la facture, les totaux (indexedMeta.amountsCents) : subTotalVatExcluded, subTotalFeesVatExcluded, totalVatExcluded, totalVat, totalVatIncluded, plus la ventilation par taux (totalVatByRate : pour chaque taux, base HT + montant de TVA — obligation légale sur la facture), amountDue (reste à payer) et amountPaid (déjà payé).
Les formules de base
Frais acheteur HT = prix d'adjudication HT × taux frais acheteur / 100
Commission vendeur HT = prix d'adjudication HT × taux commission / 100
TVA d'une ligne = montant HT × taux TVA / 100 (arrondi au centime, Math.round)
Total TTC = somme des HT + somme des TVA (par ligne × quantité)
Reversement vendeur (FEES_DEDUCTION) = encaissement vente − commission TTC
PricingTypes, blocs 001 à 030) : SELLER_COMMISSION (001), BUYER_FEES (002), SERVICE_FEES (003), frais d'application acheteur/vendeur (004/005), frais d'annulation (BUYER_CANCELLATION_FEES_NOT_PAID 006, ..._NO_PICK_UP 007, SELLER_CANCELLATION_FEES 008), transfert de véhicule (011), adhésions et abonnements (012/014)… Chaque type précise qui paie (chargeToType : SELLER, BUYER, SHOP, OTHER). Les pourcentages peuvent être à paliers selon le niveau (ITEM_BID_VALUE, SEANCE_BID_VALUE, YEAR_BID_VALUE, CONTRACT_BID_VALUE, ITEM_QUANTITY, ITEM_START_PRICE). À défaut de grille spécifique, les taux par défaut du shop s'appliquent (meta.saleInformation.rates).La TVA : les 4 régimes
| Régime | Code compta | Quand ? | Effet |
|---|---|---|---|
CLASSIC | 1 | Cas général (acheteur belge, ou particulier) | TVA normale (ex. 21 %) |
INTRA | 5 | Acheteur entreprise dans un autre pays de l'UE, avec un numéro de TVA valide | TVA à 0 % (autoliquidation par l'acheteur) ; mention spécifique sur la facture ; template invoice-intra |
EXPORT | 9 | Acheteur hors UE | TVA à 0 % (exonération export) ; template invoice-export |
FRANCHISE | 0 | Vendeur en franchise de TVA (petit assujetti) | Pas de TVA facturée ; ce code n'est jamais écrasé par les recalculs |
La détermination est automatique (setIntraAndExport) à partir des pays et types (société/particulier) du vendeur et de l'acheteur. Les numéros de TVA intracommunautaires sont vérifiés en ligne via VIES (VAT Information Exchange System : le service officiel européen de vérification des numéros de TVA intracommunautaires ; service dédié vies du monorepo) ; un échec de vérification est tracé sur la facture (indexedMeta.failViesCheck).
preserveFeesVat) : les lignes de frais (celles qui ont un feesType) gardent alors leur taux. C'est typiquement le cas en facturation double, où les frais acheteur sont une prestation de service du shop, taxable selon ses propres règles.book-keeper/src/services/invoices/computeTotalPrices.js — computeStandardTotalPrices() : si indexedMeta.intra → rateVat = 0 (sauf frais préservés) ; si docType === CREDIT_NOTE → les montants sont forcés en négatif (Math.abs(x) * -1) ; puis amountVatCents = amountVatExcludedCents × rateVat / 100 et agrégation dans totalVatByRate/totalFeesByRate. Détermination des régimes : book-keeper/src/services/invoices/setIntraAndExport.js. Vérification VIES : book-keeper/src/resources/vies.js.Le code comptable à 15 caractères
Chaque ligne de facture porte un code qui dit tout à la comptabilité. Il est assemblé ainsi :
| Position | Longueur | Contenu | Valeurs |
|---|---|---|---|
| 1–4 | 4 | Shop | AUEQ, AGEQ, AUIM, AGIM |
| 5–7 | 3 | Type de client | PUB (public), PRI (société privée), FAI (faillite), PAR (particulier), CES (cessation), MAR (marchand/trader), ACH (acheteur) |
| 8 | 1 | Type de contrat | A achat, C courtage, I immobilier, G gestion, P prestation courtage, Q prestation CP, S commissaire-priseur, V achat-revente |
| 9–11 | 3 | Bloc tarifaire | 001–030 (le pricingBlockRef du type de frais) ou 000 |
| 12 | 1 | Régime TVA | 1 classic, 5 intra, 9 export, 0 franchise |
| 13 | 1 | Type de vente | 1 full-service, 2 self-service, 3 faillite |
| 14–15 | 2 | Géographie | WA Wallonie, FL Flandre, FR, NL, LU, IN international |
Exemple : AGEQ PRI C 001 1 1 FR = Agorastore Équipement, client société privée, contrat de courtage, bloc « commission vendeur », TVA classique, full-service, France.
updateAccountingCodeVatType) — sauf si la ligne est en franchise (0), jamais écrasée.book-keeper/src/services/invoices/generateAccountingCode.js — generateAccountingCode() concatène shop(4) + clientType(3) + contractType(1) + pricingRef(3) + vat(1) + saleType(1) + geo(2). Mapping client : ContractCustomerType.SELLER_PUBLIC → PUB, SELLER_COMPANY → PRI, BANKRUPTCY → FAI, SELLER_PRIVATE → PAR, SELLER_CESSATION → CES, SELLER_TRADER → MAR, BUYER_* → ACH.