updated to silent print

This commit is contained in:
2025-09-24 21:42:22 +03:00
parent b49a22832d
commit 198563aaba
26 changed files with 693 additions and 1520 deletions

View File

@@ -0,0 +1,16 @@
# Windows Print Service Configuration
# Configure the Windows Print Service connection for cross-platform printing
# Default Windows Print Service URL
# Change this to the IP address of your Windows machine if running on different systems
# Examples:
# Same machine: http://localhost:8765
# Different machine: http://192.168.1.100:8765
# Domain name: http://printserver.company.local:8765
WINDOWS_PRINT_SERVICE_URL = "http://192.168.1.XXX:8765" # ← REPLACE XXX WITH YOUR WINDOWS IP
# Print service connection timeout (seconds)
PRINT_SERVICE_TIMEOUT = 30
# Enable print service connection (set to False to always use PDF fallback)
PRINT_SERVICE_ENABLED = True

View File

@@ -1616,145 +1616,13 @@ def import_locations_csv():
from app.warehouse import import_locations_csv_handler
return import_locations_csv_handler()
@bp.route('/print_labels_silent/<int:order_id>', 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
# NOTE for frontend/extension developers:
# To print labels, call the Chrome extension and pass the PDF URL:
# /generate_labels_pdf/<order_id>
# The extension should POST to http://localhost:8765/print/silent with:
# {
# "pdf_url": "https://your-linux-server/generate_labels_pdf/15",
# "printer_name": "default",
# "copies": 1
# }

View File

@@ -8,6 +8,17 @@
overflow: hidden;
}
/* Inserted custom CSS from user */
.card.scan-table-card table.print-module-table.scan-table thead th {
border-bottom: 2e6 !important;
background-color: #f8f9fa !important;
padding: 0.25rem 0.4rem !important;
text-align: left !important;
font-weight: 600 !important;
font-size: 10px !important;
line-height: 1.2 !important;
}
/* Enhanced table styling to match view_orders.html with higher specificity */
.card.scan-table-card table.print-module-table.scan-table {
width: 100% !important;
@@ -849,77 +860,101 @@ async function updatePrintedStatus(orderId) {
}
// PDF generation handler
// Helper to get extension ID injected by content script
function getInjectedExtensionId() {
const el = document.getElementById('chrome-extension-id');
if (el) return el.getAttribute('data-extension-id');
return null;
}
function addPDFGenerationHandler() {
const printButton = document.getElementById('print-label-btn');
if (printButton) {
printButton.addEventListener('click', async function(e) {
e.preventDefault();
// Get selected order
const selectedRow = document.querySelector('.print-module-table tbody tr.selected');
if (!selectedRow) {
alert('Please select an order first from the table below.');
return;
}
const orderId = selectedRow.dataset.orderId;
const prodOrder = selectedRow.querySelector('td:nth-child(2)').textContent.trim();
const quantity = selectedRow.querySelector('td:nth-child(5)').textContent.trim();
if (!orderId) {
alert('Error: Could not determine order ID.');
return;
}
// Show loading state
const originalText = printButton.innerHTML;
const originalColor = printButton.style.background;
printButton.innerHTML = '⏳ Processing...';
printButton.disabled = true;
if (!printButton) return;
printButton.addEventListener('click', async function(e) {
e.preventDefault();
// Get selected order
const selectedRow = document.querySelector('.print-module-table tbody tr.selected');
if (!selectedRow) {
alert('Please select an order first from the table below.');
return;
}
const orderId = selectedRow.dataset.orderId;
const prodOrder = selectedRow.querySelector('td:nth-child(2)').textContent.trim();
const quantity = selectedRow.querySelector('td:nth-child(5)').textContent.trim();
if (!orderId) {
alert('Error: Could not determine order ID.');
return;
}
// Show loading state
const originalText = printButton.innerHTML;
const originalColor = printButton.style.background;
printButton.innerHTML = '⏳ Processing...';
printButton.disabled = true;
try {
// Step 1: Generate PDF and get its URL
const pdfResponse = await fetch(`/generate_labels_pdf/${orderId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (!pdfResponse.ok) throw new Error('Failed to generate PDF');
// Try to get the PDF URL from the response (assume server returns a URL or we can construct it)
// If not, fallback to download
let pdfUrl = '';
try {
let success = false;
console.log(`🖨️ Print operation started - Service available: ${printServiceAvailable}`);
// Try Windows service first if available
if (printServiceAvailable) {
console.log('🚀 Attempting silent print via Windows service...');
try {
success = await printLabelsWithService(orderId, prodOrder, quantity);
console.log(`✅ Windows service print result: ${success}`);
} catch (serviceError) {
console.error('❌ Windows service failed:', serviceError);
console.warn('🔄 Falling back to PDF download mode');
printServiceAvailable = false; // Mark as unavailable for this session
updatePrintButtonForService(false);
}
} else {
console.log('📄 Service not available, using PDF download mode');
}
// Fallback to PDF download if service failed or unavailable
if (!success) {
console.log('📥 Generating PDF for download...');
success = await downloadPDFLabels(orderId, prodOrder, quantity);
console.log(`📄 PDF download result: ${success}`);
}
} catch (error) {
console.error('Print operation failed:', error);
alert(`❌ Print operation failed: ${error.message}\n\nPlease check:\n• Windows Print Service is running\n• Chrome extension is installed\n• Network connectivity\n• PDF generation permissions`);
} finally {
// Reset button state
printButton.innerHTML = originalText;
printButton.style.background = originalColor;
printButton.disabled = false;
// Recheck service availability for next operation
setTimeout(checkPrintServiceAvailability, 2000);
const data = await pdfResponse.json();
pdfUrl = data.pdf_url || '';
} catch {
// If not JSON, fallback to constructing the URL
pdfUrl = `/static/generated_labels/labels_${prodOrder}_${quantity}pcs.pdf`;
}
});
}
// Step 2: Prepare print job for Chrome extension
const selectedPrinter = getSelectedPrinter();
const printJob = {
pdfUrl: window.location.origin + pdfUrl,
printer: selectedPrinter,
orderId: orderId,
prodOrder: prodOrder,
quantity: quantity
};
// Step 3: Get extension ID from injected DOM
const extensionId = getInjectedExtensionId();
// Step 4: Send message to Chrome extension
if (window.chrome && window.chrome.runtime && window.chrome.runtime.sendMessage && extensionId) {
window.chrome.runtime.sendMessage(
extensionId,
{ action: 'print_pdf', ...printJob },
function(response) {
if (response && response.success) {
alert('✅ Labels sent to printer!\nOrder: ' + prodOrder + '\nQuantity: ' + quantity + '\nPrinter: ' + selectedPrinter);
updatePrintedStatus(orderId);
} else {
alert('❌ Failed to print via extension. PDF will be downloaded.');
downloadPDFLabels(orderId, prodOrder, quantity);
}
}
);
} else {
// Fallback: Download PDF
alert(' Chrome extension not detected or extension ID not injected. PDF will be downloaded.');
await downloadPDFLabels(orderId, prodOrder, quantity);
}
} catch (error) {
console.error('Print operation failed:', error);
alert('❌ Print operation failed: ' + error.message);
} finally {
printButton.innerHTML = originalText;
printButton.style.background = originalColor;
printButton.disabled = false;
}
});
}
</script>
{% endblock %}