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 encodée 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

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

 # (c) depot-vente.fvdw.fr - mars 2026
#
# Script pour consommer la file d'attente des documents PDF pour impression
#
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 getRemote(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': f"Erreur Timeout 10s" }
    except Exception as e:
        return {'success' : False, 'message': f"Une erreur inattendue est survenue : {e}"}
    finally:
        # print(f"Requête réussie. Code HTTP : {response.getcode()}")
        # print(content[:100])  # Affiche les 100 premiers caractères
        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 après impression
        os.unlink(pdf_path)
        return True

# -------------------------------------------------------------------------------------
def ping(url):
    ret = getRemote(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 côté serveur (file d'attente)
    """
    ret = getRemote(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 = getRemote(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'+'Z' pour arrêter")

    while True:
        ret = next_document(g_next_url)
        if ret["success"]:
            if ret["pdf_data"]:
                # document à 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 imprimé")
                    # supression cote serveur
                    r = del_document(g_del_url + ret["spool_slug"])
                    if not r["success"]:
                        print("Echec mise à jour du serveur")
                    else:
                        print("Serveur mis à jour")
            else:
                print("Pas de document en attente ... pause (30 sec)")
                # ATTENTION : ne pas utiliser une valeur inférieure à 30 (secondes) sans quoi les
                # performances globales seront diminuées
                time.sleep(30)
        else:
            print("Erreur : %s" % (ret["message"]))


# -------------------------------------------------------------------------------------
# -------------------------------------------------------------------------------------
if __name__ == "__main__":

    ## ICI : les variables a ajuster selon votre configuration
    ## Vous trouverez les url depuis le menu "administration" -> "paramètres de l'application".
    ## Si vous avez activé "Utiliser la file d'impression des documents PDF" = Oui, les url seront affichées
    ## en dessous des paramètres
    g_ping_url = "https:/depot-vente.fvdw.fr/SPL-PING-6B024676"
    g_next_url = "https:/depot-vente.fvdw.fr/SPL-NEXT-6B024676"
    g_del_url  = "https:/depot-vente.fvdw.fr/SPL-DEL-"
    g_sumatra_path = r"C:\Program Files\SumatraPDF\SumatraPDF.exe"
    ## FIN des variables

    main()
Téléchargez le script spool_client.py
Schémas : https://excalidraw.com/ | Captures d'écrans : https://getgreenshot.org/