Tous les articles
Travailler ensemble →
factur-x20 juin 2026 18 min
Factur-X 2026 : guide complet, exemple XML et implémentation Python & Go
Guide complet Factur-X : obligation 2026, les 5 profils, exemple XML CII EN 16931 prêt à l'emploi, code Python et Go pour générer vos factures électroniques. Intégration Shopify, Odoo et ERP sur mesure.

La facturation électronique Factur-X devient obligatoire pour toutes les entreprises françaises assujetties à la TVA à partir de 2026. Ce guide complet vous explique tout : la théorie, les profils, un exemple XML réel, et comment l'implémenter en Python et Go dans votre système existant.
Qu'est-ce que Factur-X ? Définition complète
Factur-X est un standard de facture électronique hybride franco-allemand (appelé ZUGFeRD en Allemagne). Il combine deux formats en un seul fichier :
- Un PDF/A-3 lisible par l'humain — votre facture telle que vous la connaissez
- Un fichier XML structuré embarqué dans les métadonnées du PDF — lisible par les logiciels
- Les deux sont synchronisés dans un seul fichier .pdf
L'avantage majeur : vos clients peuvent ouvrir la facture dans Adobe Reader comme d'habitude, et votre ERP peut l'importer automatiquement sans ressaisie. C'est le meilleur des deux mondes.
Factur-X est basé sur le standard international Cross Industry Invoice (CII) développé par l'UN/CEFACT, et respecte la norme européenne EN 16931 pour la facturation électronique B2B.
Pourquoi Factur-X devient obligatoire en France en 2026
La loi de finances 2024 a instauré l'obligation de facturation électronique pour toutes les entreprises françaises assujetties à la TVA. Le calendrier :
- Septembre 2026 : obligation d'émission pour les grandes entreprises (> 5 000 salariés)
- Septembre 2027 : obligation d'émission pour les ETI (250 à 5 000 salariés)
- Septembre 2027 : obligation d'émission pour les PME et TPE
- Réception des factures électroniques : obligatoire dès septembre 2026 pour TOUTES les entreprises
Important : "recevoir" une facture électronique est obligatoire dès 2026 pour toutes les tailles d'entreprises. Même une TPE doit être capable d'accepter un Factur-X dès cette date.
Les formats acceptés par la plateforme nationale Chorus Pro (et les plateformes partenaires) sont : Factur-X/ZUGFeRD, UBL (Universal Business Language) et CII pur. Factur-X est le format hybride le plus adapté aux PME car il conserve la lisibilité humaine du PDF.
Les 5 profils Factur-X — Lequel choisir ?
Factur-X définit 5 niveaux de complétude des données. Du plus simple au plus complet :
1. Profil MINIMUM
Données minimales obligatoires : identifiants acheteur/vendeur, numéro de facture, date, montant total TTC. Pas de détail des lignes. Usage limité, non compatible Chorus Pro pour les marchés publics.
2. Profil BASIC WL (Without Lines)
Comme MINIMUM mais avec les totaux TVA par taux. Toujours sans détail des lignes. Utile pour les factures simples avec une seule ligne.
3. Profil BASIC
Premières lignes de détail incluses. Montant unitaire, quantité, description. Compatible avec la plupart des flux B2B simples.
4. Profil EN 16931 (Confort) — Recommandé France
Le profil standard pour la France. Compatible Chorus Pro. Inclut toutes les données obligatoires et optionnelles de la norme EN 16931. C'est celui-ci que vous devez implémenter pour les échanges B2B en France.
5. Profil EXTENDED
Toutes les données possibles, y compris les champs spécifiques à des secteurs (logistique, contrats cadre, etc.). Utile pour des échanges EDI complexes ou des intégrations sectorielles avancées.
Pour 95% des PME françaises : implémentez le profil EN 16931. C'est le standard requis par Chorus Pro et les plateformes de dématérialisation partenaires (PDP).
Structure XML CII — Comprendre le format
Le XML Factur-X suit le standard Cross Industry Invoice (CII) de l'UN/CEFACT. Voici la structure des grandes sections :
- ExchangedDocumentContext — Contexte et profil utilisé
- ExchangedDocument — Numéro, type et date de la facture
- SupplyChainTradeTransaction — Le cœur de la facture :
- IncludedSupplyChainTradeLineItem — Les lignes de facture (produits/services)
- ApplicableHeaderTradeAgreement — Vendeur et acheteur
- ApplicableHeaderTradeDelivery — Informations de livraison
- ApplicableHeaderTradeSettlement — Totaux, TVA et conditions de paiement
Exemple XML Factur-X complet — Profil EN 16931
Voici un exemple XML CII valide et complet pour une facture avec deux lignes de service, TVA 20%, conforme au profil EN 16931 :
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Profil utilisé -->
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<!-- En-tête de la facture -->
<rsm:ExchangedDocument>
<ram:ID>FAC-2026-00042</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20260615</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>Paiement à 30 jours fin de mois. RIB : FR76 3000 1007 9400 0000 0000 143</ram:Content>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<!-- LIGNE 1 -->
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Développement API REST — intégration Factur-X</ram:Name>
<ram:Description>Développement et intégration du module de génération Factur-X dans l'ERP client</ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>1500.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>20</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1500.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<!-- LIGNE 2 -->
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Formation technique Factur-X — 4h</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>500.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>20</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>500.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<!-- VENDEUR -->
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Moussa Gaye — Développeur Web Freelance</ram:Name>
<ram:DefinedTradeContact>
<ram:EmailURIUniversalCommunication>
<ram:URIID>contact@moussagaye.com</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:LineOne>123 Boulevard Zerktouni</ram:LineOne>
<ram:CityName>Casablanca</ram:CityName>
<ram:CountryID>MA</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR12345678901</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<!-- ACHETEUR -->
<ram:BuyerTradeParty>
<ram:Name>Entreprise Cliente SAS</ram:Name>
<ram:PostalTradeAddress>
<ram:LineOne>45 Rue de Rivoli</ram:LineOne>
<ram:CityName>Paris</ram:CityName>
<ram:PostcodeCode>75001</ram:PostcodeCode>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR98765432109</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>BON-2026-098</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20260610</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<!-- TOTAUX ET TVA -->
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>400.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>2000.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>20</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Paiement à 30 jours fin de mois</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20260715</udt:DateTimeString>
</ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>2000.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>2000.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">400.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>2400.00</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>2400.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>Générer Factur-X en Python — Guide complet
La bibliothèque Python `factur-x` (maintenue par Akretion) est la référence open source pour générer des fichiers Factur-X. Elle gère l'embarquement du XML dans le PDF/A-3 et la validation XSD automatiquement.
Installation
pip install factur-x reportlabGénérer un Factur-X depuis un PDF existant
from facturx import generate_facturx_from_file
import os
def generer_facturx(chemin_pdf, chemin_xml, chemin_sortie, profil='EN 16931'):
"""
Génère un fichier Factur-X à partir d'un PDF et d'un XML CII.
Args:
chemin_pdf: Chemin vers le PDF source (votre facture)
chemin_xml: Chemin vers le fichier XML CII
chemin_sortie: Chemin du fichier Factur-X généré
profil: 'MINIMUM', 'BASIC WL', 'BASIC', 'EN 16931', ou 'EXTENDED'
"""
generate_facturx_from_file(
pdf_file=chemin_pdf,
xml_file=chemin_xml,
flavor=profil,
output_pdf_file=chemin_sortie,
attachments=None,
lang='fr',
facturx_level=profil.lower().replace(' ', ''),
)
taille = os.path.getsize(chemin_sortie)
print(f"✅ Factur-X généré : {chemin_sortie} ({taille / 1024:.1f} Ko)")
return chemin_sortie
# Usage
generer_facturx(
chemin_pdf="facture_originale.pdf",
chemin_xml="facture_cii.xml",
chemin_sortie="facture_facturx.pdf",
profil="EN 16931"
)Générer le XML CII dynamiquement en Python
from lxml import etree
from datetime import date
def generer_xml_cii(facture: dict) -> str:
"""
Génère un XML CII Factur-X EN 16931 depuis un dictionnaire Python.
facture = {
'numero': 'FAC-2026-001',
'date': date(2026, 6, 15),
'date_echeance': date(2026, 7, 15),
'vendeur': {'nom': '...', 'tva': 'FR...', 'adresse': '...'},
'acheteur': {'nom': '...', 'tva': 'FR...'},
'lignes': [{'description': '...', 'prix_ht': 1500.0, 'tva_pct': 20}],
}
"""
NS = {
'rsm': 'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100',
'ram': 'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100',
'udt': 'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100',
}
root = etree.Element('{%s}CrossIndustryInvoice' % NS['rsm'], nsmap=NS)
# Contexte
ctx = etree.SubElement(root, '{%s}ExchangedDocumentContext' % NS['rsm'])
guide = etree.SubElement(ctx, '{%s}GuidelineSpecifiedDocumentContextParameter' % NS['ram'])
etree.SubElement(guide, '{%s}ID' % NS['ram']).text = (
'urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931'
)
# En-tête
doc = etree.SubElement(root, '{%s}ExchangedDocument' % NS['rsm'])
etree.SubElement(doc, '{%s}ID' % NS['ram']).text = facture['numero']
etree.SubElement(doc, '{%s}TypeCode' % NS['ram']).text = '380'
dt = etree.SubElement(doc, '{%s}IssueDateTime' % NS['ram'])
etree.SubElement(dt, '{%s}DateTimeString' % NS['udt'],
format='102').text = facture['date'].strftime('%Y%m%d')
# Calculs
total_ht = sum(l['prix_ht'] for l in facture['lignes'])
total_tva = sum(l['prix_ht'] * l['tva_pct'] / 100 for l in facture['lignes'])
total_ttc = total_ht + total_tva
# Transaction
tx = etree.SubElement(root, '{%s}SupplyChainTradeTransaction' % NS['rsm'])
# Lignes
for i, ligne in enumerate(facture['lignes'], 1):
li = etree.SubElement(tx, '{%s}IncludedSupplyChainTradeLineItem' % NS['ram'])
doc_li = etree.SubElement(li, '{%s}AssociatedDocumentLineDocument' % NS['ram'])
etree.SubElement(doc_li, '{%s}LineID' % NS['ram']).text = str(i)
prod = etree.SubElement(li, '{%s}SpecifiedTradeProduct' % NS['ram'])
etree.SubElement(prod, '{%s}Name' % NS['ram']).text = ligne['description']
agr = etree.SubElement(li, '{%s}SpecifiedLineTradeAgreement' % NS['ram'])
prix = etree.SubElement(agr, '{%s}NetPriceProductTradePrice' % NS['ram'])
etree.SubElement(prix, '{%s}ChargeAmount' % NS['ram']).text = f"{ligne['prix_ht']:.2f}"
deliv = etree.SubElement(li, '{%s}SpecifiedLineTradeDelivery' % NS['ram'])
etree.SubElement(deliv, '{%s}BilledQuantity' % NS['ram'], unitCode='C62').text = '1'
sett = etree.SubElement(li, '{%s}SpecifiedLineTradeSettlement' % NS['ram'])
tax = etree.SubElement(sett, '{%s}ApplicableTradeTax' % NS['ram'])
etree.SubElement(tax, '{%s}TypeCode' % NS['ram']).text = 'VAT'
etree.SubElement(tax, '{%s}CategoryCode' % NS['ram']).text = 'S'
etree.SubElement(tax, '{%s}RateApplicablePercent' % NS['ram']).text = str(ligne['tva_pct'])
summ = etree.SubElement(sett, '{%s}SpecifiedTradeSettlementLineMonetarySummation' % NS['ram'])
etree.SubElement(summ, '{%s}LineTotalAmount' % NS['ram']).text = f"{ligne['prix_ht']:.2f}"
return etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='UTF-8').decode()
# Test
facture = {
'numero': 'FAC-2026-001',
'date': date(2026, 6, 15),
'vendeur': {'nom': 'Moussa Gaye', 'tva': 'FR12345678901'},
'acheteur': {'nom': 'Client SAS', 'tva': 'FR98765432109'},
'lignes': [
{'description': 'Développement API', 'prix_ht': 1500.0, 'tva_pct': 20},
{'description': 'Formation', 'prix_ht': 500.0, 'tva_pct': 20},
],
}
xml = generer_xml_cii(facture)
print(xml[:500])Générer Factur-X en Go
Go n'a pas de bibliothèque Factur-X dédiée aussi mature que Python. L'approche consiste à générer le XML manuellement avec `encoding/xml`, puis à embarquer ce XML dans un PDF/A-3 avec la bibliothèque `pdfcpu`.
Installation des dépendances Go
go get github.com/pdfcpu/pdfcpu/pkg/api
go get github.com/pdfcpu/pdfcpu/pkg/pdfcpu/modelStructure Go pour le XML CII
package facturx
import (
"encoding/xml"
"fmt"
"time"
)
// CrossIndustryInvoice représente la racine du XML Factur-X CII
type CrossIndustryInvoice struct {
XMLName xml.Name `xml:"rsm:CrossIndustryInvoice"`
NSRsm string `xml:"xmlns:rsm,attr"`
NSRam string `xml:"xmlns:ram,attr"`
NSUdt string `xml:"xmlns:udt,attr"`
Context ExchangedDocumentContext `xml:"rsm:ExchangedDocumentContext"`
Document ExchangedDocument `xml:"rsm:ExchangedDocument"`
Trade SupplyChainTradeTransaction `xml:"rsm:SupplyChainTradeTransaction"`
}
type ExchangedDocumentContext struct {
Guideline struct {
ID string `xml:"ram:ID"`
} `xml:"ram:GuidelineSpecifiedDocumentContextParameter"`
}
type ExchangedDocument struct {
ID string `xml:"ram:ID"`
TypeCode string `xml:"ram:TypeCode"`
IssueDate struct {
DateTimeString struct {
Value string `xml:",chardata"`
Format string `xml:"format,attr"`
} `xml:"udt:DateTimeString"`
} `xml:"ram:IssueDateTime"`
}
type Invoice struct {
Numero string
Date time.Time
DateEcheance time.Time
VendeurNom string
VendeurTVA string
AcheteurNom string
AcheteurTVA string
Lignes []LigneFacture
}
type LigneFacture struct {
Description string
PrixHT float64
TauxTVA float64
}
// GenererXMLCII génère le XML CII pour une facture
func GenererXMLCII(inv Invoice) ([]byte, error) {
totalHT := 0.0
for _, l := range inv.Lignes {
totalHT += l.PrixHT
}
totalTVA := totalHT * 0.20 // simplification TVA 20%
totalTTC := totalHT + totalTVA
doc := CrossIndustryInvoice{
NSRsm: "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100",
NSRam: "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100",
NSUdt: "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100",
}
doc.Context.Guideline.ID = "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931"
doc.Document.ID = inv.Numero
doc.Document.TypeCode = "380"
doc.Document.IssueDate.DateTimeString.Value = inv.Date.Format("20060102")
doc.Document.IssueDate.DateTimeString.Format = "102"
_ = fmt.Sprintf("%.2f + %.2f = %.2f", totalHT, totalTVA, totalTTC)
return xml.MarshalIndent(doc, "", " ")
}Valider votre fichier Factur-X
Avant d'envoyer votre premier Factur-X à un client ou à Chorus Pro, validez-le avec ces outils :
1. Validation via Python (en ligne de commande)
from facturx import check_facturx_xsd
# Valide le XML embarqué dans le PDF Factur-X
result = check_facturx_xsd("ma_facture_facturx.pdf")
if result is None:
print("✅ Factur-X valide — conforme au schéma XSD")
else:
print(f"❌ Erreur de validation : {result}")2. Portail de validation officiel
- Validateur FNFE-MPE : validator.fnfe-mpe.org (validation XSD + règles métier)
- Mustang Project : validation via CLI Java — idéal pour l'intégration CI/CD
- Chorus Pro : portail officiel de l'État pour les marchés publics
Intégrer Factur-X dans votre système — Cas concrets
Cas 1 : Shopify → génération automatique à chaque commande
Voici comment déclencher la génération Factur-X à chaque commande Shopify payée via webhook :
import hmac
import hashlib
import base64
from flask import Flask, request
from facturx import generate_facturx_from_file
import json
app = Flask(__name__)
SHOPIFY_SECRET = "votre_secret_webhook"
def verifier_webhook_shopify(data, hmac_header):
digest = hmac.new(SHOPIFY_SECRET.encode('utf-8'), data, hashlib.sha256).digest()
computed = base64.b64encode(digest).decode('utf-8')
return hmac.compare_digest(computed, hmac_header)
@app.route('/webhook/shopify/orders/paid', methods=['POST'])
def commande_payee():
# Vérification sécurité
if not verifier_webhook_shopify(request.data, request.headers.get('X-Shopify-Hmac-Sha256')):
return 'Unauthorized', 401
commande = json.loads(request.data)
# Générer le XML CII depuis les données Shopify
xml_content = mapper_shopify_vers_cii(commande)
# Générer le PDF Factur-X
chemin_pdf = generer_pdf_facture(commande) # votre générateur PDF
chemin_xml = f"/tmp/facture_{commande['order_number']}.xml"
chemin_sortie = f"/factures/FAC-{commande['order_number']}.pdf"
with open(chemin_xml, 'w') as f:
f.write(xml_content)
generate_facturx_from_file(chemin_pdf, chemin_xml, 'EN 16931', chemin_sortie)
# Stocker + envoyer par email
envoyer_facture_client(commande['email'], chemin_sortie)
return 'OK', 200Cas 2 : Intégration Odoo
Odoo dispose d'un module officiel `account_facturx` disponible sur l'App Store Odoo. Pour les versions custom :
# Dans votre module Odoo personnalisé
from odoo import models, fields
class AccountMove(models.Model):
_inherit = 'account.move'
def action_generate_facturx(self):
"""Génère le Factur-X pour la facture courante."""
for facture in self:
if facture.move_type != 'out_invoice':
continue
# Récupérer les données Odoo
data = {
'numero': facture.name,
'date': facture.invoice_date,
'vendeur': {
'nom': facture.company_id.name,
'tva': facture.company_id.vat,
},
'acheteur': {
'nom': facture.partner_id.name,
'tva': facture.partner_id.vat,
},
'lignes': [{
'description': line.name,
'prix_ht': line.price_subtotal,
'tva_pct': line.tax_ids[0].amount if line.tax_ids else 0,
} for line in facture.invoice_line_ids],
}
# Générer via votre module facturx
xml = votre_generateur_cii(data)
facture.write({'facturx_xml': xml})Checklist avant mise en production
- ☐ Valider le XML contre le schéma XSD officiel (validator.fnfe-mpe.org)
- ☐ Vérifier que le PDF est en format PDF/A-3 (pas juste PDF/A-1)
- ☐ Confirmer que le fichier XML embarqué porte le nom factur-x.xml (convention)
- ☐ Tester avec un vrai compte Chorus Pro (environnement de qualification)
- ☐ Vérifier que les numéros TVA vendeur/acheteur sont au format FR suivi de 11 chiffres
- ☐ S'assurer que les montants sont cohérents (LineTotalAmount = GrandTotalAmount - TaxTotalAmount)
- ☐ Mettre en place un log de toutes les factures générées avec leur statut de validation
- ☐ Prévoir une procédure de correction en cas de facture rejetée
Vous n'avez pas les ressources pour intégrer Factur-X vous-même avant janvier 2026 ? Je propose une prestation d'intégration sur mesure dans votre logiciel existant — contactez-moi sur contact@moussagaye.com
Questions fréquentes
Factur-X est-il obligatoire pour les auto-entrepreneurs ?
Oui, à terme. L'obligation d'émission s'applique à toutes les entreprises assujetties à la TVA, y compris les micro-entreprises. Les auto-entrepreneurs en franchise de TVA (sous le seuil) ne sont pas concernés par l'émission mais doivent pouvoir recevoir des factures électroniques.
Peut-on continuer à envoyer des PDF classiques ?
Non, à partir des échéances 2026-2027, l'émission de factures en PDF classique ne sera plus légalement valable pour les transactions B2B entre entreprises françaises assujetties à la TVA.
Factur-X remplace-t-il Chorus Pro ?
Non. Chorus Pro est la plateforme de l'État pour les marchés publics. Factur-X est le format. Pour les marchés publics, vous envoyez vos factures Factur-X via Chorus Pro. Pour les échanges B2B privés, vous passez par une Plateforme de Dématérialisation Partenaire (PDP) agréée ou l'annuaire central.
Quelle est la différence entre Factur-X et ZUGFeRD ?
ZUGFeRD est l'équivalent allemand de Factur-X. À partir de la version ZUGFeRD 2.0 / Factur-X 1.0, les deux standards sont alignés et un fichier ZUGFeRD 2.0 profil EN 16931 est également un Factur-X valide. Vous pouvez utiliser la même implémentation pour les deux marchés.
Moussa Gaye
Développeur web freelance — France, Maroc, Sénégal