updated : solutions
This commit is contained in:
@@ -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