uploadte to corect preview and print the labels for 1 row

This commit is contained in:
2025-09-20 17:31:20 +03:00
parent beeaa02c35
commit 2c01db9fea
6 changed files with 865 additions and 120 deletions

357
py_app/app/pdf_generator.py Normal file
View File

@@ -0,0 +1,357 @@
"""
PDF Label Generator for Print Module
Generates 80x110mm labels with sequential numbering based on quantity
"""
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.units import mm
from reportlab.lib import colors
from reportlab.pdfgen import canvas
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.graphics.barcode import code128
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing
import os
from flask import current_app
import io
def mm_to_points(mm_value):
"""Convert millimeters to points (ReportLab uses points)"""
return mm_value * mm
class LabelPDFGenerator:
def __init__(self):
# Label dimensions: 80mm x 110mm
self.label_width = mm_to_points(80)
self.label_height = mm_to_points(110)
# Match the HTML preview dimensions exactly
# Preview: 227.4px width x 321.3px height
# Convert to proportional dimensions for 80x110mm
self.content_width = mm_to_points(60) # ~227px scaled to 80mm
self.content_height = mm_to_points(85) # ~321px scaled to 110mm
# Position content in label, leaving space for barcodes
self.content_x = mm_to_points(3) # 3mm from left edge
self.content_y = mm_to_points(15) # 15mm from bottom (space for bottom barcode)
# Row dimensions (9 rows total, row 6 is double height)
self.row_height = self.content_height / 10 # 8.5mm per standard row
self.double_row_height = self.row_height * 2
# Column split at 40% (90.96px / 227.4px = 40%)
self.left_column_width = self.content_width * 0.4
self.right_column_width = self.content_width * 0.6
# Vertical divider starts from row 3
self.vertical_divider_start_y = self.content_y + self.content_height - (2 * self.row_height)
def generate_labels_pdf(self, order_data, quantity):
"""
Generate PDF with multiple labels based on quantity
Creates sequential labels: CP00000711-001 to CP00000711-XXX
"""
buffer = io.BytesIO()
# Create canvas with label dimensions
c = canvas.Canvas(buffer, pagesize=(self.label_width, self.label_height))
# Extract base production order number for sequential numbering
prod_order = order_data.get('comanda_productie', 'CP00000000')
# Generate labels for each quantity
for i in range(1, quantity + 1):
if i > 1: # Add new page for each label except first
c.showPage()
# Create sequential label number: CP00000711-001, CP00000711-002, etc.
sequential_number = f"{prod_order}-{i:03d}"
# Draw single label
self._draw_label(c, order_data, sequential_number, i, quantity)
c.save()
buffer.seek(0)
return buffer
def _draw_label(self, canvas, order_data, sequential_number, current_num, total_qty):
"""Draw a single label matching the HTML preview layout exactly"""
# Draw main content border (like the HTML preview rectangle)
canvas.setStrokeColor(colors.black)
canvas.setLineWidth(2)
canvas.rect(self.content_x, self.content_y, self.content_width, self.content_height)
# Calculate row positions from top
current_y = self.content_y + self.content_height
# Row 1: Company Header - "INNOFA RROMANIA SRL"
row_y = current_y - self.row_height
canvas.setFont("Helvetica-Bold", 10)
text = "INNOFA RROMANIA SRL"
text_width = canvas.stringWidth(text, "Helvetica-Bold", 10)
x_centered = self.content_x + (self.content_width - text_width) / 2
canvas.drawString(x_centered, row_y + self.row_height/3, text)
current_y = row_y
# Row 2: Customer Name
row_y = current_y - self.row_height
canvas.setFont("Helvetica-Bold", 9)
customer_name = str(order_data.get('customer_name', ''))[:30]
text_width = canvas.stringWidth(customer_name, "Helvetica-Bold", 9)
x_centered = self.content_x + (self.content_width - text_width) / 2
canvas.drawString(x_centered, row_y + self.row_height/3, customer_name)
current_y = row_y
# Draw horizontal lines after rows 1 and 2
canvas.setLineWidth(1)
canvas.line(self.content_x, current_y, self.content_x + self.content_width, current_y)
canvas.line(self.content_x, current_y + self.row_height, self.content_x + self.content_width, current_y + self.row_height)
# Draw vertical divider line (starts from row 3, goes to bottom)
vertical_x = self.content_x + self.left_column_width
canvas.line(vertical_x, current_y, vertical_x, self.content_y)
# Row 3: Quantity ordered
row_y = current_y - self.row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.row_height/3, "Quantity ordered")
canvas.setFont("Helvetica-Bold", 11)
quantity = str(order_data.get('cantitate', '0'))
q_text_width = canvas.stringWidth(quantity, "Helvetica-Bold", 11)
q_x_centered = vertical_x + (self.right_column_width - q_text_width) / 2
canvas.drawString(q_x_centered, row_y + self.row_height/3, quantity)
current_y = row_y
# Row 4: Customer order
row_y = current_y - self.row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.row_height/3, "Customer order")
canvas.setFont("Helvetica-Bold", 10)
customer_order = str(order_data.get('com_achiz_client', 'N/A'))[:15]
co_text_width = canvas.stringWidth(customer_order, "Helvetica-Bold", 10)
co_x_centered = vertical_x + (self.right_column_width - co_text_width) / 2
canvas.drawString(co_x_centered, row_y + self.row_height/3, customer_order)
current_y = row_y
# Row 5: Delivery date
row_y = current_y - self.row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.row_height/3, "Delivery date")
canvas.setFont("Helvetica-Bold", 10)
delivery_date = str(order_data.get('data_livrare', 'N/A'))
if delivery_date != 'N/A' and delivery_date:
try:
# Format date if it's a valid date
from datetime import datetime
if isinstance(delivery_date, str) and len(delivery_date) > 8:
delivery_date = delivery_date[:10] # Take first 10 chars for date
except:
pass
dd_text_width = canvas.stringWidth(delivery_date, "Helvetica-Bold", 10)
dd_x_centered = vertical_x + (self.right_column_width - dd_text_width) / 2
canvas.drawString(dd_x_centered, row_y + self.row_height/3, delivery_date)
current_y = row_y
# Row 6: Description (double height)
row_y = current_y - self.double_row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.double_row_height/2, "Description")
# Handle description text wrapping for double height area
canvas.setFont("Helvetica-Bold", 9)
description = str(order_data.get('descr_com_prod', 'N/A'))
max_chars_per_line = 18
lines = []
words = description.split()
current_line = ""
for word in words:
if len(current_line + word + " ") <= max_chars_per_line:
current_line += word + " "
else:
if current_line:
lines.append(current_line.strip())
current_line = word + " "
if current_line:
lines.append(current_line.strip())
# Draw up to 3 lines in the double height area
line_spacing = self.double_row_height / 4
start_y = row_y + 3 * line_spacing
for i, line in enumerate(lines[:3]):
line_y = start_y - (i * line_spacing)
l_text_width = canvas.stringWidth(line, "Helvetica-Bold", 9)
l_x_centered = vertical_x + (self.right_column_width - l_text_width) / 2
canvas.drawString(l_x_centered, line_y, line)
current_y = row_y
# Row 7: Size
row_y = current_y - self.row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.row_height/3, "Size")
canvas.setFont("Helvetica-Bold", 10)
size = str(order_data.get('dimensiune', 'N/A'))[:12]
s_text_width = canvas.stringWidth(size, "Helvetica-Bold", 10)
s_x_centered = vertical_x + (self.right_column_width - s_text_width) / 2
canvas.drawString(s_x_centered, row_y + self.row_height/3, size)
current_y = row_y
# Row 8: Article Code
row_y = current_y - self.row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.row_height/3, "Article Code")
canvas.setFont("Helvetica-Bold", 10)
article_code = str(order_data.get('cod_articol', 'N/A'))[:12]
ac_text_width = canvas.stringWidth(article_code, "Helvetica-Bold", 10)
ac_x_centered = vertical_x + (self.right_column_width - ac_text_width) / 2
canvas.drawString(ac_x_centered, row_y + self.row_height/3, article_code)
current_y = row_y
# Row 9: Prod Order (but we'll show sequential number instead)
row_y = current_y - self.row_height
canvas.setFont("Helvetica", 8)
canvas.drawString(self.content_x + mm_to_points(2), row_y + self.row_height/3, "Prod Order")
canvas.setFont("Helvetica-Bold", 10)
# Show original production order
prod_order = str(order_data.get('comanda_productie', 'N/A'))
po_text_width = canvas.stringWidth(prod_order, "Helvetica-Bold", 10)
po_x_centered = vertical_x + (self.right_column_width - po_text_width) / 2
canvas.drawString(po_x_centered, row_y + self.row_height/3, prod_order)
# Draw all horizontal lines between rows (from row 3 onwards)
for i in range(6): # 6 lines between 7 rows (3-9)
line_y = self.content_y + self.content_height - (2 + i + 1) * self.row_height
if i == 3: # Account for double height description row
line_y -= self.row_height
canvas.line(self.content_x, line_y, self.content_x + self.content_width, line_y)
# Bottom horizontal barcode - positioned within label bounds
barcode_area_height = mm_to_points(12) # Reserve space for barcode
barcode_y = mm_to_points(5) # 5mm from bottom of label
barcode_width = self.content_width # Use full content width
barcode_x = self.content_x
try:
# Create barcode for sequential number
barcode = code128.Code128(sequential_number,
barWidth=0.25*mm, # Adjust bar width for better fit
barHeight=mm_to_points(10)) # Increase height to 10mm
# Always scale to fit the full allocated width
scale_factor = barcode_width / barcode.width
canvas.saveState()
canvas.translate(barcode_x, barcode_y)
canvas.scale(scale_factor, 1)
barcode.drawOn(canvas, 0, 0)
canvas.restoreState()
# NO TEXT BELOW BARCODE - Remove all text rendering for horizontal barcode
except Exception as e:
# Fallback: Simple barcode pattern that fills the width
canvas.setStrokeColor(colors.black)
canvas.setFillColor(colors.black)
bar_width = barcode_width / 50 # 50 bars across width
for i in range(50):
if i % 3 < 2: # Create barcode-like pattern
x_pos = barcode_x + (i * bar_width)
canvas.rect(x_pos, barcode_y, bar_width * 0.8, mm_to_points(8), fill=1)
# Right side vertical barcode - positioned 3mm further right and fill frame
vertical_barcode_x = self.content_x + self.content_width + mm_to_points(4) # Moved 3mm right (1mm + 3mm = 4mm)
vertical_barcode_y = self.content_y
vertical_barcode_height = self.content_height
vertical_barcode_width = mm_to_points(12) # Increased width for better fill
try:
# Create vertical barcode code
vertical_code = f"{current_num:03d}-{total_qty:02d}"
# Create a vertical barcode using Code128
v_barcode = code128.Code128(vertical_code,
barWidth=0.15*mm, # Thinner bars for better fit
barHeight=mm_to_points(8)) # Increased bar height
# Draw rotated barcode - fill the entire frame height
canvas.saveState()
canvas.translate(vertical_barcode_x + mm_to_points(6), vertical_barcode_y)
canvas.rotate(90)
# Always scale to fill the frame height
scale_factor = vertical_barcode_height / v_barcode.width
canvas.scale(scale_factor, 1)
v_barcode.drawOn(canvas, 0, 0)
canvas.restoreState()
# NO TEXT FOR VERTICAL BARCODE - Remove all text rendering
except Exception as e:
# Fallback: Vertical barcode pattern that fills the frame
canvas.setStrokeColor(colors.black)
canvas.setFillColor(colors.black)
bar_height = vertical_barcode_height / 60 # 60 bars across height
for i in range(60):
if i % 3 < 2: # Create barcode pattern
y_pos = vertical_barcode_y + (i * bar_height)
canvas.rect(vertical_barcode_x, y_pos, mm_to_points(8), bar_height * 0.8, fill=1)
def generate_order_labels_pdf(order_id, order_data):
"""
Main function to generate PDF for an order with multiple labels
"""
try:
generator = LabelPDFGenerator()
# Get quantity from order data
quantity = int(order_data.get('cantitate', 1))
# Generate PDF
pdf_buffer = generator.generate_labels_pdf(order_data, quantity)
return pdf_buffer
except Exception as e:
print(f"Error generating PDF labels: {e}")
raise e
def update_order_printed_status(order_id):
"""
Update the order status to printed in the database
"""
try:
from .print_module import get_db_connection
conn = get_db_connection()
cursor = conn.cursor()
# Check if printed_labels column exists
cursor.execute("SHOW COLUMNS FROM order_for_labels LIKE 'printed_labels'")
column_exists = cursor.fetchone()
if column_exists:
# Update printed status
cursor.execute("""
UPDATE order_for_labels
SET printed_labels = 1, updated_at = NOW()
WHERE id = %s
""", (order_id,))
else:
# If column doesn't exist, we could add it or use another method
print(f"Warning: printed_labels column doesn't exist for order {order_id}")
conn.commit()
conn.close()
return True
except Exception as e:
print(f"Error updating printed status for order {order_id}: {e}")
return False