From 9a2e21796e98334a825e76ce7ee511ad47e6f7dd Mon Sep 17 00:00:00 2001 From: Quality App System Date: Fri, 26 Dec 2025 22:28:29 +0200 Subject: [PATCH] Implement professional PDF-based label printing for boxes and locations - Replace ZPL/image-based printing with ReportLab PDF generation - Box labels: 8cm x 5cm landscape with 'BOX Nr:' header and CODE128 barcode - Location labels: 8cm x 5cm landscape with 'Location nr:' header and CODE128 barcode - Add /generate_box_label_pdf endpoint using same approach as print_module - Update FG scan quick box creation to use PDF printing with default printer - Switch from CDN QZ Tray to local patched version for pairing-key auth - Improve error handling and logging throughout printing workflow - Fix import issues (add mm unit to warehouse.py) - Optimize barcode size and spacing for better readability --- py_app/app/routes.py | 127 +++++++++++++++++++++ py_app/app/templates/create_locations.html | 10 +- py_app/app/templates/fg_scan.html | 75 +++++++++--- py_app/app/templates/manage_boxes.html | 116 ++++++++++++++++--- py_app/app/warehouse.py | 110 +++++++++++++----- 5 files changed, 375 insertions(+), 63 deletions(-) diff --git a/py_app/app/routes.py b/py_app/app/routes.py index 15ca5f5..04c4ff7 100644 --- a/py_app/app/routes.py +++ b/py_app/app/routes.py @@ -3710,6 +3710,133 @@ def generate_labels_pdf(order_id, paper_saving_mode='true'): return jsonify({'error': str(e)}), 500 +@bp.route('/generate_box_label_pdf', methods=['POST']) +def generate_box_label_pdf(): + """Generate a PDF box label with barcode for printing via QZ Tray""" + + if 'role' not in session: + return jsonify({'error': 'Access denied. Please log in.'}), 403 + + try: + from io import BytesIO + from reportlab.lib.pagesizes import letter + from reportlab.pdfgen import canvas + from reportlab.lib import colors + from reportlab.lib.units import mm + from reportlab.graphics.barcode import code128 + from flask import make_response + + # Get box number from request + box_number = request.form.get('box_number', 'Unknown') + + print(f"DEBUG: Generating box label PDF for box: {box_number}") + + # Create PDF buffer + pdf_buffer = BytesIO() + + # Create canvas with 8cm x 5cm size in landscape orientation + page_width = 80 * mm # 8 cm + page_height = 50 * mm # 5 cm + c = canvas.Canvas(pdf_buffer, pagesize=(page_width, page_height)) + + # Optimize for label printer + c.setPageCompression(1) + c.setCreator("Trasabilitate Box Label System") + c.setTitle("Box Label - Optimized for Label Printers") + + # Define margins and usable area + margin = 2 * mm + usable_width = page_width - (2 * margin) + usable_height = page_height - (2 * margin) + + # Calculate vertical layout + # Top section: "BOX Nr: XXXXXXXX" text + # Bottom section: Barcode + text_height = 12 * mm # Space for text at top (reduced from 15mm) + barcode_height = usable_height - text_height - (1 * mm) # Rest for barcode with minimal spacing (reduced from 3mm) + + # === TOP SECTION: BOX Nr Label === + # Position from top of usable area + text_y = page_height - margin - text_height + + # Draw "BOX Nr:" label + c.setFont("Helvetica-Bold", 14) + label_text = "BOX Nr:" + label_width = c.stringWidth(label_text, "Helvetica-Bold", 14) + + # Draw box number + c.setFont("Helvetica-Bold", 18) + number_text = box_number + number_width = c.stringWidth(number_text, "Helvetica-Bold", 18) + + # Calculate total width and center everything + total_text_width = label_width + 3*mm + number_width # 3mm spacing between label and number + start_x = margin + (usable_width - total_text_width) / 2 + + # Draw label text + c.setFont("Helvetica-Bold", 14) + c.drawString(start_x, text_y + 5*mm, label_text) + + # Draw box number + c.setFont("Helvetica-Bold", 18) + c.drawString(start_x + label_width + 3*mm, text_y + 5*mm, number_text) + + # === BOTTOM SECTION: Barcode === + barcode_y = margin + + try: + # Create barcode for box number + barcode = code128.Code128( + box_number, + barWidth=0.4*mm, # Thicker bars for better scanning + barHeight=barcode_height, + humanReadable=True, + fontSize=10 + ) + + # Calculate scaling to fit width + scale_factor = usable_width / barcode.width + + # Center the barcode horizontally + barcode_x = margin + (usable_width - (barcode.width * scale_factor)) / 2 + + # Draw the barcode + c.saveState() + c.translate(barcode_x, barcode_y) + c.scale(scale_factor, 1) + barcode.drawOn(c, 0, 0) + c.restoreState() + + print(f"DEBUG: Barcode generated successfully with scale factor: {scale_factor}") + + except Exception as e: + print(f"DEBUG: Error generating barcode: {e}") + # Fallback: draw text if barcode fails + c.setFont("Helvetica-Bold", 12) + text_width = c.stringWidth(box_number, "Helvetica-Bold", 12) + c.drawString((page_width - text_width) / 2, barcode_y + barcode_height/2, box_number) + + c.save() + + # Get PDF data + pdf_buffer.seek(0) + pdf_data = pdf_buffer.getvalue() + + # Create response + response = make_response(pdf_data) + response.headers['Content-Type'] = 'application/pdf' + response.headers['Content-Disposition'] = f'inline; filename="box_label_{box_number}.pdf"' + + print(f"DEBUG: Box label PDF generated successfully") + return response + + except Exception as e: + print(f"DEBUG: Error generating box label PDF: {e}") + import traceback + traceback.print_exc() + return jsonify({'error': str(e)}), 500 + + @bp.route('/generate_label_pdf', methods=['POST']) def generate_label_pdf(): """Generate a single label PDF for thermal printing via QZ Tray""" diff --git a/py_app/app/templates/create_locations.html b/py_app/app/templates/create_locations.html index 9e23c72..c02bf98 100644 --- a/py_app/app/templates/create_locations.html +++ b/py_app/app/templates/create_locations.html @@ -510,11 +510,13 @@ async function printLocationBarcode() { printStatus.textContent = 'Sending to printer...'; - // Configure QZ Tray for PDF printing with 4x8cm size + // Configure QZ Tray for PDF printing with 8x5cm size in landscape const config = qzTray.configs.create(selectedPrinter, { - size: { width: 4, height: 8, units: 'cm' }, - margins: { top: 0, right: 0, bottom: 0, left: 0 }, - orientation: 'portrait' + scaleContent: false, + rasterize: false, + size: { width: 80, height: 50 }, + units: 'mm', + margins: { top: 0, right: 0, bottom: 0, left: 0 } }); const data = [{ diff --git a/py_app/app/templates/fg_scan.html b/py_app/app/templates/fg_scan.html index a66fb47..7255b7e 100644 --- a/py_app/app/templates/fg_scan.html +++ b/py_app/app/templates/fg_scan.html @@ -3,8 +3,8 @@ {% block title %}Finish Good Scan{% endblock %} {% block head %} - - + +