Updated to print service power shell

This commit is contained in:
2025-09-21 16:42:18 +03:00
parent 7a1785d048
commit ed8ebd9e76
23 changed files with 4711 additions and 139 deletions

View File

@@ -236,12 +236,35 @@ table tbody tr.selected td {
</div>
</div>
<!-- PDF Information -->
<div style="width: 100%; margin-top: 15px; padding: 0 15px; text-align: center;">
<div style="background: #e8f4f8; border: 1px solid #bee5eb; border-radius: 6px; padding: 12px; font-size: 11px; color: #0c5460;">
<strong>📄 PDF Label Generation</strong><br>
Labels will be generated as PDF files for universal printing compatibility.<br>
<small style="color: #6c757d;">Works with any browser and printer - no extensions needed!</small>
<!-- Printer Selection and Service Setup -->
<div style="width: 100%; margin-top: 15px; padding: 0 15px;">
<!-- Printer Selection -->
<div class="mb-3">
<label for="printer-select" class="form-label" style="font-size: 13px; font-weight: 600; color: #495057; margin-bottom: 5px;">
🖨️ Choose Printer
</label>
<select id="printer-select" class="form-control" style="font-size: 12px; padding: 6px 10px;">
<option value="default">Default Printer</option>
<option value="detecting" disabled>Detecting printers...</option>
</select>
<small id="printer-status" class="text-muted" style="font-size: 10px;">
Checking for available printers...
</small>
</div>
<!-- Service Installation Link -->
<div class="text-center">
<div style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 10px; margin-bottom: 10px;">
<div style="font-size: 11px; color: #856404; margin-bottom: 8px;">
<strong><EFBFBD> Upgrade to Silent Printing</strong>
</div>
<a href="{{ url_for('main.download_extension') }}" class="btn btn-warning btn-sm" target="_blank" style="font-size: 11px; padding: 4px 12px;">
📥 Install Print Service & Extension
</a>
<div style="font-size: 9px; color: #6c757d; margin-top: 5px;">
5-minute setup • Auto-starts with Windows • Silent printing
</div>
</div>
</div>
</div>
@@ -568,12 +591,242 @@ function addFallbackPrintHandler() {
}
}
// Windows Print Service Integration
const PRINT_SERVICE_URL = 'http://localhost:8765';
let printServiceAvailable = false;
let availablePrinters = [];
// Check print service availability on page load
window.addEventListener('DOMContentLoaded', function() {
checkPrintServiceAvailability();
initializePrinterDropdown();
});
function initializePrinterDropdown() {
const select = document.getElementById('printer-select');
if (!select) return;
select.innerHTML = `
<option value="default">Default Printer</option>
<option value="detecting" disabled>Detecting printers...</option>
`;
}
async function checkPrintServiceAvailability() {
const printerStatus = document.getElementById('printer-status');
try {
printerStatus.textContent = 'Checking Windows Print Service...';
const response = await fetch(`${PRINT_SERVICE_URL}/health`, {
method: 'GET',
signal: AbortSignal.timeout(3000)
});
if (response.ok) {
printServiceAvailable = true;
console.log('✅ Windows Print Service is available');
updatePrintButtonForService(true);
await loadAvailablePrinters();
} else {
throw new Error('Service not responding');
}
} catch (error) {
printServiceAvailable = false;
console.log('⚠️ Windows Print Service not available, using fallback PDF download');
updatePrintButtonForService(false);
updatePrinterStatus('Windows Print Service not detected - PDF download mode');
}
}
async function loadAvailablePrinters() {
try {
const response = await fetch(`${PRINT_SERVICE_URL}/printers`);
if (response.ok) {
const data = await response.json();
availablePrinters = data.printers || [];
updatePrinterDropdown();
updatePrinterStatus(`${availablePrinters.length} printer(s) detected via Windows service`);
}
} catch (error) {
console.warn('Failed to load printers:', error);
updatePrinterStatus('Failed to detect printers - using default');
}
}
function updatePrinterDropdown() {
const select = document.getElementById('printer-select');
if (!select) return;
// Clear and rebuild options
select.innerHTML = '<option value="default">Default Printer (Recommended)</option>';
availablePrinters.forEach((printer, index) => {
const option = document.createElement('option');
option.value = printer.name || printer;
option.textContent = `${printer.name || printer}`;
if (printer.is_default) {
option.textContent += ' (Default)';
option.selected = true;
}
select.appendChild(option);
});
if (availablePrinters.length === 0) {
const option = document.createElement('option');
option.value = 'none';
option.textContent = 'No printers detected';
option.disabled = true;
select.appendChild(option);
}
}
function updatePrinterStatus(message) {
const status = document.getElementById('printer-status');
if (status) {
status.textContent = message;
}
}
function getSelectedPrinter() {
const select = document.getElementById('printer-select');
return select ? select.value : 'default';
}
function updatePrintButtonForService(serviceAvailable) {
const printButton = document.getElementById('print-label-btn');
if (!printButton) return;
if (serviceAvailable) {
printButton.innerHTML = '🖨️ Print Labels (Silent)';
printButton.title = 'Print labels directly to selected printer using Windows service';
printButton.style.background = '#28a745'; // Green for direct print
} else {
printButton.innerHTML = '📄 Generate PDF';
printButton.title = 'Generate PDF for manual printing (Windows service not available)';
printButton.style.background = '#007bff'; // Blue for PDF download
}
}
// Enhanced print function with Windows service support
async function printLabelsWithService(orderId, prodOrder, quantity) {
try {
// Generate PDF URL
const pdfUrl = `${window.location.origin}/generate_labels_pdf/${orderId}`;
// Get selected printer from dropdown
const selectedPrinter = getSelectedPrinter();
// Prepare print data for service
const printData = {
pdf_url: pdfUrl,
printer_name: selectedPrinter,
copies: 1,
silent: true,
order_id: orderId,
quantity: quantity
};
// Send to Windows service
const response = await fetch(`${PRINT_SERVICE_URL}/print/silent`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(printData)
});
const result = await response.json();
if (response.ok && result.success) {
// Success - labels printed silently
const printerName = selectedPrinter === 'default' ? 'default printer' : selectedPrinter;
alert(`✅ Labels printed successfully!\n\n📊 Order: ${prodOrder}\n📦 Quantity: ${quantity} labels\n🖨️ Printer: ${printerName}\n📋 Sequential: ${prodOrder}-001 to ${prodOrder}-${String(quantity).padStart(3, '0')}\n\n🎯 Printed silently via Windows service!`);
// Update order status in database
await updatePrintedStatus(orderId);
return true;
} else {
throw new Error(result.error || 'Print service failed');
}
} catch (error) {
console.error('Windows service print error:', error);
throw error;
}
}
// Fallback PDF download function
async function downloadPDFLabels(orderId, prodOrder, quantity) {
try {
// Generate PDF
const response = await fetch(`/generate_labels_pdf/${orderId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (!response.ok) {
const data = await response.json().catch(() => ({}));
throw new Error(data.error || `HTTP ${response.status}`);
}
// Get filename from response headers
const contentDisposition = response.headers.get('Content-Disposition');
let filename = `labels_${prodOrder}_qty${quantity}.pdf`;
if (contentDisposition) {
const matches = contentDisposition.match(/filename="?([^"]+)"?/);
if (matches) filename = matches[1];
}
const blob = await response.blob();
// Download PDF
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
// Show success message
alert(`📄 PDF downloaded successfully!\n\n📊 Order: ${prodOrder}\n📦 Quantity: ${quantity} labels\n📁 File: ${filename}\n📋 Sequential: ${prodOrder}-001 to ${prodOrder}-${String(quantity).padStart(3, '0')}\n\n➡️ Please print the PDF manually`);
return true;
} catch (error) {
console.error('PDF download error:', error);
throw error;
}
}
// Update printed status in database
async function updatePrintedStatus(orderId) {
try {
const response = await fetch(`/update_printed_status/${orderId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
// Refresh the orders table
setTimeout(() => {
document.getElementById('check-db-btn').click();
}, 1000);
}
} catch (error) {
console.warn('Failed to update printed status:', error);
}
}
// PDF generation handler
function addPDFGenerationHandler() {
const printButton = document.getElementById('print-label-btn');
if (printButton) {
printButton.addEventListener('click', function(e) {
printButton.addEventListener('click', async function(e) {
e.preventDefault();
// Get selected order
@@ -594,61 +847,41 @@ function addPDFGenerationHandler() {
// Show loading state
const originalText = printButton.innerHTML;
printButton.innerHTML = '⏳ Generating PDF...';
const originalColor = printButton.style.background;
printButton.innerHTML = '⏳ Processing...';
printButton.disabled = true;
// Generate PDF
fetch(`/generate_labels_pdf/${orderId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => {
if (!response.ok) {
return response.json().then(data => {
throw new Error(data.error || `HTTP ${response.status}`);
});
try {
let success = false;
// Try Windows service first if available
if (printServiceAvailable) {
try {
success = await printLabelsWithService(orderId, prodOrder, quantity);
} catch (serviceError) {
console.warn('Windows service failed, falling back to PDF download:', serviceError);
printServiceAvailable = false; // Mark as unavailable for this session
updatePrintButtonForService(false);
}
}
// Get filename from response headers or create default
const contentDisposition = response.headers.get('Content-Disposition');
let filename = `labels_${prodOrder}_qty${quantity}.pdf`;
if (contentDisposition) {
const matches = contentDisposition.match(/filename="?([^"]+)"?/);
if (matches) filename = matches[1];
// Fallback to PDF download if service failed or unavailable
if (!success) {
success = await downloadPDFLabels(orderId, prodOrder, quantity);
}
return response.blob().then(blob => ({ blob, filename }));
})
.then(({ blob, filename }) => {
// Create download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
// Show success message
alert(`✅ PDF generated successfully!\n\n📄 ${quantity} labels created for ${prodOrder}\n📋 Sequential numbering: ${prodOrder}-001 to ${prodOrder}-${String(quantity).padStart(3, '0')}\n📁 File: ${filename}\n\n➡️ The PDF is ready to print from your browser!`);
// Refresh the orders table to show updated print status
setTimeout(() => {
document.getElementById('check-db-btn').click();
}, 1000);
})
.catch(error => {
console.error('PDF generation error:', error);
alert(`❌ Error generating PDF: ${error.message}\n\nPlease try again or contact support.`);
})
.finally(() => {
} 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);
}
});
}
}