Dépôt / Vente

Installation et configuration de la file d'impression

API
Le client
Le script python
Retour

Les API

L'application depot-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
Toutes ces méthodes retournent un flux JSON. Les URL de ces API sont accessibles depuis la page administration -> Paramétrage de l'évènement.

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éTypeValeur
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éTypeValeur
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éTypeValeur
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 client (installé sur le Poste 3) doit utiliser les API (service impression) pour obtenir les documents PDF à imprimer issus de la file d'attente (sur le serveur depot-vente.fvdw.fr).
impression avec file
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
Boucle sur file des document a imprimer

Exemple de client d'impression sous windows

Pour cet exemple, vous aurez besoin de python et de Sumatra PDF.
Un script (qui tient sur un seul fichier) écrit en python interroge le serveur via les API, et utilise le programme Sumatra PDF pour imprimer le fichier PDF sur l'imprimante par défaut.
Le choix de Sumatra PDF se justifie par le fait que 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).

Script python

1    # (c) depot-vente.fvdw.fr - mars 2026
2    #
3    # Script pour consommer la file d'attente des documents PDF pour impression
4    #
5    import base64
6    import time
7    import tempfile
8    import os
9    import subprocess
10   import json
11   import binascii
12   from urllib.request import urlopen
13   from urllib.error import URLError, HTTPError
14   
15   # -------------------------------------------------------------------------------------
16   def getRemote(url):
17       try:
18           with urlopen(url, timeout=10) as response:
19               resp_data = json.loads(response.read())
20       except HTTPError as e:
21           return {'success' : False, 'message': f"Erreur HTTP : {e.code} - {e.reason}" }
22       except URLError as e:
23           return {'success' : False, 'message': f"Erreur URL : {e.reason}" }
24       except TimeoutError:
25           return {'success' : False, 'message': "Erreur Timeout 10s" }
26       except Exception as e:
27           return {'success' : False, 'message': f"Une erreur inattendue est survenue : {e}"}
28       finally:
29           # print(f"Requête reussie. Code HTTP : {response.getcode()}")
30           # print(content[:100])  # Affiche les 100 premiers caracteres
31           resp_data["success"] = True
32           return resp_data
33   
34   # -------------------------------------------------------------------------------------
35   def print_pdf(pdf_data, sumatra_path):
36       # Enregistre le PDF dans un fichier temporaire
37       with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as f:
38           f.write(pdf_data)
39           pdf_path = f.name
40   
41       # Imprime le PDF via SumatraPDF
42       try:
43           subprocess.run([sumatra_path, "-print-to-default", pdf_path], check=True)
44       except Exception as e:
45           print( f"Impression via Sumatra : Une erreur inattendue est survenue : {e}")
46           return False
47       finally:
48           # Supprime le fichier local temporaire apres impression
49           os.unlink(pdf_path)
50           return True
51   
52   # -------------------------------------------------------------------------------------
53   def ping(url):
54       ret = getRemote(url)
55   
56       ret["action"] = "ping"
57       if not ret["success"]:
58           ret["error"]  = True
59       else :
60           if ret["error"]:
61               ret["success"] = False
62       return ret
63   
64   # -------------------------------------------------------------------------------------
65   def del_document(url):
66       """
67       Demande de supression du document cote serveur (file d'attente)
68       """
69       ret = getRemote(url)
70       ret["action"] = "del"
71       if not ret["success"]:
72           print("Erreur " + ret["message"])
73       return ret
74   
75   # -------------------------------------------------------------------------------------
76   def next_document(url):
77       """
78       Interroge la file d'attente : si au moins un document en attente retourne
79       le binaire du 1er document de la file
80       """
81       content = getRemote(url)
82       content["action"] = "next"
83       if not content['success']:
84           # Erreur
85           content["pdf_data"] = False
86           return content
87   
88       if not content['pdf_b64']:
89           # Pas de fichier en attente
90           content["pdf_data"] = False
91           return content
92           
93       # ctrl CRC
94       pdf_data = base64.b64decode(content['pdf_b64'])
95       crc = binascii.crc32(pdf_data)
96       if crc != content["crc"] :
97           content["success"] = False
98           content["message"] = "Le flux reçu est corrompu !"
99           content["pdf_b64"] = "/"
100          content["pdf_data"] = False
101          return content
102      content["pdf_b64"] = "/"
103      content["pdf_data"] = pdf_data # data binaires
104  
105      ## print("Ctrl : local crc = %d - remote crc = %d "  % (crc, content["crc"]) )
106      return content
107  
108  # -------------------------------------------------------------------------------------
109  def main():
110      """
111      Boucle sur les douments de la file d'attente
112      """
113      ret = ping(g_ping_url)
114      if not ret["success"]:
115          print("Echec de connexion au serveur : " + ret["message"])
116          return
117  
118      print("Appuyez sur 'Ctrl'+'Z' pour arrêter")
119  
120      while True:
121          ret = next_document(g_next_url)
122          if ret["success"]:
123              if ret["pdf_data"]:
124                  # document a traiter
125                  print("Impression du document #%s..." % (ret["spool_slug"]))
126                  if not print_pdf(ret["pdf_data"], g_sumatra_path):
127                      print("Echec impression")
128                  else:
129                      print("Document imprime")
130                      # supression cote serveur
131                      r = del_document(g_del_url + ret["spool_slug"])
132                      if not r["success"]:
133                          print("Echec mise a jour du serveur")
134                      else:
135                          print("Serveur mis a jour")
136              else:
137                  print("Pas de document en attente ... pause (30 sec)")
138                  # ATTENTION : ne pas utiliser une valeur inferieure a 30 (secondes) sans quoi les
139                  # performances globales seront diminuees
140                  time.sleep(30)
141          else:
142              print("Erreur : %s" % (ret["message"]))
143              break
144  
145  
146  # -------------------------------------------------------------------------------------
147  #
148  # -------------------------------------------------------------------------------------
149  if __name__ == "__main__":
150  
151      # ICI : les variables a ajuster selon votre configuration
152      # Vous trouverez les url depuis le menu "administration" -> "parametres de l'application".
153      # Si vous avez active "Utiliser la file d'impression des documents PDF" = Oui, les url seront affichees
154      # en dessous des parametres
155      g_ping_url = "https://depot-vente.fvdw.fr/SPL-PING-6B024676"
156      g_next_url = "https://depot-vente.fvdw.fr/SPL-NEXT-6B024676"
157      g_del_url  = "https://depot-vente.fvdw.fr/SPL-DEL-"
158      g_sumatra_path = r"C:\Program Files\SumatraPDF\SumatraPDF.exe"
159      # FIN des variables
160  
161      main()
162  
Téléchargez le script spool_client.py


Schémas : https://excalidraw.com/ | Captures d'écrans : https://getgreenshot.org/