diff --git a/python/Bag3.py b/python/Bag3.py index ac9c2ce..96114cd 100644 --- a/python/Bag3.py +++ b/python/Bag3.py @@ -213,15 +213,12 @@ def generate_zpl_dataflex( lot_no: Optional[str] = None, font_regular: str = "E:STXihei.ttf", font_bold: str = "E:STXihei.ttf", - reset_counter_first: bool = False, ) -> str: """ Row 1 (from zero): QR code, then item name (rotated 90°). Row 2: Batch/lot (left), item code (right). Label and QR use lotNo from API when present, else batch_no (Bxxxxx). - - When reset_counter_first is True, Zebra counter reset commands (~RO1, ~RO2) are inserted after ^XA - in the *same* label job. Many printers ignore a separate reset-only TCP job. + Job counter reset (~RO) is sent separately via [send_dataflex_job_counter_reset] before labels. """ desc = _zpl_escape((item_name or "—").strip()) code = _zpl_escape((item_code or "—").strip()) @@ -233,9 +230,8 @@ def generate_zpl_dataflex( else: qr_payload = label_line if label_line else batch_no.strip() qr_value = _zpl_escape(qr_payload) - counter_lines = _zpl_dataflex_counter_reset_lines() if reset_counter_first else "" return f"""^XA -{counter_lines}^CI28 +^CI28 ^PW700 ^LL500 ^PO N @@ -250,13 +246,23 @@ def generate_zpl_dataflex( ^XZ""" -def _zpl_dataflex_counter_reset_lines() -> str: +def send_dataflex_job_counter_reset(ip: str, port: int) -> None: """ - Zebra ZPL counter reset (tilde commands), embedded after ^XA on the first label of each job: - ~RO1 = reset counter 1, ~RO2 = reset counter 2. - See Zebra ZPL / printer manual; add ~RO3 etc. if your model exposes more counters. + Reset printer job / label counters when switching to a new job (new row). + + Zebra: ~RO1 / ~RO2 reset counters 1 and 2. Sent as a *standalone* TCP write *before* any ^XA…^XZ + label, because many firmwares ignore ~ commands inside a format block. + + Uses CRLF line endings (common Zebra expectation). Raises on TCP error like [send_zpl_to_dataflex]. """ - return "~RO1\n~RO2\n" + raw = "~RO1\r\n~RO2\r\n".encode("ascii") + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(DATAFLEX_SEND_TIMEOUT) + try: + sock.connect((ip, port)) + sock.sendall(raw) + finally: + sock.close() def generate_zpl_label_small( @@ -563,7 +569,7 @@ def send_image_to_label_printer(printer_name: str, pil_image: "Image.Image") -> def send_zpl_to_dataflex(ip: str, port: int, zpl: str) -> None: - """Send ZPL to DataFlex printer via TCP. Raises on connection/send error.""" + """Send ZPL label (^XA…^XZ) to DataFlex printer via TCP. Raises on connection/send error.""" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(DATAFLEX_SEND_TIMEOUT) try: @@ -1628,16 +1634,6 @@ def main() -> None: item_id=item_id, stock_in_line_id=stock_in_line_id, lot_no=lot_no, - reset_counter_first=False, - ) - zpl_first_job = generate_zpl_dataflex( - b, - item_code, - item_name, - item_id=item_id, - stock_in_line_id=stock_in_line_id, - lot_no=lot_no, - reset_counter_first=True, ) label_text = (lot_no or b).strip() if continuous: @@ -1648,9 +1644,9 @@ def main() -> None: printed = 0 error_shown = False try: + send_dataflex_job_counter_reset(ip, port) while not stop_ev.is_set(): - payload = zpl_first_job if printed == 0 else zpl - send_zpl_to_dataflex(ip, port, payload) + send_zpl_to_dataflex(ip, port, zpl) printed += 1 _sleep_interruptible(stop_ev, 2.0) except ConnectionRefusedError: @@ -1718,12 +1714,9 @@ def main() -> None: threading.Thread(target=dflex_worker, daemon=True).start() else: try: + send_dataflex_job_counter_reset(ip, port) for i in range(n): - send_zpl_to_dataflex( - ip, - port, - zpl_first_job if i == 0 else zpl, - ) + send_zpl_to_dataflex(ip, port, zpl) if i < n - 1: time.sleep(2) set_status_message(f"已送出列印:批次 {label_text} x {n} 張", is_error=False)