This commit is contained in:
2025-09-25 22:26:32 +03:00
parent 854b6980bc
commit 02277dd55b
27 changed files with 3636 additions and 1855 deletions

View File

@@ -8,8 +8,11 @@
<div class="row justify-content-center mb-4">
<div class="col-md-12">
<div class="text-center">
<h1 class="display-4">🖨️ Quality Recticel Print Service</h1>
<p class="lead">Professional Silent Printing Solution for Windows</p>
<h1 class="display-4">🖨️ Quality Recticel Print Extension</h1>
<p class="lead">Simple & Robust Chrome Extension for PDF Printing</p>
<div class="alert alert-success mx-auto" style="max-width: 600px;">
<strong>✨ NEW SIMPLIFIED APPROACH:</strong> No Windows service needed! Just install the Chrome extension and print directly from your browser.
</div>
</div>
</div>
</div>
@@ -19,28 +22,28 @@
<div class="col-md-10">
<div class="card border-primary">
<div class="card-header bg-primary text-white">
<h3 class="mb-0"><EFBFBD> Complete Printing Solution</h3>
<h3 class="mb-0">🚀 Simple Chrome Extension Solution</h3>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h5>🏆 What You Get:</h5>
<ul>
<li><strong>Silent PDF Printing</strong> - No manual downloads</li>
<li><strong>Automatic Detection</strong> - Smart service fallback</li>
<li><strong>Zero Configuration</strong> - Works out of the box</li>
<li><strong>Auto-Start Service</strong> - Boots with Windows</li>
<li><strong>Professional Integration</strong> - Seamless workflow</li>
<li><strong>Direct PDF Printing</strong> - Uses browser's print dialog</li>
<li><strong>Zero Configuration</strong> - Works immediately after install</li>
<li><strong>Cross-Platform</strong> - Works on Windows, Mac, Linux</li>
<li><strong>No External Services</strong> - No Windows service needed</li>
<li><strong>Robust Fallback</strong> - Downloads PDF if extension unavailable</li>
</ul>
</div>
<div class="col-md-6">
<h5>🔧 System Components:</h5>
<h5>🔧 How It Works:</h5>
<ul>
<li>🖥️ <strong>Windows Print Service</strong> - Local API (localhost:8765)</li>
<li>🌐 <strong>Chrome Extension</strong> - Browser integration</li>
<li>📄 <strong>Web Integration</strong> - Smart button detection</li>
<li>🔄 <strong>Fallback System</strong> - PDF download backup</li>
<li>🛡️ <strong>Security</strong> - Local-only connections</li>
<li>🌐 <strong>Chrome Extension</strong> - Simple browser integration</li>
<li>📄 <strong>Hidden Tab Method</strong> - Opens PDF in background tab</li>
<li><EFBFBD> <strong>Native Print Dialog</strong> - User controls printer selection</li>
<li>🔄 <strong>Auto Cleanup</strong> - Closes tab after printing</li>
<li>🛡️ <strong>Secure</strong> - No external connections required</li>
</ul>
</div>
</div>
@@ -51,85 +54,45 @@
<!-- Download Cards Row -->
<div class="row justify-content-center">
<!-- Windows Service Card -->
<div class="col-md-5 mb-4">
<!-- Chrome Extension Card - NOW THE ONLY COMPONENT NEEDED -->
<div class="col-md-8 mb-4">
<div class="card h-100 border-success">
<div class="card-header bg-success text-white text-center">
<h4 class="mb-0">🖥️ Windows Print Service</h4>
<small>Core printing engine</small>
<h4 class="mb-0">🌐 Chrome Extension - All You Need!</h4>
<small>Simple browser-based printing solution</small>
</div>
<div class="card-body d-flex flex-column">
<div class="alert alert-success">
<strong>🚀 Install First:</strong> The Windows service provides the printing API and must be installed before the Chrome extension.
<strong>🎉 SIMPLIFIED:</strong> Just install this Chrome extension - no Windows service needed!
</div>
<h5>📦 Package Contents:</h5>
<h5>🎯 Key Features:</h5>
<ul>
<li>🔧 <code>install_service.bat</code> - One-click installer</li>
<li>🖥️ <code>print_service.py</code> - Main service application</li>
<li>⚙️ <code>service_manager.py</code> - Service management</li>
<li>🌐 <code>chrome_extension/</code> - Browser extension</li>
<li>📚 Complete documentation package</li>
</ul>
<h5>⚡ Quick Install:</h5>
<ol>
<li>Download and extract the service package</li>
<li><strong>Right-click</strong> <code>install_service.bat</code></li>
<li>Select <strong>"Run as administrator"</strong></li>
<li>Wait for installation to complete</li>
</ol>
<div class="text-center mt-auto">
<button class="btn btn-success btn-lg mb-2" id="download-service-btn">
📥 Download Windows Service
</button>
<br>
<small class="text-muted">Complete package (~50KB)</small>
</div>
</div>
</div>
</div>
<!-- Chrome Extension Card -->
<div class="col-md-5 mb-4">
<div class="card h-100 border-info">
<div class="card-header bg-info text-white text-center">
<h4 class="mb-0">🌐 Chrome Extension</h4>
<small>Browser integration</small>
</div>
<div class="card-body d-flex flex-column">
<div class="alert alert-info">
<strong>🔗 Install Second:</strong> The Chrome extension connects your browser to the Windows service for seamless printing.
</div>
<h5>🎯 Features:</h5>
<ul>
<li>🖨️ Silent printing via native messaging</li>
<li>🔍 Automatic service detection</li>
<li>📊 Print status monitoring</li>
<li><EFBFBD> Opens PDF in hidden browser tab and triggers print dialog</li>
<li>🔍 Automatic extension detection on web page</li>
<li>📊 Print status feedback and error handling</li>
<li>🔄 Graceful fallback to PDF download</li>
<li>⚙️ Printer management interface</li>
<li>⚙️ Works with any printer Chrome can access</li>
<li>🌍 Cross-platform (Windows, Mac, Linux)</li>
</ul>
<h5>🚀 Quick Install:</h5>
<h5>🚀 Quick Install (3 steps):</h5>
<ol>
<li>Download and extract extension files</li>
<li>Download and extract the extension files</li>
<li>Open Chrome → <code>chrome://extensions/</code></li>
<li>Enable <strong>"Developer mode"</strong></li>
<li>Click <strong>"Load unpacked"</strong> → Select folder</li>
<li>Enable <strong>"Developer mode"</strong> → Click <strong>"Load unpacked"</strong> → Select folder</li>
</ol>
<div class="text-center mt-auto">
<button class="btn btn-info btn-lg mb-2" id="download-extension-btn">
<button class="btn btn-success btn-lg mb-3" id="download-extension-btn">
📥 Download Chrome Extension
</button>
<br>
<small class="text-muted">Extension package (~15KB)</small>
<small class="text-muted">Extension package (~10KB)</small>
<hr>
<div class="text-center">
<small class="text-muted">Individual files:</small><br>
<small class="text-muted">Individual files for inspection:</small><br>
<a href="{{ url_for('main.extension_files', filename='manifest.json') }}" target="_blank" class="btn btn-sm btn-outline-secondary">manifest.json</a>
<a href="{{ url_for('main.extension_files', filename='background.js') }}" target="_blank" class="btn btn-sm btn-outline-secondary">background.js</a>
<a href="{{ url_for('main.extension_files', filename='content.js') }}" target="_blank" class="btn btn-sm btn-outline-secondary">content.js</a>
@@ -208,21 +171,22 @@
<div class="col-md-6">
<h5>💻 Requirements:</h5>
<ul>
<li><strong>OS:</strong> Windows 10/11 (64-bit)</li>
<li><strong>Python:</strong> 3.8+ (auto-installed if missing)</li>
<li><strong>Browser:</strong> Google Chrome (latest)</li>
<li><strong>Privileges:</strong> Administrator (for installation only)</li>
<li><strong>Network:</strong> Localhost access (no internet required)</li>
<li><strong>Browser:</strong> Google Chrome (any recent version)</li>
<li><strong>OS:</strong> Windows, Mac, or Linux</li>
<li><strong>Privileges:</strong> None required (standard user)</li>
<li><strong>Internet:</strong> Not required (works offline)</li>
<li><strong>Installation:</strong> Just load extension in Chrome</li>
</ul>
</div>
<div class="col-md-6">
<h5>🔍 How It Works:</h5>
<div class="alert alert-light">
<ol class="mb-0">
<li>🌐 Web page detects service status</li>
<li>🖨️ <strong>Service Available</strong> → Green "Print Labels (Silent)" button</li>
<li>📄 <strong>Service Unavailable</strong> → Blue "Generate PDF" button</li>
<li>🔄 Automatic fallback ensures printing always works</li>
<li>🌐 Web page detects Chrome extension</li>
<li>🖨️ <strong>Extension Available</strong> → Green "Print Labels (Extension)" button</li>
<li>📄 <strong>Extension Unavailable</strong> → Blue "Generate PDF" button</li>
<li>🔄 Extension opens PDF in hidden tab → triggers print dialog</li>
<li>✅ User selects printer and confirms → automatic cleanup</li>
</ol>
</div>
</div>
@@ -234,11 +198,22 @@
<!-- Action Buttons -->
<div class="row justify-content-center mb-5">
<div class="col-md-8 text-center">
<div class="col-md-10 text-center">
<div class="card border-dark">
<div class="card-body">
<h5>🚀 Ready to Start?</h5>
<p class="text-muted">Installation takes ~5 minutes • Zero maintenance required</p>
<h5>🚀 Ready to Test?</h5>
<p class="text-muted">Installation takes ~2 minutes • Zero maintenance required</p>
<!-- Test Extension Button -->
<div class="alert alert-info">
<h6>🧪 Test the Extension</h6>
<p class="mb-2">After installing the extension, click below to test if the print module detects it correctly:</p>
<button class="btn btn-info mb-2" id="test-extension-btn">
🔍 Test Extension Detection
</button>
<div id="test-results" class="mt-2" style="display: none;"></div>
</div>
<div class="btn-group-vertical btn-group-lg" role="group">
<a href="{{ url_for('main.print_module') }}" class="btn btn-success btn-lg">
🖨️ Go to Print Module
@@ -254,46 +229,6 @@
</div>
<script>
// Windows Service Download Handler
document.getElementById('download-service-btn').addEventListener('click', function(e) {
e.preventDefault();
// Show loading state
const originalText = this.innerHTML;
this.innerHTML = '⏳ Preparing Windows Service Package...';
this.disabled = true;
// Create the Windows service package
fetch('/create_service_package', {method: 'POST'})
.then(response => response.json())
.then(data => {
if (data.success) {
// Start download
window.location.href = data.download_url;
// Show success message
setTimeout(() => {
this.innerHTML = '✅ Download Started!';
}, 500);
// Reset button
setTimeout(() => {
this.innerHTML = originalText;
this.disabled = false;
}, 3000);
} else {
alert('Error creating Windows service package: ' + data.error);
this.innerHTML = originalText;
this.disabled = false;
}
})
.catch(error => {
alert('Error: ' + error.message);
this.innerHTML = originalText;
this.disabled = false;
});
});
// Chrome Extension Download Handler
document.getElementById('download-extension-btn').addEventListener('click', function(e) {
e.preventDefault();
@@ -334,20 +269,115 @@ document.getElementById('download-extension-btn').addEventListener('click', func
});
});
// Documentation links - track clicks for analytics
document.querySelectorAll('a[href*="/static/documentation/"]').forEach(link => {
link.addEventListener('click', function(e) {
// Could add analytics tracking here
console.log('Documentation accessed:', this.href);
});
// Extension Test Functionality
document.getElementById('test-extension-btn').addEventListener('click', function(e) {
e.preventDefault();
const testResults = document.getElementById('test-results');
const originalText = this.innerHTML;
this.innerHTML = '🔍 Testing...';
this.disabled = true;
testResults.style.display = 'block';
testResults.innerHTML = '<div class="spinner-border spinner-border-sm" role="status"></div> Checking Chrome extension...';
// Test extension detection (same logic as print module)
testExtensionConnection()
.then(result => {
if (result.success) {
testResults.innerHTML = `
<div class="alert alert-success">
<strong>✅ Extension Test Successful!</strong><br>
Extension ID: ${result.extensionId || 'Detected'}<br>
Version: ${result.version || 'Unknown'}<br>
Status: Ready for printing<br>
<small class="text-muted">The print module will show the green "Print Labels (Extension)" button</small>
</div>
`;
} else {
testResults.innerHTML = `
<div class="alert alert-warning">
<strong>❌ Extension Not Detected</strong><br>
Reason: ${result.error}<br>
<small class="text-muted">
Make sure you've:<br>
1. Downloaded and extracted the extension<br>
2. Loaded it in Chrome at chrome://extensions/<br>
3. Enabled "Developer mode" first<br>
4. Refreshed this page after installation
</small>
</div>
`;
}
})
.catch(error => {
testResults.innerHTML = `
<div class="alert alert-danger">
<strong>❌ Test Failed</strong><br>
Error: ${error.message}<br>
<small class="text-muted">Chrome extension communication failed</small>
</div>
`;
})
.finally(() => {
this.innerHTML = originalText;
this.disabled = false;
});
});
// Show installation progress tips
// Test extension connection function
async function testExtensionConnection() {
return new Promise((resolve) => {
// Try to get extension ID from injected DOM element or use fallback
const extensionElement = document.getElementById('chrome-extension-id');
const extensionId = extensionElement ?
extensionElement.getAttribute('data-extension-id') :
'cifcoidplhgclhcnlcgdkjbaoempjmdl'; // Fallback
if (!window.chrome || !window.chrome.runtime) {
resolve({ success: false, error: 'Chrome runtime not available' });
return;
}
try {
chrome.runtime.sendMessage(extensionId, { action: 'ping' }, function(response) {
if (chrome.runtime.lastError) {
resolve({
success: false,
error: chrome.runtime.lastError.message,
extensionId: extensionId
});
} else if (response && response.success) {
resolve({
success: true,
extensionId: extensionId,
version: response.extension_version,
message: response.message
});
} else {
resolve({
success: false,
error: 'Extension ping failed - no response',
extensionId: extensionId
});
}
});
} catch (error) {
resolve({
success: false,
error: 'Exception: ' + error.message,
extensionId: extensionId
});
}
});
}
// Show installation tips
function showInstallationTips() {
const tips = [
'💡 Tip: The Windows service automatically starts with your computer',
'💡 Tip: Both components work together - install the service first',
'💡 Tip: Check the documentation for troubleshooting common issues',
'💡 Tip: This new approach is much simpler - no Windows service needed!',
'💡 Tip: The extension works on Windows, Mac, and Linux',
'💡 Tip: Users will see Chrome\'s print dialog for printer selection',
'💡 Tip: The system gracefully falls back to PDF downloads if needed'
];

View File

@@ -10,7 +10,7 @@
/* Inserted custom CSS from user */
.card.scan-table-card table.print-module-table.scan-table thead th {
border-bottom: 2e6 !important;
border-bottom: 2px solid #dee2e6 !important;
background-color: #f8f9fa !important;
padding: 0.25rem 0.4rem !important;
text-align: left !important;
@@ -602,211 +602,313 @@ function addFallbackPrintHandler() {
}
}
// Windows Print Service Integration
const PRINT_SERVICE_URL = 'http://localhost:8765';
let printServiceAvailable = false;
let availablePrinters = [];
// SIMPLIFIED CHROME EXTENSION PRINTING - NO WINDOWS SERVICE NEEDED
// Extension detection and communication
let extensionId = null;
let extensionReady = false;
// Check print service availability on page load
// Check extension availability on page load
window.addEventListener('DOMContentLoaded', function() {
checkPrintServiceAvailability();
initializePrinterDropdown();
detectExtension();
initializePrintButton();
});
function initializePrinterDropdown() {
const select = document.getElementById('printer-select');
if (!select) return;
// Detect Chrome extension
function detectExtension() {
// Method 1: Try to get extension ID from injected DOM element
const extensionElement = document.getElementById('chrome-extension-id');
if (extensionElement) {
extensionId = extensionElement.getAttribute('data-extension-id');
console.log('✅ Extension ID detected from DOM:', extensionId);
}
select.innerHTML = `
<option value="default">Default Printer</option>
<option value="detecting" disabled>Detecting printers...</option>
`;
// Method 2: Fallback to hardcoded extension ID
if (!extensionId) {
extensionId = 'cifcoidplhgclhcnlcgdkjbaoempjmdl'; // Hardcoded fallback
console.log(' Using fallback extension ID:', extensionId);
}
// Test extension communication
if (window.chrome && window.chrome.runtime) {
try {
chrome.runtime.sendMessage(extensionId, { action: 'ping' }, function(response) {
if (chrome.runtime.lastError) {
console.warn('❌ Extension not responding:', chrome.runtime.lastError.message);
extensionReady = false;
} else if (response && response.success) {
console.log('✅ Extension ready:', response);
extensionReady = true;
// Try to get available printers from extension
loadPrintersFromExtension();
} else {
console.warn('❌ Extension ping failed:', response);
extensionReady = false;
}
updatePrintButton(extensionReady);
});
} catch (error) {
console.error('❌ Extension communication error:', error);
extensionReady = false;
updatePrintButton(false);
}
} else {
console.warn('❌ Chrome runtime not available');
extensionReady = false;
updatePrintButton(false);
}
}
async function checkPrintServiceAvailability() {
const printerStatus = document.getElementById('printer-status');
// Load available printers from extension
function loadPrintersFromExtension() {
if (!extensionReady) return;
try {
printerStatus.textContent = 'Checking Windows Print Service...';
console.log(`🔍 Checking Windows Print Service at: ${PRINT_SERVICE_URL}/health`);
const response = await fetch(`${PRINT_SERVICE_URL}/health`, {
method: 'GET',
signal: AbortSignal.timeout(5000)
});
console.log(`📡 Service response status: ${response.status}`);
if (response.ok) {
const data = await response.json();
console.log('📋 Service response data:', data);
chrome.runtime.sendMessage(extensionId, { action: 'get_printers' }, function(response) {
if (chrome.runtime.lastError) {
console.warn('Failed to get printers:', chrome.runtime.lastError.message);
return;
}
printServiceAvailable = true;
console.log('✅ Windows Print Service is available and responding!');
updatePrintButtonForService(true);
updatePrinterStatus(`Windows Print Service detected (${data.platform || 'Unknown platform'})`);
await loadAvailablePrinters();
} else {
throw new Error(`Service responded with status ${response.status}`);
}
if (response && response.success && response.printers) {
updatePrinterDropdown(response.printers);
}
});
} catch (error) {
printServiceAvailable = false;
console.error('❌ Windows Print Service check failed:', error);
console.log(`🔧 Troubleshooting:
1. Is the service running? Check: sc query QualityLabelPrinting
2. Is port 8765 accessible? Try: http://localhost:8765/health in new tab
3. Service logs: C:\\Program Files\\QualityLabelPrinting\\PrintService\\print_service.log`);
updatePrintButtonForService(false);
updatePrinterStatus(`Windows Print Service not detected - ${error.message}`);
console.warn('Error loading printers:', error);
}
}
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() {
// Update printer dropdown with available printers
function updatePrinterDropdown(printers) {
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) => {
// Add common printer names that users might have
const commonPrinters = [
'Microsoft Print to PDF',
'Brother HL-L2340D',
'HP LaserJet',
'Canon PIXMA',
'Epson WorkForce',
'Samsung ML-1640',
'Zebra ZP 450'
];
commonPrinters.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;
}
option.value = printer;
option.textContent = printer;
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);
// Add separator
const separator = document.createElement('option');
separator.disabled = true;
separator.textContent = '── System Printers ──';
select.appendChild(separator);
// Add printers from extension response
if (printers && printers.length > 0) {
printers.forEach((printer, index) => {
const option = document.createElement('option');
option.value = printer.name || printer;
option.textContent = `${printer.display_name || printer.name || printer}`;
if (printer.is_default) {
option.textContent += ' (System Default)';
}
select.appendChild(option);
});
}
const printerStatus = document.getElementById('printer-status');
if (printerStatus && extensionReady) {
const totalPrinters = commonPrinters.length + (printers ? printers.length : 0);
printerStatus.textContent = `${totalPrinters} printer options available - select one above`;
printerStatus.style.color = '#28a745';
}
}
function updatePrinterStatus(message) {
const status = document.getElementById('printer-status');
if (status) {
status.textContent = message;
// Update print button based on extension availability
function updatePrintButton(isExtensionReady) {
const printButton = document.getElementById('print-label-btn');
const printerStatus = document.getElementById('printer-status');
if (!printButton) return;
if (isExtensionReady) {
printButton.innerHTML = '🖨️ Print Labels (Windows Service)';
printButton.title = 'Send PDF directly to Windows Print Service for silent printing';
printButton.style.background = '#28a745'; // Green
if (printerStatus) {
printerStatus.textContent = 'Chrome extension ready - Windows service mode enabled';
printerStatus.style.color = '#28a745';
}
// Update printer selection label for Windows service mode
const printerLabel = document.querySelector('label[for="printer-select"]');
if (printerLabel) {
printerLabel.innerHTML = '🖨️ Select Printer (Windows Service will print directly)';
}
} else {
printButton.innerHTML = '📄 Generate PDF';
printButton.title = 'Generate PDF for manual printing (Windows Service not available)';
printButton.style.background = '#007bff'; // Blue
if (printerStatus) {
printerStatus.textContent = 'Extension/Service not detected - PDF download mode';
printerStatus.style.color = '#6c757d';
}
// Update printer selection label for manual mode
const printerLabel = document.querySelector('label[for="printer-select"]');
if (printerLabel) {
printerLabel.innerHTML = '🖨️ Choose Printer (for reference only)';
}
}
}
// Initialize print button functionality
function initializePrintButton() {
const printButton = document.getElementById('print-label-btn');
if (!printButton) return;
// Remove any existing event listeners
const newButton = printButton.cloneNode(true);
printButton.parentNode.replaceChild(newButton, printButton);
newButton.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 = newButton.innerHTML;
newButton.innerHTML = '⏳ Processing...';
newButton.disabled = true;
try {
if (extensionReady) {
await printViaExtension(orderId, prodOrder, quantity);
} else {
await downloadPDFLabels(orderId, prodOrder, quantity);
}
} catch (error) {
console.error('Print operation failed:', error);
alert('❌ Print operation failed: ' + error.message);
} finally {
newButton.innerHTML = originalText;
newButton.disabled = false;
}
});
}
// Print via Chrome extension (communicates with Windows service)
async function printViaExtension(orderId, prodOrder, quantity) {
try {
// Get selected printer from dropdown
const selectedPrinter = getSelectedPrinter();
console.log(`🖨️ Selected printer for Windows service: ${selectedPrinter}`);
// Generate PDF first
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');
}
// Get PDF URL (or construct it)
let pdfUrl;
try {
const data = await pdfResponse.json();
pdfUrl = data.pdf_url || `/static/generated_labels/labels_${prodOrder}_qty${quantity}.pdf`;
} catch {
// If response is not JSON, construct URL
pdfUrl = `/static/generated_labels/labels_${prodOrder}_qty${quantity}.pdf`;
}
// Make URL absolute
const fullPdfUrl = window.location.origin + pdfUrl;
// Send to extension which will communicate with Windows service
chrome.runtime.sendMessage(extensionId, {
action: 'print_pdf',
pdfUrl: fullPdfUrl,
orderId: orderId,
prodOrder: prodOrder,
quantity: quantity,
printerName: selectedPrinter // Pass selected printer to extension
}, function(response) {
if (chrome.runtime.lastError) {
throw new Error('Extension communication failed: ' + chrome.runtime.lastError.message);
}
if (response && response.success) {
const printerInfo = selectedPrinter === 'default' ? 'default printer' : selectedPrinter;
let message = `✅ Print job sent to Windows service!\n\n📊 Order: ${prodOrder}\n📦 Quantity: ${quantity} labels\n🖨️ Target Printer: ${printerInfo}\n🔧 Method: ${response.method || 'Windows Print Service'}`;
if (response.instruction) {
message += `\n\n📋 Status: ${response.instruction}`;
} else {
message += `\n\n📋 The PDF has been sent directly to the printer queue`;
}
alert(message);
updatePrintedStatus(orderId);
} else if (response && response.fallback) {
// Service not available, handle fallback
alert(`⚠️ Windows Print Service not available.\n\nError: ${response.error}\n\n📋 Fallback: ${response.instruction}\n\nPlease ensure the Windows Print Service is installed and running.`);
// Still try to download PDF as fallback
await downloadPDFLabels(orderId, prodOrder, quantity);
} else {
throw new Error(response?.error || 'Extension print failed');
}
});
} catch (error) {
console.error('Extension print error:', error);
// Fallback to PDF download
alert(`❌ Print via Windows service failed.\n\nError: ${error.message}\n\n🔄 Falling back to PDF download for manual printing.`);
await downloadPDFLabels(orderId, prodOrder, quantity);
}
}
// Helper function to get selected printer
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 - NEW SERVER-SIDE APPROACH
async function printLabelsWithService(orderId, prodOrder, quantity) {
console.log(`🖨️ printLabelsWithService called - Order: ${orderId}, Quantity: ${quantity}`);
try {
// Get selected printer from dropdown
const selectedPrinter = getSelectedPrinter();
console.log(`🖨️ Selected printer: ${selectedPrinter}`);
// Use new server-side endpoint that bypasses CORS
const printData = {
printer_name: selectedPrinter
};
console.log('📋 Print request data:', printData);
console.log(`📡 Sending to server endpoint: /print_labels_silent/${orderId}`);
// Send to Flask server which handles Windows service communication
const response = await fetch(`/print_labels_silent/${orderId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(printData)
});
console.log(`📨 Server response status: ${response.status}`);
const result = await response.json();
console.log('📋 Server response data:', result);
if (response.ok && result.success) {
// Success - labels printed silently
const printerName = selectedPrinter === 'default' ? 'default printer' : selectedPrinter;
console.log(`✅ Print successful to printer: ${printerName}`);
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 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('❌ Server returned error:', result);
throw new Error(result.error || `Print operation failed with status ${response.status}`);
}
} catch (error) {
console.error('❌ Server-side print error:', error);
throw error;
}
}
// Fallback PDF download function
// Fallback: Download PDF for manual printing
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}`);
throw new Error(`HTTP ${response.status}`);
}
// Get filename from response headers
@@ -829,10 +931,7 @@ async function downloadPDFLabels(orderId, prodOrder, quantity) {
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;
alert(`📄 PDF downloaded successfully!\n\n📊 Order: ${prodOrder}\n📦 Quantity: ${quantity} labels\n📁 File: ${filename}\n\n➡️ Please print the PDF manually from your Downloads folder.`);
} catch (error) {
console.error('PDF download error:', error);
@@ -851,111 +950,13 @@ async function updatePrintedStatus(orderId) {
if (response.ok) {
// Refresh the orders table
setTimeout(() => {
document.getElementById('check-db-btn').click();
const checkButton = document.getElementById('check-db-btn');
if (checkButton) checkButton.click();
}, 1000);
}
} catch (error) {
console.warn('Failed to update printed status:', error);
}
}
// PDF generation handler
// Helper to get extension ID injected by content script, or fallback to hardcoded value
function getInjectedExtensionId() {
const el = document.getElementById('chrome-extension-id');
if (el) return el.getAttribute('data-extension-id');
// Fallback to hardcoded extension ID if not injected
return 'cifcoidplhgclhcnlcgdkjbaoempjmdl';
}
function addPDFGenerationHandler() {
const printButton = document.getElementById('print-label-btn');
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 {
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 %}