---
title: "Projet : extraction de factures vers un fichier vérifié"
description: "Un lot de factures fabriquées, lues par un programme, vérifiées par des règles. Données fabriquées, critères de réussite et correction commentée."
url: https://meridal.fr/apprendre/projet-extraction-de-factures/
language: fr
written: 2026-10-07
verified: 2026-10-07
license: CC BY 4.0
---

[Apprendre](https://meridal.fr/apprendre/) › [Projets d'entraînement](https://meridal.fr/apprendre/dossier/projets/)

S'exercer · Niveau 3, Construire · 30 minutes

# Projet : extraction de factures vers un fichier vérifié

Un lot de huit factures fabriquées, lues par un programme, vérifiées par des règles, puis rangées : les justes dans un fichier, les autres de côté, chacune avec la règle en échec. La chaîne d'une extraction qu'on peut confier à un programme.

Écrit le 7 octobre 2026 · Vérifié le 7 octobre 2026

## Vous saurez

- Lire un lot de documents avec un format imposé
- Vérifier chaque lecture par des règles : calculs, date, doublons
- Ranger les justes dans un fichier, et mettre les autres de côté
- Dire pourquoi une facture est mise de côté

## Dans le parcours

[Premiers pas en développement](https://meridal.fr/apprendre/parcours/dev-debut/)

Pour finir le parcours

Aussi dans : [Progression par projets](https://meridal.fr/apprendre/projet-extraction-de-factures/)

- [← Avant Réponse dans un format imposé](https://meridal.fr/apprendre/format-impose/)
- [↓ Plus concret Projet : un assistant de projet pour une équipe](https://meridal.fr/apprendre/projet-assistant-de-projet/)
- [→ Le parcours suivant Développement d'applications d'IA](https://meridal.fr/apprendre/parcours/dev-avance/)

L'essentiel

1. Trois temps : lire chaque facture avec un format imposé, la vérifier par des règles, la ranger.
2. Le modèle recopie ; le programme calcule et juge. Aucun montant n'est calculé par le modèle.
3. Une facture qui échoue n'est ni corrigée ni comblée : elle est mise de côté, avec la règle en échec, pour une personne.
4. Les doublons et les dates absentes se voient par des règles aussi simples que les calculs.
5. Le fichier final ne contient que ce qui a passé toutes les règles.

## Objectif

Écrire un programme qui lit huit factures, garde celles qui passent toutes les règles dans un fichier `acceptees.csv`, et met les autres de côté en disant pourquoi.

Les factures sont fabriquées ; cinq portent une anomalie voulue. La lecture par le modèle (étape 1) suit la documentation d'OpenAI lue le 7 octobre 2026 et n'a pas encore été exécutée par Meridal ; la vérification et le rangement ont tourné, sur la lecture attendue donnée dans la correction.

Avant : [la réponse dans un format imposé](https://meridal.fr/apprendre/format-impose/). La même chaîne, en vrai, sur les comptes d'un cabinet : [la réalisation du modèle financier](https://meridal.fr/realisations/modele-financier/).

## Données fournies

- Lot de huit factures fournisseurs Texte Markdown, 2 Ko · septembre 2026, recopiées en texte [Télécharger](https://meridal.fr/assets/apprendre/fichiers/projet-factures/lot-de-factures.md)

1. **FACTURE** n° F-101 du 2 septembre 2026 Atelier Rivière entreprise fictive

   Total hors taxe 1 200,00 €

   TVA à 20 % 240,00 €

   Total TTC 1 440,00 €
  - Désignation Montant HT
  - Maintenance des machines 1 200,00 €
2. **FACTURE** n° 2026-0412 du 15 septembre 2026 Cabinet Exemple entreprise fictive

   Total hors taxe 1 250,00 €

   TVA à 20 % 250,00 €

   Total TTC 1 500,00 €
  - Désignation Montant HT
  - Conseil, 10 heures 1 000,00 €
  - Frais de déplacement 250,00 €
3. **FACTURE** n° 8834 du 9 septembre 2026 Imprimerie du Port entreprise fictive

   Total hors taxe 2 000,00 €

   TVA à 20 % 400,00 €

   Total TTC 2 040,00 €
  - Désignation Montant HT
  - Impression de catalogues 2 000,00 €
4. **FACTURE** n° T-77 du 11 septembre 2026 Transports Lemaire entreprise fictive

   Total hors taxe 800,00 €

   TVA à 20 % 120,00 €

   Total TTC 920,00 €
  - Désignation Montant HT
  - Livraison régionale 800,00 €
5. **FACTURE** n° F-101 du 2 septembre 2026 Atelier Rivière entreprise fictive

   Total hors taxe 1 200,00 €

   TVA à 20 % 240,00 €

   Total TTC 1 440,00 €
  - Désignation Montant HT
  - Maintenance des machines 1 200,00 €
6. **FACTURE** n° 2026-55 Bureau Fournitures Sud entreprise fictive

   Total hors taxe 150,00 €

   TVA à 20 % 30,00 €

   Total TTC 180,00 €
  - Désignation Montant HT
  - Papier et classeurs 150,00 €
7. **FACTURE** n° C-3021 du 22 septembre 2026 Café Service Pro entreprise fictive

   Total hors taxe 120,00 €

   TVA à 20 % 24,00 €

   Total TTC 144,00 €
  - Désignation Montant HT
  - Location de machine 60,00 €
  - Capsules 45,00 €
8. **FACTURE** n° L-2026-09 du 30 septembre 2026 Librairie Technique entreprise fictive

   Total hors taxe 300,00 €

   TVA à 5,5 % 16,50 €

   Total TTC 316,50 €
  - Désignation Montant HT
  - Ouvrages professionnels 300,00 €

*Les huit factures du lot, telles qu'elles arrivent. Fabriquées pour l'exercice : les fournisseurs, les numéros et les montants sont inventés. Avant de lancer l'étape 2, comptez celles qui passeront les cinq règles ; la correction dit lesquelles.*

Aussi en Word, pour l'essayer dans un assistant : [lot-de-factures.docx](https://meridal.fr/assets/apprendre/fichiers/projet-factures/lot-de-factures.docx).

## Consignes

### Format et règles

Le format de la page précédente, avec une date qui peut être vide ; et cinq règles, dont deux nouvelles : la date présente, et la facture pas déjà reçue (même fournisseur, même numéro).

`facture.py`

```
from pydantic import BaseModel, Field

class Ligne(BaseModel):
    libelle: str
    montant_ht: float

class Facture(BaseModel):
    fournisseur: str
    numero: str
    date: str = Field(description="Date au format AAAA-MM-JJ ; chaîne vide si la facture n'en porte pas")
    lignes: list[Ligne]
    total_ht: float
    taux_tva: float = Field(description="Taux de TVA en pour cent, par exemple 20 ou 5.5")
    total_tva: float
    total_ttc: float

def controler(f, deja_vues, ecart=0.01):
    """Les règles d'une facture recevable ; le modèle lit, le programme vérifie."""
    regles = [
        ("date présente", f.date != ""),
        ("hors taxe = somme des lignes", abs(sum(l.montant_ht for l in f.lignes) - f.total_ht) <= ecart),
        ("TVA = hors taxe × taux", abs(f.total_ht * f.taux_tva / 100 - f.total_tva) <= ecart),
        ("total = hors taxe + TVA", abs(f.total_ht + f.total_tva - f.total_ttc) <= ecart),
        ("pas déjà reçue", (f.fournisseur, f.numero) not in deja_vues),
    ]
    return [nom for nom, passe in regles if not passe]
```

### Étape 1. Lire le lot

Une facture par section du fichier ; chacune lue avec le format imposé, et la lecture gardée dans `lectures.json`. Pour un autre éditeur, remplacez l'appel par celui de son onglet dans [la page du format imposé](https://meridal.fr/apprendre/format-impose/).

`lire_lot.py`

```
import json
import re
from pathlib import Path

from dotenv import load_dotenv
load_dotenv()

from openai import OpenAI

from facture import Facture

client = OpenAI()
texte = Path("lot-de-factures.md").read_text(encoding="utf-8")
factures = re.split(r"\n## Facture \d+\n", texte)[1:]   # une facture par section

lectures = []
for t in factures:
    r = client.responses.parse(
        model="gpt-6-luna",
        input=[
            {"role": "system", "content": "Extrais les informations de la facture. "
             "Recopie les montants tels qu'ils sont écrits ; ne calcule rien."},
            {"role": "user", "content": t},
        ],
        text_format=Facture,
    )
    lectures.append(r.output_parsed.model_dump())

Path("lectures.json").write_text(json.dumps(lectures, ensure_ascii=False, indent=1), encoding="utf-8")
print(len(lectures), "factures lues")
```

La sortie`uv run lire_lot.py`

**Pas encore exécuté par Meridal.** Ce qu'on attend : « 8 factures lues », et un fichier lectures.json de huit lectures.

### Étape 2. Vérifier et ranger

Chaque lecture passe les cinq règles ; celles qui passent toutes vont dans `acceptees.csv`, séparé par des points-virgules pour s'ouvrir dans un tableur français.

`verifier_lot.py`

```
import csv
import json

from facture import Facture, controler

lectures = [Facture(**x) for x in json.load(open("lectures.json", encoding="utf-8"))]
deja_vues, acceptees, de_cote = set(), [], []
for n, f in enumerate(lectures, 1):
    echecs = controler(f, deja_vues)
    deja_vues.add((f.fournisseur, f.numero))
    (de_cote if echecs else acceptees).append((n, f, echecs))
    print(f"Facture {n} ({f.numero}) :", "acceptée" if not echecs else "de côté, règle en échec : " + " ; ".join(echecs))

with open("acceptees.csv", "w", newline="", encoding="utf-8") as sortie:
    w = csv.writer(sortie, delimiter=";")
    w.writerow(["fournisseur", "numero", "date", "total_ht", "total_tva", "total_ttc"])
    for _, f, _ in acceptees:
        w.writerow([f.fournisseur, f.numero, f.date, f.total_ht, f.total_tva, f.total_ttc])
print(f"{len(acceptees)} acceptées, écrites dans acceptees.csv ; {len(de_cote)} mises de côté")
```

## Critères de réussite

- Huit lectures dans `lectures.json`
- Cinq factures mises de côté, chacune avec une seule règle en échec si une facture juste est mise de côté, relisez sa lecture : le modèle s'est trompé
- Trois factures dans `acceptees.csv`, dont celle à 5,5 % de TVA
- La facture reçue deux fois n'entre qu'une fois
- Aucun montant n'a été modifié entre la facture et le fichier

## Indications

**Une facture juste est mise de côté**

**Cause**Le modèle a mal recopié un montant, ou l'a recalculé.

**À faire**Comparez sa lecture au texte ; la consigne « recopie les montants tels qu'ils sont écrits ; ne calcule rien » est là pour ça.

**La facture à 5,5 % échoue sur la TVA**

**Cause**Le taux a été lu 5 au lieu de 5,5, ou recopié en texte avec sa virgule.

**À faire**Vérifiez la description du champ `taux_tva` : un nombre, avec un point décimal.

**La facture sans date reçoit une date**

**Cause**Le modèle a mis la date du jour, ou celle d'une autre facture.

**À faire**La description du champ dit « chaîne vide si la facture n'en porte pas » ; gardez-la, et testez cette facture à part.

**Les montants s'arrondissent mal**

**Cause**Un nombre à virgule flottante ne tombe pas toujours juste.

**À faire**Les règles tolèrent un centime d'écart ; pour une vraie comptabilité, passer par `Decimal`.

## Correction commentée

**Ouvrir la correction**

**La lecture attendue**Ce que l'étape 1 doit produire, recopié de chaque facture sans rien calculer :

`lectures.json`

```
[
 {"fournisseur": "Atelier Rivière", "numero": "F-101", "date": "2026-09-02", "lignes": [{"libelle": "Maintenance des machines", "montant_ht": 1200.0}], "total_ht": 1200.0, "taux_tva": 20.0, "total_tva": 240.0, "total_ttc": 1440.0},
 {"fournisseur": "Cabinet Exemple", "numero": "2026-0412", "date": "2026-09-15", "lignes": [{"libelle": "Conseil, 10 heures", "montant_ht": 1000.0}, {"libelle": "Frais de déplacement", "montant_ht": 250.0}], "total_ht": 1250.0, "taux_tva": 20.0, "total_tva": 250.0, "total_ttc": 1500.0},
 {"fournisseur": "Imprimerie du Port", "numero": "8834", "date": "2026-09-09", "lignes": [{"libelle": "Impression de catalogues", "montant_ht": 2000.0}], "total_ht": 2000.0, "taux_tva": 20.0, "total_tva": 400.0, "total_ttc": 2040.0},
 {"fournisseur": "Transports Lemaire", "numero": "T-77", "date": "2026-09-11", "lignes": [{"libelle": "Livraison régionale", "montant_ht": 800.0}], "total_ht": 800.0, "taux_tva": 20.0, "total_tva": 120.0, "total_ttc": 920.0},
 {"fournisseur": "Atelier Rivière", "numero": "F-101", "date": "2026-09-02", "lignes": [{"libelle": "Maintenance des machines", "montant_ht": 1200.0}], "total_ht": 1200.0, "taux_tva": 20.0, "total_tva": 240.0, "total_ttc": 1440.0},
 {"fournisseur": "Bureau Fournitures Sud", "numero": "2026-55", "date": "", "lignes": [{"libelle": "Papier et classeurs", "montant_ht": 150.0}], "total_ht": 150.0, "taux_tva": 20.0, "total_tva": 30.0, "total_ttc": 180.0},
 {"fournisseur": "Café Service Pro", "numero": "C-3021", "date": "2026-09-22", "lignes": [{"libelle": "Location de machine", "montant_ht": 60.0}, {"libelle": "Capsules", "montant_ht": 45.0}], "total_ht": 120.0, "taux_tva": 20.0, "total_tva": 24.0, "total_ttc": 144.0},
 {"fournisseur": "Librairie Technique", "numero": "L-2026-09", "date": "2026-09-30", "lignes": [{"libelle": "Ouvrages professionnels", "montant_ht": 300.0}], "total_ht": 300.0, "taux_tva": 5.5, "total_tva": 16.5, "total_ttc": 316.5}
]
```

**La vérification**Le programme de l'étape 2, lancé sur cette lecture :

La sortie`uv run verifier_lot.py`

```
Facture 1 (F-101) : acceptée
Facture 2 (2026-0412) : acceptée
Facture 3 (8834) : de côté, règle en échec : total = hors taxe + TVA
Facture 4 (T-77) : de côté, règle en échec : TVA = hors taxe × taux
Facture 5 (F-101) : de côté, règle en échec : pas déjà reçue
Facture 6 (2026-55) : de côté, règle en échec : date présente
Facture 7 (C-3021) : de côté, règle en échec : hors taxe = somme des lignes
Facture 8 (L-2026-09) : acceptée
3 acceptées, écrites dans acceptees.csv ; 5 mises de côté
```

Essayé le 7 octobre 2026 avec Python 3.12.7 et Pydantic 2.6.0.

**Les cinq anomalies**Le même lot, rangé par le programme. Chaque facture mise de côté échoue sur une seule règle, celle qui dit quoi vérifier.

Acceptées (3)

1. **FACTURE** n° F-101 du 2 septembre 2026 Atelier Rivière entreprise fictive Acceptée

   Total hors taxe 1 200,00 €

   TVA à 20 % 240,00 €

   Total TTC 1 440,00 €
  - Désignation Montant HT
  - Maintenance des machines 1 200,00 €
2. **FACTURE** n° 2026-0412 du 15 septembre 2026 Cabinet Exemple entreprise fictive Acceptée

   Total hors taxe 1 250,00 €

   TVA à 20 % 250,00 €

   Total TTC 1 500,00 €
  - Désignation Montant HT
  - Conseil, 10 heures 1 000,00 €
  - Frais de déplacement 250,00 €
3. **FACTURE** n° L-2026-09 du 30 septembre 2026 Librairie Technique entreprise fictive Acceptée

   Total hors taxe 300,00 €

   TVA à 5,5 % 16,50 €

   Total TTC 316,50 €
  - Désignation Montant HT
  - Ouvrages professionnels 300,00 €

Mises de côté (5)

1. **FACTURE** n° 8834 du 9 septembre 2026 Imprimerie du Port entreprise fictive **Règle en échec : total = hors taxe + TVA**2 000,00 € + 400,00 € font 2 400,00 €, pas 2 040,00 €.

   Total hors taxe 2 000,00 €

   TVA à 20 % 400,00 €

   Total TTC 2 040,00 €
  - Désignation Montant HT
  - Impression de catalogues 2 000,00 €
2. **FACTURE** n° T-77 du 11 septembre 2026 Transports Lemaire entreprise fictive **Règle en échec : TVA = hors taxe × taux**20 % de 800,00 € font 160,00 €, pas 120,00 €.

   Total hors taxe 800,00 €

   TVA à 20 % 120,00 €

   Total TTC 920,00 €
  - Désignation Montant HT
  - Livraison régionale 800,00 €
3. **FACTURE** n° F-101 du 2 septembre 2026 Atelier Rivière entreprise fictive **Règle en échec : pas déjà reçue**Même fournisseur, même numéro que la facture 1.

   Total hors taxe 1 200,00 €

   TVA à 20 % 240,00 €

   Total TTC 1 440,00 €
  - Désignation Montant HT
  - Maintenance des machines 1 200,00 €
4. **FACTURE** n° 2026-55 sans date Bureau Fournitures Sud entreprise fictive **Règle en échec : date présente**La facture ne porte aucune date.

   Total hors taxe 150,00 €

   TVA à 20 % 30,00 €

   Total TTC 180,00 €
  - Désignation Montant HT
  - Papier et classeurs 150,00 €
5. **FACTURE** n° C-3021 du 22 septembre 2026 Café Service Pro entreprise fictive **Règle en échec : hors taxe = somme des lignes**60,00 € + 45,00 € font 105,00 €, pas 120,00 €.

   Total hors taxe 120,00 €

   TVA à 20 % 24,00 €

   Total TTC 144,00 €
  - Désignation Montant HT
  - Location de machine 60,00 €
  - Capsules 45,00 €

*Les cercles et les calculs viennent des cinq règles, appliquées au lot par le script qui écrit cette page ; les factures restent fabriquées.*

**Pourquoi des règles et pas le modèle**Un modèle qui recalcule « corrige » sans le dire : la facture 3 deviendrait juste, et l'erreur du fournisseur disparaîtrait. Le programme, lui, montre l'écart et laisse décider une personne.

## Extensions

- **Les vraies factures** : des PDF plutôt que du texte, avec les limites que dit [l'extraction des chiffres d'un document](https://meridal.fr/apprendre/extraction-des-chiffres/).
- **D'autres règles** : un numéro de TVA intracommunautaire bien formé, un fournisseur connu, une date d'échéance dans les délais légaux, 45 jours fin de mois ou 60 jours au plus.
- **La file de validation** : un fichier ou un tableau des factures mises de côté, où une personne corrige et relance.
- **Mesurer** : sur cinquante factures dont vous connaissez la lecture, le nombre de lectures justes ; voir [l'évaluation d'un outil d'IA](https://meridal.fr/apprendre/evaluer-un-outil-d-ia/).

## Lectures suivantes

↑ Plus général

Rien avant : c'est un point de départ.

← Avant [Réponse dans un format imposé S'exercer · Niveau 3 · 20 minutes](https://meridal.fr/apprendre/format-impose/)

Vous êtes ici

Projet : extraction de factures vers un fichier vérifié

→ Le parcours suivant [Développement d'applications d'IA Niveau 3](https://meridal.fr/apprendre/parcours/dev-avance/)

↓ Plus concret [Projet : un assistant de projet pour une équipe S'exercer · Niveau 1 · 40 minutes](https://meridal.fr/apprendre/projet-assistant-de-projet/)

[Tout le dossier « Projets d'entraînement »](https://meridal.fr/apprendre/dossier/projets/)

Les pages qui renvoient ici

- [Projet : une relance automatique avec validation sur n8n](https://meridal.fr/apprendre/projet-relance-automatique-sur-n8n/)
- [Déploiement en région européenne](https://meridal.fr/apprendre/deploiement-en-europe/)

**Limites et sources**

La lecture par le modèle suit la documentation d'OpenAI du 7 octobre 2026 et n'a pas encore été exécutée par Meridal ; la vérification a tourné sur la lecture attendue.

Les factures, les fournisseurs et les anomalies sont fabriqués.

1. [OpenAI, Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs) ; [Service Public Entreprendre, délais de paiement](https://entreprendre.service-public.gouv.fr/vosdroits/F23211).
2. Le lot de factures, en Markdown : `apprendre/pages/projets/projet-factures/fichiers/`.
3. L'image d'ouverture : Comble à l'impériale, figures 95 et 96, Encyclopédie de Diderot et d'Alembert, recueil de planches, tome 2, Charpenterie ; domaine public, [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Encyclopedie_volume_2-285_(fig_95-96).png).

Écrit par Meridal, avec l'aide de l'IA ; chaque fait vérifié à sa source et relu avant publication. Texte et schémas sous licence [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.fr) : reprenez-les en citant Meridal. Le code sous licence MIT.

Service correspondant

Préparer les documents qui reviennent

1 650 € à 5 100 €, puis sur devis

[Voir le service](https://meridal.fr/offre/#documents)

## Un premier échange de 30 minutes

En visio et sans frais : vous décrivez votre situation, nous vous indiquons ce qui est réalisable, avec quels outils et pour quel ordre de prix. Vous pouvez aussi nous écrire ; chaque message reçoit une réponse écrite.

[Réserver 30 minutes](https://meridal.fr/contact/#reserver) [Écrire un message](https://meridal.fr/contact/)
