Manuel administration fiscale
Téléchargement de l'export
TODO
Utilisation de l'export
Cette documentation explique comment vérifier l’intégrité et l’authenticité d’un export fiscal du logiciel WInOrtho.
L’archive contient toutes les factures et leurs lignes d'une période donnée (maximum un an), avec une signature Ed25519 assurant la non-altération.
La période concernée est précisée dans le nom de l'archive.
L’archive
• export_2024-01-01_2025-07-31.zip : archive ZIP contenant le fichier l'export.
• export_2024-01-01_2025-07-31.zip.sig : signature Ed25519 de l’archive ZIP.
• winortho_verify_key.hex : clé publique fournie par le Présence Informatique pour vérification des données.
Le fichier factures.json contient toutes les factures et leurs lignes enfants sous cette structure : TODO: définir un format définitif
[
{
"numero": "000000001",
"date": "2025-09-23",
"montant": "1000.00",
"previous_signature": "",
"signature": "abc123...",
"lignes": [
{
"libelle": "Acte A",
"quantite": 1,
"montant": "1000.00",
"tva": "20.00"
`
]
}
]
previous_signature : chaîne avec la signature de la facture précédente pour maintenir l’intégrité de la blockchain.
signature : signature Ed25519 de la facture.
Le fichier règlements.json contient tous les règlement sous cette structure : TODO: définir un format définitif
[
{
"facture": "000000001",
"dateCreation": "2025-09-23",
"dateReglement": "2025-09-23",
"montant": "1000.00",
"mode": "CB",
"libelle": "Reglement M. ABC",
"signature": "abc123...",
"previous_signature": "poiuyt...",
},
]
previous_signature : chaîne avec la signature de la facture précédente pour maintenir l’intégrité de la blockchain.
signature : signature Ed25519 de la facture.
Enfin le fichier log.json contient les logs de toutes les actions des utilisateurs dans le logiciel :
{
"model": "activitylog.activitylog",
"pk": 291,
"fields": {
"timestamp": "2025-06-24T12:02:44.257Z",
"user": "florian",
"action": "Impression",
"model": "Facture",
"object_pk": 105,
"diff": {},
"object": {
"pdf_file": "/media/impressions/v2/factures_hors_teletrans/Facture-105.pdf"
},
"instance": "v2",
"commentaire": "Impression facture 250600077 du type facture_hors_teletrans avec le modèle : Facture",
"signature": "4c640482fc4253e4adab9a608513afa4717c1883c840fbfae1709f850d3f94e7",
"previous_signature": "00232eaa0365661e4827daadd6e019b0199956fa385f5470eac383544e04fec8"
}
},
{
"model": "activitylog.activitylog",
"pk": 292,
"fields": {
"timestamp": "2025-06-25T07:59:42.342Z",
"user": "florian",
"action": "Mise à jour",
"model": "LigneFacture",
"object_pk": 192,
"diff": { "quantite": [1, 2] },
"object": {
"code": "2110490",
"conditionnement": 1,
"dateActe": "2025-06-01",
"libelle": "CHUP, ADULTE NEUT, PODIABETES PARADIS, LA PAIRE",
"ligneParent": 0,
"lpp": 28075,
"montantRemboursementAMC": 0.0,
"montantRemboursementAMO": 0.0,
"nomCodeActe": "DVO",
"pcRO": null,
"prestaFse": null,
"prixSS": 55.02,
"prixUnitaireHT": 53.89,
"prixVente": 55.02,
...
},
"instance": "v2",
"commentaire": "Aperçu des modifications : {'quantite': [1, 2]}...",
"signature": "bc162eaaa1a018fa45d5b197633a25d7c7b0602bcfbd69628cc9a081f557607f",
"previous_signature": "c9460eb3b93bb34742e4774094a389f515d1255b6dd88f56a0376eea06146c94"
}
}
...
Vérification de l'archive et de la chaîne de factures
Le script permet de :
- Vérifier puis décompresser export_2024-01-01_2025-07-31.zip pour obtenir le fichier export.json.
- Charger le JSON et vérifier chaque facture et son chainage
Prérequis pour l'exécution du script
- Python 3.x
- Installer la librairie PyNaCl :
pip install pynacl
Aperçu du script pour analyse :
import json
import zipfile
from nacl.signing import VerifyKey
import hashlib
def compute_fiscal_hash(facture):
data = {
"numero": facture["numero"],
"date": facture["date"],
"montant": facture["montant"],
"type_client": facture["type_client"],
"lignes": sorted([
{"libelle": l["libelle"], "quantite": l["quantite"], "montant": l["montant"], "tva": l["tva"]}
for l in facture["lignes"]
], key=lambda x: x["libelle"])
}
json_data = json.dumps(data, sort_keys=True)
return hashlib.sha256(json_data.encode()).hexdigest()
def verify_archive_and_chain(zip_path, sig_path, verify_key_path):
# Charger clé publique
with open(verify_key_path, "r") as f:
verify_key = VerifyKey(bytes.fromhex(f.read()))
# Vérifier signature ZIP
with open(zip_path, "rb") as f:
zip_bytes = f.read()
with open(sig_path, "r") as f:
signature_hex = f.read()
try:
verify_key.verify(bytes.fromhex(signature_hex), zip_bytes)
print("✅ Signature ZIP valide")
except:
print("❌ Signature ZIP invalide")
return False
# Décompresser JSON
with zipfile.ZipFile(zip_path, "r") as zip_file:
with zip_file.open("factures.json") as f:
factures = json.load(f)
# Vérification de la chaîne
previous_sig = None
all_ok = True
for facture in factures:
fiscal_hash = compute_fiscal_hash(facture)
data_to_verify = fiscal_hash
if previous_sig:
data_to_verify += previous_sig
try:
verify_key.verify(bytes.fromhex(facture["signature"]), data_to_verify.encode())
print(f"✅ Facture {facture['numero']} OK")
except:
print(f"❌ Facture {facture['numero']} INVALIDE")
all_ok = False
previous_sig = facture["signature"]
if all_ok:
print("✅ La chaîne de factures est intacte")
else:
print("❌ La chaîne de factures est compromise")
return all_ok
# Exemple d'utilisation
if __name__ == "__main__":
verify_archive_and_chain("factures_archive.zip", "factures_archive.zip.sig", "verify_key.hex")
Interprétation des résultats
- ✅ Facture OK : intégrité de la facture et chainage valide.
- ❌ Facture INVALIDE : la facture a été modifiée ou la signature ne correspond pas.
- ✅ La chaîne de factures est intacte : toutes les factures sont conformes et la blockchain interne n’a pas été altérée.
- ❌ La chaîne de factures est compromise : au moins une facture a été modifiée, ce qui invalide toute la suite.
Notes importantes
L’éditeur fournit une archive contenant une chaîne de factures intègre. Cette chaîne est vérifiée automatiquement lors de la génération de l’archive.
Si, lors de votre propre vérification, la chaîne apparaît comme compromise, cela signifie que le fichier factures.json a été modifié en dehors du logiciel et ne doit pas être utilisé.