Files
quality_recticel/old code/backup/print_module copy.html
Quality System Admin 50c791e242 cleaning structure
2025-10-16 01:42:59 +03:00

1085 lines
51 KiB
HTML
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block head %}
<style>
#label-preview {
background: #fafafa;
position: relative;
overflow: hidden;
}
/* Inserted custom CSS from user */
.card.scan-table-card table.print-module-table.scan-table thead th {
border-bottom: 2px solid #dee2e6 !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;
} catch (error) {
console.error(' Extension communication error:', error);
extensionReady = false;
serviceMode = 'none';
updatePrintButton(false);
}
}
}
// Try alternative extension IDs if first one fails
function tryAlternativeExtensionIds() {
const alternatives = [
'kdhcldgldnpgbnpgbmbaobfhmgebfgoc',
'mpnmjmebdohmbibmnpdbgblfdbklpbng'
];
let currentIndex = 0;
function tryNext() {
if (currentIndex >= alternatives.length) {
console.warn(' No working extension found');
extensionReady = false;
serviceMode = 'none';
updatePrintButton(false);
return;
}
const altId = alternatives[currentIndex];
console.log(`🔄 Trying alternative extension ID: ${altId}`);
chrome.runtime.sendMessage(altId, { action: 'ping' }, function(response) {
if (chrome.runtime.lastError) {
currentIndex++;
tryNext();
} else if (response && response.success) {
extensionId = altId;
extensionReady = true;
serviceMode = response.mode || 'browser_only';
console.log(`✅ Alternative extension working: ${altId}, mode: ${serviceMode}`);
if (serviceMode === 'windows_service') {
testWindowsServiceConnection();
}
loadPrintersFromExtension();
updatePrintButton(true);
} else {
currentIndex++;
tryNext();
}
});
}
tryNext();
}
// Test direct Windows service connection
async function testWindowsServiceConnection() {
try {
const response = await fetch('http://localhost:8765/health', {
method: 'GET',
timeout: 5000
});
if (response.ok) {
const data = await response.json();
console.log(' Windows Print Service directly accessible:', data);
return true;
} else {
console.warn(' Windows Print Service not responding directly');
return false;
}
} catch (error) {
console.warn(' Windows Print Service not accessible directly:', error.message);
return false;
}ottom: 1rem !important;
color: #212529 !important;
border-collapse: collapse !important;
}
.card.scan-table-card table.print-module-table.scan-table thead th {
vertical-align: bottom !important;
border-bottom: 2px solid #dee2e6 !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;
}
.card.scan-table-card table.print-module-table.scan-table tbody td {
padding: 0.25rem 0.4rem !important;
vertical-align: middle !important;
border-top: 1px solid #dee2e6 !important;
font-size: 9px !important;
line-height: 1.2 !important;
}
/* HOVER EFFECTS - Higher specificity */
.card.scan-table-card table.print-module-table.scan-table tbody tr:hover td {
background-color: #f8f9fa !important;
cursor: pointer !important;
}
.card.scan-table-card table.print-module-table.scan-table tbody tr:not(.selected):hover td {
background-color: #f8f9fa !important;
}
/* ROW SELECTION STYLES - Maximum specificity */
.card.scan-table-card table.print-module-table.scan-table tbody tr.selected td {
background-color: #007bff !important;
background: #007bff !important;
color: white !important;
border-color: #0056b3 !important;
}
.card.scan-table-card table.print-module-table.scan-table tbody tr.selected:hover td {
background-color: #0056b3 !important;
background: #0056b3 !important;
color: white !important;
border-color: #004085 !important;
}
.card.scan-table-card table.print-module-table.scan-table tbody tr.selected td span {
color: white !important;
}
/* Additional universal overrides for selection */
tr.selected td {
background-color: #007bff !important;
background: #007bff !important;
color: white !important;
}
tbody tr.selected td {
background-color: #007bff !important;
background: #007bff !important;
color: white !important;
}
table tbody tr.selected td {
background-color: #007bff !important;
background: #007bff !important;
color: white !important;
}
/* COLUMN WIDTH SPECIFICATIONS - Higher specificity */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(1),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(1) { width: 50px !important; } /* ID */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(2),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(2) { width: 80px !important; } /* Comanda Productie */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(3),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(3) { width: 80px !important; } /* Cod Articol */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(4),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(4) { width: 150px !important; } /* Descr Com Prod */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(5),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(5) { width: 70px !important; } /* Cantitate */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(6),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(6) { width: 80px !important; } /* Data Livrare */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(7),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(7) { width: 75px !important; } /* Dimensiune */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(8),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(8) { width: 90px !important; } /* Com Achiz Client */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(9),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(9) { width: 70px !important; } /* Nr Linie */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(10),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(10) { width: 100px !important; } /* Customer Name */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(11),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(11) { width: 90px !important; } /* Customer Art Nr */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(12),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(12) { width: 70px !important; } /* Open Order */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(13),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(13) { width: 50px !important; } /* Line */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(14),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(14) { width: 70px !important; } /* Printed */
.card.scan-table-card table.print-module-table.scan-table th:nth-child(15),
.card.scan-table-card table.print-module-table.scan-table td:nth-child(15) { width: 100px !important; } /* Created */
</style>
{% endblock %}
{% block content %}
<div class="scan-container" style="display: flex; flex-direction: row; gap: 20px; width: 100%; align-items: flex-start;">
<!-- Label Preview Card -->
<div class="card scan-form-card" style="display: flex; flex-direction: column; justify-content: flex-start; align-items: center; min-height: 480px; width: 330px; flex-shrink: 0; position: relative;">
<div class="label-view-title" style="width: 100%; text-align: center; padding: 18px 0 0 0; font-size: 18px; font-weight: bold; letter-spacing: 0.5px;">Label View</div>
<h3 style="position: absolute; top: 15px; left: 15px; display: none;">Label Preview</h3>
<div id="label-preview" style="border: 1px solid #ddd; padding: 10px; position: relative; background: #fafafa; width: 301px; height: 434.7px;">
<!-- Label content rectangle -->
<div id="label-content" style="position: absolute; top: 65.7px; left: 11.34px; width: 227.4px; height: 321.3px; border: 2px solid #333; background: white;">
<!-- Top row content: Company name -->
<div style="position: absolute; top: 0; left: 0; right: 0; height: 32.13px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 12px; color: #000; z-index: 10;">
INNOFA RROMANIA SRL
</div>
<!-- Row 2 content: Customer Name -->
<div id="customer-name-row" style="position: absolute; top: 32.13px; left: 0; right: 0; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #000;">
<!-- Customer name will be populated here -->
</div>
<!-- Horizontal dividing lines for 9 rows (row 6 is double height) -->
<div style="position: absolute; top: 32.13px; left: 0; right: 0; height: 1px; background: #999;"></div>
<div style="position: absolute; top: 64.26px; left: 0; right: 0; height: 1px; background: #999;"></div>
<div style="position: absolute; top: 96.39px; left: 0; right: 0; height: 1px; background: #999;"></div>
<div style="position: absolute; top: 128.52px; left: 0; right: 0; height: 1px; background: #999;"></div>
<div style="position: absolute; top: 160.65px; left: 0; right: 0; height: 1px; background: #999;"></div>
<!-- Row 6 is double height for Description -->
<div style="position: absolute; top: 224.91px; left: 0; right: 0; height: 1px; background: #999;"></div>
<!-- Row 7 for Size -->
<div style="position: absolute; top: 257.04px; left: 0; right: 0; height: 1px; background: #999;"></div>
<!-- Row 8 for Article Code -->
<div style="position: absolute; top: 289.17px; left: 0; right: 0; height: 1px; background: #999;"></div>
<!-- Row 9 for Prod Order (final row) -->
<!-- Vertical dividing line starting from row 3 to bottom at 40% width -->
<div style="position: absolute; left: 90.96px; top: 64.26px; width: 1px; height: 257.04px; background: #999;"></div>
<!-- Row 3 content: Quantity ordered -->
<div style="position: absolute; top: 64.26px; left: 0; width: 90.96px; height: 32.13px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Quantity ordered
</div>
<div id="quantity-ordered-value" style="position: absolute; top: 64.26px; left: 90.96px; width: 136.44px; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: bold; color: #000;">
<!-- Quantity value will be populated here -->
</div>
<!-- Row 4 content: Customer order -->
<div style="position: absolute; top: 96.39px; left: 0; width: 90.96px; height: 32.13px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Customer order
</div>
<div id="client-order-info" style="position: absolute; top: 96.39px; left: 90.96px; width: 136.44px; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; color: #000;">
<!-- Client order info will be populated here -->
</div>
<!-- Row 5 content: Delivery date -->
<div style="position: absolute; top: 128.52px; left: 0; width: 90.96px; height: 32.13px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Delivery date
</div>
<div id="delivery-date-value" style="position: absolute; top: 128.52px; left: 90.96px; width: 136.44px; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; color: #000;">
<!-- Delivery date value will be populated here -->
</div>
<!-- Row 6 content: Description (double height row) -->
<div style="position: absolute; top: 160.65px; left: 0; width: 90.96px; height: 64.26px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Description
</div>
<div id="description-value" style="position: absolute; top: 160.65px; left: 90.96px; width: 136.44px; height: 64.26px; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: bold; color: #000; text-align: center; line-height: 1.2; padding: 2px; overflow: hidden; word-wrap: break-word;">
<!-- Description value will be populated here -->
</div>
<!-- Row 7 content: Size -->
<div style="position: absolute; top: 224.91px; left: 0; width: 90.96px; height: 32.13px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Size
</div>
<div id="size-value" style="position: absolute; top: 224.91px; left: 90.96px; width: 136.44px; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; color: #000;">
<!-- Size value will be populated here -->
</div>
<!-- Row 8 content: Article Code -->
<div style="position: absolute; top: 257.04px; left: 0; width: 90.96px; height: 32.13px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Article Code
</div>
<div id="article-code-value" style="position: absolute; top: 257.04px; left: 90.96px; width: 136.44px; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; color: #000;">
<!-- Article code value will be populated here -->
</div>
<!-- Row 9 content: Prod Order (final row) -->
<div style="position: absolute; top: 289.17px; left: 0; width: 90.96px; height: 32.13px; display: flex; align-items: center; padding-left: 5px; font-size: 10px; color: #000;">
Prod Order
</div>
<div id="prod-order-value" style="position: absolute; top: 289.17px; left: 90.96px; width: 136.44px; height: 32.13px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; color: #000;">
<!-- Prod order value will be populated here -->
</div>
</div>
<!-- Barcode Frame - positioned 10px below rectangle with 2mm side margins -->
<div id="barcode-frame" style="position: absolute; top: 395px; left: 7.56px; width: 295.44px; height: 50px; background: white; display: flex; flex-direction: column; align-items: center; justify-content: center;">
<!-- Code 128 Barcode representation -->
<div id="barcode-display" style="width: 100%; height: 45px; background: linear-gradient(90deg, #000 1px, transparent 1px, transparent 2px, #000 2px, transparent 3px, #000 4px, transparent 5px, #000 6px, transparent 7px, #000 8px, transparent 9px, #000 10px, transparent 11px, #000 12px, transparent 13px); background-size: 15px 100%; background-repeat: repeat-x;">
</div>
<!-- Barcode text below the bars -->
<div id="barcode-text" style="font-size: 8px; font-family: 'Courier New', monospace; margin-top: 2px; text-align: center; font-weight: bold;">
<!-- Barcode text will be populated here -->
</div>
</div>
<!-- Vertical Barcode Frame - positioned on the right side of the label -->
<div id="vertical-barcode-frame" style="position: absolute; top: 70px; left: 245px; width: 50px; height: 309.96px; background: white; display: flex; flex-direction: column; align-items: center; justify-content: center;">
<!-- Vertical Code 128 Barcode representation -->
<div id="vertical-barcode-display" style="width: 50px; height: 280px; background: linear-gradient(0deg, #000 1px, transparent 1px, transparent 2px, #000 2px, transparent 3px, #000 4px, transparent 5px, #000 6px, transparent 7px, #000 8px, transparent 9px, #000 10px, transparent 11px, #000 12px, transparent 13px); background-size: 100% 15px; background-repeat: repeat-y;">
</div>
<!-- Vertical barcode text -->
<div id="vertical-barcode-text" style="font-size: 6px; font-family: 'Courier New', monospace; margin-top: 5px; text-align: center; font-weight: bold; writing-mode: vertical-rl; text-orientation: mixed;">
<!-- Vertical barcode text will be populated here -->
</div>
</div>
</div>
<!-- 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>
<!-- Print Button Section -->
<div style="width: 100%; display: flex; justify-content: center; align-items: center; gap: 12px; margin-top: 15px;">
<label for="print-label-btn" style="font-size: 14px; font-weight: 500; color: var(--app-card-text); margin-bottom: 0;">Generate PDF Labels (80x110mm)</label>
<button id="print-label-btn" class="btn btn-success" style="font-size: 14px; padding: 8px 28px; border-radius: 6px;">📄 Generate PDF</button>
</div>
<div style="width: 100%; text-align: center; margin-top: 8px; color: #6c757d; font-size: 12px;">
Creates sequential labels based on quantity (e.g., CP00000711-001 to CP00000711-063)
</div>
<div style="width: 100%; text-align: center; margin-top: 12px;">
<small style="font-size: 11px; color: #6c757d;">
<20> PDF labels can be printed directly from your browser or saved for later use
</small>
</div>
</div>
<!-- Data Preview Card -->
<div class="card scan-table-card" style="min-height: 700px; width: calc(100% - 350px); margin: 0;">
<h3>Data Preview (Unprinted Orders)</h3>
<button id="check-db-btn" class="btn btn-primary mb-3">Check Database</button>
<div class="report-table-container">
<table class="scan-table print-module-table">
<thead>
<tr>
<th>ID</th>
<th>Comanda<br>Productie</th>
<th>Cod<br>Articol</th>
<th>Descr. Com.<br>Prod</th>
<th>Cantitate</th>
<th>Data<br>Livrare</th>
<th>Dimensiune</th>
<th>Com.Achiz.<br>Client</th>
<th>Nr.<br>Linie</th>
<th>Customer<br>Name</th>
<th>Customer<br>Art. Nr.</th>
<th>Open<br>Order</th>
<th>Line</th>
<th>Printed</th>
<th>Created</th>
</tr>
</thead>
<tbody id="unprinted-orders-table">
<!-- Data will be loaded here via JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
<script>
document.getElementById('check-db-btn').addEventListener('click', function() {
console.log('🔍 Check Database button clicked - starting request...');
// Show loading state
const button = this;
const originalText = button.textContent;
button.textContent = 'Loading...';
button.disabled = true;
fetch('/get_unprinted_orders')
.then(response => {
console.log('🔍 Response status:', response.status);
console.log('🔍 Response headers:', response.headers);
if (response.status === 403) {
return response.json().then(errorData => {
console.error('❌ Access denied:', errorData);
throw new Error(`Access Denied: ${errorData.error}`);
});
} else if (!response.ok) {
return response.text().then(text => {
console.error('❌ HTTP error:', response.status, text);
throw new Error(`HTTP ${response.status}: ${text}`);
});
}
return response.json();
})
.then(data => {
console.log('Received data:', data);
const tbody = document.getElementById('unprinted-orders-table');
tbody.innerHTML = '';
data.forEach((order, index) => {
const tr = document.createElement('tr');
tr.dataset.orderId = order.id;
tr.dataset.orderIndex = index;
tr.style.cursor = 'pointer';
tr.innerHTML = `
<td style="font-size: 9px;">${order.id}</td>
<td style="font-size: 9px;"><strong>${order.comanda_productie}</strong></td>
<td style="font-size: 9px;">${order.cod_articol || '-'}</td>
<td style="font-size: 9px;">${order.descr_com_prod}</td>
<td style="text-align: right; font-weight: 600; font-size: 9px;">${order.cantitate}</td>
<td style="text-align: center; font-size: 9px;">
${order.data_livrare ? new Date(order.data_livrare).toLocaleDateString() : '-'}
</td>
<td style="text-align: center; font-size: 9px;">${order.dimensiune || '-'}</td>
<td style="font-size: 9px;">${order.com_achiz_client || '-'}</td>
<td style="text-align: right; font-size: 9px;">${order.nr_linie_com_client || '-'}</td>
<td style="font-size: 9px;">${order.customer_name || '-'}</td>
<td style="font-size: 9px;">${order.customer_article_number || '-'}</td>
<td style="font-size: 9px;">${order.open_for_order || '-'}</td>
<td style="text-align: right; font-size: 9px;">${order.line_number || '-'}</td>
<td style="text-align: center; font-size: 9px;">
${order.printed_labels == 1 ?
'<span style="color: #28a745; font-weight: bold;">✓ Yes</span>' :
'<span style="color: #dc3545;">✗ No</span>'}
</td>
<td style="font-size: 9px; color: #6c757d;">
${order.created_at ? new Date(order.created_at).toLocaleString() : '-'}
</td>
`;
// Add click event for row selection
tr.addEventListener('click', function() {
console.log('Row clicked:', order.order_number);
// Remove selection from other rows
document.querySelectorAll('.print-module-table tbody tr').forEach(row => {
row.classList.remove('selected');
// Clear inline styles
const cells = row.querySelectorAll('td');
cells.forEach(cell => {
cell.style.backgroundColor = '';
cell.style.color = '';
});
});
// Select this row
this.classList.add('selected');
console.log('Row selected, classes:', this.className);
// Force visual selection with inline styles
const cells = this.querySelectorAll('td');
cells.forEach(cell => {
cell.style.backgroundColor = '#007bff';
cell.style.color = 'white';
});
// Update label preview with selected order data
updateLabelPreview(order);
});
tbody.appendChild(tr);
});
// Update the label preview with first row by default
if (data.length > 0) {
updateLabelPreview(data[0]);
// Add fallback print functionality if extension is not available
addFallbackPrintHandler();
// Auto-select first row
setTimeout(() => {
const firstRow = document.querySelector('.print-module-table tbody tr');
if (firstRow) {
firstRow.classList.add('selected');
}
}, 100);
} else {
document.getElementById('customer-name-row').textContent = 'No data available';
document.getElementById('quantity-ordered-value').textContent = '0';
document.getElementById('client-order-info').textContent = 'N/A';
document.getElementById('delivery-date-value').textContent = 'N/A';
document.getElementById('size-value').textContent = 'N/A';
document.getElementById('description-value').textContent = 'N/A';
document.getElementById('article-code-value').textContent = 'N/A';
document.getElementById('prod-order-value').textContent = 'N/A';
document.getElementById('barcode-text').textContent = 'N/A';
document.getElementById('vertical-barcode-text').textContent = '000000-00';
}
})
.catch(error => {
console.error('Error fetching data:', error);
// Show user-friendly error message
const errorMessage = error.message || 'Unknown error occurred';
const tbody = document.getElementById('unprinted-orders-table');
let helpText;
if (errorMessage.includes('Access Denied')) {
helpText = '<em>Please ensure you are logged in with appropriate permissions (superadmin, warehouse_manager, or etichete role)</em>';
} else {
helpText = '<em>Please check your network connection and try again</em>';
}
tbody.innerHTML = '<tr><td colspan="15" style="text-align: center; padding: 20px; color: #dc3545;"><strong>❌ Failed to load data</strong><br><small>' + errorMessage + '</small><br><br>' + helpText + '</td></tr>';
// Also update label preview with error
document.getElementById('customer-name-row').textContent = 'Error loading data';
document.getElementById('quantity-ordered-value').textContent = 'Error';
document.getElementById('client-order-info').textContent = 'Error';
document.getElementById('delivery-date-value').textContent = 'Error';
document.getElementById('size-value').textContent = 'Error';
document.getElementById('description-value').textContent = 'Error';
document.getElementById('article-code-value').textContent = 'Error';
document.getElementById('prod-order-value').textContent = 'Error';
document.getElementById('barcode-text').textContent = 'Error';
document.getElementById('vertical-barcode-text').textContent = '000000-00';
// Reset button state
button.textContent = originalText;
button.disabled = false;
});
});
// Function to update label preview with selected order data
function updateLabelPreview(order) {
const customerName = order.customer_name || 'N/A';
document.getElementById('customer-name-row').textContent = customerName;
// Update quantity ordered value
const quantity = order.cantitate || '0';
document.getElementById('quantity-ordered-value').textContent = quantity;
// Update client order info (Com.Achiz.Client - Nr. Linie)
const comAchizClient = order.com_achiz_client || '';
const nrLinie = order.nr_linie_com_client || '';
const clientOrderInfo = comAchizClient && nrLinie ? `${comAchizClient}-${nrLinie}` : 'N/A';
document.getElementById('client-order-info').textContent = clientOrderInfo;
// Update vertical barcode with client order info or default
const verticalBarcodeData = clientOrderInfo !== 'N/A' ? clientOrderInfo : '000000-00';
document.getElementById('vertical-barcode-text').textContent = verticalBarcodeData;
// Update delivery date (using data_livrare column)
const deliveryDate = order.data_livrare ? new Date(order.data_livrare).toLocaleDateString() : 'N/A';
document.getElementById('delivery-date-value').textContent = deliveryDate;
// Update size (using dimensiune column)
const size = order.dimensiune || 'N/A';
document.getElementById('size-value').textContent = size;
// Update description (Descr. Com. Prod)
const description = order.descr_com_prod || 'N/A';
document.getElementById('description-value').textContent = description;
// Update article code (using customer_article_number column)
const articleCode = order.customer_article_number || 'N/A';
document.getElementById('article-code-value').textContent = articleCode;
// Update prod order (comanda_productie - cantitate)
const comandaProductie = order.comanda_productie || '';
const cantitate = order.cantitate || '';
const prodOrder = comandaProductie && cantitate ? `${comandaProductie}-${cantitate}` : 'N/A';
document.getElementById('prod-order-value').textContent = prodOrder;
// Update barcode with the same prod order data
document.getElementById('barcode-text').textContent = prodOrder;
}
// PDF Generation System - No printer setup needed
// Labels are generated as PDF files for universal compatibility
// Legacy function name - now handles PDF generation
function addFallbackPrintHandler() {
// Initialize PDF print button
const printButton = document.getElementById('print-label-btn');
if (printButton) {
// Update button text and appearance for PDF generation
printButton.innerHTML = '<27> Generate PDF Labels';
printButton.title = 'Generate PDF with multiple labels based on quantity';
printButton.addEventListener('click', 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 quantityCell = selectedRow.querySelector('td:nth-child(5)'); // Cantitate column
const quantity = quantityCell ? parseInt(quantityCell.textContent) : 1;
const prodOrderCell = selectedRow.querySelector('td:nth-child(2)'); // Comanda Productie column
const prodOrder = prodOrderCell ? prodOrderCell.textContent.trim() : 'N/A';
if (!orderId) {
alert('Could not determine order ID. Please refresh and try again.');
return;
}
// Show loading state
const originalText = this.textContent;
this.textContent = 'Generating PDF...';
this.disabled = true;
console.log(`Generating PDF for order ${orderId} with ${quantity} labels`);
// Generate PDF
fetch(`/generate_labels_pdf/${orderId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.blob();
})
.then(blob => {
// Create download link for PDF
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `labels_${prodOrder}_${quantity}pcs.pdf`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
// Also open PDF in new tab for printing
const printWindow = window.open(url, '_blank');
printWindow.focus();
// Show success message
alert(`✅ PDF generated successfully!\n📊 Order: ${prodOrder}\n📦 Labels: ${quantity} pieces\n\nThe PDF has been downloaded and opened for printing.`);
// Refresh the orders table to reflect printed status
document.getElementById('check-db-btn').click();
})
.catch(error => {
console.error('Error generating PDF:', error);
alert('❌ Failed to generate PDF labels. Error: ' + error.message);
})
.finally(() => {
// Reset button state
this.textContent = originalText;
this.disabled = false;
});
});
}
}
// ENHANCED CHROME EXTENSION + WINDOWS SERVICE DETECTION
// Extension detection and communication
let extensionId = null;
let extensionReady = false;
let serviceMode = 'unknown'; // 'windows_service', 'browser_only', or 'none'
// Check extension availability on page load
window.addEventListener('DOMContentLoaded', function() {
detectExtension();
initializePrintButton();
});
// Detect Chrome extension and determine mode
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);
}
// Method 2: Try common extension IDs for our service
const possibleExtensionIds = [
'cifcoidplhgclhcnlcgdkjbaoempjmdl', // Default fallback
'kdhcldgldnpgbnpgbmbaobfhmgebfgoc', // Alternative ID
'mpnmjmebdohmbibmnpdbgblfdbklpbng' // Another alternative
];
if (!extensionId) {
// Try each possible extension ID
extensionId = possibleExtensionIds[0];
console.log(' Using fallback extension ID:', extensionId);
}
// Test extension communication
if (window.chrome && window.chrome.runtime) {
testExtensionCommunication();
} else {
console.warn('❌ Chrome runtime not available');
extensionReady = false;
serviceMode = 'none';
updatePrintButton(false);
}
}
// Test communication with extension and detect service mode
function testExtensionCommunication() {
try {
chrome.runtime.sendMessage(extensionId, { action: 'ping' }, function(response) {
if (chrome.runtime.lastError) {
console.warn('❌ Extension not responding:', chrome.runtime.lastError.message);
// Try alternative extension IDs
tryAlternativeExtensionIds();
} else if (response && response.success) {
console.log('✅ Extension ready:', response);
extensionReady = true;
// Determine service mode based on response
if (response.mode === 'windows_service') {
serviceMode = 'windows_service';
console.log('🔧 Windows Service mode detected');
// Also test direct service connection
testWindowsServiceConnection();
} else {
serviceMode = 'browser_only';
console.log('🌐 Browser-only mode detected');
}
// Load printers based on mode
loadPrintersFromExtension();
updatePrintButton(extensionReady);
} else {
console.warn('❌ Extension ping failed:', response);
extensionReady = false;
serviceMode = 'none';
updatePrintButton(false);
}
});
} catch (error) {
console.error('❌ Extension communication error:', error);
extensionReady = false;
updatePrintButton(false);
}
} else {
console.warn('❌ Chrome runtime not available');
extensionReady = false;
updatePrintButton(false);
}
}
// Load available printers from extension
function loadPrintersFromExtension() {
if (!extensionReady) return;
try {
chrome.runtime.sendMessage(extensionId, { action: 'get_printers' }, function(response) {
if (chrome.runtime.lastError) {
console.warn('Failed to get printers:', chrome.runtime.lastError.message);
return;
}
if (response && response.success && response.printers) {
updatePrinterDropdown(response.printers);
}
});
} catch (error) {
console.warn('Error loading printers:', error);
}
}
// 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>';
// 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;
option.textContent = printer;
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';
}
}
// 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';
}
// Fallback: Download PDF for manual printing
async function downloadPDFLabels(orderId, prodOrder, quantity) {
try {
const response = await fetch(`/generate_labels_pdf/${orderId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (!response.ok) {
throw new 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);
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);
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(() => {
const checkButton = document.getElementById('check-db-btn');
if (checkButton) checkButton.click();
}, 1000);
}
} catch (error) {
console.warn('Failed to update printed status:', error);
}
}
</script>
{% endblock %}