updated : solutions
This commit is contained in:
Binary file not shown.
@@ -2065,6 +2065,47 @@ def update_printed_status(order_id):
|
||||
print(f"DEBUG: Error in update_printed_status: {e}")
|
||||
return jsonify({'error': 'Internal server error'}), 500
|
||||
|
||||
|
||||
@bp.route('/download_print_service')
|
||||
def download_print_service():
|
||||
"""Download the direct print service package"""
|
||||
try:
|
||||
from flask import send_from_directory, current_app
|
||||
import os
|
||||
|
||||
# Check if complete package is requested
|
||||
package_type = request.args.get('package', 'basic')
|
||||
|
||||
if package_type == 'complete':
|
||||
# Serve the complete package
|
||||
filename = 'QualityPrintService_Complete.zip'
|
||||
else:
|
||||
# Serve the basic package (legacy)
|
||||
filename = 'RecticelPrintService.zip'
|
||||
|
||||
# Path to the print service files
|
||||
service_path = os.path.join(current_app.root_path, 'static', 'downloads')
|
||||
|
||||
# Create the directory if it doesn't exist
|
||||
os.makedirs(service_path, exist_ok=True)
|
||||
|
||||
# Check if the zip file exists
|
||||
full_path = os.path.join(service_path, filename)
|
||||
|
||||
if not os.path.exists(full_path):
|
||||
# If the zip doesn't exist, return information about creating it
|
||||
return jsonify({
|
||||
'error': f'Print service package ({filename}) not found',
|
||||
'message': f'The {package_type} print service package is not available',
|
||||
'suggestion': 'Please contact the administrator or use the basic package'
|
||||
}), 404
|
||||
|
||||
return send_from_directory(service_path, filename, as_attachment=True)
|
||||
|
||||
except Exception as e:
|
||||
print(f"DEBUG: Error downloading print service: {e}")
|
||||
return jsonify({'error': 'Failed to download print service'}), 500
|
||||
|
||||
@bp.route('/get_order_data/<int:order_id>', methods=['GET'])
|
||||
def get_order_data(order_id):
|
||||
"""Get specific order data for preview"""
|
||||
|
||||
@@ -204,6 +204,25 @@
|
||||
<div style="margin-bottom: 5px;">Creates sequential labels based on quantity</div>
|
||||
<small>(e.g., CP00000711-001 to CP00000711-063)</small>
|
||||
</div>
|
||||
|
||||
<!-- Direct Print Service Download -->
|
||||
<div style="width: 100%; text-align: center; margin-top: 20px; padding-top: 15px; border-top: 1px solid #e9ecef;">
|
||||
<div style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 12px; margin-bottom: 10px;">
|
||||
<div style="font-size: 11px; color: #856404; margin-bottom: 8px;">
|
||||
<strong>📦 Quality Print Service</strong>
|
||||
</div>
|
||||
<div style="font-size: 10px; color: #6c757d; margin-bottom: 10px; line-height: 1.3;">
|
||||
Professional Windows service for instant direct printing to thermal label printers without PDF dialogs
|
||||
</div>
|
||||
<a href="{{ url_for('main.download_print_service') }}?package=complete" class="btn btn-outline-warning btn-sm" download style="font-size: 10px; padding: 4px 12px; text-decoration: none;">
|
||||
📥 Download Complete Package
|
||||
</a>
|
||||
</div>
|
||||
<div style="font-size: 9px; color: #6c757d; margin-top: 5px; line-height: 1.2;">
|
||||
<strong>Easy Install:</strong> Extract → Run install.bat as Admin → Done!<br>
|
||||
<small>Supports all thermal printers • Auto-starts with Windows • One-click installation</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- Data Preview Card -->
|
||||
<div class="card scan-table-card" style="min-height: 700px; width: calc(100% - 350px); margin: 0;">
|
||||
@@ -330,6 +349,9 @@ document.getElementById('check-db-btn').addEventListener('click', function() {
|
||||
// Initialize PDF generation functionality
|
||||
addPDFGenerationHandler();
|
||||
|
||||
// Initialize print service
|
||||
initializePrintService();
|
||||
|
||||
// Auto-select first row
|
||||
setTimeout(() => {
|
||||
const firstRow = document.querySelector('.print-module-table tbody tr');
|
||||
@@ -396,6 +418,96 @@ function updateLabelPreview(order) {
|
||||
document.getElementById('barcode-text').textContent = prodOrder;
|
||||
}
|
||||
|
||||
// Initialize print service connection and load available printers
|
||||
function initializePrintService() {
|
||||
// Check service status and load printers
|
||||
checkPrintServiceStatus()
|
||||
.then(serviceStatus => {
|
||||
if (serviceStatus) {
|
||||
console.log('✅ Print service is available');
|
||||
loadAvailablePrinters();
|
||||
updateServiceStatusIndicator(true);
|
||||
} else {
|
||||
console.log('⚠️ Print service not available');
|
||||
updateServiceStatusIndicator(false);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('❌ Print service connection failed:', error);
|
||||
updateServiceStatusIndicator(false);
|
||||
});
|
||||
}
|
||||
|
||||
// Load available printers from print service
|
||||
function loadAvailablePrinters() {
|
||||
fetch('http://localhost:8899/printers', {
|
||||
method: 'GET',
|
||||
mode: 'cors'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const printerSelect = document.getElementById('printerSelect');
|
||||
|
||||
// Clear existing options except default ones
|
||||
const defaultOptions = ['default', 'Epson TM-T20', 'Citizen CTS-310', 'custom'];
|
||||
Array.from(printerSelect.options).forEach(option => {
|
||||
if (!defaultOptions.includes(option.value)) {
|
||||
option.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Add available printers
|
||||
if (data.printers && data.printers.length > 0) {
|
||||
data.printers.forEach(printer => {
|
||||
// Don't add if already exists in default options
|
||||
if (!defaultOptions.includes(printer.name)) {
|
||||
const option = document.createElement('option');
|
||||
option.value = printer.name;
|
||||
option.textContent = `${printer.name}${printer.default ? ' (Default)' : ''}${printer.status !== 'ready' ? ' - Offline' : ''}`;
|
||||
|
||||
// Insert before "Other Printer..." option
|
||||
const customOption = printerSelect.querySelector('option[value="custom"]');
|
||||
printerSelect.insertBefore(option, customOption);
|
||||
}
|
||||
});
|
||||
|
||||
// Set default printer if available
|
||||
const defaultPrinter = data.printers.find(p => p.default);
|
||||
if (defaultPrinter) {
|
||||
printerSelect.value = defaultPrinter.name;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Loaded ${data.printers.length} printers from service`);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Could not load printers from service:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Update service status indicator
|
||||
function updateServiceStatusIndicator(isAvailable) {
|
||||
// Find or create status indicator
|
||||
let statusIndicator = document.getElementById('service-status-indicator');
|
||||
if (!statusIndicator) {
|
||||
statusIndicator = document.createElement('div');
|
||||
statusIndicator.id = 'service-status-indicator';
|
||||
statusIndicator.style.cssText = 'font-size: 9px; color: #6c757d; margin-top: 5px; text-align: center;';
|
||||
|
||||
// Insert after printer selection
|
||||
const printerSelection = document.getElementById('printerSelection');
|
||||
printerSelection.appendChild(statusIndicator);
|
||||
}
|
||||
|
||||
if (isAvailable) {
|
||||
statusIndicator.innerHTML = '🟢 <strong>Print service connected</strong><br><small>Direct printing available</small>';
|
||||
statusIndicator.style.color = '#28a745';
|
||||
} else {
|
||||
statusIndicator.innerHTML = '🔴 <strong>Print service offline</strong><br><small>Install and start the service for direct printing</small>';
|
||||
statusIndicator.style.color = '#dc3545';
|
||||
}
|
||||
}
|
||||
|
||||
// PDF Generation System - No printer setup needed
|
||||
// Labels are generated as PDF files for universal compatibility
|
||||
function addPDFGenerationHandler() {
|
||||
@@ -463,67 +575,114 @@ function handleDirectPrint(selectedRow) {
|
||||
printerName = prompt('Enter your printer name:');
|
||||
if (!printerName) return;
|
||||
} else if (printerName === 'default') {
|
||||
printerName = 'default';
|
||||
printerName = ''; // Empty for default printer
|
||||
}
|
||||
|
||||
console.log(`Direct printing to: ${printerName}`);
|
||||
console.log(`Direct printing to: ${printerName || 'default printer'}`);
|
||||
|
||||
// Extract order data from selected row
|
||||
const cells = selectedRow.querySelectorAll('td');
|
||||
const orderData = {
|
||||
order_id: parseInt(orderId),
|
||||
comanda_productie: cells[1].textContent.trim(),
|
||||
cod_articol: cells[2].textContent.trim(),
|
||||
descr_com_prod: cells[3].textContent.trim(),
|
||||
cantitate: parseInt(cells[4].textContent.trim()),
|
||||
data_livrare: cells[5].textContent.trim(),
|
||||
dimensiune: cells[6].textContent.trim(),
|
||||
com_achiz_client: cells[7].textContent.trim(),
|
||||
nr_linie_com_client: cells[8].textContent.trim(),
|
||||
customer_name: cells[9].textContent.trim(),
|
||||
customer_article_number: cells[10].textContent.trim()
|
||||
};
|
||||
|
||||
// Print each label individually
|
||||
for (let i = 1; i <= quantity; i++) {
|
||||
const labelData = {
|
||||
...orderData,
|
||||
sequential_number: `${orderData.comanda_productie}-${i.toString().padStart(3, '0')}`,
|
||||
current_label: i,
|
||||
total_labels: quantity
|
||||
};
|
||||
|
||||
// Encode data as base64 JSON
|
||||
const jsonString = JSON.stringify(labelData);
|
||||
const base64Data = btoa(unescape(encodeURIComponent(jsonString)));
|
||||
|
||||
// Create custom protocol URL
|
||||
const printUrl = `recticel-print://${encodeURIComponent(printerName)}/${base64Data}`;
|
||||
|
||||
console.log(`Printing label ${i}/${quantity}: ${printUrl.substring(0, 100)}...`);
|
||||
|
||||
// Trigger direct print via custom protocol
|
||||
try {
|
||||
window.location.href = printUrl;
|
||||
} catch (error) {
|
||||
console.error(`Failed to print label ${i}:`, error);
|
||||
alert(`❌ Failed to print label ${i}/${quantity}. Please check if the print service is installed.`);
|
||||
return;
|
||||
// Check if print service is available
|
||||
checkPrintServiceStatus()
|
||||
.then(serviceStatus => {
|
||||
if (!serviceStatus) {
|
||||
throw new Error('Print service is not available');
|
||||
}
|
||||
|
||||
// Generate PDF first for printing
|
||||
return generatePrintablePDF(orderId, true); // true for paper-saving mode
|
||||
})
|
||||
.then(pdfUrl => {
|
||||
// Send PDF to print service
|
||||
const printData = {
|
||||
pdf_url: pdfUrl,
|
||||
printer: printerName,
|
||||
copies: 1,
|
||||
order_id: parseInt(orderId),
|
||||
paper_saving: true
|
||||
};
|
||||
|
||||
return fetch('http://localhost:8899/print-pdf', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(printData)
|
||||
});
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Print service error: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
alert(`✅ Successfully sent ${quantity} labels to printer!\n📊 Order: ${prodOrder}\n🖨️ Printer: ${printerName || 'Default'}\n📄 Job ID: ${result.job_id || 'N/A'}`);
|
||||
|
||||
// Update database status and refresh table
|
||||
updatePrintedStatus(orderId);
|
||||
} else {
|
||||
throw new Error(result.error || 'Unknown print error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Direct print error:', error);
|
||||
|
||||
let errorMessage = '❌ Direct printing failed: ' + error.message;
|
||||
|
||||
if (error.message.includes('service is not available')) {
|
||||
errorMessage += '\n\n💡 Solutions:\n' +
|
||||
'1. Install the print service using the download link below\n' +
|
||||
'2. Ensure the service is running (check Windows Services)\n' +
|
||||
'3. Try restarting the print service\n' +
|
||||
'4. Use PDF generation as alternative';
|
||||
} else if (error.message.includes('fetch')) {
|
||||
errorMessage += '\n\n💡 The print service may not be running.\n' +
|
||||
'Please start the Quality Print Service from Windows Services.';
|
||||
}
|
||||
|
||||
alert(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to check print service status
|
||||
function checkPrintServiceStatus() {
|
||||
return fetch('http://localhost:8899/status', {
|
||||
method: 'GET',
|
||||
mode: 'cors'
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json().then(data => {
|
||||
console.log('Print service status:', data);
|
||||
return data.status === 'running';
|
||||
});
|
||||
}
|
||||
|
||||
// Small delay between labels to prevent overwhelming the printer
|
||||
if (i < quantity) {
|
||||
setTimeout(() => {}, 100);
|
||||
return false;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Print service not available:', error.message);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to generate PDF for printing
|
||||
function generatePrintablePDF(orderId, paperSaving = true) {
|
||||
return fetch(`/generate_labels_pdf/${orderId}/${paperSaving ? 'true' : 'false'}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
|
||||
// Show success message
|
||||
setTimeout(() => {
|
||||
alert(`✅ Sent ${quantity} labels to printer: ${printerName}\n📊 Order: ${prodOrder}`);
|
||||
|
||||
// Update database status and refresh table
|
||||
updatePrintedStatus(orderId);
|
||||
}, 500);
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to generate PDF: ${response.status}`);
|
||||
}
|
||||
return response.blob();
|
||||
})
|
||||
.then(blob => {
|
||||
// Create a temporary URL for the PDF
|
||||
return URL.createObjectURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
function handlePDFGeneration(selectedRow) {
|
||||
|
||||
Reference in New Issue
Block a user