Exemple complet — une vente de bout en bout
Cet exemple exécute une vente complète à l’aide des utilitaires de cadrage de Format des trames. Chaque implémentation construit ses chaînes DATA en échappant les valeurs, envoie la commande, et vérifie result avant de passer à la suivante. Les trois langages produisent exactement la même séquence de commandes et les mêmes chaînes DATA — seule l’API série diffère.
Chaque onglet réutilise les utilitaires de framing de Format des trames : le module Python datamega.py (send_command, escape), la classe C# TccProtocol (SendCommand, Escape) ou la classe Java TccProtocol (sendCommand, escape). Copiez d’abord ces utilitaires dans votre projet.
Python (pyserial)
import serial
from datamega import send_command, escape
def field(*values):
"""Join values into a DATA string, escaping each value (field commas stay literal)."""
return ",".join(escape(str(v)) for v in values)
def step(port, cmd, data=""):
reply = send_command(port, cmd, data)
if not reply.startswith("1"):
raise RuntimeError(f"cmd {cmd:#x} failed: {reply}")
return reply
port = serial.Serial("COM3", 115200, timeout=3) # your device's port + settings
# 0) Confirm the device and capture verify_url for the QR.
status = send_command(port, 0xC1)
verify_url = status[2:].split(",")[-1]
# 1) Start a sales invoice.
step(port, 0xC0, "salesInvoice")
# 2) Customer (individual, not taxable). Escape any commas in text values (field() does it).
step(port, 0xC3, field("individual", "John Doe", "", "", "123 Main St, New York", "", "", "0"))
# 3) One item: apple, product, unit price 99.99, qty 1, 5 fixed discount, Tax T.
item = step(port, 0x31, field("apple", "", "product", "99.99", "1", "5", "fixed", "T"))
print("item totals (subtotal,net,tax,total):", item.split(",", 1)[1])
# 4) Subtotal: no global discount.
totals = step(port, 0x33, field("0", "fixed"))
print("invoice totals:", totals.split(",", 1)[1])
# 5) Payment: cash.
step(port, 0x35, "cash")
# 6) End invoice -> receipt number + QR data.
end = send_command(port, 0x38) # e.g. 1,1,?sign=...^amphmac=...
result, receipt_no, qrcode = end.split(",", 2)
qr_content = (verify_url + qrcode).replace("^amp;", "&").replace("^amp", "&") # resolve & (see "Building the QR Code")
print("receipt:", receipt_no)
print("QR content:", qr_content)
port.close()Ce que fait l’exemple, étape par étape
C1hconfirme que le dispositif est en ligne et capture laverify_url(nécessaire pour le QR).C0hdémarre une facture de vente (salesInvoice).C3henregistre le client (les virgules dans l’adresse sont échappées parfield()/Field()). Cet exemple envoierecipient_typesous forme texte (individual) ; certains dispositifs attendent la forme numérique (1= individual,2= company) — voir la noterecipient_typedans la Référence des commandes.31hajoute une ligne article et renvoie ses totaux.33happlique la remise globale (ici aucune) et renvoie les totaux de la facture.35henregistre le paiement (cash).38hclôture la facture et renvoiereceipt_NO+qrcode, à partir desquels on construit le contenu du QR (verify_url+qrcodedéséchappé).
Pour un avoir (note de crédit) plutôt qu’une vente, remplacez les étapes 2–4 par la relecture de la facture d’origine (C4h → 41h en boucle → 43h), puis poursuivez avec 35h et 38h. Voir Transaction de facturation.
Deux points pour la relecture d’avoir : les réponses C4h/41h peuvent contenir une adresse avec une virgule échappée, donc découpez puis déséchappez chaque champ (split_fields / Fields / fields, jamais l’inverse) ; et la boucle 41h se termine par result = 2 (« plus d’items »), que le raccourci step() — qui exige result = 1 — ne gère pas : traitez 41h avec sa propre condition d’arrêt.
Étape suivante → FAQ