diff --git a/py_app/app/__pycache__/routes.cpython-312.pyc b/py_app/app/__pycache__/routes.cpython-312.pyc index dbbf39f..0e60eaa 100644 Binary files a/py_app/app/__pycache__/routes.cpython-312.pyc and b/py_app/app/__pycache__/routes.cpython-312.pyc differ diff --git a/py_app/app/routes.py b/py_app/app/routes.py index fad8d52..d1ebedd 100644 --- a/py_app/app/routes.py +++ b/py_app/app/routes.py @@ -1614,4 +1614,147 @@ def create_locations(): @warehouse_bp.route('/import_locations_csv', methods=['GET', 'POST']) def import_locations_csv(): from app.warehouse import import_locations_csv_handler - return import_locations_csv_handler() \ No newline at end of file + return import_locations_csv_handler() + +@bp.route('/print_labels_silent/', methods=['POST']) +def print_labels_silent(order_id): + """Generate PDF and send directly to Windows Print Service - bypasses CORS""" + print(f"DEBUG: print_labels_silent called for order_id: {order_id}") + + if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']: + return jsonify({'error': 'Access denied'}), 403 + + try: + import requests + import tempfile + import os + from .pdf_generator import generate_order_labels_pdf, update_order_printed_status + from .print_module import get_db_connection + + # Get printer name from request + data = request.get_json() or {} + printer_name = data.get('printer_name', 'default') + + print(f"DEBUG: Using printer: {printer_name}") + + # Get order data from database + conn = get_db_connection() + cursor = conn.cursor() + + cursor.execute(""" + SELECT id, comanda_productie, cod_articol, descr_com_prod, cantitate, + data_livrare, dimensiune, com_achiz_client, nr_linie_com_client, customer_name, + customer_article_number, open_for_order, line_number, + printed_labels, created_at, updated_at + FROM order_for_labels + WHERE id = %s + """, (order_id,)) + + order_data = cursor.fetchone() + cursor.close() + conn.close() + + if not order_data: + return jsonify({'error': 'Order not found'}), 404 + + # Convert to dictionary for easier access + columns = ['id', 'comanda_productie', 'cod_articol', 'descr_com_prod', 'cantitate', + 'data_livrare', 'dimensiune', 'com_achiz_client', 'nr_linie_com_client', + 'customer_name', 'customer_article_number', 'open_for_order', 'line_number', + 'printed_labels', 'created_at', 'updated_at'] + order_dict = dict(zip(columns, order_data)) + + print(f"DEBUG: Order data: {order_dict}") + + # Generate PDF content in memory + pdf_content = generate_order_labels_pdf(order_dict) + + # Save PDF to a location accessible by Windows service + pdf_dir = r"C:\temp\quality_labels" + if not os.path.exists(pdf_dir): + os.makedirs(pdf_dir, exist_ok=True) + + pdf_filename = f"order_{order_id}_{order_dict['comanda_productie']}.pdf" + pdf_path = os.path.join(pdf_dir, pdf_filename) + + # Write PDF to file + with open(pdf_path, 'wb') as pdf_file: + pdf_file.write(pdf_content) + + print(f"DEBUG: Created PDF file: {pdf_path}") + + try: + # Send to Windows Print Service with local file path + print_service_url = 'http://localhost:8765' + + # Create the print request with local file path + print_data = { + 'pdf_path': pdf_path, + 'printer_name': printer_name, + 'copies': 1, + 'silent': True, + 'order_id': order_id, + 'quantity': order_dict['cantitate'] + } + + print(f"DEBUG: Sending print request to {print_service_url}/print/silent") + + # Send request to Windows service + response = requests.post( + f'{print_service_url}/print/silent', + json=print_data, + headers={'Content-Type': 'application/json'}, + timeout=30 + ) + + print(f"DEBUG: Print service response: {response.status_code}") + + if response.status_code == 200: + result = response.json() + print(f"DEBUG: Print result: {result}") + + if result.get('success'): + # Update order status + update_order_printed_status(order_id) + + return jsonify({ + 'success': True, + 'message': 'Labels printed successfully', + 'printer': printer_name, + 'order': order_dict['comanda_productie'], + 'quantity': order_dict['cantitate'] + }) + else: + return jsonify({ + 'success': False, + 'error': result.get('error', 'Print service returned error') + }), 500 + else: + return jsonify({ + 'success': False, + 'error': f'Print service returned status {response.status_code}' + }), 500 + + except requests.exceptions.RequestException as e: + print(f"DEBUG: Print service connection error: {e}") + # Fallback: Return the PDF for manual printing + return jsonify({ + 'success': False, + 'error': f'Windows Print Service not available: {str(e)}', + 'fallback': 'pdf_download', + 'pdf_path': pdf_path + }), 503 + + finally: + # Clean up PDF file + try: + os.unlink(pdf_path) + print(f"DEBUG: Cleaned up PDF file: {pdf_path}") + except Exception as e: + print(f"DEBUG: Error cleaning up PDF file: {e}") + + except Exception as e: + print(f"DEBUG: Error in print_labels_silent: {e}") + import traceback + traceback.print_exc() + return jsonify({'error': str(e)}), 500 \ No newline at end of file diff --git a/py_app/app/templates/print_module.html b/py_app/app/templates/print_module.html index 8f1b63e..7b4ade3 100644 --- a/py_app/app/templates/print_module.html +++ b/py_app/app/templates/print_module.html @@ -720,34 +720,25 @@ function updatePrintButtonForService(serviceAvailable) { } } -// Enhanced print function with Windows service support +// Enhanced print function with Windows service support - NEW SERVER-SIDE APPROACH async function printLabelsWithService(orderId, prodOrder, quantity) { console.log(`šŸ–Øļø printLabelsWithService called - Order: ${orderId}, Quantity: ${quantity}`); try { - // Generate PDF URL - const pdfUrl = `${window.location.origin}/generate_labels_pdf/${orderId}`; - console.log(`šŸ“„ PDF URL: ${pdfUrl}`); - // Get selected printer from dropdown const selectedPrinter = getSelectedPrinter(); console.log(`šŸ–Øļø Selected printer: ${selectedPrinter}`); - // Prepare print data for service + // Use new server-side endpoint that bypasses CORS const printData = { - pdf_url: pdfUrl, - printer_name: selectedPrinter, - copies: 1, - silent: true, - order_id: orderId, - quantity: quantity + printer_name: selectedPrinter }; console.log('šŸ“‹ Print request data:', printData); - console.log(`šŸ“” Sending to: ${PRINT_SERVICE_URL}/print/silent`); + console.log(`šŸ“” Sending to server endpoint: /print_labels_silent/${orderId}`); - // Send to Windows service - const response = await fetch(`${PRINT_SERVICE_URL}/print/silent`, { + // Send to Flask server which handles Windows service communication + const response = await fetch(`/print_labels_silent/${orderId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -755,10 +746,10 @@ async function printLabelsWithService(orderId, prodOrder, quantity) { body: JSON.stringify(printData) }); - console.log(`šŸ“Ø Service response status: ${response.status}`); + console.log(`šŸ“Ø Server response status: ${response.status}`); const result = await response.json(); - console.log('šŸ“‹ Service response data:', result); + console.log('šŸ“‹ Server response data:', result); if (response.ok && result.success) { // Success - labels printed silently @@ -771,13 +762,24 @@ async function printLabelsWithService(orderId, prodOrder, quantity) { await updatePrintedStatus(orderId); return true; + } else if (response.status === 503 && result.fallback === 'pdf_download') { + // Windows service not available - inform user and suggest fallback + console.warn('āš ļø Windows service not available, showing service setup info'); + + alert(`āš ļø Windows Print Service Not Available\n\n${result.error}\n\nšŸ“‹ To enable silent printing:\n1. Install the Windows Print Service\n2. Start the service: sc start QualityLabelPrinting\n3. Restart your browser\n\nšŸ’” For now, use the "Generate PDF" button for manual printing.`); + + // Mark service as unavailable for this session + printServiceAvailable = false; + updatePrintButtonForService(false); + + throw new Error('Windows Print Service not available'); } else { - console.error('āŒ Service returned error:', result); - throw new Error(result.error || `Print service failed with status ${response.status}`); + console.error('āŒ Server returned error:', result); + throw new Error(result.error || `Print operation failed with status ${response.status}`); } } catch (error) { - console.error('āŒ Windows service print error:', error); + console.error('āŒ Server-side print error:', error); throw error; } } diff --git a/windows_print_service/print_service.ps1 b/windows_print_service/print_service.ps1 index 3794ea4..aac6168 100644 --- a/windows_print_service/print_service.ps1 +++ b/windows_print_service/print_service.ps1 @@ -96,6 +96,51 @@ function Invoke-PrintPDF { } } +# Print local PDF file function +function Invoke-PrintLocalPDF { + param( + [string]$PdfPath, + [string]$PrinterName = "default", + [int]$Copies = 1 + ) + + try { + Write-ServiceLog "Local print request: File=$PdfPath, Printer=$PrinterName, Copies=$Copies" + + # Check if file exists + if (!(Test-Path $PdfPath)) { + throw "PDF file not found: $PdfPath" + } + + # Get default printer if needed + if ($PrinterName -eq "default" -or [string]::IsNullOrEmpty($PrinterName)) { + $defaultPrinter = Get-WmiObject -Class Win32_Printer | Where-Object { $_.Default -eq $true } + $PrinterName = $defaultPrinter.Name + } + + Write-ServiceLog "Using printer: $PrinterName" + + # Print using Windows shell + $printJob = Start-Process -FilePath $PdfPath -Verb Print -PassThru -WindowStyle Hidden + Start-Sleep -Seconds 2 + + Write-ServiceLog "Print job sent successfully to printer: $PrinterName" + return @{ + success = $true + message = "Print job sent successfully" + printer = $PrinterName + timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + } + } + catch { + Write-ServiceLog "Print error: $($_.Exception.Message)" + return @{ + success = $false + error = $_.Exception.Message + } + } +} + # HTTP Response function function Send-HttpResponse { param( @@ -179,7 +224,7 @@ function Start-PrintService { Send-HttpResponse -Context $context -Body ($printersData | ConvertTo-Json -Depth 3) } - "^/print/(pdf|silent)$" { + "^/print/(pdf|silent|file)$" { if ($method -eq "POST") { try { # Read request body @@ -190,8 +235,16 @@ function Start-PrintService { # Parse JSON $printData = $body | ConvertFrom-Json - # Print PDF - $result = Invoke-PrintPDF -PdfUrl $printData.pdf_url -PrinterName $printData.printer_name -Copies $printData.copies + # Print PDF - handle both URL and local file path + if ($printData.pdf_path -and (Test-Path $printData.pdf_path)) { + Write-ServiceLog "Using local PDF file: $($printData.pdf_path)" + $result = Invoke-PrintLocalPDF -PdfPath $printData.pdf_path -PrinterName $printData.printer_name -Copies $printData.copies + } elseif ($printData.pdf_url) { + Write-ServiceLog "Using PDF URL: $($printData.pdf_url)" + $result = Invoke-PrintPDF -PdfUrl $printData.pdf_url -PrinterName $printData.printer_name -Copies $printData.copies + } else { + throw "Either pdf_path or pdf_url must be provided" + } if ($result.success) { Send-HttpResponse -Context $context -Body ($result | ConvertTo-Json) @@ -219,7 +272,7 @@ function Start-PrintService { $errorResponse = @{ success = $false error = "Endpoint not found" - available_endpoints = @("/health", "/printers", "/print/pdf", "/print/silent") + available_endpoints = @("/health", "/printers", "/print/pdf", "/print/silent", "/print/file") } Send-HttpResponse -Context $context -StatusCode 404 -Body ($errorResponse | ConvertTo-Json) }