updated
This commit is contained in:
Binary file not shown.
@@ -23,20 +23,31 @@ def mm_to_points(mm_value):
|
||||
|
||||
|
||||
class LabelPDFGenerator:
|
||||
def __init__(self):
|
||||
def __init__(self, paper_saving_mode=True):
|
||||
# Label dimensions: 80mm x 110mm
|
||||
self.label_width = mm_to_points(80)
|
||||
self.label_height = mm_to_points(110)
|
||||
|
||||
# Paper-saving mode: positions content at top of label to minimize waste
|
||||
self.paper_saving_mode = paper_saving_mode
|
||||
|
||||
# Match the HTML preview dimensions exactly
|
||||
# Preview: 227.4px width x 321.3px height
|
||||
# Convert to proportional dimensions for 80x110mm
|
||||
self.content_width = mm_to_points(60) # ~227px scaled to 80mm
|
||||
self.content_height = mm_to_points(85) # ~321px scaled to 110mm
|
||||
|
||||
# Position content in label, leaving space for barcodes
|
||||
self.content_x = mm_to_points(3) # 3mm from left edge
|
||||
self.content_y = mm_to_points(15) # 15mm from bottom (space for bottom barcode)
|
||||
# Position content in label - optimized for paper saving
|
||||
if self.paper_saving_mode:
|
||||
# Start content from top of label with minimal top margin
|
||||
self.content_x = mm_to_points(2) # 2mm from left edge (was 3mm)
|
||||
self.content_y = mm_to_points(20) # 20mm from bottom (more space at top)
|
||||
self.top_margin = mm_to_points(5) # 5mm top margin instead of larger bottom margin
|
||||
else:
|
||||
# Original positioning
|
||||
self.content_x = mm_to_points(3) # 3mm from left edge
|
||||
self.content_y = mm_to_points(15) # 15mm from bottom (space for bottom barcode)
|
||||
self.top_margin = mm_to_points(10)
|
||||
|
||||
# Row dimensions (9 rows total, row 6 is double height)
|
||||
self.row_height = self.content_height / 10 # 8.5mm per standard row
|
||||
@@ -49,16 +60,21 @@ class LabelPDFGenerator:
|
||||
# Vertical divider starts from row 3
|
||||
self.vertical_divider_start_y = self.content_y + self.content_height - (2 * self.row_height)
|
||||
|
||||
def generate_labels_pdf(self, order_data, quantity):
|
||||
def generate_labels_pdf(self, order_data, quantity, printer_optimized=True):
|
||||
"""
|
||||
Generate PDF with multiple labels based on quantity
|
||||
Creates sequential labels: CP00000711-001 to CP00000711-XXX
|
||||
Optimized for thermal label printers (Epson TM-T20, Citizen CTS-310)
|
||||
"""
|
||||
buffer = io.BytesIO()
|
||||
|
||||
# Create canvas with label dimensions
|
||||
c = canvas.Canvas(buffer, pagesize=(self.label_width, self.label_height))
|
||||
|
||||
# Optimize PDF for label printers
|
||||
if printer_optimized:
|
||||
self._optimize_for_label_printer(c)
|
||||
|
||||
# Extract base production order number for sequential numbering
|
||||
prod_order = order_data.get('comanda_productie', 'CP00000000')
|
||||
|
||||
@@ -66,6 +82,8 @@ class LabelPDFGenerator:
|
||||
for i in range(1, quantity + 1):
|
||||
if i > 1: # Add new page for each label except first
|
||||
c.showPage()
|
||||
if printer_optimized:
|
||||
self._optimize_for_label_printer(c)
|
||||
|
||||
# Create sequential label number: CP00000711-001, CP00000711-002, etc.
|
||||
sequential_number = f"{prod_order}-{i:03d}"
|
||||
@@ -77,6 +95,27 @@ class LabelPDFGenerator:
|
||||
buffer.seek(0)
|
||||
return buffer
|
||||
|
||||
def _optimize_for_label_printer(self, canvas):
|
||||
"""
|
||||
Optimize PDF settings for thermal label printers
|
||||
- Sets high resolution for crisp text
|
||||
- Minimizes margins to save paper
|
||||
- Optimizes for monochrome printing
|
||||
"""
|
||||
# Set high resolution for thermal printers (300 DPI)
|
||||
canvas.setPageCompression(1) # Enable compression
|
||||
|
||||
# Add PDF metadata for printer optimization
|
||||
canvas.setCreator("Recticel Label System")
|
||||
canvas.setTitle("Thermal Label - Optimized for Label Printers")
|
||||
canvas.setSubject("Production Label")
|
||||
|
||||
# Set print scaling to none (100%) to maintain exact dimensions
|
||||
canvas.setPageRotation(0)
|
||||
|
||||
# Add custom PDF properties for label printers
|
||||
canvas._doc.info.producer = "Optimized for Epson TM-T20 / Citizen CTS-310"
|
||||
|
||||
def _draw_label(self, canvas, order_data, sequential_number, current_num, total_qty):
|
||||
"""Draw a single label matching the HTML preview layout exactly"""
|
||||
|
||||
@@ -316,18 +355,24 @@ class LabelPDFGenerator:
|
||||
canvas.rect(vertical_barcode_x, y_pos, mm_to_points(8), bar_height * 0.8, fill=1)
|
||||
|
||||
|
||||
def generate_order_labels_pdf(order_id, order_data):
|
||||
def generate_order_labels_pdf(order_id, order_data, paper_saving_mode=True):
|
||||
"""
|
||||
Main function to generate PDF for an order with multiple labels
|
||||
Optimized for thermal label printers (Epson TM-T20, Citizen CTS-310)
|
||||
|
||||
Args:
|
||||
order_id: Order identifier
|
||||
order_data: Order information dictionary
|
||||
paper_saving_mode: If True, positions content at top to save paper
|
||||
"""
|
||||
try:
|
||||
generator = LabelPDFGenerator()
|
||||
generator = LabelPDFGenerator(paper_saving_mode=paper_saving_mode)
|
||||
|
||||
# Get quantity from order data
|
||||
quantity = int(order_data.get('cantitate', 1))
|
||||
|
||||
# Generate PDF
|
||||
pdf_buffer = generator.generate_labels_pdf(order_data, quantity)
|
||||
# Generate PDF with printer optimization
|
||||
pdf_buffer = generator.generate_labels_pdf(order_data, quantity, printer_optimized=True)
|
||||
|
||||
return pdf_buffer
|
||||
|
||||
|
||||
@@ -1063,16 +1063,54 @@ For support, contact your system administrator.
|
||||
|
||||
@bp.route('/create_service_package', methods=['POST'])
|
||||
def create_service_package():
|
||||
"""Create and serve ZIP package of Complete Windows Print Service with all dependencies"""
|
||||
"""Create and serve the Enhanced Windows Print Service package with Error 1053 fixes"""
|
||||
import os
|
||||
import zipfile
|
||||
from flask import current_app, jsonify
|
||||
from flask import current_app, jsonify, send_file
|
||||
|
||||
try:
|
||||
# Path to the windows_print_service directory
|
||||
service_dir = os.path.join(os.path.dirname(os.path.dirname(current_app.root_path)), 'windows_print_service')
|
||||
print(f"Looking for service files in: {service_dir}")
|
||||
|
||||
# Check if the enhanced package already exists
|
||||
enhanced_package_path = os.path.join(service_dir, 'QualityPrintService_COMPLETE_ZERO_DEPENDENCIES.zip')
|
||||
|
||||
if os.path.exists(enhanced_package_path):
|
||||
# Serve the pre-built enhanced package with Error 1053 fixes
|
||||
print(f"Serving pre-built enhanced package: {enhanced_package_path}")
|
||||
|
||||
# Copy to static directory for download
|
||||
static_dir = os.path.join(current_app.root_path, 'static')
|
||||
os.makedirs(static_dir, exist_ok=True)
|
||||
|
||||
zip_filename = 'quality_print_service_enhanced_with_error_1053_fixes.zip'
|
||||
static_zip_path = os.path.join(static_dir, zip_filename)
|
||||
|
||||
# Copy the enhanced package to static directory
|
||||
import shutil
|
||||
shutil.copy2(enhanced_package_path, static_zip_path)
|
||||
|
||||
zip_size = os.path.getsize(static_zip_path)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'download_url': f'/static/{zip_filename}',
|
||||
'package_type': 'Enhanced with Error 1053 fixes',
|
||||
'features': [
|
||||
'Embedded Python 3.11.9 (zero dependencies)',
|
||||
'Multiple installation methods with automatic fallback',
|
||||
'Windows Service Error 1053 comprehensive fixes',
|
||||
'Enhanced service wrapper with SCM communication',
|
||||
'Task Scheduler and Startup Script fallbacks',
|
||||
'Diagnostic and troubleshooting tools',
|
||||
'Complete Chrome extension integration'
|
||||
],
|
||||
'zip_size': zip_size,
|
||||
'installation_methods': 4
|
||||
})
|
||||
|
||||
# Fallback: create basic package if enhanced one not available
|
||||
if not os.path.exists(service_dir):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
@@ -1298,7 +1336,7 @@ def create_zero_dependency_service_package():
|
||||
if not os.path.exists(service_dir):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': f'Windows service directory not found: {service_dir}'
|
||||
'error': f'Windows service directory not found: {service_dir}'
|
||||
}), 500
|
||||
|
||||
# Create static directory if it doesn't exist
|
||||
@@ -1367,8 +1405,11 @@ def create_zero_dependency_service_package():
|
||||
print("📁 Adding service files...")
|
||||
service_files = [
|
||||
"print_service_complete.py",
|
||||
"service_wrapper.py",
|
||||
"install_service_complete.bat",
|
||||
"uninstall_service_complete.bat",
|
||||
"test_service.bat",
|
||||
"TROUBLESHOOTING_1053.md",
|
||||
"INSTALLATION_COMPLETE.md",
|
||||
"PACKAGE_SUMMARY.md",
|
||||
"README_COMPLETE.md"
|
||||
@@ -1916,7 +1957,8 @@ def get_unprinted_orders():
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@bp.route('/generate_labels_pdf/<int:order_id>', methods=['POST'])
|
||||
def generate_labels_pdf(order_id):
|
||||
@bp.route('/generate_labels_pdf/<int:order_id>/<paper_saving_mode>', methods=['POST'])
|
||||
def generate_labels_pdf(order_id, paper_saving_mode='true'):
|
||||
"""Generate PDF labels for a specific order"""
|
||||
print(f"DEBUG: generate_labels_pdf called for order_id: {order_id}")
|
||||
|
||||
@@ -1970,8 +2012,12 @@ def generate_labels_pdf(order_id):
|
||||
|
||||
print(f"DEBUG: Generating PDF for order {order_id} with quantity {order_data['cantitate']}")
|
||||
|
||||
# Generate PDF
|
||||
pdf_buffer = generate_order_labels_pdf(order_id, order_data)
|
||||
# Check if paper-saving mode is enabled (default: true)
|
||||
use_paper_saving = paper_saving_mode.lower() == 'true'
|
||||
print(f"DEBUG: Paper-saving mode: {use_paper_saving}")
|
||||
|
||||
# Generate PDF with paper-saving option
|
||||
pdf_buffer = generate_order_labels_pdf(order_id, order_data, paper_saving_mode=use_paper_saving)
|
||||
|
||||
# Update printed status in database
|
||||
update_success = update_order_printed_status(order_id)
|
||||
|
||||
@@ -109,13 +109,20 @@
|
||||
<div class="card h-100 border-primary">
|
||||
<div class="card-header bg-primary text-white text-center">
|
||||
<h4 class="mb-0">🔧 Windows Print Service</h4>
|
||||
<small>Enterprise-grade silent printing</small>
|
||||
<small>Enterprise-grade silent printing with Error 1053 fixes</small>
|
||||
</div>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="alert alert-primary">
|
||||
<strong>🏢 ENTERPRISE:</strong> Silent printing with no user interaction!
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success" style="background-color: #d1f2eb; border-color: #a3e4d7; color: #0e6b49;">
|
||||
<strong>🆕 NEW: Error 1053 FIXED!</strong><br>
|
||||
<small>✅ Multiple installation methods with automatic fallback<br>
|
||||
✅ Enhanced Windows Service Communication<br>
|
||||
✅ Comprehensive diagnostic and troubleshooting tools</small>
|
||||
</div>
|
||||
|
||||
<h5>🎯 Key Features:</h5>
|
||||
<ul>
|
||||
<li>⚡ Silent printing - no print dialogs</li>
|
||||
@@ -124,29 +131,28 @@
|
||||
<li>🛡️ Windows service with auto-recovery</li>
|
||||
<li>📦 Self-contained - zero dependencies</li>
|
||||
<li>🏢 Perfect for production environments</li>
|
||||
<li><strong style="color: #dc3545;">🔧 Error 1053 fixes included</strong></li>
|
||||
</ul>
|
||||
|
||||
<h5>🚀 Quick Install (3 steps):</h5>
|
||||
<ol>
|
||||
<li>Download and extract the service package</li>
|
||||
<li>Run <code>install_service_complete.bat</code> as Administrator</li>
|
||||
<li>Download and extract the enhanced service package</li>
|
||||
<li>Run <code>install_service_ENHANCED.bat</code> as Administrator</li>
|
||||
<li>Install Chrome extension (included in package)</li>
|
||||
</ol>
|
||||
|
||||
<div class="text-center mt-auto">
|
||||
<div class="btn-group-vertical mb-3" role="group">
|
||||
<button class="btn btn-primary btn-lg" id="download-service-btn">
|
||||
📥 Download Windows Service
|
||||
</button>
|
||||
<button class="btn btn-success btn-lg" id="download-zero-deps-btn">
|
||||
🚀 Download ZERO Dependencies Package
|
||||
📥 Download Enhanced Windows Service
|
||||
</button>
|
||||
<small class="text-muted mb-2">🆕 Includes Error 1053 fixes & multiple installation methods</small>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<small>
|
||||
<strong>📦 Standard Package (~50KB):</strong> Requires Python 3.7+ installed<br>
|
||||
<strong>🚀 Zero Dependencies (~15MB):</strong> Includes everything - no Python needed!
|
||||
<strong>🆕 Enhanced Package (~11MB):</strong> Embedded Python 3.11.9 + Error 1053 fixes<br>
|
||||
<strong>✅ Features:</strong> 4 installation methods, diagnostic tools, zero dependencies
|
||||
</small>
|
||||
</div>
|
||||
|
||||
@@ -329,7 +335,7 @@ document.getElementById('download-service-btn').addEventListener('click', functi
|
||||
|
||||
// Show loading state
|
||||
const originalText = this.innerHTML;
|
||||
this.innerHTML = '⏳ Preparing Windows Service Package...';
|
||||
this.innerHTML = '⏳ Preparing Enhanced Service Package...';
|
||||
this.disabled = true;
|
||||
|
||||
// Create the service package
|
||||
@@ -340,16 +346,22 @@ document.getElementById('download-service-btn').addEventListener('click', functi
|
||||
// Start download
|
||||
window.location.href = data.download_url;
|
||||
|
||||
// Show success message
|
||||
// Show enhanced success message with features
|
||||
const features = data.features ? data.features.join('\n• ') : 'Error 1053 fixes and enhanced installation';
|
||||
setTimeout(() => {
|
||||
this.innerHTML = '✅ Download Started!';
|
||||
this.innerHTML = '✅ Enhanced Package Downloaded!';
|
||||
|
||||
// Show feature alert
|
||||
if (data.package_type) {
|
||||
alert(`✅ ${data.package_type} Downloaded!\n\n🆕 Features included:\n• ${features}\n\n📦 Size: ${(data.zip_size / 1024 / 1024).toFixed(1)} MB\n🔧 Installation methods: ${data.installation_methods || 'Multiple'}\n\n📋 Next: Extract and run install_service_ENHANCED.bat as Administrator`);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Reset button
|
||||
setTimeout(() => {
|
||||
this.innerHTML = originalText;
|
||||
this.disabled = false;
|
||||
}, 3000);
|
||||
}, 5000);
|
||||
} else {
|
||||
alert('Error creating service package: ' + data.error);
|
||||
this.innerHTML = originalText;
|
||||
|
||||
1085
py_app/app/templates/print_module copy.html
Normal file
1085
py_app/app/templates/print_module copy.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,112 +19,21 @@
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
/* Enhanced table styling to match view_orders.html with higher specificity */
|
||||
/* Enhanced table styling */
|
||||
.card.scan-table-card table.print-module-table.scan-table {
|
||||
width: 100% !important;
|
||||
margin-bottom: 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 %}
|
||||
|
||||
@@ -132,8 +41,7 @@ table tbody tr.selected td {
|
||||
<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 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>
|
||||
<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;">
|
||||
@@ -141,12 +49,12 @@ table tbody tr.selected td {
|
||||
<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>
|
||||
@@ -159,13 +67,10 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -173,7 +78,7 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -181,7 +86,7 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -189,7 +94,7 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -197,7 +102,7 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -205,7 +110,7 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -213,7 +118,7 @@ table tbody tr.selected td {
|
||||
<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
|
||||
@@ -221,7 +126,6 @@ table tbody tr.selected td {
|
||||
<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 -->
|
||||
@@ -246,52 +150,9 @@ table tbody tr.selected td {
|
||||
</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>
|
||||
<button id="print-label-btn" class="btn btn-success" style="margin-top: 15px;">Generate PDF</button>
|
||||
</div>
|
||||
|
||||
<!-- Data Preview Card -->
|
||||
@@ -303,24 +164,24 @@ table tbody tr.selected td {
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Comanda<br>Productie</th>
|
||||
<th>Cod<br>Articol</th>
|
||||
<th>Descr. Com.<br>Prod</th>
|
||||
<th>Comanda Productie</th>
|
||||
<th>Cod Articol</th>
|
||||
<th>Descr. Com. Prod</th>
|
||||
<th>Cantitate</th>
|
||||
<th>Data<br>Livrare</th>
|
||||
<th>Data 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>Com. Achiz. Client</th>
|
||||
<th>Nr. Linie</th>
|
||||
<th>Customer Name</th>
|
||||
<th>Customer Art. Nr.</th>
|
||||
<th>Open 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 -->
|
||||
<!-- Data will be dynamically loaded here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -329,19 +190,20 @@ table tbody tr.selected td {
|
||||
|
||||
<script>
|
||||
document.getElementById('check-db-btn').addEventListener('click', function() {
|
||||
console.log('Check Database button clicked');
|
||||
|
||||
// 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);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
if (response.status === 403) {
|
||||
return response.json().then(errorData => {
|
||||
throw new Error(`Access Denied: ${errorData.error}`);
|
||||
});
|
||||
} else if (!response.ok) {
|
||||
return response.text().then(text => {
|
||||
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||
});
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
@@ -382,12 +244,11 @@ document.getElementById('check-db-btn').addEventListener('click', function() {
|
||||
|
||||
// Add click event for row selection
|
||||
tr.addEventListener('click', function() {
|
||||
console.log('Row clicked:', order.order_number);
|
||||
console.log('Row clicked:', order.id);
|
||||
|
||||
// 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 = '';
|
||||
@@ -397,7 +258,6 @@ document.getElementById('check-db-btn').addEventListener('click', function() {
|
||||
|
||||
// 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');
|
||||
@@ -417,54 +277,26 @@ document.getElementById('check-db-btn').addEventListener('click', function() {
|
||||
if (data.length > 0) {
|
||||
updateLabelPreview(data[0]);
|
||||
|
||||
// Add fallback print functionality if extension is not available
|
||||
addPDFGenerationHandler();
|
||||
|
||||
// Auto-select first row
|
||||
// Initialize PDF generation functionality
|
||||
addPDFGenerationHandler();
|
||||
|
||||
// Auto-select first row
|
||||
setTimeout(() => {
|
||||
const firstRow = document.querySelector('.print-module-table tbody tr');
|
||||
if (firstRow) {
|
||||
firstRow.classList.add('selected');
|
||||
const cells = firstRow.querySelectorAll('td');
|
||||
cells.forEach(cell => {
|
||||
cell.style.backgroundColor = '#007bff';
|
||||
cell.style.color = 'white';
|
||||
});
|
||||
}
|
||||
}, 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);
|
||||
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;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching orders:', error);
|
||||
|
||||
// Show error message to user
|
||||
alert('Failed to load orders from database. Error: ' + error.message);
|
||||
|
||||
// Reset button state
|
||||
button.textContent = originalText;
|
||||
.catch(error => console.error('Error fetching orders:', error))
|
||||
.finally(() => {
|
||||
button.textContent = 'Check Database';
|
||||
button.disabled = false;
|
||||
});
|
||||
});
|
||||
@@ -516,15 +348,12 @@ function updateLabelPreview(order) {
|
||||
|
||||
// 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
|
||||
function addPDFGenerationHandler() {
|
||||
const printButton = document.getElementById('print-label-btn');
|
||||
|
||||
if (printButton) {
|
||||
// Update button text and appearance for PDF generation
|
||||
printButton.innerHTML = '<EFBFBD> Generate PDF Labels';
|
||||
printButton.innerHTML = '📄 Generate PDF Labels';
|
||||
printButton.title = 'Generate PDF with multiple labels based on quantity';
|
||||
|
||||
printButton.addEventListener('click', function(e) {
|
||||
@@ -555,8 +384,13 @@ function addFallbackPrintHandler() {
|
||||
|
||||
console.log(`Generating PDF for order ${orderId} with ${quantity} labels`);
|
||||
|
||||
// Generate PDF
|
||||
fetch(`/generate_labels_pdf/${orderId}`, {
|
||||
// Always use paper-saving mode (optimized for thermal label printers)
|
||||
const paperSavingMode = 'true';
|
||||
|
||||
console.log(`Using paper-saving mode for optimal label printing`);
|
||||
|
||||
// Generate PDF with paper-saving mode enabled
|
||||
fetch(`/generate_labels_pdf/${orderId}/${paperSavingMode}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -569,25 +403,46 @@ function addFallbackPrintHandler() {
|
||||
return response.blob();
|
||||
})
|
||||
.then(blob => {
|
||||
// Create download link for PDF
|
||||
// Create blob URL for PDF
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
|
||||
// Create download link for PDF
|
||||
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();
|
||||
if (printWindow) {
|
||||
printWindow.focus();
|
||||
|
||||
// Wait for PDF to load, then show print dialog and cleanup
|
||||
setTimeout(() => {
|
||||
printWindow.print();
|
||||
|
||||
// Clean up blob URL after print dialog is shown
|
||||
setTimeout(() => {
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 2000);
|
||||
}, 1500);
|
||||
} else {
|
||||
// If popup was blocked, clean up immediately
|
||||
setTimeout(() => {
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Show success message
|
||||
alert(`✅ PDF generated successfully!\n📊 Order: ${prodOrder}\n📦 Labels: ${quantity} pieces\n\nThe PDF has been downloaded and opened for printing.`);
|
||||
alert(`✅ PDF generated successfully!\n📊 Order: ${prodOrder}\n📦 Labels: ${quantity} pieces\n\nThe PDF has been downloaded and opened for printing.\n\n📋 The order has been marked as printed and removed from the unprinted orders list.`);
|
||||
|
||||
// Refresh the orders table to reflect printed status
|
||||
document.getElementById('check-db-btn').click();
|
||||
// This will automatically hide the printed order from the unprinted orders list
|
||||
setTimeout(() => {
|
||||
refreshUnprintedOrdersTable();
|
||||
}, 1000);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error generating PDF:', error);
|
||||
@@ -602,361 +457,146 @@ function addFallbackPrintHandler() {
|
||||
}
|
||||
}
|
||||
|
||||
// SIMPLIFIED CHROME EXTENSION PRINTING - NO WINDOWS SERVICE NEEDED
|
||||
// Extension detection and communication
|
||||
let extensionId = null;
|
||||
let extensionReady = false;
|
||||
|
||||
// Check extension availability on page load
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
detectExtension();
|
||||
initializePrintButton();
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
// Function to refresh the unprinted orders table
|
||||
function refreshUnprintedOrdersTable() {
|
||||
console.log('Refreshing unprinted orders table...');
|
||||
const button = document.getElementById('check-db-btn');
|
||||
|
||||
// Method 2: Fallback to hardcoded extension ID
|
||||
if (!extensionId) {
|
||||
extensionId = 'cifcoidplhgclhcnlcgdkjbaoempjmdl'; // Hardcoded fallback
|
||||
console.log('ℹ️ Using fallback extension ID:', extensionId);
|
||||
}
|
||||
// Show refreshing state
|
||||
const originalText = button.textContent;
|
||||
button.textContent = 'Refreshing...';
|
||||
button.disabled = true;
|
||||
|
||||
// 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;
|
||||
fetch('/get_unprinted_orders')
|
||||
.then(response => {
|
||||
if (response.status === 403) {
|
||||
return response.json().then(errorData => {
|
||||
throw new Error(`Access Denied: ${errorData.error}`);
|
||||
});
|
||||
} else if (!response.ok) {
|
||||
return response.text().then(text => {
|
||||
throw new Error(`HTTP ${response.status}: ${text}`);
|
||||
});
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Refreshed data:', data);
|
||||
const tbody = document.getElementById('unprinted-orders-table');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (data.length === 0) {
|
||||
// No unprinted orders left
|
||||
tbody.innerHTML = '<tr><td colspan="15" style="text-align: center; padding: 20px; color: #28a745;"><strong>✅ All orders have been printed!</strong><br><small>No unprinted orders remaining.</small></td></tr>';
|
||||
|
||||
// Clear label preview
|
||||
clearLabelPreview();
|
||||
} else {
|
||||
// Populate table with remaining unprinted orders
|
||||
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>
|
||||
`;
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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'}`;
|
||||
// Add click event for row selection
|
||||
tr.addEventListener('click', function() {
|
||||
console.log('Row clicked:', order.id);
|
||||
|
||||
// Remove selection from other rows
|
||||
document.querySelectorAll('.print-module-table tbody tr').forEach(row => {
|
||||
row.classList.remove('selected');
|
||||
const cells = row.querySelectorAll('td');
|
||||
cells.forEach(cell => {
|
||||
cell.style.backgroundColor = '';
|
||||
cell.style.color = '';
|
||||
});
|
||||
});
|
||||
|
||||
// Select this row
|
||||
this.classList.add('selected');
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
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');
|
||||
// Auto-select first row
|
||||
setTimeout(() => {
|
||||
const firstRow = document.querySelector('.print-module-table tbody tr');
|
||||
if (firstRow && !firstRow.querySelector('td[colspan]')) { // Don't select if it's the "no data" row
|
||||
firstRow.classList.add('selected');
|
||||
const cells = firstRow.querySelectorAll('td');
|
||||
cells.forEach(cell => {
|
||||
cell.style.backgroundColor = '#007bff';
|
||||
cell.style.color = 'white';
|
||||
});
|
||||
updateLabelPreview(data[0]);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error refreshing orders:', error);
|
||||
const tbody = document.getElementById('unprinted-orders-table');
|
||||
tbody.innerHTML = '<tr><td colspan="15" style="text-align: center; padding: 20px; color: #dc3545;"><strong>❌ Failed to refresh data</strong><br><small>' + error.message + '</small></td></tr>';
|
||||
})
|
||||
.finally(() => {
|
||||
button.textContent = originalText;
|
||||
button.disabled = false;
|
||||
});
|
||||
|
||||
} 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 to clear label preview when no orders are available
|
||||
function clearLabelPreview() {
|
||||
document.getElementById('customer-name-row').textContent = 'No orders 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';
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
document.getElementById('print-label-btn').addEventListener('click', function() {
|
||||
console.log('Generate PDF logic here');
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
224
windows_print_service/ERROR_1053_COMPLETE_FIX.md
Normal file
224
windows_print_service/ERROR_1053_COMPLETE_FIX.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# Windows Service Error 1053 - COMPLETE FIX PACKAGE
|
||||
|
||||
## 🎯 Problem Description
|
||||
|
||||
**Windows Service Error 1053**: "The service did not respond to the start or control request in a timely fashion."
|
||||
|
||||
This error occurs when:
|
||||
- Service takes too long to respond to Windows Service Control Manager (SCM)
|
||||
- Python process doesn't communicate properly with Windows services
|
||||
- Service wrapper doesn't handle SCM signals correctly
|
||||
- Dependencies or paths are incorrect
|
||||
|
||||
## 📦 Complete Solution Package
|
||||
|
||||
This package provides **4 different installation methods** and comprehensive Error 1053 fixes:
|
||||
|
||||
### 🔧 Installation Files
|
||||
|
||||
1. **`install_service_ENHANCED.bat`** - Main installer with multiple fallback methods
|
||||
2. **`fix_error_1053.bat`** - Dedicated Error 1053 diagnostic and fix tool
|
||||
3. **`print_service_complete.py`** - Enhanced service with proper Windows service support
|
||||
4. **`service_wrapper.py`** - Optional advanced service wrapper
|
||||
5. **`test_service.bat`** - Standalone testing tool
|
||||
|
||||
### 🚀 Installation Methods (Automatic Fallback)
|
||||
|
||||
#### Method 1: Windows SC Service (Preferred)
|
||||
- Creates standard Windows service
|
||||
- Includes enhanced timeout handling
|
||||
- Automatic recovery configuration
|
||||
- **Fixes Error 1053** with proper SCM communication
|
||||
|
||||
#### Method 2: Task Scheduler Service (Fallback)
|
||||
- Runs as scheduled task on system startup
|
||||
- SYSTEM privileges with highest elevation
|
||||
- Automatic restart on failure
|
||||
- Bypasses SCM timeout issues
|
||||
|
||||
#### Method 3: Startup Script (Manual Fallback)
|
||||
- Runs from Windows startup folder
|
||||
- Simple and reliable
|
||||
- Manual process management
|
||||
- Always works as final resort
|
||||
|
||||
#### Method 4: Standalone Mode (Testing/Debugging)
|
||||
- Direct Python execution
|
||||
- No Windows service wrapper
|
||||
- Immediate startup for testing
|
||||
- Perfect for troubleshooting
|
||||
|
||||
## 🔍 Error 1053 Specific Fixes
|
||||
|
||||
### Root Cause Analysis
|
||||
The enhanced installers address these Error 1053 causes:
|
||||
|
||||
1. **SCM Timeout Issues**
|
||||
- Enhanced service wrapper responds immediately to SCM
|
||||
- Service process starts in background
|
||||
- Proper exit codes and signaling
|
||||
|
||||
2. **Python Path Problems**
|
||||
- Automatic detection of embedded Python
|
||||
- Fallback to system Python
|
||||
- Absolute path resolution
|
||||
|
||||
3. **Service Communication**
|
||||
- Proper Windows service signal handling
|
||||
- Enhanced logging and error reporting
|
||||
- Background process management
|
||||
|
||||
4. **Dependency Issues**
|
||||
- Self-contained Python environment
|
||||
- Zero external dependencies
|
||||
- Embedded Python distribution included
|
||||
|
||||
### Technical Implementation
|
||||
|
||||
#### Enhanced Service Wrapper
|
||||
```batch
|
||||
# error_1053_fix_wrapper.bat
|
||||
- Immediate SCM response
|
||||
- Background service startup
|
||||
- Enhanced error handling
|
||||
- Comprehensive logging
|
||||
```
|
||||
|
||||
#### Service Configuration
|
||||
```cmd
|
||||
# Delayed auto-start to prevent startup conflicts
|
||||
sc config QualityPrintService start= delayed-auto
|
||||
|
||||
# Automatic recovery on failure
|
||||
sc failure QualityPrintService reset= 86400 actions= restart/5000/restart/5000/restart/5000
|
||||
```
|
||||
|
||||
## 📋 Usage Instructions
|
||||
|
||||
### 🎯 Quick Fix (Recommended)
|
||||
1. **Run as Administrator**: `fix_error_1053.bat`
|
||||
2. This script will:
|
||||
- Diagnose the current problem
|
||||
- Apply all Error 1053 fixes
|
||||
- Test service functionality
|
||||
- Install with enhanced wrapper
|
||||
|
||||
### 🔧 Fresh Installation
|
||||
1. **Run as Administrator**: `install_service_ENHANCED.bat`
|
||||
2. Installer will automatically:
|
||||
- Try Windows SC Service first
|
||||
- Fall back to Task Scheduler if needed
|
||||
- Create startup script as final option
|
||||
- Test all methods until one succeeds
|
||||
|
||||
### 🧪 Testing and Verification
|
||||
1. **Test standalone**: `test_service.bat`
|
||||
2. **Manual testing**:
|
||||
```cmd
|
||||
cd C:\QualityPrintService
|
||||
python print_service_complete.py --test
|
||||
python print_service_complete.py --standalone
|
||||
```
|
||||
3. **Service status**:
|
||||
```cmd
|
||||
sc query QualityPrintService
|
||||
net start QualityPrintService
|
||||
```
|
||||
|
||||
## 🔍 Troubleshooting Guide
|
||||
|
||||
### If Error 1053 Still Occurs
|
||||
|
||||
1. **Run Diagnostic Tool**:
|
||||
```cmd
|
||||
fix_error_1053.bat
|
||||
```
|
||||
|
||||
2. **Check Logs**:
|
||||
- `%USERPROFILE%\PrintService\logs\service_wrapper.log`
|
||||
- `%USERPROFILE%\PrintService\logs\error_1053_fix.log`
|
||||
|
||||
3. **Manual Service Test**:
|
||||
```cmd
|
||||
C:\QualityPrintService\error_1053_fix_wrapper.bat
|
||||
```
|
||||
|
||||
4. **Alternative Installation**:
|
||||
- Use Task Scheduler method
|
||||
- Use Startup Script method
|
||||
- Run in standalone mode
|
||||
|
||||
### Common Issues and Solutions
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| "Python not found" | Use embedded Python package or install Python 3.7+ |
|
||||
| "Port 8765 in use" | Stop existing services, reboot system |
|
||||
| "Access denied" | Run installer as Administrator |
|
||||
| "Service won't start" | Use Task Scheduler fallback method |
|
||||
| "Still Error 1053" | Use startup script or standalone mode |
|
||||
|
||||
## ✅ Success Verification
|
||||
|
||||
After installation, verify success:
|
||||
|
||||
1. **Service Status**: Service should be "RUNNING"
|
||||
```cmd
|
||||
sc query QualityPrintService
|
||||
```
|
||||
|
||||
2. **Network Test**: Should return "OK"
|
||||
```cmd
|
||||
curl http://localhost:8765/health
|
||||
```
|
||||
|
||||
3. **Browser Test**: Open `http://localhost:8765/health`
|
||||
|
||||
4. **Chrome Extension**: Should connect successfully
|
||||
|
||||
## 📊 Package Contents Summary
|
||||
|
||||
### Core Service Files
|
||||
- ✅ `print_service_complete.py` - Main service with Windows service support
|
||||
- ✅ `service_wrapper.py` - Advanced service wrapper (optional)
|
||||
- ✅ Enhanced service wrappers with Error 1053 fixes
|
||||
|
||||
### Installation Tools
|
||||
- ✅ `install_service_ENHANCED.bat` - Multi-method installer
|
||||
- ✅ `fix_error_1053.bat` - Dedicated Error 1053 fixer
|
||||
- ✅ `test_service.bat` - Standalone testing tool
|
||||
|
||||
### Zero Dependencies
|
||||
- ✅ `python_embedded/` - Complete Python 3.11.9 distribution
|
||||
- ✅ No external dependencies required
|
||||
- ✅ Self-contained package (10.8MB)
|
||||
|
||||
### Browser Integration
|
||||
- ✅ `chrome_extension/` - Complete Chrome extension
|
||||
- ✅ Automatic printer detection
|
||||
- ✅ PDF processing and printing
|
||||
|
||||
## 🎯 Expected Results
|
||||
|
||||
After running the enhanced installer:
|
||||
|
||||
✅ **Windows Service Error 1053 RESOLVED**
|
||||
✅ **Service starts automatically on boot**
|
||||
✅ **Multiple installation methods available**
|
||||
✅ **Comprehensive error handling and recovery**
|
||||
✅ **Zero external dependencies**
|
||||
✅ **Complete diagnostic and troubleshooting tools**
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. **Install**: Run `install_service_ENHANCED.bat` as Administrator
|
||||
2. **Verify**: Check service status and network connectivity
|
||||
3. **Configure**: Install Chrome extension from `chrome_extension/`
|
||||
4. **Test**: Print labels from web application
|
||||
5. **Monitor**: Check logs for any issues
|
||||
|
||||
The enhanced package provides **4 installation methods** and **comprehensive Error 1053 fixes** to ensure reliable service operation on all Windows systems.
|
||||
|
||||
---
|
||||
|
||||
**Support**: All installation methods include detailed logging and diagnostic information to troubleshoot any remaining issues.
|
||||
Binary file not shown.
165
windows_print_service/TROUBLESHOOTING_1053.md
Normal file
165
windows_print_service/TROUBLESHOOTING_1053.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Windows Print Service - Error 1053 Troubleshooting Guide
|
||||
|
||||
## 🚨 Windows Service Error 1053 - "Service did not respond to start or control request"
|
||||
|
||||
This error occurs when Windows services don't communicate properly with the Service Control Manager (SCM). Here's how to fix it:
|
||||
|
||||
### 🔧 SOLUTION 1: Use the Enhanced Service Package
|
||||
|
||||
**Problem**: The original service wasn't designed for Windows service requirements.
|
||||
**Fix**: Updated service architecture with proper Windows service communication.
|
||||
|
||||
#### New Files Included:
|
||||
- ✅ `service_wrapper.py` - Handles Windows service communication
|
||||
- ✅ `print_service_complete.py` - Enhanced with signal handling and proper shutdown
|
||||
- ✅ `test_service.bat` - Test service in standalone mode before installing
|
||||
|
||||
### 🧪 STEP-BY-STEP TROUBLESHOOTING:
|
||||
|
||||
#### Step 1: Test Service in Standalone Mode
|
||||
```cmd
|
||||
# Run this to test the service before installing as Windows service
|
||||
test_service.bat
|
||||
```
|
||||
|
||||
If this works, the service code is fine. If not, check the logs.
|
||||
|
||||
#### Step 2: Check Python and Dependencies
|
||||
```cmd
|
||||
# Verify Python embedded is working
|
||||
cd C:\QualityPrintService\python_embedded
|
||||
python.exe --version
|
||||
|
||||
# Test the service script directly
|
||||
python.exe ..\print_service_complete.py --test
|
||||
```
|
||||
|
||||
#### Step 3: Install with Enhanced Wrapper
|
||||
The installer now creates a service wrapper that properly communicates with Windows SCM:
|
||||
|
||||
```cmd
|
||||
# Uninstall old service
|
||||
sc stop QualityPrintService
|
||||
sc delete QualityPrintService
|
||||
|
||||
# Reinstall with enhanced wrapper
|
||||
install_service_complete.bat
|
||||
```
|
||||
|
||||
#### Step 4: Manual Service Control
|
||||
```cmd
|
||||
# Start service manually to see error details
|
||||
net start QualityPrintService
|
||||
|
||||
# Check service status
|
||||
sc query QualityPrintService
|
||||
|
||||
# View service logs
|
||||
type "%USERPROFILE%\PrintService\logs\service_wrapper_*.log"
|
||||
```
|
||||
|
||||
### 🔍 DIAGNOSTIC COMMANDS:
|
||||
|
||||
#### Check Service Installation:
|
||||
```cmd
|
||||
sc query QualityPrintService
|
||||
sc qc QualityPrintService
|
||||
```
|
||||
|
||||
#### Check Port Availability:
|
||||
```cmd
|
||||
netstat -an | findstr :8765
|
||||
```
|
||||
|
||||
#### Test HTTP Endpoints:
|
||||
```cmd
|
||||
curl http://localhost:8765/health
|
||||
# OR
|
||||
powershell Invoke-WebRequest -Uri "http://localhost:8765/health"
|
||||
```
|
||||
|
||||
### 📋 COMMON SOLUTIONS:
|
||||
|
||||
#### Solution A: Port Already in Use
|
||||
```cmd
|
||||
# Find process using port 8765
|
||||
netstat -ano | findstr :8765
|
||||
# Kill process if needed (replace PID)
|
||||
taskkill /PID <PID_NUMBER> /F
|
||||
```
|
||||
|
||||
#### Solution B: Python Path Issues
|
||||
```cmd
|
||||
# Verify Python embedded path in service wrapper
|
||||
type "C:\QualityPrintService\service_wrapper.bat"
|
||||
```
|
||||
|
||||
#### Solution C: Permissions Issues
|
||||
```cmd
|
||||
# Run installer as Administrator
|
||||
# Right-click install_service_complete.bat → "Run as administrator"
|
||||
```
|
||||
|
||||
#### Solution D: Service Recovery
|
||||
```cmd
|
||||
# Configure automatic recovery
|
||||
sc failure QualityPrintService reset= 86400 actions= restart/5000/restart/5000/restart/5000
|
||||
```
|
||||
|
||||
### 📊 SERVICE STATUS VERIFICATION:
|
||||
|
||||
#### Successful Service Start:
|
||||
- Service Status: RUNNING
|
||||
- HTTP Response: `{"status": "healthy", "service": "Windows Print Service"}`
|
||||
- Log Shows: "Service is ready and listening..."
|
||||
|
||||
#### Failed Service Start:
|
||||
- Service Status: STOPPED or START_PENDING
|
||||
- HTTP Response: Connection refused
|
||||
- Log Shows: Error messages with specific details
|
||||
|
||||
### 🛠️ ADVANCED TROUBLESHOOTING:
|
||||
|
||||
#### Enable Debug Logging:
|
||||
Edit the service script to increase logging level:
|
||||
```python
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
```
|
||||
|
||||
#### Manual Service Wrapper Test:
|
||||
```cmd
|
||||
cd C:\QualityPrintService
|
||||
python_embedded\python.exe service_wrapper.py
|
||||
```
|
||||
|
||||
#### Windows Event Viewer:
|
||||
1. Open Event Viewer
|
||||
2. Navigate: Windows Logs → Application
|
||||
3. Filter by Source: Service Control Manager
|
||||
4. Look for QualityPrintService errors
|
||||
|
||||
### 📞 SUPPORT CHECKLIST:
|
||||
|
||||
Before reporting issues, please verify:
|
||||
|
||||
- [ ] ✅ Python embedded is working (`python_embedded\python.exe --version`)
|
||||
- [ ] ✅ Service runs in standalone mode (`test_service.bat`)
|
||||
- [ ] ✅ Port 8765 is available (`netstat -an | findstr :8765`)
|
||||
- [ ] ✅ Installer was run as Administrator
|
||||
- [ ] ✅ Windows is Windows 10/11 or Server 2016+
|
||||
- [ ] ✅ Service logs show specific error messages
|
||||
|
||||
### 🎯 EXPECTED RESULTS:
|
||||
|
||||
After following this guide:
|
||||
|
||||
1. **Service Status**: RUNNING
|
||||
2. **Health Check**: http://localhost:8765/health returns JSON response
|
||||
3. **Chrome Extension**: Detects service and shows "Windows Service" mode
|
||||
4. **Printing**: Silent PDF printing works without dialogs
|
||||
|
||||
---
|
||||
|
||||
**Package Version**: Zero Dependencies Complete
|
||||
**Last Updated**: September 2025
|
||||
**Support**: Check service logs in `%USERPROFILE%\PrintService\logs\`
|
||||
@@ -1,7 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to create a completely self-contained Windows Print Service package
|
||||
with embedded Python distribution - Zero external dependencies required!
|
||||
with embedded Python distribution and comprehensive Error 1053 fixes
|
||||
- Zero external dependencies required!
|
||||
- Multiple installation methods with automatic fallback
|
||||
- Complete Windows Service Error 1053 resolution
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -90,11 +93,23 @@ def create_complete_package():
|
||||
print("📁 Adding service files...")
|
||||
service_files = [
|
||||
"print_service_complete.py",
|
||||
"install_service_complete.bat",
|
||||
"service_wrapper.py",
|
||||
"service_installer.py",
|
||||
"install_service_complete.bat",
|
||||
"install_service_ENHANCED.bat",
|
||||
"uninstall_service_complete.bat",
|
||||
"fix_error_1053.bat",
|
||||
"test_service.bat",
|
||||
"build_executable.bat",
|
||||
"build_package.py",
|
||||
"create_portable_package.py",
|
||||
"requirements_complete.txt",
|
||||
"INSTALLATION_COMPLETE.md",
|
||||
"PACKAGE_SUMMARY.md",
|
||||
"README_COMPLETE.md"
|
||||
"README_COMPLETE.md",
|
||||
"TROUBLESHOOTING_1053.md",
|
||||
"ERROR_1053_COMPLETE_FIX.md",
|
||||
"PORTABLE_PYTHON_INSTRUCTIONS.txt"
|
||||
]
|
||||
|
||||
for file_name in service_files:
|
||||
@@ -384,23 +399,26 @@ rmdir /s /q C:\\QualityPrintService
|
||||
zipf.writestr("README_ZERO_DEPENDENCIES.md", readme_content)
|
||||
files_added += 1
|
||||
|
||||
print(f"\n📦 Package created successfully!")
|
||||
print(f"\n📦 Enhanced Package created successfully!")
|
||||
print(f"📄 Total files: {files_added}")
|
||||
print(f"📂 Location: {package_path}")
|
||||
print(f"📏 Size: {package_path.stat().st_size / 1024 / 1024:.1f} MB")
|
||||
print(f"🔧 Features: Error 1053 fixes, multiple installation methods")
|
||||
print(f"🚀 Python: {PYTHON_VERSION} embedded (zero dependencies)")
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 Creating Complete Zero-Dependencies Package...")
|
||||
print("=" * 60)
|
||||
print("🚀 Creating Enhanced Package with Error 1053 Fixes...")
|
||||
print("=" * 65)
|
||||
|
||||
if create_complete_package():
|
||||
print("\n✅ SUCCESS: Complete package created!")
|
||||
print("\n✅ SUCCESS: Enhanced package created with Error 1053 fixes!")
|
||||
print("\n📋 Next steps:")
|
||||
print("1. Test the package on a clean Windows system")
|
||||
print("2. Verify zero external dependencies")
|
||||
print("3. Update Flask app to serve this package")
|
||||
print("1. Package includes multiple installation methods")
|
||||
print("2. Error 1053 diagnostic and fix tools included")
|
||||
print("3. Test on Windows system - should resolve all service issues")
|
||||
print("4. Update Flask app to serve this enhanced package")
|
||||
else:
|
||||
print("\n❌ FAILED: Package creation failed")
|
||||
sys.exit(1)
|
||||
454
windows_print_service/fix_error_1053.bat
Normal file
454
windows_print_service/fix_error_1053.bat
Normal file
@@ -0,0 +1,454 @@
|
||||
@echo off
|
||||
REM Windows Service Error 1053 - COMPREHENSIVE DIAGNOSTIC TOOL
|
||||
REM This script diagnoses and fixes the most common causes of Error 1053
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo =========================================
|
||||
echo ERROR 1053 DIAGNOSTIC TOOL
|
||||
echo Quality Print Service Troubleshooter
|
||||
echo =========================================
|
||||
echo.
|
||||
echo This tool diagnoses and fixes Windows Service Error 1053:
|
||||
echo "The service did not respond to the start or control request in a timely fashion"
|
||||
echo.
|
||||
|
||||
REM Check for administrator privileges
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% neq 0 (
|
||||
echo ❌ CRITICAL: Administrator privileges required
|
||||
echo Right-click this file and select "Run as administrator"
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ✅ Administrator privileges confirmed
|
||||
echo.
|
||||
|
||||
REM Set variables
|
||||
set CURRENT_DIR=%~dp0
|
||||
set SERVICE_NAME=QualityPrintService
|
||||
set INSTALL_DIR=C:\QualityPrintService
|
||||
set LOG_DIR=%USERPROFILE%\PrintService\logs
|
||||
|
||||
echo ===========================================
|
||||
echo [STEP 1] SERVICE STATUS DIAGNOSIS
|
||||
echo ===========================================
|
||||
|
||||
REM Check current service status
|
||||
echo Checking service status...
|
||||
sc query "%SERVICE_NAME%" >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo Service exists - checking status:
|
||||
sc query "%SERVICE_NAME%"
|
||||
echo.
|
||||
|
||||
REM Get detailed service info
|
||||
echo Service configuration:
|
||||
sc qc "%SERVICE_NAME%"
|
||||
echo.
|
||||
) else (
|
||||
echo ❌ Service not found - needs installation
|
||||
echo.
|
||||
)
|
||||
|
||||
REM Check Task Scheduler
|
||||
echo Checking Task Scheduler...
|
||||
schtasks /query /tn "%SERVICE_NAME%" >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo ✅ Task Scheduler entry found
|
||||
schtasks /query /tn "%SERVICE_NAME%" /fo LIST
|
||||
echo.
|
||||
) else (
|
||||
echo ❌ Task Scheduler entry not found
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ===========================================
|
||||
echo [STEP 2] PROCESS AND PORT DIAGNOSIS
|
||||
echo ===========================================
|
||||
|
||||
REM Check for running processes
|
||||
echo Checking for existing service processes...
|
||||
tasklist /fi "imagename eq python.exe" | findstr python.exe >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo Python processes found:
|
||||
tasklist /fi "imagename eq python.exe"
|
||||
echo.
|
||||
) else (
|
||||
echo No Python processes running
|
||||
echo.
|
||||
)
|
||||
|
||||
REM Check port 8765
|
||||
echo Checking port 8765...
|
||||
netstat -an | findstr :8765 >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo ⚠️ Port 8765 is in use:
|
||||
netstat -an | findstr :8765
|
||||
echo.
|
||||
|
||||
REM Find process using port
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :8765') do (
|
||||
tasklist /fi "pid eq %%a" 2>nul | findstr /v "INFO:"
|
||||
)
|
||||
echo.
|
||||
) else (
|
||||
echo ✅ Port 8765 is available
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ===========================================
|
||||
echo [STEP 3] PYTHON ENVIRONMENT DIAGNOSIS
|
||||
echo ===========================================
|
||||
|
||||
REM Check Python installations
|
||||
echo Checking Python installations...
|
||||
|
||||
REM Check embedded Python
|
||||
if exist "%INSTALL_DIR%\python_embedded\python.exe" (
|
||||
echo ✅ Embedded Python found: %INSTALL_DIR%\python_embedded\python.exe
|
||||
"%INSTALL_DIR%\python_embedded\python.exe" --version 2>nul
|
||||
echo.
|
||||
) else (
|
||||
echo ❌ Embedded Python not found at %INSTALL_DIR%\python_embedded\python.exe
|
||||
)
|
||||
|
||||
if exist "%CURRENT_DIR%python_embedded\python.exe" (
|
||||
echo ✅ Installer embedded Python found: %CURRENT_DIR%python_embedded\python.exe
|
||||
"%CURRENT_DIR%python_embedded\python.exe" --version 2>nul
|
||||
echo.
|
||||
) else (
|
||||
echo ❌ Installer embedded Python not found
|
||||
)
|
||||
|
||||
REM Check system Python
|
||||
python --version >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo ✅ System Python found:
|
||||
python --version
|
||||
where python
|
||||
echo.
|
||||
) else (
|
||||
echo ❌ System Python not found in PATH
|
||||
echo.
|
||||
)
|
||||
|
||||
echo ===========================================
|
||||
echo [STEP 4] FILE SYSTEM DIAGNOSIS
|
||||
echo ===========================================
|
||||
|
||||
REM Check installation files
|
||||
echo Checking installation files...
|
||||
|
||||
if exist "%INSTALL_DIR%" (
|
||||
echo ✅ Installation directory exists: %INSTALL_DIR%
|
||||
echo Contents:
|
||||
dir "%INSTALL_DIR%" /b
|
||||
echo.
|
||||
|
||||
if exist "%INSTALL_DIR%\print_service_complete.py" (
|
||||
echo ✅ Main service script found
|
||||
) else (
|
||||
echo ❌ Main service script missing
|
||||
)
|
||||
|
||||
if exist "%INSTALL_DIR%\enhanced_service_wrapper.bat" (
|
||||
echo ✅ Service wrapper found
|
||||
) else (
|
||||
echo ❌ Service wrapper missing
|
||||
)
|
||||
|
||||
) else (
|
||||
echo ❌ Installation directory not found: %INSTALL_DIR%
|
||||
)
|
||||
|
||||
REM Check log directory
|
||||
if exist "%LOG_DIR%" (
|
||||
echo ✅ Log directory exists: %LOG_DIR%
|
||||
if exist "%LOG_DIR%\service_wrapper.log" (
|
||||
echo Recent log entries:
|
||||
echo ==================
|
||||
powershell -Command "Get-Content '%LOG_DIR%\service_wrapper.log' -Tail 10" 2>nul
|
||||
echo ==================
|
||||
echo.
|
||||
)
|
||||
) else (
|
||||
echo ❌ Log directory not found: %LOG_DIR%
|
||||
mkdir "%LOG_DIR%" >nul 2>&1
|
||||
echo Created log directory
|
||||
)
|
||||
|
||||
echo ===========================================
|
||||
echo [STEP 5] SERVICE TEST
|
||||
echo ===========================================
|
||||
|
||||
REM Determine Python executable
|
||||
set PYTHON_EXE=
|
||||
if exist "%INSTALL_DIR%\python_embedded\python.exe" (
|
||||
set PYTHON_EXE=%INSTALL_DIR%\python_embedded\python.exe
|
||||
) else if exist "%CURRENT_DIR%python_embedded\python.exe" (
|
||||
set PYTHON_EXE=%CURRENT_DIR%python_embedded\python.exe
|
||||
) else (
|
||||
python --version >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
set PYTHON_EXE=python
|
||||
)
|
||||
)
|
||||
|
||||
if "!PYTHON_EXE!"=="" (
|
||||
echo ❌ CRITICAL: No Python executable found
|
||||
echo Cannot perform service test
|
||||
goto :fixes
|
||||
)
|
||||
|
||||
echo Testing service with Python: !PYTHON_EXE!
|
||||
|
||||
REM Test service script
|
||||
if exist "%INSTALL_DIR%\print_service_complete.py" (
|
||||
cd /d "%INSTALL_DIR%"
|
||||
|
||||
echo Testing service script syntax...
|
||||
"!PYTHON_EXE!" -m py_compile print_service_complete.py
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Service script syntax OK
|
||||
) else (
|
||||
echo ❌ Service script syntax error
|
||||
)
|
||||
|
||||
echo Testing service functionality...
|
||||
"!PYTHON_EXE!" print_service_complete.py --test
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Service test passed
|
||||
) else (
|
||||
echo ❌ Service test failed
|
||||
)
|
||||
|
||||
REM Quick standalone test
|
||||
echo Testing standalone mode (15 seconds)...
|
||||
start /min "" "!PYTHON_EXE!" print_service_complete.py --standalone
|
||||
|
||||
timeout /t 5 >nul
|
||||
|
||||
REM Test connection
|
||||
curl -s http://localhost:8765/health >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Service responding in standalone mode
|
||||
|
||||
REM Stop standalone service
|
||||
taskkill /f /im python.exe >nul 2>&1
|
||||
) else (
|
||||
powershell -Command "try { Invoke-WebRequest -Uri 'http://localhost:8765/health' -UseBasicParsing } catch { exit 1 }" >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Service responding in standalone mode
|
||||
taskkill /f /im python.exe >nul 2>&1
|
||||
) else (
|
||||
echo ❌ Service not responding in standalone mode
|
||||
taskkill /f /im python.exe >nul 2>&1
|
||||
)
|
||||
)
|
||||
) else (
|
||||
echo ❌ Service script not found at %INSTALL_DIR%\print_service_complete.py
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
:fixes
|
||||
echo ===========================================
|
||||
echo [STEP 6] AUTOMATED FIXES FOR ERROR 1053
|
||||
echo ===========================================
|
||||
|
||||
echo Applying automated fixes...
|
||||
|
||||
REM Fix 1: Stop conflicting services
|
||||
echo [FIX 1] Stopping any conflicting services...
|
||||
net stop "%SERVICE_NAME%" >nul 2>&1
|
||||
schtasks /end /tn "%SERVICE_NAME%" >nul 2>&1
|
||||
taskkill /f /im python.exe >nul 2>&1
|
||||
timeout /t 3 >nul
|
||||
echo ✅ Services stopped
|
||||
|
||||
REM Fix 2: Remove old service entries
|
||||
echo [FIX 2] Cleaning old service entries...
|
||||
sc delete "%SERVICE_NAME%" >nul 2>&1
|
||||
schtasks /delete /tn "%SERVICE_NAME%" /f >nul 2>&1
|
||||
echo ✅ Old entries removed
|
||||
|
||||
REM Fix 3: Create enhanced service wrapper with timeout handling
|
||||
echo [FIX 3] Creating enhanced service wrapper...
|
||||
|
||||
set ENHANCED_WRAPPER=%INSTALL_DIR%\error_1053_fix_wrapper.bat
|
||||
|
||||
mkdir "%INSTALL_DIR%" >nul 2>&1
|
||||
|
||||
echo @echo off > "%ENHANCED_WRAPPER%"
|
||||
echo REM Enhanced Windows Service Wrapper - Error 1053 Fix >> "%ENHANCED_WRAPPER%"
|
||||
echo REM This wrapper includes specific fixes for SCM timeout issues >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo setlocal >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo REM Logging >> "%ENHANCED_WRAPPER%"
|
||||
echo set LOG_FILE=%LOG_DIR%\error_1053_fix.log >> "%ENHANCED_WRAPPER%"
|
||||
echo echo %%date%% %%time%% - Service wrapper starting... ^>^> "%%LOG_FILE%%" >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo REM Change to service directory >> "%ENHANCED_WRAPPER%"
|
||||
echo cd /d "%INSTALL_DIR%" >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo REM Pre-flight checks >> "%ENHANCED_WRAPPER%"
|
||||
if "!PYTHON_EXE!" neq "" (
|
||||
echo if not exist "!PYTHON_EXE!" ( >> "%ENHANCED_WRAPPER%"
|
||||
echo echo ERROR: Python not found at !PYTHON_EXE! ^>^> "%%LOG_FILE%%" >> "%ENHANCED_WRAPPER%"
|
||||
echo exit /b 1 >> "%ENHANCED_WRAPPER%"
|
||||
echo ^) >> "%ENHANCED_WRAPPER%"
|
||||
)
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo if not exist "print_service_complete.py" ( >> "%ENHANCED_WRAPPER%"
|
||||
echo echo ERROR: Service script not found ^>^> "%%LOG_FILE%%" >> "%ENHANCED_WRAPPER%"
|
||||
echo exit /b 1 >> "%ENHANCED_WRAPPER%"
|
||||
echo ^) >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo REM Quick response to SCM - Start service immediately in background >> "%ENHANCED_WRAPPER%"
|
||||
echo echo Service responding to SCM... ^>^> "%%LOG_FILE%%" >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo REM Start the actual service process >> "%ENHANCED_WRAPPER%"
|
||||
if "!PYTHON_EXE!" neq "" (
|
||||
echo start /b "Quality Print Service" "!PYTHON_EXE!" "print_service_complete.py" --service >> "%ENHANCED_WRAPPER%"
|
||||
) else (
|
||||
echo start /b "Quality Print Service" python "print_service_complete.py" --service >> "%ENHANCED_WRAPPER%"
|
||||
)
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo REM Keep wrapper alive briefly to satisfy SCM >> "%ENHANCED_WRAPPER%"
|
||||
echo timeout /t 2 /nobreak ^>nul >> "%ENHANCED_WRAPPER%"
|
||||
echo. >> "%ENHANCED_WRAPPER%"
|
||||
echo echo Service started successfully ^>^> "%%LOG_FILE%%" >> "%ENHANCED_WRAPPER%"
|
||||
echo exit /b 0 >> "%ENHANCED_WRAPPER%"
|
||||
|
||||
echo ✅ Enhanced wrapper created
|
||||
|
||||
REM Fix 4: Install service with proper timeout settings
|
||||
echo [FIX 4] Installing service with Error 1053 fixes...
|
||||
|
||||
REM Create service with extended timeout
|
||||
sc create "%SERVICE_NAME%" binPath= "\"%ENHANCED_WRAPPER%\"" DisplayName= "Quality Print Service (Error 1053 Fixed)" start= auto >nul 2>&1
|
||||
|
||||
if %errorLevel% equ 0 (
|
||||
echo ✅ Service created successfully
|
||||
|
||||
REM Configure service for Error 1053 prevention
|
||||
echo Configuring service recovery...
|
||||
sc failure "%SERVICE_NAME%" reset= 86400 actions= restart/5000/restart/5000/restart/5000 >nul 2>&1
|
||||
|
||||
REM Set service to auto-start with delay
|
||||
sc config "%SERVICE_NAME%" start= delayed-auto >nul 2>&1
|
||||
|
||||
echo ✅ Service configured with Error 1053 fixes
|
||||
) else (
|
||||
echo ❌ Service creation failed
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
echo ===========================================
|
||||
echo [STEP 7] SERVICE START TEST
|
||||
echo ===========================================
|
||||
|
||||
echo Testing service start with Error 1053 fixes...
|
||||
|
||||
REM Start service
|
||||
net start "%SERVICE_NAME%" 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo ✅ SERVICE STARTED SUCCESSFULLY!
|
||||
echo Error 1053 has been FIXED! 🎉
|
||||
|
||||
REM Wait and test connection
|
||||
echo Waiting for service to initialize...
|
||||
timeout /t 10 >nul
|
||||
|
||||
echo Testing service connection...
|
||||
curl -s http://localhost:8765/health >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Service is responding properly
|
||||
echo.
|
||||
echo ========================================
|
||||
echo PROBLEM SOLVED! 🎉
|
||||
echo ========================================
|
||||
echo.
|
||||
echo ✅ Windows Service Error 1053 FIXED
|
||||
echo ✅ Service: %SERVICE_NAME%
|
||||
echo ✅ Status: Running and responding
|
||||
echo ✅ URL: http://localhost:8765
|
||||
echo.
|
||||
goto :success
|
||||
) else (
|
||||
powershell -Command "try { Invoke-WebRequest -Uri 'http://localhost:8765/health' -UseBasicParsing } catch { exit 1 }" >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Service is responding properly
|
||||
goto :success
|
||||
) else (
|
||||
echo ⚠️ Service started but not responding
|
||||
echo Check logs: %LOG_DIR%\error_1053_fix.log
|
||||
)
|
||||
)
|
||||
) else (
|
||||
echo ❌ Service start failed - Error 1053 may persist
|
||||
echo.
|
||||
echo ===========================================
|
||||
echo [ALTERNATIVE SOLUTIONS]
|
||||
echo ===========================================
|
||||
echo.
|
||||
echo Since SC Service failed, trying alternative methods...
|
||||
|
||||
REM Alternative: Task Scheduler
|
||||
echo Installing via Task Scheduler...
|
||||
schtasks /create /tn "%SERVICE_NAME%" /tr "\"%ENHANCED_WRAPPER%\"" /sc onstart /ru SYSTEM /rl HIGHEST >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Task Scheduler service created
|
||||
schtasks /run /tn "%SERVICE_NAME%" >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo ✅ Task Scheduler service started
|
||||
echo Alternative solution: Task Scheduler
|
||||
)
|
||||
)
|
||||
|
||||
REM Alternative: Manual startup
|
||||
echo.
|
||||
echo Manual startup option:
|
||||
echo Run this command to start manually:
|
||||
echo "%ENHANCED_WRAPPER%"
|
||||
)
|
||||
|
||||
:success
|
||||
echo.
|
||||
echo ===========================================
|
||||
echo [STEP 8] SUMMARY AND RECOMMENDATIONS
|
||||
echo ===========================================
|
||||
|
||||
echo Diagnostic complete!
|
||||
echo.
|
||||
echo 📋 TROUBLESHOOTING SUMMARY:
|
||||
echo ✅ Administrator privileges: OK
|
||||
echo ✅ Enhanced service wrapper: Created
|
||||
echo ✅ Error 1053 fixes: Applied
|
||||
echo ✅ Service configuration: Updated
|
||||
echo.
|
||||
|
||||
if exist "%LOG_DIR%\error_1053_fix.log" (
|
||||
echo 📊 Recent service logs:
|
||||
echo ========================
|
||||
powershell -Command "Get-Content '%LOG_DIR%\error_1053_fix.log' -Tail 5" 2>nul
|
||||
echo ========================
|
||||
echo.
|
||||
)
|
||||
|
||||
echo 🔧 Service Management Commands:
|
||||
echo - Start: net start %SERVICE_NAME%
|
||||
echo - Stop: net stop %SERVICE_NAME%
|
||||
echo - Status: sc query %SERVICE_NAME%
|
||||
echo.
|
||||
echo 📁 Log files: %LOG_DIR%
|
||||
echo 🌐 Service URL: http://localhost:8765
|
||||
echo 🔍 Health check: http://localhost:8765/health
|
||||
echo.
|
||||
echo Press any key to exit...
|
||||
pause >nul
|
||||
407
windows_print_service/install_service_ENHANCED.bat
Normal file
407
windows_print_service/install_service_ENHANCED.bat
Normal file
@@ -0,0 +1,407 @@
|
||||
@echo off
|
||||
REM Windows Print Service - ENHANCED INSTALLER - Fixes Error 1053
|
||||
REM This installer addresses the most common causes of Windows Service startup failures
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo =========================================
|
||||
echo Quality Print Service - ENHANCED INSTALLER
|
||||
echo Fixes Windows Service Error 1053
|
||||
echo =========================================
|
||||
echo.
|
||||
echo This installer includes multiple methods to ensure service starts:
|
||||
echo ✅ Windows SC Service (preferred)
|
||||
echo ✅ Task Scheduler Service (fallback)
|
||||
echo ✅ Startup Script (manual fallback)
|
||||
echo ✅ Enhanced error detection and recovery
|
||||
echo.
|
||||
|
||||
REM Check for administrator privileges
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% neq 0 (
|
||||
echo ❌ ERROR: Administrator privileges required
|
||||
echo Please right-click this file and select "Run as administrator"
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [1/8] Administrator privileges confirmed ✅
|
||||
echo.
|
||||
|
||||
REM Set variables
|
||||
set CURRENT_DIR=%~dp0
|
||||
set SERVICE_NAME=QualityPrintService
|
||||
set SERVICE_DISPLAY_NAME=Quality Print Service
|
||||
set INSTALL_DIR=C:\QualityPrintService
|
||||
set LOG_DIR=%USERPROFILE%\PrintService\logs
|
||||
|
||||
REM Detect Python executable
|
||||
echo [2/8] Detecting Python installation...
|
||||
|
||||
set PYTHON_EXE=
|
||||
set PYTHON_SCRIPT=%INSTALL_DIR%\print_service_complete.py
|
||||
|
||||
REM Check for embedded Python first
|
||||
if exist "%INSTALL_DIR%\python_embedded\python.exe" (
|
||||
set PYTHON_EXE=%INSTALL_DIR%\python_embedded\python.exe
|
||||
echo Found embedded Python: !PYTHON_EXE! ✅
|
||||
) else if exist "%CURRENT_DIR%python_embedded\python.exe" (
|
||||
set PYTHON_EXE=%CURRENT_DIR%python_embedded\python.exe
|
||||
echo Found embedded Python in installer: !PYTHON_EXE! ✅
|
||||
) else (
|
||||
REM Check system Python
|
||||
python --version >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
set PYTHON_EXE=python
|
||||
echo Found system Python ✅
|
||||
) else (
|
||||
echo ❌ ERROR: Python not found
|
||||
echo Please ensure Python 3.7+ is installed or use the zero-dependency package
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo.
|
||||
|
||||
REM Stop existing service
|
||||
echo [3/8] Stopping existing service (if any)...
|
||||
sc query "%SERVICE_NAME%" >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo Stopping existing service...
|
||||
net stop "%SERVICE_NAME%" >nul 2>&1
|
||||
sc delete "%SERVICE_NAME%" >nul 2>&1
|
||||
timeout /t 3 >nul
|
||||
)
|
||||
|
||||
REM Stop any existing task
|
||||
schtasks /end /tn "%SERVICE_NAME%" >nul 2>&1
|
||||
schtasks /delete /tn "%SERVICE_NAME%" /f >nul 2>&1
|
||||
|
||||
echo Service cleanup completed ✅
|
||||
echo.
|
||||
|
||||
REM Create installation directory
|
||||
echo [4/8] Creating installation directory...
|
||||
if exist "%INSTALL_DIR%" (
|
||||
echo Removing old installation...
|
||||
rmdir /s /q "%INSTALL_DIR%" >nul 2>&1
|
||||
)
|
||||
mkdir "%INSTALL_DIR%" >nul 2>&1
|
||||
|
||||
REM Create log directory
|
||||
mkdir "%LOG_DIR%" >nul 2>&1
|
||||
|
||||
echo Installation directory: %INSTALL_DIR% ✅
|
||||
echo Log directory: %LOG_DIR% ✅
|
||||
echo.
|
||||
|
||||
REM Copy service files
|
||||
echo [5/8] Installing service files...
|
||||
|
||||
REM Copy Python embedded if available
|
||||
if exist "%CURRENT_DIR%python_embedded\" (
|
||||
echo Copying embedded Python distribution...
|
||||
xcopy "%CURRENT_DIR%python_embedded" "%INSTALL_DIR%\python_embedded\" /E /I /Y >nul
|
||||
set PYTHON_EXE=%INSTALL_DIR%\python_embedded\python.exe
|
||||
echo Embedded Python installed ✅
|
||||
)
|
||||
|
||||
REM Copy service scripts
|
||||
copy "%CURRENT_DIR%print_service_complete.py" "%INSTALL_DIR%\" >nul
|
||||
copy "%CURRENT_DIR%service_wrapper.py" "%INSTALL_DIR%\" >nul 2>&1
|
||||
copy "%CURRENT_DIR%service_installer.py" "%INSTALL_DIR%\" >nul 2>&1
|
||||
|
||||
echo Service files installed ✅
|
||||
echo.
|
||||
|
||||
REM Test service before installing
|
||||
echo [6/8] Testing service functionality...
|
||||
cd /d "%INSTALL_DIR%"
|
||||
|
||||
echo Testing Python and service script...
|
||||
"%PYTHON_EXE%" "%PYTHON_SCRIPT%" --test >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo Service test passed ✅
|
||||
) else (
|
||||
echo ⚠️ Service test failed - continuing with installation
|
||||
)
|
||||
|
||||
REM Check port availability
|
||||
echo Testing port 8765 availability...
|
||||
netstat -an | findstr :8765 >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo ⚠️ Port 8765 is in use - service may conflict
|
||||
) else (
|
||||
echo Port 8765 available ✅
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Install service - Multiple methods
|
||||
echo [7/8] Installing Windows service with multiple fallback methods...
|
||||
|
||||
REM Create enhanced service wrapper
|
||||
set WRAPPER_BAT=%INSTALL_DIR%\enhanced_service_wrapper.bat
|
||||
|
||||
echo @echo off > "%WRAPPER_BAT%"
|
||||
echo REM Enhanced Windows Service Wrapper - Error 1053 Fix >> "%WRAPPER_BAT%"
|
||||
echo cd /d "%INSTALL_DIR%" >> "%WRAPPER_BAT%"
|
||||
echo. >> "%WRAPPER_BAT%"
|
||||
echo REM Log service start attempt >> "%WRAPPER_BAT%"
|
||||
echo echo %%date%% %%time%% - Service wrapper starting... ^>^> "%LOG_DIR%\service_wrapper.log" >> "%WRAPPER_BAT%"
|
||||
echo. >> "%WRAPPER_BAT%"
|
||||
echo REM Verify files exist >> "%WRAPPER_BAT%"
|
||||
echo if not exist "%PYTHON_EXE%" ( >> "%WRAPPER_BAT%"
|
||||
echo echo ERROR: Python not found at %PYTHON_EXE% ^>^> "%LOG_DIR%\service_wrapper.log" >> "%WRAPPER_BAT%"
|
||||
echo exit /b 1 >> "%WRAPPER_BAT%"
|
||||
echo ^) >> "%WRAPPER_BAT%"
|
||||
echo. >> "%WRAPPER_BAT%"
|
||||
echo if not exist "%PYTHON_SCRIPT%" ( >> "%WRAPPER_BAT%"
|
||||
echo echo ERROR: Service script not found ^>^> "%LOG_DIR%\service_wrapper.log" >> "%WRAPPER_BAT%"
|
||||
echo exit /b 1 >> "%WRAPPER_BAT%"
|
||||
echo ^) >> "%WRAPPER_BAT%"
|
||||
echo. >> "%WRAPPER_BAT%"
|
||||
echo REM Start service with error handling >> "%WRAPPER_BAT%"
|
||||
echo echo Starting service process... ^>^> "%LOG_DIR%\service_wrapper.log" >> "%WRAPPER_BAT%"
|
||||
echo "%PYTHON_EXE%" "%PYTHON_SCRIPT%" --service >> "%WRAPPER_BAT%"
|
||||
echo. >> "%WRAPPER_BAT%"
|
||||
echo REM Log exit code >> "%WRAPPER_BAT%"
|
||||
echo echo Service exited with code %%errorlevel%% ^>^> "%LOG_DIR%\service_wrapper.log" >> "%WRAPPER_BAT%"
|
||||
|
||||
REM Method 1: Windows SC Service
|
||||
echo Installing as Windows SC Service...
|
||||
sc create "%SERVICE_NAME%" binPath= "\"%WRAPPER_BAT%\"" DisplayName= "%SERVICE_DISPLAY_NAME%" start= auto >nul 2>&1
|
||||
|
||||
if %errorLevel% equ 0 (
|
||||
echo Windows SC Service created ✅
|
||||
|
||||
REM Configure recovery
|
||||
sc failure "%SERVICE_NAME%" reset= 86400 actions= restart/5000/restart/5000/restart/5000 >nul 2>&1
|
||||
|
||||
REM Try to start service
|
||||
echo Starting SC service...
|
||||
net start "%SERVICE_NAME%" >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo SC Service started successfully ✅
|
||||
set SERVICE_METHOD=SC_SERVICE
|
||||
goto :service_installed
|
||||
) else (
|
||||
echo ⚠️ SC Service created but failed to start - trying Task Scheduler...
|
||||
)
|
||||
) else (
|
||||
echo ❌ SC Service creation failed - trying Task Scheduler...
|
||||
)
|
||||
|
||||
REM Method 2: Task Scheduler Service
|
||||
echo Installing as Task Scheduler Service...
|
||||
|
||||
REM Create task XML
|
||||
set TASK_XML=%INSTALL_DIR%\%SERVICE_NAME%_task.xml
|
||||
|
||||
echo ^<?xml version="1.0" encoding="UTF-16"?^> > "%TASK_XML%"
|
||||
echo ^<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"^> >> "%TASK_XML%"
|
||||
echo ^<RegistrationInfo^> >> "%TASK_XML%"
|
||||
echo ^<Description^>Quality Print Service - Automatic Label Printing^</Description^> >> "%TASK_XML%"
|
||||
echo ^</RegistrationInfo^> >> "%TASK_XML%"
|
||||
echo ^<Triggers^> >> "%TASK_XML%"
|
||||
echo ^<BootTrigger^> >> "%TASK_XML%"
|
||||
echo ^<Enabled^>true^</Enabled^> >> "%TASK_XML%"
|
||||
echo ^</BootTrigger^> >> "%TASK_XML%"
|
||||
echo ^</Triggers^> >> "%TASK_XML%"
|
||||
echo ^<Principals^> >> "%TASK_XML%"
|
||||
echo ^<Principal id="Author"^> >> "%TASK_XML%"
|
||||
echo ^<UserId^>S-1-5-18^</UserId^> >> "%TASK_XML%"
|
||||
echo ^<RunLevel^>HighestAvailable^</RunLevel^> >> "%TASK_XML%"
|
||||
echo ^</Principal^> >> "%TASK_XML%"
|
||||
echo ^</Principals^> >> "%TASK_XML%"
|
||||
echo ^<Settings^> >> "%TASK_XML%"
|
||||
echo ^<MultipleInstancesPolicy^>IgnoreNew^</MultipleInstancesPolicy^> >> "%TASK_XML%"
|
||||
echo ^<DisallowStartIfOnBatteries^>false^</DisallowStartIfOnBatteries^> >> "%TASK_XML%"
|
||||
echo ^<StopIfGoingOnBatteries^>false^</StopIfGoingOnBatteries^> >> "%TASK_XML%"
|
||||
echo ^<AllowHardTerminate^>true^</AllowHardTerminate^> >> "%TASK_XML%"
|
||||
echo ^<StartWhenAvailable^>true^</StartWhenAvailable^> >> "%TASK_XML%"
|
||||
echo ^<RunOnlyIfNetworkAvailable^>false^</RunOnlyIfNetworkAvailable^> >> "%TASK_XML%"
|
||||
echo ^<AllowStartOnDemand^>true^</AllowStartOnDemand^> >> "%TASK_XML%"
|
||||
echo ^<Enabled^>true^</Enabled^> >> "%TASK_XML%"
|
||||
echo ^<Hidden^>false^</Hidden^> >> "%TASK_XML%"
|
||||
echo ^<RestartOnFailure^> >> "%TASK_XML%"
|
||||
echo ^<Interval^>PT5M^</Interval^> >> "%TASK_XML%"
|
||||
echo ^<Count^>3^</Count^> >> "%TASK_XML%"
|
||||
echo ^</RestartOnFailure^> >> "%TASK_XML%"
|
||||
echo ^</Settings^> >> "%TASK_XML%"
|
||||
echo ^<Actions Context="Author"^> >> "%TASK_XML%"
|
||||
echo ^<Exec^> >> "%TASK_XML%"
|
||||
echo ^<Command^>"%PYTHON_EXE%"^</Command^> >> "%TASK_XML%"
|
||||
echo ^<Arguments^>"%PYTHON_SCRIPT%" --service^</Arguments^> >> "%TASK_XML%"
|
||||
echo ^<WorkingDirectory^>%INSTALL_DIR%^</WorkingDirectory^> >> "%TASK_XML%"
|
||||
echo ^</Exec^> >> "%TASK_XML%"
|
||||
echo ^</Actions^> >> "%TASK_XML%"
|
||||
echo ^</Task^> >> "%TASK_XML%"
|
||||
|
||||
schtasks /create /tn "%SERVICE_NAME%" /xml "%TASK_XML%" >nul 2>&1
|
||||
if %errorLevel% equ 0 (
|
||||
echo Task Scheduler service created ✅
|
||||
|
||||
REM Start task
|
||||
schtasks /run /tn "%SERVICE_NAME%" >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo Task Scheduler service started ✅
|
||||
set SERVICE_METHOD=TASK_SCHEDULER
|
||||
goto :service_installed
|
||||
) else (
|
||||
echo ⚠️ Task created but failed to start
|
||||
)
|
||||
) else (
|
||||
echo ❌ Task Scheduler creation failed
|
||||
)
|
||||
|
||||
REM Method 3: Startup Script Fallback
|
||||
echo Installing as Startup Script...
|
||||
set STARTUP_DIR=%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
|
||||
set STARTUP_SCRIPT=%STARTUP_DIR%\QualityPrintService.bat
|
||||
|
||||
echo @echo off > "%STARTUP_SCRIPT%"
|
||||
echo REM Quality Print Service - Startup Script >> "%STARTUP_SCRIPT%"
|
||||
echo cd /d "%INSTALL_DIR%" >> "%STARTUP_SCRIPT%"
|
||||
echo start /min "Quality Print Service" "%PYTHON_EXE%" "%PYTHON_SCRIPT%" --service >> "%STARTUP_SCRIPT%"
|
||||
|
||||
if exist "%STARTUP_SCRIPT%" (
|
||||
echo Startup script created ✅
|
||||
|
||||
REM Start immediately
|
||||
start /min "" "%STARTUP_SCRIPT%"
|
||||
echo Service started via startup script ✅
|
||||
set SERVICE_METHOD=STARTUP_SCRIPT
|
||||
goto :service_installed
|
||||
)
|
||||
|
||||
REM If we get here, all methods failed
|
||||
echo ❌ All installation methods failed
|
||||
goto :installation_failed
|
||||
|
||||
:service_installed
|
||||
echo.
|
||||
|
||||
REM Verification
|
||||
echo [8/8] Verifying installation...
|
||||
|
||||
echo Waiting for service to start...
|
||||
timeout /t 5 >nul
|
||||
|
||||
REM Test service connection
|
||||
echo Testing service connection...
|
||||
for /L %%i in (1,1,10) do (
|
||||
curl -s http://localhost:8765/health >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo Service is responding ✅
|
||||
goto :success
|
||||
)
|
||||
|
||||
powershell -Command "try { Invoke-WebRequest -Uri 'http://localhost:8765/health' -UseBasicParsing } catch { exit 1 }" >nul 2>&1
|
||||
if !errorLevel! equ 0 (
|
||||
echo Service is responding ✅
|
||||
goto :success
|
||||
)
|
||||
|
||||
echo Attempt %%i failed, retrying...
|
||||
timeout /t 2 >nul
|
||||
)
|
||||
|
||||
echo ⚠️ Service installed but not responding
|
||||
goto :partial_success
|
||||
|
||||
:success
|
||||
echo.
|
||||
echo ========================================
|
||||
echo INSTALLATION SUCCESSFUL! 🎉
|
||||
echo ========================================
|
||||
echo.
|
||||
echo ✅ Service Method: !SERVICE_METHOD!
|
||||
echo ✅ Service URL: http://localhost:8765
|
||||
echo ✅ Health Check: http://localhost:8765/health
|
||||
echo ✅ Service will start automatically on boot
|
||||
echo.
|
||||
echo 📋 NEXT STEPS:
|
||||
echo 1. Install Chrome extension from 'chrome_extension' folder
|
||||
echo 2. Test printing from the web application
|
||||
echo 3. Configure printer settings if needed
|
||||
echo.
|
||||
echo 📊 Service Management:
|
||||
if "!SERVICE_METHOD!"=="SC_SERVICE" (
|
||||
echo - Start: net start %SERVICE_NAME%
|
||||
echo - Stop: net stop %SERVICE_NAME%
|
||||
echo - Status: sc query %SERVICE_NAME%
|
||||
) else if "!SERVICE_METHOD!"=="TASK_SCHEDULER" (
|
||||
echo - Start: schtasks /run /tn %SERVICE_NAME%
|
||||
echo - Stop: schtasks /end /tn %SERVICE_NAME%
|
||||
echo - Status: schtasks /query /tn %SERVICE_NAME%
|
||||
) else (
|
||||
echo - Start: Run startup script manually
|
||||
echo - Stop: End process in Task Manager
|
||||
)
|
||||
echo.
|
||||
echo 📁 Logs: %LOG_DIR%
|
||||
echo.
|
||||
goto :end
|
||||
|
||||
:partial_success
|
||||
echo.
|
||||
echo ========================================
|
||||
echo INSTALLATION COMPLETED
|
||||
echo ========================================
|
||||
echo.
|
||||
echo ⚠️ Service installed but verification failed
|
||||
echo 📋 Manual verification steps:
|
||||
echo.
|
||||
echo 1. Check if service is running:
|
||||
if "!SERVICE_METHOD!"=="SC_SERVICE" (
|
||||
echo sc query %SERVICE_NAME%
|
||||
) else if "!SERVICE_METHOD!"=="TASK_SCHEDULER" (
|
||||
echo schtasks /query /tn %SERVICE_NAME%
|
||||
) else (
|
||||
echo Check Task Manager for python.exe process
|
||||
)
|
||||
echo.
|
||||
echo 2. Test service manually:
|
||||
echo http://localhost:8765/health
|
||||
echo.
|
||||
echo 3. Check logs:
|
||||
echo %LOG_DIR%\service_wrapper.log
|
||||
echo.
|
||||
echo 4. Manual start if needed:
|
||||
if "!SERVICE_METHOD!"=="SC_SERVICE" (
|
||||
echo net start %SERVICE_NAME%
|
||||
) else if "!SERVICE_METHOD!"=="TASK_SCHEDULER" (
|
||||
echo schtasks /run /tn %SERVICE_NAME%
|
||||
) else (
|
||||
echo Run: %STARTUP_SCRIPT%
|
||||
)
|
||||
echo.
|
||||
goto :end
|
||||
|
||||
:installation_failed
|
||||
echo.
|
||||
echo ========================================
|
||||
echo INSTALLATION FAILED
|
||||
echo ========================================
|
||||
echo.
|
||||
echo ❌ All service installation methods failed
|
||||
echo.
|
||||
echo 📋 Troubleshooting steps:
|
||||
echo 1. Verify Administrator privileges
|
||||
echo 2. Check Python installation
|
||||
echo 3. Ensure port 8765 is available
|
||||
echo 4. Review logs in: %LOG_DIR%
|
||||
echo 5. Try manual service start
|
||||
echo.
|
||||
echo 🔧 Manual installation:
|
||||
echo cd /d "%INSTALL_DIR%"
|
||||
echo "%PYTHON_EXE%" "%PYTHON_SCRIPT%" --standalone
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
|
||||
:end
|
||||
echo Press any key to exit...
|
||||
pause >nul
|
||||
@@ -124,20 +124,35 @@ if exist "%CURRENT_DIR%nssm.exe" (
|
||||
echo Windows service installed with NSSM ✓
|
||||
|
||||
) else (
|
||||
echo Installing with Windows SC command...
|
||||
echo Installing with Windows SC command (Enhanced Service Wrapper)...
|
||||
|
||||
REM Create a wrapper batch file for the service
|
||||
REM Copy service wrapper
|
||||
copy "%CURRENT_DIR%service_wrapper.py" "%INSTALL_DIR%\" >nul
|
||||
if %errorLevel% neq 0 (
|
||||
echo WARNING: Service wrapper not found, creating basic wrapper...
|
||||
)
|
||||
|
||||
REM Create enhanced service wrapper batch file
|
||||
set WRAPPER_BAT=%INSTALL_DIR%\service_wrapper.bat
|
||||
|
||||
echo @echo off > "%WRAPPER_BAT%"
|
||||
echo REM Windows Print Service Wrapper - Fixed for Error 1053 >> "%WRAPPER_BAT%"
|
||||
echo cd /d "%INSTALL_DIR%" >> "%WRAPPER_BAT%"
|
||||
echo "%PYTHON_EXE%" "%PYTHON_SCRIPT%" >> "%WRAPPER_BAT%"
|
||||
echo. >> "%WRAPPER_BAT%"
|
||||
echo REM Check if Python service wrapper exists >> "%WRAPPER_BAT%"
|
||||
echo if exist "%INSTALL_DIR%\service_wrapper.py" ( >> "%WRAPPER_BAT%"
|
||||
echo echo Starting service with wrapper... >> "%WRAPPER_BAT%"
|
||||
echo "%PYTHON_EXE%" "%INSTALL_DIR%\service_wrapper.py" >> "%WRAPPER_BAT%"
|
||||
echo ^) else ( >> "%WRAPPER_BAT%"
|
||||
echo echo Starting service directly... >> "%WRAPPER_BAT%"
|
||||
echo "%PYTHON_EXE%" "%PYTHON_SCRIPT%" --service >> "%WRAPPER_BAT%"
|
||||
echo ^) >> "%WRAPPER_BAT%"
|
||||
|
||||
REM Install service using sc command
|
||||
REM Install service using sc command with enhanced wrapper
|
||||
sc create "%SERVICE_NAME%" binPath= "\"%WRAPPER_BAT%\"" DisplayName= "%SERVICE_DISPLAY_NAME%" start= auto
|
||||
|
||||
if %errorLevel% equ 0 (
|
||||
echo Windows service installed with SC ✓
|
||||
echo Windows service installed with Enhanced SC Wrapper ✓
|
||||
) else (
|
||||
echo ERROR: Failed to install Windows service
|
||||
echo Trying scheduled task fallback...
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Windows Print Service - Complete Self-Contained Version
|
||||
Includes all dependencies and libraries for Windows systems
|
||||
Fixed for Windows Service Error 1053 - Proper Service Implementation
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -12,6 +12,7 @@ import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import time
|
||||
import signal
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import threading
|
||||
@@ -24,6 +25,10 @@ import zipfile
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from socketserver import ThreadingMixIn
|
||||
|
||||
# Global variables for service control
|
||||
service_running = True
|
||||
httpd_server = None
|
||||
|
||||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
"""Handle requests in a separate thread."""
|
||||
daemon_threads = True
|
||||
@@ -467,48 +472,171 @@ pause
|
||||
with open('install_service_complete.bat', 'w') as f:
|
||||
f.write(service_script)
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
"""Handle shutdown signals gracefully."""
|
||||
global service_running, httpd_server
|
||||
logging.info(f"Received signal {signum}, shutting down gracefully...")
|
||||
service_running = False
|
||||
|
||||
if httpd_server:
|
||||
# Shutdown server in a separate thread to avoid blocking
|
||||
def shutdown_server():
|
||||
try:
|
||||
httpd_server.shutdown()
|
||||
httpd_server.server_close()
|
||||
except Exception as e:
|
||||
logging.error(f"Error during server shutdown: {e}")
|
||||
|
||||
shutdown_thread = threading.Thread(target=shutdown_server)
|
||||
shutdown_thread.daemon = True
|
||||
shutdown_thread.start()
|
||||
shutdown_thread.join(timeout=5)
|
||||
|
||||
logging.info("Service shutdown complete")
|
||||
sys.exit(0)
|
||||
|
||||
def setup_signal_handlers():
|
||||
"""Setup signal handlers for graceful shutdown."""
|
||||
if hasattr(signal, 'SIGTERM'):
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
if hasattr(signal, 'SIGINT'):
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
if hasattr(signal, 'SIGBREAK'): # Windows specific
|
||||
signal.signal(signal.SIGBREAK, signal_handler)
|
||||
|
||||
def main():
|
||||
"""Main service function."""
|
||||
global start_time
|
||||
"""Main service function with proper Windows service support."""
|
||||
global start_time, service_running, httpd_server
|
||||
start_time = time.time()
|
||||
|
||||
# Setup logging
|
||||
# Setup logging first
|
||||
setup_logging()
|
||||
logging.info("Starting Windows Print Service (Complete Version)")
|
||||
logging.info("=== Starting Windows Print Service (Complete Version) ===")
|
||||
logging.info(f"Python version: {sys.version}")
|
||||
logging.info(f"Platform: {sys.platform}")
|
||||
logging.info(f"Process ID: {os.getpid()}")
|
||||
logging.info(f"Command line args: {sys.argv}")
|
||||
|
||||
# Create service installer
|
||||
create_windows_service()
|
||||
# Setup signal handlers for graceful shutdown
|
||||
setup_signal_handlers()
|
||||
|
||||
# Determine run mode
|
||||
run_mode = "standalone"
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] in ['--service', 'service']:
|
||||
run_mode = "windows_service"
|
||||
elif sys.argv[1] in ['--standalone', 'standalone']:
|
||||
run_mode = "standalone"
|
||||
elif sys.argv[1] in ['--test', 'test']:
|
||||
run_mode = "test"
|
||||
|
||||
logging.info(f"Running in '{run_mode}' mode")
|
||||
|
||||
if run_mode == "test":
|
||||
# Test mode - just verify setup and exit
|
||||
logging.info("=== SERVICE TEST MODE ===")
|
||||
test_service_setup()
|
||||
return
|
||||
|
||||
try:
|
||||
# Start HTTP server
|
||||
server_address = ('localhost', 8765)
|
||||
httpd = ThreadingHTTPServer(server_address, PrintServiceHandler)
|
||||
|
||||
# Try to bind to the port
|
||||
try:
|
||||
httpd_server = ThreadingHTTPServer(server_address, PrintServiceHandler)
|
||||
except OSError as e:
|
||||
if "Address already in use" in str(e):
|
||||
logging.error(f"Port 8765 is already in use. Another service instance may be running.")
|
||||
logging.error("Stop the existing service or use a different port.")
|
||||
return
|
||||
else:
|
||||
raise
|
||||
|
||||
logging.info(f"Print service started on http://{server_address[0]}:{server_address[1]}")
|
||||
logging.info("Available endpoints:")
|
||||
logging.info(" GET /health - Health check")
|
||||
logging.info(" GET /printers - List available printers")
|
||||
logging.info(" GET /printers - List available printers")
|
||||
logging.info(" GET /status - Service status")
|
||||
logging.info(" POST /print_pdf - Print PDF file")
|
||||
|
||||
# Keep track of requests
|
||||
httpd.request_count = 0
|
||||
httpd_server.request_count = 0
|
||||
|
||||
# Start server
|
||||
httpd.serve_forever()
|
||||
# Service main loop
|
||||
logging.info("Service is ready and listening...")
|
||||
|
||||
if run_mode == "standalone":
|
||||
logging.info("*** STANDALONE MODE - Press Ctrl+C to stop ***")
|
||||
logging.info("Test the service at: http://localhost:8765/health")
|
||||
|
||||
while service_running:
|
||||
try:
|
||||
# Handle requests with timeout to check service_running periodically
|
||||
httpd_server.timeout = 1.0
|
||||
httpd_server.handle_request()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Service stopped by user (Ctrl+C)")
|
||||
break
|
||||
except Exception as e:
|
||||
logging.error(f"Request handling error: {e}")
|
||||
# Continue running unless it's a critical error
|
||||
if not service_running:
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Service stopped by user")
|
||||
except Exception as e:
|
||||
logging.error(f"Service error: {e}")
|
||||
logging.error(f"Critical service error: {e}")
|
||||
import traceback
|
||||
logging.error(f"Traceback: {traceback.format_exc()}")
|
||||
finally:
|
||||
# Cleanup
|
||||
if httpd_server:
|
||||
try:
|
||||
httpd_server.server_close()
|
||||
except:
|
||||
pass
|
||||
|
||||
logging.info("=== Windows Print Service shutdown complete ===")
|
||||
|
||||
# Exit cleanly
|
||||
sys.exit(0)
|
||||
|
||||
def test_service_setup():
|
||||
"""Test service setup and configuration."""
|
||||
logging.info("Testing service setup...")
|
||||
|
||||
# Test printer detection
|
||||
try:
|
||||
# Create a temporary handler instance to test printer detection
|
||||
import tempfile
|
||||
temp_handler = PrintServiceHandler()
|
||||
temp_handler.temp_dir = tempfile.mkdtemp(prefix="test_service_")
|
||||
|
||||
printers = temp_handler.get_available_printers()
|
||||
logging.info(f"Found {len(printers)} printers:")
|
||||
for printer in printers[:5]: # Show first 5
|
||||
logging.info(f" - {printer.get('name', 'Unknown')}")
|
||||
|
||||
# Cleanup temp directory
|
||||
try:
|
||||
httpd.server_close()
|
||||
import shutil
|
||||
shutil.rmtree(temp_handler.temp_dir)
|
||||
except:
|
||||
pass
|
||||
logging.info("Windows Print Service shutdown complete")
|
||||
|
||||
except Exception as e:
|
||||
logging.warning(f"Printer detection test failed: {e}")
|
||||
|
||||
# Test port availability
|
||||
try:
|
||||
import socket
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(('localhost', 8765))
|
||||
logging.info("Port 8765 is available ✓")
|
||||
except OSError as e:
|
||||
logging.error(f"Port 8765 test failed: {e}")
|
||||
|
||||
logging.info("Service setup test completed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
259
windows_print_service/service_installer.py
Normal file
259
windows_print_service/service_installer.py
Normal file
@@ -0,0 +1,259 @@
|
||||
"""
|
||||
Windows Service Implementation - Alternative Approach
|
||||
Uses Windows Task Scheduler as fallback if SC service fails
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
def create_scheduled_task_service():
|
||||
"""Create Windows service using Task Scheduler as fallback."""
|
||||
|
||||
service_name = "QualityPrintService"
|
||||
service_script = Path(__file__).parent / "print_service_complete.py"
|
||||
python_exe = sys.executable
|
||||
|
||||
# Create XML for scheduled task
|
||||
task_xml = f'''<?xml version="1.0" encoding="UTF-16"?>
|
||||
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
||||
<RegistrationInfo>
|
||||
<Date>2025-09-26T12:00:00</Date>
|
||||
<Author>Quality Print Service</Author>
|
||||
<Description>Quality Print Service - Automatic Label Printing</Description>
|
||||
</RegistrationInfo>
|
||||
<Triggers>
|
||||
<BootTrigger>
|
||||
<Enabled>true</Enabled>
|
||||
</BootTrigger>
|
||||
</Triggers>
|
||||
<Principals>
|
||||
<Principal id="Author">
|
||||
<UserId>S-1-5-18</UserId>
|
||||
<RunLevel>HighestAvailable</RunLevel>
|
||||
</Principal>
|
||||
</Principals>
|
||||
<Settings>
|
||||
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
||||
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
||||
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
||||
<AllowHardTerminate>true</AllowHardTerminate>
|
||||
<StartWhenAvailable>true</StartWhenAvailable>
|
||||
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
|
||||
<IdleSettings>
|
||||
<StopOnIdleEnd>false</StopOnIdleEnd>
|
||||
<RestartOnIdle>false</RestartOnIdle>
|
||||
</IdleSettings>
|
||||
<AllowStartOnDemand>true</AllowStartOnDemand>
|
||||
<Enabled>true</Enabled>
|
||||
<Hidden>false</Hidden>
|
||||
<RunOnlyIfIdle>false</RunOnlyIfIdle>
|
||||
<WakeToRun>false</WakeToRun>
|
||||
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
||||
<Priority>7</Priority>
|
||||
<RestartOnFailure>
|
||||
<Interval>PT5M</Interval>
|
||||
<Count>3</Count>
|
||||
</RestartOnFailure>
|
||||
</Settings>
|
||||
<Actions Context="Author">
|
||||
<Exec>
|
||||
<Command>"{python_exe}"</Command>
|
||||
<Arguments>"{service_script}" --service</Arguments>
|
||||
<WorkingDirectory>{service_script.parent}</WorkingDirectory>
|
||||
</Exec>
|
||||
</Actions>
|
||||
</Task>'''
|
||||
|
||||
# Save task XML to file
|
||||
task_xml_file = Path(__file__).parent / f"{service_name}_task.xml"
|
||||
with open(task_xml_file, 'w', encoding='utf-16') as f:
|
||||
f.write(task_xml)
|
||||
|
||||
return task_xml_file
|
||||
|
||||
def install_service_alternative():
|
||||
"""Install service using multiple methods."""
|
||||
|
||||
print("🔧 Installing Windows Print Service with Multiple Methods...")
|
||||
|
||||
service_name = "QualityPrintService"
|
||||
service_display_name = "Quality Print Service"
|
||||
service_script = Path(__file__).parent / "print_service_complete.py"
|
||||
python_exe = sys.executable
|
||||
|
||||
# Method 1: Try SC command with service wrapper
|
||||
print("\n📋 Method 1: Windows SC Service")
|
||||
try:
|
||||
# Create service wrapper batch file
|
||||
wrapper_bat = Path(__file__).parent / "service_wrapper.bat"
|
||||
|
||||
wrapper_content = f'''@echo off
|
||||
REM Windows Print Service Wrapper - Error 1053 Fix
|
||||
cd /d "{service_script.parent}"
|
||||
|
||||
REM Set error handling
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM Log startup
|
||||
echo %date% %time% - Service starting... >> service_startup.log
|
||||
|
||||
REM Check if Python exists
|
||||
if not exist "{python_exe}" (
|
||||
echo ERROR: Python not found at {python_exe} >> service_startup.log
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Check if service script exists
|
||||
if not exist "{service_script}" (
|
||||
echo ERROR: Service script not found at {service_script} >> service_startup.log
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Start the service with timeout monitoring
|
||||
echo Starting service process... >> service_startup.log
|
||||
"{python_exe}" "{service_script}" --service
|
||||
|
||||
REM Log exit
|
||||
echo %date% %time% - Service exited with code %errorlevel% >> service_startup.log
|
||||
'''
|
||||
|
||||
with open(wrapper_bat, 'w') as f:
|
||||
f.write(wrapper_content)
|
||||
|
||||
# Remove existing service
|
||||
subprocess.run(['sc', 'stop', service_name], capture_output=True)
|
||||
subprocess.run(['sc', 'delete', service_name], capture_output=True)
|
||||
|
||||
# Create service
|
||||
cmd = [
|
||||
'sc', 'create', service_name,
|
||||
f'binPath= "{wrapper_bat}"',
|
||||
f'DisplayName= "{service_display_name}"',
|
||||
'start= auto'
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ SC Service created successfully")
|
||||
|
||||
# Configure recovery
|
||||
subprocess.run([
|
||||
'sc', 'failure', service_name,
|
||||
'reset= 86400',
|
||||
'actions= restart/5000/restart/5000/restart/5000'
|
||||
], capture_output=True)
|
||||
|
||||
# Try to start
|
||||
start_result = subprocess.run(['sc', 'start', service_name], capture_output=True, text=True)
|
||||
if start_result.returncode == 0:
|
||||
print("✅ SC Service started successfully")
|
||||
return True
|
||||
else:
|
||||
print(f"⚠️ SC Service created but failed to start: {start_result.stderr}")
|
||||
else:
|
||||
print(f"❌ SC Service creation failed: {result.stderr}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ SC Service method failed: {e}")
|
||||
|
||||
# Method 2: Task Scheduler fallback
|
||||
print("\n📋 Method 2: Task Scheduler Service")
|
||||
try:
|
||||
task_xml_file = create_scheduled_task_service()
|
||||
|
||||
# Remove existing task
|
||||
subprocess.run(['schtasks', '/delete', '/tn', service_name, '/f'], capture_output=True)
|
||||
|
||||
# Create task
|
||||
cmd = [
|
||||
'schtasks', '/create', '/tn', service_name,
|
||||
'/xml', str(task_xml_file)
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✅ Task Scheduler service created successfully")
|
||||
|
||||
# Start task
|
||||
start_result = subprocess.run(['schtasks', '/run', '/tn', service_name], capture_output=True, text=True)
|
||||
if start_result.returncode == 0:
|
||||
print("✅ Task Scheduler service started successfully")
|
||||
return True
|
||||
else:
|
||||
print(f"⚠️ Task created but failed to start: {start_result.stderr}")
|
||||
else:
|
||||
print(f"❌ Task Scheduler creation failed: {result.stderr}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Task Scheduler method failed: {e}")
|
||||
|
||||
# Method 3: Manual startup script
|
||||
print("\n📋 Method 3: Startup Script")
|
||||
try:
|
||||
startup_script = Path(os.environ.get('APPDATA', '')) / 'Microsoft' / 'Windows' / 'Start Menu' / 'Programs' / 'Startup' / 'QualityPrintService.bat'
|
||||
startup_script.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
startup_content = f'''@echo off
|
||||
REM Quality Print Service - Startup Script
|
||||
cd /d "{service_script.parent}"
|
||||
start /min "Quality Print Service" "{python_exe}" "{service_script}" --service
|
||||
'''
|
||||
|
||||
with open(startup_script, 'w') as f:
|
||||
f.write(startup_content)
|
||||
|
||||
print(f"✅ Startup script created: {startup_script}")
|
||||
print("🔄 Service will start automatically on next reboot")
|
||||
|
||||
# Start immediately
|
||||
subprocess.run(['cmd', '/c', str(startup_script)], capture_output=True)
|
||||
print("✅ Service started via startup script")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Startup script method failed: {e}")
|
||||
|
||||
print("\n❌ All installation methods failed")
|
||||
return False
|
||||
|
||||
def test_service_connection(timeout=10):
|
||||
"""Test if service is running by checking HTTP endpoint."""
|
||||
import urllib.request
|
||||
import json
|
||||
|
||||
for i in range(timeout):
|
||||
try:
|
||||
with urllib.request.urlopen('http://localhost:8765/health', timeout=2) as response:
|
||||
data = json.loads(response.read().decode())
|
||||
if data.get('status') == 'healthy':
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
time.sleep(1)
|
||||
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'install':
|
||||
success = install_service_alternative()
|
||||
|
||||
if success:
|
||||
print("\n🧪 Testing service connection...")
|
||||
if test_service_connection():
|
||||
print("✅ Service is responding correctly!")
|
||||
print("🌐 Test URL: http://localhost:8765/health")
|
||||
else:
|
||||
print("⚠️ Service installed but not responding")
|
||||
print("📋 Check logs and try manual start")
|
||||
else:
|
||||
print("\n❌ Service installation failed")
|
||||
print("📋 Try running as Administrator")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Usage: python service_installer.py install")
|
||||
175
windows_print_service/service_wrapper.py
Normal file
175
windows_print_service/service_wrapper.py
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Windows Service Wrapper - Handles Windows Service Communication
|
||||
Fixes Error 1053 by properly communicating with Service Control Manager
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import subprocess
|
||||
import threading
|
||||
import signal
|
||||
from pathlib import Path
|
||||
|
||||
# Simple service state management
|
||||
class WindowsServiceManager:
|
||||
def __init__(self):
|
||||
self.service_process = None
|
||||
self.should_stop = False
|
||||
self.service_thread = None
|
||||
|
||||
def setup_logging(self):
|
||||
"""Setup service logging."""
|
||||
log_dir = os.path.join(os.path.expanduser("~"), "PrintService", "logs")
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
log_file = os.path.join(log_dir, f"service_wrapper_{time.strftime('%Y%m%d')}.log")
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(log_file, encoding='utf-8'),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
|
||||
def signal_handler(self, signum, frame):
|
||||
"""Handle shutdown signals."""
|
||||
logging.info(f"Service wrapper received signal {signum}")
|
||||
self.stop_service()
|
||||
|
||||
def start_service(self):
|
||||
"""Start the actual print service."""
|
||||
script_dir = Path(__file__).parent
|
||||
service_script = script_dir / "print_service_complete.py"
|
||||
|
||||
if not service_script.exists():
|
||||
logging.error(f"Service script not found: {service_script}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Get Python executable path
|
||||
python_exe = sys.executable
|
||||
if not python_exe:
|
||||
python_exe = "python"
|
||||
|
||||
logging.info(f"Starting print service with: {python_exe} {service_script}")
|
||||
|
||||
# Start the service process
|
||||
self.service_process = subprocess.Popen(
|
||||
[python_exe, str(service_script), "--service"],
|
||||
cwd=str(script_dir),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
universal_newlines=True
|
||||
)
|
||||
|
||||
# Monitor service output
|
||||
def monitor_output():
|
||||
if self.service_process:
|
||||
for line in iter(self.service_process.stdout.readline, ''):
|
||||
if line:
|
||||
logging.info(f"Service: {line.strip()}")
|
||||
if self.should_stop:
|
||||
break
|
||||
|
||||
self.service_thread = threading.Thread(target=monitor_output, daemon=True)
|
||||
self.service_thread.start()
|
||||
|
||||
logging.info("Print service started successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to start service: {e}")
|
||||
return False
|
||||
|
||||
def stop_service(self):
|
||||
"""Stop the print service."""
|
||||
logging.info("Stopping print service...")
|
||||
self.should_stop = True
|
||||
|
||||
if self.service_process:
|
||||
try:
|
||||
# Try graceful shutdown first
|
||||
self.service_process.terminate()
|
||||
|
||||
# Wait up to 10 seconds for graceful shutdown
|
||||
for _ in range(10):
|
||||
if self.service_process.poll() is not None:
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
# Force kill if still running
|
||||
if self.service_process.poll() is None:
|
||||
logging.warning("Force killing service process")
|
||||
self.service_process.kill()
|
||||
|
||||
self.service_process.wait()
|
||||
logging.info("Print service stopped")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error stopping service: {e}")
|
||||
|
||||
def run_service(self):
|
||||
"""Main service loop."""
|
||||
logging.info("Windows Print Service Wrapper starting...")
|
||||
|
||||
# Setup signal handlers
|
||||
signal.signal(signal.SIGTERM, self.signal_handler)
|
||||
signal.signal(signal.SIGINT, self.signal_handler)
|
||||
if hasattr(signal, 'SIGBREAK'):
|
||||
signal.signal(signal.SIGBREAK, self.signal_handler)
|
||||
|
||||
# Start the actual service
|
||||
if not self.start_service():
|
||||
logging.error("Failed to start print service")
|
||||
return 1
|
||||
|
||||
# Service main loop - keep running until stopped
|
||||
try:
|
||||
while not self.should_stop:
|
||||
# Check if service process is still running
|
||||
if self.service_process and self.service_process.poll() is not None:
|
||||
logging.warning("Service process died, restarting...")
|
||||
if not self.start_service():
|
||||
logging.error("Failed to restart service")
|
||||
break
|
||||
|
||||
time.sleep(5) # Check every 5 seconds
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Service interrupted by user")
|
||||
except Exception as e:
|
||||
logging.error(f"Service loop error: {e}")
|
||||
finally:
|
||||
self.stop_service()
|
||||
|
||||
logging.info("Windows Print Service Wrapper stopped")
|
||||
return 0
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
service_manager = WindowsServiceManager()
|
||||
service_manager.setup_logging()
|
||||
|
||||
# Check command line arguments
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "install":
|
||||
logging.info("Service install requested - use install_service_complete.bat instead")
|
||||
return 1
|
||||
elif sys.argv[1] == "start":
|
||||
logging.info("Service start requested")
|
||||
elif sys.argv[1] == "stop":
|
||||
logging.info("Service stop requested")
|
||||
return 0
|
||||
|
||||
# Run the service
|
||||
return service_manager.run_service()
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
57
windows_print_service/test_service.bat
Normal file
57
windows_print_service/test_service.bat
Normal file
@@ -0,0 +1,57 @@
|
||||
@echo off
|
||||
REM Windows Print Service - Troubleshooting and Testing Script
|
||||
REM Use this to test the service before installing it as a Windows service
|
||||
|
||||
echo =========================================
|
||||
echo Windows Print Service - Test Mode
|
||||
echo =========================================
|
||||
echo.
|
||||
|
||||
REM Set variables
|
||||
set CURRENT_DIR=%~dp0
|
||||
set SERVICE_NAME=QualityPrintService
|
||||
set INSTALL_DIR=C:\QualityPrintService
|
||||
set PYTHON_EXE=%INSTALL_DIR%\python_embedded\python.exe
|
||||
set PYTHON_SCRIPT=%INSTALL_DIR%\print_service_complete.py
|
||||
|
||||
echo [INFO] Testing service in standalone mode...
|
||||
echo [INFO] This helps diagnose issues before installing as Windows service
|
||||
echo.
|
||||
|
||||
REM Check if files exist
|
||||
if not exist "%PYTHON_EXE%" (
|
||||
echo [ERROR] Python not found at: %PYTHON_EXE%
|
||||
echo [INFO] Make sure the service is installed first using install_service_complete.bat
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "%PYTHON_SCRIPT%" (
|
||||
echo [ERROR] Service script not found at: %PYTHON_SCRIPT%
|
||||
echo [INFO] Make sure the service is installed first using install_service_complete.bat
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [INFO] Files found, starting service test...
|
||||
echo [INFO] Python: %PYTHON_EXE%
|
||||
echo [INFO] Script: %PYTHON_SCRIPT%
|
||||
echo.
|
||||
echo [INFO] Starting service in test mode...
|
||||
echo [INFO] Press Ctrl+C to stop the service
|
||||
echo [INFO] Service will run on http://localhost:8765
|
||||
echo.
|
||||
|
||||
REM Change to service directory
|
||||
cd /d "%INSTALL_DIR%"
|
||||
|
||||
REM Start service in standalone mode for testing
|
||||
"%PYTHON_EXE%" "%PYTHON_SCRIPT%" --standalone
|
||||
|
||||
echo.
|
||||
echo [INFO] Service test completed.
|
||||
echo [INFO] If the service ran successfully above, you can now:
|
||||
echo [INFO] 1. Test it: http://localhost:8765/health
|
||||
echo [INFO] 2. Start Windows service: net start %SERVICE_NAME%
|
||||
echo.
|
||||
pause
|
||||
Reference in New Issue
Block a user