Installation et configuration de la file d'impression
Le principe de fonctionnement de la file d'attente
Lorsque l'application génère un document PDF, ce dernier est "envoyé" dans une file d'attente.
Un poste de travail dédié doit être configuré pour traiter cette file d'attente (située sur le serveur depot-vente.fvdw.fr).
Ce poste (Poste 3 sur le schéma) utilise les API (service impression) pour extraire les
documents PDF à imprimer sur son imprimante.

Pour imprimer physiquement les documents, il faut utiliser un programme qui va consulter la file d'attente à interval réguliers. Si la file contient au moins un document, le programme "télécharge" le document et l'envoie à imprimante. Quand l'impression est terminée, le programme "retire" le document de la fille d'attente. Le programme se met "en attente du prochain document".
Aucune intervention humaine n'est nécessaire.
Mise en oeuvre sur un poste "Windows"
Nous vous proposons un programme de traitement de la file d'attente écrit en Python fonctionnant sous Windows.Le script (qui tient sur un seul fichier) interroge le serveur via les API, et utilise le programme Sumatra PDF pour imprimer le fichier PDF vers l'imprimante par défaut.
Installation du programme de traitement de la file d'attente :
- Créez un dossier de travail par exemple C:\file_depot_vente.
- Téléchargez et copiez le script spool_client.py dans le dossier (C:\file_depot_vente).
- Le script étant écrit en Python, l'installation de l'interpréteur Python est nécessaire pour l'exécuter.
Si python n'est pas présent sur le PC, téléchargez Python et installez-le sur votre poste. - Installez le lecteur de documents PDF :
Pour permettre l'envoi des documents PDF vers une imprimante, vous avez besoin d'un lecteur "PDF" : Sumatra PDF . Ce programme est gratuit, léger et peut même être installé en version portable (dézippez l'archive là où vous le désirez). - Créez un fichier de type
.cmd(par exemplefile_attente.cmd) qui lancera python.exe avec le scriptspool_client.pyen paramètre ainsi que les paramètres de votre configuration et application.
Exemple :@echo off echo traitement de la file d'attente... python spool_client.py 6B024676 pause
Dans cet exemple, ce fichier lance le traitement de la file d'attente pour l'application "Demo" (code application6B024676) et considère que vous avez installé Sumatra PDF dans le dossier courant.
NB : Si vous avez installé Sumatra PDF en mode standard, spécifiez le chemin complet du fichier SumatraPDF.exe, par exemple :python spool_client.py 6B024676 "C:\Program Files\SumatraPDF\SumatraPDF.exe"
- Pour obtenir votre code application, depuis l'application, à la page "Administration", cliquez sur "Paramètres de l'application". La page "Paramétrage de l'application" affiche votre code application.
Votre dossier C:\file_depot_vente devrait ressembler à ceci :

Pour lancer le traitement de la file d'attente, double cliquez sur
file_attente.cmd, une fenêtre de type "cmd" s'ouvre et affiche le traitement en cours.

Les API
L'applicationdepot-vente.fvdw.fr présente une API pour consommer les données de la file d'impression.
Les requêtes s'effectuent en GET et sont disponibles aux adresses suivantes
- https://depot-vente.fvdw.fr/SPL-PING-
code organisation - https://depot-vente.fvdw.fr/SPL-NEXT-
code organisation - https://depot-vente.fvdw.fr/SPL-GET-
numéro de document - https://depot-vente.fvdw.fr/SPL-DEL-
numéro de document
PING
Permet de tester la connexion au serveur et valider le code organisation.Cet appel retourne un flux JSON.
> curl https:/depot-vente.fvdw.fr/SPL-PING-6B024676
{'error':false,'message':'OK Démo'}
Valeurs de retour
| Clé | Type | Valeur |
|---|---|---|
| error | boolean | true|false |
| message | string | OK ou la cause de l'erreur |
NEXT
Interroge le serveur : si il existe : donne le prochain document à imprimer.Si il existe au moins un document est dans la file
> curl https:/depot-vente.fvdw.fr/SPL-NEXT-6B024676
{'pdf_b64':'JVBERi … U9GCg==','spool_slug':'285481266561','crc':2025417623,'error':false}
Si la file d'attente est vide
> curl https:/depot-vente.fvdw.fr/SPL-NEXT-6B024676
{'pdf_b64':'','spool_slug':'','crc':false,'error':false,'message':"Aucun document PDF dans la file d'attente"}
Valeurs de retour
| Clé | Type | Valeur |
|---|---|---|
| pdf_b64 | string | s'il existe : une chaine encodée en base 64 ou vide s'il n'existe pas |
| spool_slug | string | s'il existe : une série de chiffres, identifiant unique du document ou vide s'il n'existe pas |
| crc | string | s'il existe : une série de chiffres, résultat du CRC32 du pdf (non encodé) ou False s'il n'existe pas |
| error | boolean | true|false |
| message | string | Cette clé existe uniquement si une erreur se produit la cause de l'erreur |
GET
Demande un document de la file d'attente.On spécifie l'identifiant du document dans l'url
SPL-GET-xxx où xxx est le numéro
retourné lors de l'appel de SPL-NEXT, sous la clé "spool_slug". Sur base de l'exemple ci-dessus : l'url devient SPL-GET-285481266561
Le document est dans la file d'attente.
> curl https:/depot-vente.fvdw.fr/SPL-GET-285481266561
{'pdf_b64':"JVBERi0 … RU9GCg==','spool_slug':'285481266561','crc':2025417623,'error":false}
Le document n'est pas dans la file d'attente.
> curl https:/depot-vente.fvdw.fr/SPL-GET-285481266000
{'error':true,'message':'Aucun document PDF avec le code #285481266560'}
Valeurs de retour
| Clé | Type | Valeur |
|---|---|---|
| pdf_b64 | string | s'il existe : une chaine encodée en base 64 |
| spool_slug | string | s'il existe : une série de chiffres, identifiant unique du document ou vide s'il n'existe pas |
| crc | string | s'il existe : une série de chiffres, résultat du CRC32 du pdf (non encodé) ou False s'il n'existe pas |
| error | boolean | true|false |
| message | string | Cette clé existe uniquement si une erreur se produit la cause de l'erreur |
DEL
Demande l'effacement d'un document de la file d'attente.On spécifie l'identifiant du document dans l'url
SPL-GET-xxx où xxx est le numéro
retourné lors de l'appel de SPL-NEXT, sous la clé 'spool_slug'. Sur base de l'exemple ci-dessus : l'url devient
SPL-DEL-285481266561
Le document est dans la file d'attente.
> curl https:/depot-vente.fvdw.fr/SPL-DEL-285481266561
{'error':false,'message':"Document #285481266561 effac\u00e9 de la file d'attente"}
Le document n'est pas dans la file d'attente.
> curl https:/depot-vente.fvdw.fr/SPL-DEL-285481266000
{'error':false,'message':"Aucun document PDF \u00e0 effacer de la file d'attente"}
Valeurs de retour
| Clé | Type | Valeur |
|---|---|---|
| error | boolean | true|false |
| message | string | message de confirmation ou la cause de l'erreur |
Le client
Le fonctionnement préconisé est une boucle sur la méthode
SPL-NEXT-… qui attend les documents de la file d'impression.
Si des documents sont disponibles, on transforme les données reçues encodées en base 64 pour obtenir un fichier PDF que l'on passe à
un programme chargé d'imprimer ce document.Quand le document est traité, il faut demander au serveur d'effacer ce document de la file d'attente

Script python
# (c) depot-vente.fvdw.fr - octobre 2026
#
# Script pour consommer la file d'attente des documents PDF pour impression
# Version pour Windows, utilisant SumatraPDF qui imprime sur l'imprimante par défaut
#
import sys
import base64
import time
import tempfile
import os
import subprocess
import json
import binascii
from urllib.request import urlopen
from urllib.error import URLError, HTTPError
# -------------------------------------------------------------------------------------
def get_remote(url):
try:
with urlopen(url, timeout=10) as response:
resp_data = json.loads(response.read())
except HTTPError as e:
return {'success' : False, 'message': f"Erreur HTTP : {e.code} - {e.reason}" }
except URLError as e:
return {'success' : False, 'message': f"Erreur URL : {e.reason}" }
except TimeoutError:
return {'success' : False, 'message': "Erreur Timeout 10s" }
except Exception as e:
return {'success' : False, 'message': f"Une erreur inattendue est survenue : {e}"}
finally:
# print(f"Requête reussie. Code HTTP : {response.getcode()}")
# print(content[:100]) # Affiche les 100 premiers caracteres
resp_data["success"] = True
return resp_data
# -------------------------------------------------------------------------------------
def print_pdf(pdf_data, sumatra_path):
# Enregistre le PDF dans un fichier temporaire
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as f:
f.write(pdf_data)
pdf_path = f.name
# Imprime le PDF via SumatraPDF
try:
subprocess.run([sumatra_path, "-print-to-default", pdf_path], check=True)
except Exception as e:
print( f"Impression via Sumatra : Une erreur inattendue est survenue : {e}")
return False
finally:
# Supprime le fichier local temporaire apres impression
os.unlink(pdf_path)
return True
# -------------------------------------------------------------------------------------
def ping(url):
ret = get_remote(url)
ret["action"] = "ping"
if not ret["success"]:
ret["error"] = True
else :
if ret["error"]:
ret["success"] = False
return ret
# -------------------------------------------------------------------------------------
def del_document(url):
"""
Demande de supression du document cote serveur (file d'attente)
"""
ret = get_remote(url)
ret["action"] = "del"
if not ret["success"]:
print("Erreur " + ret["message"])
return ret
# -------------------------------------------------------------------------------------
def next_document(url):
"""
Interroge la file d'attente : si au moins un document en attente retourne
le binaire du 1er document de la file
"""
content = get_remote(url)
content["action"] = "next"
if not content['success']:
# Erreur
content["pdf_data"] = False
return content
if not content['pdf_b64']:
# Pas de fichier en attente
content["pdf_data"] = False
return content
# ctrl CRC
pdf_data = base64.b64decode(content['pdf_b64'])
crc = binascii.crc32(pdf_data)
if crc != content["crc"] :
content["success"] = False
content["message"] = "Le flux reçu est corrompu !"
content["pdf_b64"] = "/"
content["pdf_data"] = False
return content
content["pdf_b64"] = "/"
content["pdf_data"] = pdf_data # data binaires
## print("Ctrl : local crc = %d - remote crc = %d " % (crc, content["crc"]) )
return content
# -------------------------------------------------------------------------------------
def main():
"""
Boucle sur les douments de la file d'attente
"""
ret = ping(g_ping_url)
if not ret["success"]:
print("Echec de connexion au serveur : " + ret["message"])
return
print("Appuyez sur 'Ctrl'+'C' pour arrêter")
while True:
ret = next_document(g_next_url)
if ret["success"]:
if ret["pdf_data"]:
# document a traiter
print("Impression du document #%s..." % (ret["spool_slug"]))
if not print_pdf(ret["pdf_data"], g_sumatra_path):
print("Echec impression")
else:
print("Document imprime")
# supression cote serveur
r = del_document(g_del_url + ret["spool_slug"])
if not r["success"]:
print("Echec mise a jour du serveur")
else:
print("Serveur mis a jour")
else:
try:
print("Pas de document en attente ... pause (30 sec)")
# ATTENTION : ne pas utiliser une valeur inferieure a 30 (secondes) sans quoi les
# performances globales seront diminuees
time.sleep(30)
except KeyboardInterrupt:
print("Interruption utilisateur, fin du traitement de la file d'attente.")
return
else:
print("Erreur : %s" % (ret["message"]))
break
# -------------------------------------------------------------------------------------
# Point d'entree
# -------------------------------------------------------------------------------------
if __name__ == "__main__":
arg_info = """
1 : chaine de caractères sur 8 positions = Identifant application. Vous trouverez ce code dans la partie "Administration" - "Paramètres de l'application"
2 : path pour le programme SumatraPDF. Facultatif, par défaut "SumatraPDF.exe"
3 : url de dépôt/vente. Facultatif, par défaut : "https://depot-vente.fvdw.fr"
"""
if len(sys.argv) < 2:
print("Spécifiez dans la ligne de commande les informations suivantes :"+arg_info+"\nPar exemple " + sys.argv[0] + " 22AB22CD22 SumatraPDF.exe")
sys.exit(1)
id_app = sys.argv[1]
url = "https://depot-vente.fvdw.fr"
g_sumatra_path = r"SumatraPDF.exe"
if len(sys.argv) > 2 :
g_sumatra_path = sys.argv[2]
# ctrl path Sumatra
if not os.path.isfile(g_sumatra_path) or not os.access(g_sumatra_path, os.X_OK):
print("Le paramètre 2 : path pour l'executable SumatraPDF est invalide ('"+g_sumatra_path+"').\nLes paramètres attendus sont :"+arg_info)
sys.exit(1)
if len(sys.argv) > 3:
url = sys.argv[3]
g_ping_url = url+"/SPL-PING-"+id_app
g_next_url = url+"/SPL-NEXT-"+id_app
g_del_url = url+"/SPL-DEL-"
main()
# EoF
Téléchargez le script spool_client.py