Une facture arrive dans Dolibarr par un import ou un connecteur : la fiche affiche le bon montant HT, le PDF un total HT à 0,00. Le module Multidevise est activé et les montants "en devise" de la facture sont restés vides : Dolibarr les imprime dès que la facture n'est pas dans la devise de la société. La correction passe par Dolibarr lui-même ; le SQL n'est sûr qu'au taux 1.
D'où vient le montant à 0 ?
Avec le module Multidevise, chaque ligne et chaque facture portent deux séries de montants :
- dans la devise de la société :
subprice,total_ht,total_tva,total_ttc; - dans la devise du document :
multicurrency_subprice,multicurrency_total_ht,multicurrency_total_tva,multicurrency_total_ttc, avec le tauxmulticurrency_txsur la facture.
Le modèle PDF de facture (sponge) prend la série en devise quand le module est actif et que le taux n'est pas 1. Sur une facture en dollars (taux 1,2) dont nous avions vidé ces montants, la fiche affichait toujours "Montant HT 200,00 €", mais le PDF donnait "P.U. HT 0,00", "Total HT 0,00" et "Total TTC (€) 240,00". Sur une facture en euros, le PDF reste juste : le défaut passe inaperçu, mais l'API renvoie multicurrency_total_ht à 0.
Qui laisse ces montants vides ?
Sur Dolibarr 24, l'API REST les calcule dans les cas courants. Nous avons créé des factures de six façons (lignes dans POST /invoices ou par POST /invoices/{id}/lines, facture en USD, taux 0 envoyé, multicurrency_subprice à 0 envoyé, prix donné seulement en devise) : montants en devise justes à chaque fois. Restent trois sources :
- une devise sans aucun taux : l'écran de configuration demande un taux, mais
POST /multicurrenciessansratecrée la devise sans taux. La facture reçoit alors un taux 0 : notre facture enGBPcréée par l'API avait tous ses montants en devise à 0, PDF compris ; - le module Import, qui insère les colonnes du fichier telles quelles. Les colonnes en devise y sont facultatives, et celle du prix unitaire en devise est libellée "Taux de change de la devise" ;
- un script qui écrit directement dans
llx_facturedet, sans passer par l'API.
Comment repérer les factures concernées ?
-- Invoices with an amount but empty currency amounts SELECT f.rowid, f.ref, f.fk_statut, f.multicurrency_code, f.multicurrency_tx, f.total_ht, f.multicurrency_total_ht FROM llx_facture AS f WHERE f.total_ht <> 0 AND (f.multicurrency_total_ht = 0 OR EXISTS (SELECT 1 FROM llx_facturedet AS d WHERE d.fk_facture = f.rowid AND d.total_ht <> 0 AND d.multicurrency_total_ht = 0));
fk_statut vaut 0 pour un brouillon, 1 pour une facture validée. Sur la base de démonstration, seules nos factures abîmées pour le test sont sorties.
Comment corriger une facture brouillon ou validée sans paiement ?
Pour une devise sans taux, ajoutez d'abord son taux dans la configuration du module. Puis, sur la fiche de la facture, modifiez le champ Taux de change de la devise : gardez le taux, choisissez "Change P.U net (devise) of lines" (libellé à moitié en anglais), puis Modifier. Dolibarr recalcule le prix en devise de chaque ligne à partir du prix HT et du taux, puis les totaux. Nos factures sont repassées à 120 / 240 / 288 $ et, avec le taux 0,87, à 87 / 174 / 208,80 £.
Une facture validée se repasse d'abord en brouillon avec Modifier. Ce bouton n'apparaît que si elle n'a aucun paiement, n'est pas transférée en comptabilité et n'a pas été remplacée. Corrigez le taux, puis Valider : Dolibarr ne tire un nouveau numéro que pour une référence provisoire (PROV...). Notre facture FA2610-0004 a gardé son numéro et retrouvé exactement les montants d'une facture jumelle créée normalement.
Par l'API, le recalcul du taux n'existe pas, et PUT /invoices/{id}/lines/{lineid} remplace tous les champs de la ligne : ce qui n'est pas renvoyé (description, prix d'achat...) est perdu.
Et pour une facture payée ou déjà en comptabilité ?
Au taux 1, les deux séries sont identiques (c'est ce que Dolibarr a calculé pour toutes nos factures en euros) : la copie par SQL est sûre. Sauvegardez la base avant.
START TRANSACTION; -- 1. Lines: copy the amounts, only for invoices in the company currency (rate 1) UPDATE llx_facturedet AS d JOIN llx_facture AS f ON f.rowid = d.fk_facture SET d.multicurrency_subprice = d.subprice, d.multicurrency_total_ht = d.total_ht, d.multicurrency_total_tva = d.total_tva, d.multicurrency_total_ttc = d.total_ttc WHERE f.multicurrency_tx = 1 AND d.total_ht <> 0 AND d.multicurrency_total_ht = 0; -- 2. Header: sum of the lines, as update_price() does UPDATE llx_facture AS f JOIN (SELECT fk_facture, SUM(multicurrency_total_ht) AS ht, SUM(multicurrency_total_tva) AS tva, SUM(multicurrency_total_ttc) AS ttc FROM llx_facturedet GROUP BY fk_facture) AS s ON s.fk_facture = f.rowid SET f.multicurrency_total_ht = s.ht, f.multicurrency_total_tva = s.tva, f.multicurrency_total_ttc = s.ttc WHERE f.multicurrency_tx = 1 AND f.total_ht <> 0 AND f.multicurrency_total_ht = 0; COMMIT;
La seconde requête refait ce que fait update_price() : le total de la facture est la somme de ses lignes. L'ancienne requête de cette note visait un identifiant écrit en dur, oubliait l'en-tête llx_facture (notre PDF affichait encore "Total HT 0,00") et ignorait le taux : 100 au lieu de 120 $ sur la facture en dollars.
En devise étrangère, pas de requête fiable : Dolibarr recalcule chaque ligne depuis le prix unitaire en devise et arrondit à chaque étape. Multiplier les totaux par le taux donnait 159,99 au lieu de 159,98 sur une de nos lignes. Mieux vaut passer par Dolibarr (avoir puis nouvelle facture).
Comment un connecteur doit-il créer ses factures ?
Par l'API, en laissant Dolibarr calculer. Le prix va dans subprice, dans la devise de la société, et la devise du client dans multicurrency_code. Sans multicurrency_tx, Dolibarr prend le dernier taux connu de la devise (1,2 pour le dollar dans notre test), ou 0 s'il n'en connaît aucun. Avec "multicurrency_tx": 0.87, notre facture en livres était juste malgré l'absence de taux.
{ "socid": 1, "multicurrency_code": "USD", "lines": [ {"desc": "Prestation", "subprice": 100, "qty": 2, "tva_tx": 20, "product_type": 1} ] }
curl -X POST -H "DOLAPIKEY: votre_cle" -H "Content-Type: application/json" -d @facture.json "https://erp.example/api/index.php/invoices"
Après la création, relisez la facture (GET /invoices/{id}) et vérifiez que multicurrency_total_ht n'est pas à 0 quand total_ht ne l'est pas. Ce contrôle a sa place dans tout connecteur qui crée des factures. D'autres requêtes testées sont réunies dans Requêtes SQL utiles pour Dolibarr, et le prix d'achat à 0 dans cette note.
- PDF à 0 : montants en devise vides sur une facture dont le taux n'est pas 1 (devise sans taux, import, écriture directe).
- Brouillon ou validée sans paiement : ressaisir le taux avec le recalcul des prix en devise.
- SQL seulement au taux 1, lignes puis en-tête, sur les factures détectées.
- Connecteur :
POST /invoices, Dolibarr calcule, puis contrôle du total en devise.
Testé avec Dolibarr 24.0.2 (module Multidevise activé, données de démonstration) et MariaDB 11.4.13.
Questions fréquentes
Les factures en euros sont-elles concernées ?
Leur PDF reste juste, car Dolibarr imprime les montants dans la devise de la société quand le taux vaut 1. Mais l'API renvoie des montants en devise à 0 aux logiciels qui les lisent : la requête de correction au taux 1 les remet d'aplomb.
Un connecteur doit-il envoyer multicurrency_subprice ?
Non. Dans nos essais, Dolibarr a calculé le prix en devise à partir de subprice et du taux, même quand multicurrency_subprice était envoyé à 0. Il suffit d'envoyer la devise et, si besoin, le taux.
Comment ajouter un taux à une devise par l'API ?
Avec PUT /multicurrencies/{id}/rates et un corps {"rate": 0.93}. Les factures créées ensuite dans cette devise reprennent ce taux.
Peut-on corriger une facture déjà payée en devise étrangère ?
Pas de façon fiable en SQL, car Dolibarr arrondit ligne par ligne. Le plus sûr est de passer par Dolibarr : avoir, puis nouvelle facture créée correctement.