saved
This commit is contained in:
Binary file not shown.
@@ -2038,6 +2038,33 @@ def generate_labels_pdf(order_id, paper_saving_mode='true'):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/update_printed_status/<int:order_id>', methods=['POST'])
|
||||||
|
def update_printed_status(order_id):
|
||||||
|
"""Update printed status for direct printing (without PDF generation)"""
|
||||||
|
print(f"DEBUG: update_printed_status called for order_id: {order_id}")
|
||||||
|
|
||||||
|
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||||
|
print(f"DEBUG: Access denied for role: {session.get('role')}")
|
||||||
|
return jsonify({'error': 'Access denied. Required roles: superadmin, warehouse_manager, etichete'}), 403
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .pdf_generator import update_order_printed_status
|
||||||
|
|
||||||
|
# Update printed status in database
|
||||||
|
update_success = update_order_printed_status(order_id)
|
||||||
|
|
||||||
|
if update_success:
|
||||||
|
print(f"DEBUG: Successfully updated printed status for order {order_id}")
|
||||||
|
return jsonify({'success': True, 'message': f'Order {order_id} marked as printed'})
|
||||||
|
else:
|
||||||
|
print(f"WARNING: Could not update printed status for order {order_id}")
|
||||||
|
return jsonify({'error': 'Could not update printed status'}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error in update_printed_status: {e}")
|
||||||
|
return jsonify({'error': 'Internal server error'}), 500
|
||||||
|
|
||||||
@bp.route('/get_order_data/<int:order_id>', methods=['GET'])
|
@bp.route('/get_order_data/<int:order_id>', methods=['GET'])
|
||||||
def get_order_data(order_id):
|
def get_order_data(order_id):
|
||||||
"""Get specific order data for preview"""
|
"""Get specific order data for preview"""
|
||||||
|
|||||||
@@ -40,8 +40,10 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="scan-container" style="display: flex; flex-direction: row; gap: 20px; width: 100%; align-items: flex-start;">
|
<div class="scan-container" style="display: flex; flex-direction: row; gap: 20px; width: 100%; align-items: flex-start;">
|
||||||
<!-- Label Preview Card -->
|
<!-- 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="card scan-form-card" style="display: flex; flex-direction: column; justify-content: flex-start; align-items: center; min-height: 700px; width: 330px; flex-shrink: 0; position: relative; padding: 15px;">
|
||||||
<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 class="label-view-title" style="width: 100%; text-align: center; padding: 0 0 15px 0; font-size: 18px; font-weight: bold; letter-spacing: 0.5px;">Label View</div>
|
||||||
|
|
||||||
|
<!-- Label Preview Section -->
|
||||||
<div id="label-preview" style="border: 1px solid #ddd; padding: 10px; position: relative; background: #fafafa; width: 301px; height: 434.7px;">
|
<div id="label-preview" style="border: 1px solid #ddd; padding: 10px; position: relative; background: #fafafa; width: 301px; height: 434.7px;">
|
||||||
<!-- Label content rectangle -->
|
<!-- 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;">
|
<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;">
|
||||||
@@ -150,12 +152,60 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Print Options and Button Section - Inside the Card -->
|
||||||
|
<div style="width: 100%; margin-top: 20px;">
|
||||||
|
<!-- Print Method Selection -->
|
||||||
|
<div style="margin-bottom: 15px;">
|
||||||
|
<label style="font-size: 12px; font-weight: 600; color: #495057; margin-bottom: 8px; display: block;">
|
||||||
|
🖨️ Print Method:
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input class="form-check-input" type="radio" name="printMethod" id="directPrint" value="direct" checked>
|
||||||
|
<label class="form-check-label" for="directPrint" style="font-size: 11px; line-height: 1.3;">
|
||||||
|
<strong>Direct Print</strong><br>
|
||||||
|
<span class="text-muted">Print directly to thermal label printer</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="print-label-btn" class="btn btn-success" style="margin-top: 15px;">Generate PDF</button>
|
<div class="form-check mb-2">
|
||||||
|
<input class="form-check-input" type="radio" name="printMethod" id="pdfGenerate" value="pdf">
|
||||||
|
<label class="form-check-label" for="pdfGenerate" style="font-size: 11px; line-height: 1.3;">
|
||||||
|
<strong>Generate PDF</strong><br>
|
||||||
|
<span class="text-muted">Create PDF for manual printing</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Data Preview Card -->
|
<!-- Printer Selection -->
|
||||||
|
<div id="printerSelection" style="margin-bottom: 15px;">
|
||||||
|
<label style="font-size: 12px; font-weight: 600; color: #495057; margin-bottom: 5px; display: block;">
|
||||||
|
Select Printer:
|
||||||
|
</label>
|
||||||
|
<select id="printerSelect" class="form-control form-control-sm" style="font-size: 11px; padding: 4px 8px;">
|
||||||
|
<option value="default">Default Printer</option>
|
||||||
|
<option value="Epson TM-T20">Epson TM-T20</option>
|
||||||
|
<option value="Citizen CTS-310">Citizen CTS-310</option>
|
||||||
|
<option value="custom">Other Printer...</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted" style="font-size: 10px;">Choose your thermal label printer</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Print Button -->
|
||||||
|
<div style="width: 100%; text-align: center; margin-bottom: 15px;">
|
||||||
|
<button id="print-label-btn" class="btn btn-success" style="font-size: 14px; padding: 10px 30px; border-radius: 6px; font-weight: 600;">
|
||||||
|
🖨️ Print Labels
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Print Information -->
|
||||||
|
<div style="width: 100%; text-align: center; color: #6c757d; font-size: 11px; line-height: 1.4;">
|
||||||
|
<div style="margin-bottom: 5px;">Creates sequential labels based on quantity</div>
|
||||||
|
<small>(e.g., CP00000711-001 to CP00000711-063)</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> <!-- Data Preview Card -->
|
||||||
<div class="card scan-table-card" style="min-height: 700px; width: calc(100% - 350px); margin: 0;">
|
<div class="card scan-table-card" style="min-height: 700px; width: calc(100% - 350px); margin: 0;">
|
||||||
<h3>Data Preview (Unprinted Orders)</h3>
|
<h3>Data Preview (Unprinted Orders)</h3>
|
||||||
<button id="check-db-btn" class="btn btn-primary mb-3">Check Database</button>
|
<button id="check-db-btn" class="btn btn-primary mb-3">Check Database</button>
|
||||||
@@ -352,9 +402,13 @@ function addPDFGenerationHandler() {
|
|||||||
const printButton = document.getElementById('print-label-btn');
|
const printButton = document.getElementById('print-label-btn');
|
||||||
|
|
||||||
if (printButton) {
|
if (printButton) {
|
||||||
// Update button text and appearance for PDF generation
|
// Update button text and appearance based on print method
|
||||||
printButton.innerHTML = '📄 Generate PDF Labels';
|
updatePrintButtonText();
|
||||||
printButton.title = 'Generate PDF with multiple labels based on quantity';
|
|
||||||
|
// Add event listeners for radio buttons
|
||||||
|
document.querySelectorAll('input[name="printMethod"]').forEach(radio => {
|
||||||
|
radio.addEventListener('change', updatePrintButtonText);
|
||||||
|
});
|
||||||
|
|
||||||
printButton.addEventListener('click', function(e) {
|
printButton.addEventListener('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -366,21 +420,123 @@ function addPDFGenerationHandler() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get print method
|
||||||
|
const printMethod = document.querySelector('input[name="printMethod"]:checked').value;
|
||||||
|
|
||||||
|
if (printMethod === 'direct') {
|
||||||
|
handleDirectPrint(selectedRow);
|
||||||
|
} else {
|
||||||
|
handlePDFGeneration(selectedRow);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePrintButtonText() {
|
||||||
|
const printButton = document.getElementById('print-label-btn');
|
||||||
|
const printMethod = document.querySelector('input[name="printMethod"]:checked').value;
|
||||||
|
const printerSelection = document.getElementById('printerSelection');
|
||||||
|
|
||||||
|
if (printMethod === 'direct') {
|
||||||
|
printButton.innerHTML = '🖨️ Print Directly';
|
||||||
|
printButton.title = 'Print directly to thermal label printer';
|
||||||
|
printerSelection.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
printButton.innerHTML = '📄 Generate PDF';
|
||||||
|
printButton.title = 'Generate PDF with multiple labels based on quantity';
|
||||||
|
printerSelection.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDirectPrint(selectedRow) {
|
||||||
const orderId = selectedRow.dataset.orderId;
|
const orderId = selectedRow.dataset.orderId;
|
||||||
const quantityCell = selectedRow.querySelector('td:nth-child(5)'); // Cantitate column
|
const quantityCell = selectedRow.querySelector('td:nth-child(5)');
|
||||||
const quantity = quantityCell ? parseInt(quantityCell.textContent) : 1;
|
const quantity = quantityCell ? parseInt(quantityCell.textContent) : 1;
|
||||||
const prodOrderCell = selectedRow.querySelector('td:nth-child(2)'); // Comanda Productie column
|
const prodOrderCell = selectedRow.querySelector('td:nth-child(2)');
|
||||||
const prodOrder = prodOrderCell ? prodOrderCell.textContent.trim() : 'N/A';
|
const prodOrder = prodOrderCell ? prodOrderCell.textContent.trim() : 'N/A';
|
||||||
|
|
||||||
if (!orderId) {
|
// Get selected printer
|
||||||
alert('Could not determine order ID. Please refresh and try again.');
|
const printerSelect = document.getElementById('printerSelect');
|
||||||
|
let printerName = printerSelect.value;
|
||||||
|
|
||||||
|
if (printerName === 'custom') {
|
||||||
|
printerName = prompt('Enter your printer name:');
|
||||||
|
if (!printerName) return;
|
||||||
|
} else if (printerName === 'default') {
|
||||||
|
printerName = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Direct printing to: ${printerName}`);
|
||||||
|
|
||||||
|
// Extract order data from selected row
|
||||||
|
const cells = selectedRow.querySelectorAll('td');
|
||||||
|
const orderData = {
|
||||||
|
order_id: parseInt(orderId),
|
||||||
|
comanda_productie: cells[1].textContent.trim(),
|
||||||
|
cod_articol: cells[2].textContent.trim(),
|
||||||
|
descr_com_prod: cells[3].textContent.trim(),
|
||||||
|
cantitate: parseInt(cells[4].textContent.trim()),
|
||||||
|
data_livrare: cells[5].textContent.trim(),
|
||||||
|
dimensiune: cells[6].textContent.trim(),
|
||||||
|
com_achiz_client: cells[7].textContent.trim(),
|
||||||
|
nr_linie_com_client: cells[8].textContent.trim(),
|
||||||
|
customer_name: cells[9].textContent.trim(),
|
||||||
|
customer_article_number: cells[10].textContent.trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Print each label individually
|
||||||
|
for (let i = 1; i <= quantity; i++) {
|
||||||
|
const labelData = {
|
||||||
|
...orderData,
|
||||||
|
sequential_number: `${orderData.comanda_productie}-${i.toString().padStart(3, '0')}`,
|
||||||
|
current_label: i,
|
||||||
|
total_labels: quantity
|
||||||
|
};
|
||||||
|
|
||||||
|
// Encode data as base64 JSON
|
||||||
|
const jsonString = JSON.stringify(labelData);
|
||||||
|
const base64Data = btoa(unescape(encodeURIComponent(jsonString)));
|
||||||
|
|
||||||
|
// Create custom protocol URL
|
||||||
|
const printUrl = `recticel-print://${encodeURIComponent(printerName)}/${base64Data}`;
|
||||||
|
|
||||||
|
console.log(`Printing label ${i}/${quantity}: ${printUrl.substring(0, 100)}...`);
|
||||||
|
|
||||||
|
// Trigger direct print via custom protocol
|
||||||
|
try {
|
||||||
|
window.location.href = printUrl;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to print label ${i}:`, error);
|
||||||
|
alert(`❌ Failed to print label ${i}/${quantity}. Please check if the print service is installed.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show loading state
|
// Small delay between labels to prevent overwhelming the printer
|
||||||
const originalText = this.textContent;
|
if (i < quantity) {
|
||||||
this.textContent = 'Generating PDF...';
|
setTimeout(() => {}, 100);
|
||||||
this.disabled = true;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show success message
|
||||||
|
setTimeout(() => {
|
||||||
|
alert(`✅ Sent ${quantity} labels to printer: ${printerName}\n📊 Order: ${prodOrder}`);
|
||||||
|
|
||||||
|
// Update database status and refresh table
|
||||||
|
updatePrintedStatus(orderId);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePDFGeneration(selectedRow) {
|
||||||
|
const orderId = selectedRow.dataset.orderId;
|
||||||
|
const quantityCell = selectedRow.querySelector('td:nth-child(5)');
|
||||||
|
const quantity = quantityCell ? parseInt(quantityCell.textContent) : 1;
|
||||||
|
const prodOrderCell = selectedRow.querySelector('td:nth-child(2)');
|
||||||
|
const prodOrder = prodOrderCell ? prodOrderCell.textContent.trim() : 'N/A';
|
||||||
|
|
||||||
|
const button = document.getElementById('print-label-btn');
|
||||||
|
const originalText = button.textContent;
|
||||||
|
button.textContent = 'Generating PDF...';
|
||||||
|
button.disabled = true;
|
||||||
|
|
||||||
console.log(`Generating PDF for order ${orderId} with ${quantity} labels`);
|
console.log(`Generating PDF for order ${orderId} with ${quantity} labels`);
|
||||||
|
|
||||||
@@ -450,11 +606,30 @@ function addPDFGenerationHandler() {
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
// Reset button state
|
// Reset button state
|
||||||
this.textContent = originalText;
|
button.textContent = originalText;
|
||||||
this.disabled = false;
|
button.disabled = false;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePrintedStatus(orderId) {
|
||||||
|
// Call backend to update printed status for direct printing
|
||||||
|
fetch(`/update_printed_status/${orderId}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('Updated printed status:', data);
|
||||||
|
// Refresh table
|
||||||
|
setTimeout(() => {
|
||||||
|
refreshUnprintedOrdersTable();
|
||||||
|
}, 1000);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error updating printed status:', error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to refresh the unprinted orders table
|
// Function to refresh the unprinted orders table
|
||||||
|
|||||||
146
recticel_print_service/INSTALLATION_GUIDE.md
Normal file
146
recticel_print_service/INSTALLATION_GUIDE.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# Recticel Direct Print Service - Installation Guide
|
||||||
|
|
||||||
|
## 🎯 Overview
|
||||||
|
|
||||||
|
This service enables direct printing from web browsers to thermal label printers (Epson TM-T20, Citizen CTS-310, etc.) without requiring PDF generation or manual printer dialogs.
|
||||||
|
|
||||||
|
## 🔧 Installation Steps
|
||||||
|
|
||||||
|
### 1. **Build the C# Application**
|
||||||
|
|
||||||
|
**Requirements:**
|
||||||
|
- Visual Studio 2019 or later
|
||||||
|
- .NET Framework 4.7.2 or later
|
||||||
|
- Windows 10/11
|
||||||
|
|
||||||
|
**Build Steps:**
|
||||||
|
1. Open `RecticelPrintService.sln` in Visual Studio
|
||||||
|
2. Restore NuGet packages (Newtonsoft.Json)
|
||||||
|
3. Build in Release mode
|
||||||
|
4. Copy the entire `bin\Release` folder to `C:\RecticelPrintService\`
|
||||||
|
|
||||||
|
### 2. **Register the Custom Protocol**
|
||||||
|
|
||||||
|
**Option A: Double-click the registry file**
|
||||||
|
1. Right-click `recticel-print-protocol.reg`
|
||||||
|
2. Select "Run as administrator"
|
||||||
|
3. Confirm the registry import
|
||||||
|
|
||||||
|
**Option B: Manual registry import**
|
||||||
|
1. Open Command Prompt as Administrator
|
||||||
|
2. Run: `reg import "recticel-print-protocol.reg"`
|
||||||
|
|
||||||
|
### 3. **Install Printer Drivers**
|
||||||
|
|
||||||
|
**For Epson TM-T20:**
|
||||||
|
- Download and install Epson TM-T20 drivers from Epson website
|
||||||
|
- Configure printer as "Epson TM-T20" in Windows
|
||||||
|
|
||||||
|
**For Citizen CTS-310:**
|
||||||
|
- Download and install Citizen CTS-310 drivers
|
||||||
|
- Configure printer as "Citizen CTS-310" in Windows
|
||||||
|
|
||||||
|
### 4. **Configure Printer Settings**
|
||||||
|
|
||||||
|
1. Open Windows "Printers & scanners"
|
||||||
|
2. Set paper size to **80mm x 110mm** (or closest available)
|
||||||
|
3. Set print quality to **300 DPI** for thermal printers
|
||||||
|
4. Disable margins (set to 0 if possible)
|
||||||
|
|
||||||
|
### 5. **Test the Installation**
|
||||||
|
|
||||||
|
1. Open your web browser
|
||||||
|
2. Navigate to the print module page
|
||||||
|
3. Select an order
|
||||||
|
4. Choose "Direct Print" option
|
||||||
|
5. Select your thermal printer
|
||||||
|
6. Click "Print Labels"
|
||||||
|
|
||||||
|
## 🖨️ Printer Configuration
|
||||||
|
|
||||||
|
### Label Size Settings
|
||||||
|
- **Width**: 80mm
|
||||||
|
- **Height**: 110mm
|
||||||
|
- **Margins**: 0mm (all sides)
|
||||||
|
- **Print Quality**: 300 DPI
|
||||||
|
|
||||||
|
### Thermal Printer Specific Settings
|
||||||
|
|
||||||
|
**Epson TM-T20:**
|
||||||
|
- Paper Type: Continuous label
|
||||||
|
- Print Speed: Normal
|
||||||
|
- Print Density: Adjust based on label stock
|
||||||
|
|
||||||
|
**Citizen CTS-310:**
|
||||||
|
- Media Type: Label
|
||||||
|
- Print Method: Thermal Transfer or Direct Thermal
|
||||||
|
- Print Speed: Medium
|
||||||
|
|
||||||
|
## 🔄 How It Works
|
||||||
|
|
||||||
|
1. **Web Interface**: User selects order and clicks "Direct Print"
|
||||||
|
2. **Data Encoding**: Order data is encoded as Base64 JSON
|
||||||
|
3. **Custom Protocol**: Browser calls `recticel-print://printer/data`
|
||||||
|
4. **Service Activation**: Windows launches RecticelPrintService.exe
|
||||||
|
5. **Data Processing**: Service decodes and formats label data
|
||||||
|
6. **Direct Printing**: Label is sent directly to the thermal printer
|
||||||
|
7. **Status Update**: Database is updated to mark order as printed
|
||||||
|
|
||||||
|
## 🚀 URL Format
|
||||||
|
|
||||||
|
```
|
||||||
|
recticel-print://[printer_name]/[base64_encoded_json]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```
|
||||||
|
recticel-print://Epson%20TM-T20/eyJvcmRlcl9pZCI6MTIzLCJjb21hbmRhX3Byb2R1Y3RpZSI6IkNQMDAwMDA3MTEifQ==
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚠️ Troubleshooting
|
||||||
|
|
||||||
|
### Service Not Starting
|
||||||
|
1. Check if the service is installed in `C:\RecticelPrintService\`
|
||||||
|
2. Verify registry entries are correct
|
||||||
|
3. Run as Administrator if needed
|
||||||
|
|
||||||
|
### Printer Not Found
|
||||||
|
1. Check printer name in Windows exactly matches selection
|
||||||
|
2. Ensure printer drivers are installed
|
||||||
|
3. Test print from Windows to verify printer works
|
||||||
|
|
||||||
|
### Labels Not Printing
|
||||||
|
1. Verify paper size is set to 80x110mm
|
||||||
|
2. Check printer margins are set to 0
|
||||||
|
3. Ensure thermal paper is loaded correctly
|
||||||
|
|
||||||
|
### Browser Security
|
||||||
|
- Some browsers may block custom protocols
|
||||||
|
- Add site to trusted sites if needed
|
||||||
|
- Chrome may show a confirmation dialog
|
||||||
|
|
||||||
|
## 🔧 Advanced Configuration
|
||||||
|
|
||||||
|
### Custom Printer Names
|
||||||
|
Users can add custom printer names by selecting "Other Printer..." and entering the exact Windows printer name.
|
||||||
|
|
||||||
|
### Multiple Label Quantities
|
||||||
|
The service automatically prints the quantity specified in the order, with sequential numbering (CP00000711-001, CP00000711-002, etc.).
|
||||||
|
|
||||||
|
### Fallback to PDF
|
||||||
|
If direct printing fails, users can switch to "Generate PDF" mode for manual printing.
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
For technical support:
|
||||||
|
1. Check Windows Event Viewer for service errors
|
||||||
|
2. Verify printer connectivity and driver installation
|
||||||
|
3. Test with PDF generation mode as fallback
|
||||||
|
4. Contact IT support with specific error messages
|
||||||
|
|
||||||
|
## 🔒 Security Notes
|
||||||
|
|
||||||
|
- The service only processes label data from trusted sources
|
||||||
|
- Registry changes require Administrator privileges
|
||||||
|
- Service runs with current user permissions
|
||||||
|
- No network connections are made by the service
|
||||||
24
recticel_print_service/RecticelPrintService.sln
Normal file
24
recticel_print_service/RecticelPrintService.sln
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.28010.2046
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RecticelPrintService", "RecticelPrintService\RecticelPrintService.csproj", "{41ED6235-3C76-4723-A5F6-02D2FA51E677}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{41ED6235-3C76-4723-A5F6-02D2FA51E677}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{41ED6235-3C76-4723-A5F6-02D2FA51E677}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{41ED6235-3C76-4723-A5F6-02D2FA51E677}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{41ED6235-3C76-4723-A5F6-02D2FA51E677}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {FC401D2A-E68E-47EE-B315-E1A2F0B292FA}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
6
recticel_print_service/RecticelPrintService/App.config
Normal file
6
recticel_print_service/RecticelPrintService/App.config
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
288
recticel_print_service/RecticelPrintService/LabelPrinter.cs
Normal file
288
recticel_print_service/RecticelPrintService/LabelPrinter.cs
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Printing;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace RecticelPrintService
|
||||||
|
{
|
||||||
|
public class LabelPrinter
|
||||||
|
{
|
||||||
|
private PrintData _labelData;
|
||||||
|
|
||||||
|
// Label dimensions in millimeters (80x110mm)
|
||||||
|
private const float LABEL_WIDTH_MM = 80f;
|
||||||
|
private const float LABEL_HEIGHT_MM = 110f;
|
||||||
|
|
||||||
|
// Convert mm to hundredths of an inch (used by .NET printing)
|
||||||
|
private float MmToHundredthsOfInch(float mm)
|
||||||
|
{
|
||||||
|
return mm * 3.937f; // 1mm = 0.03937 inches, * 100 for hundredths
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PrintLabel(string printerName, string jsonData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Parse JSON data
|
||||||
|
_labelData = JsonConvert.DeserializeObject<PrintData>(jsonData);
|
||||||
|
|
||||||
|
if (_labelData == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed to parse JSON data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up print document
|
||||||
|
PrintDocument printDoc = new PrintDocument();
|
||||||
|
printDoc.PrinterSettings.PrinterName = printerName;
|
||||||
|
|
||||||
|
// Check if printer exists
|
||||||
|
if (!printDoc.PrinterSettings.IsValid)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Printer '{printerName}' not found or not available");
|
||||||
|
Console.WriteLine("Available printers:");
|
||||||
|
foreach (string printer in PrinterSettings.InstalledPrinters)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" - {printer}");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set paper size for 80x110mm labels
|
||||||
|
PaperSize labelSize = new PaperSize("Label 80x110mm",
|
||||||
|
(int)MmToHundredthsOfInch(LABEL_WIDTH_MM),
|
||||||
|
(int)MmToHundredthsOfInch(LABEL_HEIGHT_MM));
|
||||||
|
|
||||||
|
printDoc.DefaultPageSettings.PaperSize = labelSize;
|
||||||
|
printDoc.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Set print event handler
|
||||||
|
printDoc.PrintPage += PrintDoc_PrintPage;
|
||||||
|
|
||||||
|
// Print the document
|
||||||
|
printDoc.Print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error printing label: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Graphics g = e.Graphics;
|
||||||
|
|
||||||
|
// Define fonts
|
||||||
|
Font companyFont = new Font("Arial", 10, FontStyle.Bold);
|
||||||
|
Font headerFont = new Font("Arial", 8, FontStyle.Bold);
|
||||||
|
Font dataFont = new Font("Arial", 9, FontStyle.Bold);
|
||||||
|
Font labelFont = new Font("Arial", 7);
|
||||||
|
Font barcodeFont = new Font("Courier New", 6, FontStyle.Bold);
|
||||||
|
|
||||||
|
// Define brushes and pens
|
||||||
|
Brush textBrush = Brushes.Black;
|
||||||
|
Pen borderPen = new Pen(Color.Black, 2);
|
||||||
|
Pen dividerPen = new Pen(Color.Gray, 1);
|
||||||
|
|
||||||
|
// Calculate positions (in pixels, 300 DPI assumed)
|
||||||
|
float dpiX = e.Graphics.DpiX;
|
||||||
|
float dpiY = e.Graphics.DpiY;
|
||||||
|
|
||||||
|
// Convert mm to pixels
|
||||||
|
float labelWidth = (LABEL_WIDTH_MM / 25.4f) * dpiX;
|
||||||
|
float labelHeight = (LABEL_HEIGHT_MM / 25.4f) * dpiY;
|
||||||
|
|
||||||
|
// Content area (similar to your HTML preview)
|
||||||
|
float contentX = (3f / 25.4f) * dpiX; // 3mm margin
|
||||||
|
float contentY = (15f / 25.4f) * dpiY; // 15mm from bottom
|
||||||
|
float contentWidth = (60f / 25.4f) * dpiX; // 60mm width
|
||||||
|
float contentHeight = (85f / 25.4f) * dpiY; // 85mm height
|
||||||
|
|
||||||
|
// Draw main content border
|
||||||
|
g.DrawRectangle(borderPen, contentX, contentY, contentWidth, contentHeight);
|
||||||
|
|
||||||
|
// Calculate row height
|
||||||
|
float rowHeight = contentHeight / 10f; // 9 rows + spacing
|
||||||
|
float currentY = contentY;
|
||||||
|
|
||||||
|
// Row 1: Company Header
|
||||||
|
string companyText = "INNOFA RROMANIA SRL";
|
||||||
|
SizeF companySize = g.MeasureString(companyText, companyFont);
|
||||||
|
float companyX = contentX + (contentWidth - companySize.Width) / 2;
|
||||||
|
g.DrawString(companyText, companyFont, textBrush, companyX, currentY + rowHeight/3);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider after company
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 2: Customer Name
|
||||||
|
string customerName = _labelData.CustomerName ?? "N/A";
|
||||||
|
SizeF customerSize = g.MeasureString(customerName, headerFont);
|
||||||
|
float customerX = contentX + (contentWidth - customerSize.Width) / 2;
|
||||||
|
g.DrawString(customerName, headerFont, textBrush, customerX, currentY + rowHeight/3);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider after customer
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Vertical divider (40% from left)
|
||||||
|
float verticalDividerX = contentX + contentWidth * 0.4f;
|
||||||
|
g.DrawLine(dividerPen, verticalDividerX, currentY, verticalDividerX, contentY + contentHeight);
|
||||||
|
|
||||||
|
// Row 3: Quantity
|
||||||
|
g.DrawString("Quantity ordered", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string quantity = _labelData.Cantitate.ToString();
|
||||||
|
SizeF qtySize = g.MeasureString(quantity, dataFont);
|
||||||
|
float qtyX = verticalDividerX + (contentWidth * 0.6f - qtySize.Width) / 2;
|
||||||
|
g.DrawString(quantity, dataFont, textBrush, qtyX, currentY + rowHeight/4);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 4: Customer Order
|
||||||
|
g.DrawString("Customer order", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string customerOrder = $"{_labelData.ComAchizClient}-{_labelData.NrLinieComClient}";
|
||||||
|
if (string.IsNullOrEmpty(_labelData.ComAchizClient)) customerOrder = "N/A";
|
||||||
|
SizeF orderSize = g.MeasureString(customerOrder, dataFont);
|
||||||
|
float orderX = verticalDividerX + (contentWidth * 0.6f - orderSize.Width) / 2;
|
||||||
|
g.DrawString(customerOrder, dataFont, textBrush, orderX, currentY + rowHeight/4);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 5: Delivery Date
|
||||||
|
g.DrawString("Delivery date", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string deliveryDate = _labelData.DataLivrare ?? "N/A";
|
||||||
|
if (!string.IsNullOrEmpty(deliveryDate) && deliveryDate != "N/A")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DateTime dt = DateTime.Parse(deliveryDate);
|
||||||
|
deliveryDate = dt.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
SizeF dateSize = g.MeasureString(deliveryDate, dataFont);
|
||||||
|
float dateX = verticalDividerX + (contentWidth * 0.6f - dateSize.Width) / 2;
|
||||||
|
g.DrawString(deliveryDate, dataFont, textBrush, dateX, currentY + rowHeight/4);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 6: Description (double height)
|
||||||
|
g.DrawString("Description", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string description = _labelData.DescrComProd ?? "N/A";
|
||||||
|
// Word wrap description if needed
|
||||||
|
RectangleF descRect = new RectangleF(verticalDividerX + 5, currentY + 5,
|
||||||
|
contentWidth * 0.6f - 10, rowHeight * 2 - 10);
|
||||||
|
g.DrawString(description, dataFont, textBrush, descRect);
|
||||||
|
currentY += rowHeight * 2;
|
||||||
|
|
||||||
|
// Horizontal divider
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 7: Size
|
||||||
|
g.DrawString("Size", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string size = _labelData.Dimensiune ?? "N/A";
|
||||||
|
SizeF sizeSize = g.MeasureString(size, dataFont);
|
||||||
|
float sizeX = verticalDividerX + (contentWidth * 0.6f - sizeSize.Width) / 2;
|
||||||
|
g.DrawString(size, dataFont, textBrush, sizeX, currentY + rowHeight/4);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 8: Article Code
|
||||||
|
g.DrawString("Article Code", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string articleCode = _labelData.CustomerArticleNumber ?? "N/A";
|
||||||
|
SizeF artSize = g.MeasureString(articleCode, dataFont);
|
||||||
|
float artX = verticalDividerX + (contentWidth * 0.6f - artSize.Width) / 2;
|
||||||
|
g.DrawString(articleCode, dataFont, textBrush, artX, currentY + rowHeight/4);
|
||||||
|
currentY += rowHeight;
|
||||||
|
|
||||||
|
// Horizontal divider
|
||||||
|
g.DrawLine(dividerPen, contentX, currentY, contentX + contentWidth, currentY);
|
||||||
|
|
||||||
|
// Row 9: Prod Order
|
||||||
|
g.DrawString("Prod Order", labelFont, textBrush, contentX + 5, currentY + rowHeight/4);
|
||||||
|
string prodOrder = _labelData.SequentialNumber ?? $"{_labelData.ComandaProductie}-{_labelData.Cantitate}";
|
||||||
|
SizeF prodSize = g.MeasureString(prodOrder, dataFont);
|
||||||
|
float prodX = verticalDividerX + (contentWidth * 0.6f - prodSize.Width) / 2;
|
||||||
|
g.DrawString(prodOrder, dataFont, textBrush, prodX, currentY + rowHeight/4);
|
||||||
|
|
||||||
|
// Bottom barcode area
|
||||||
|
float barcodeY = contentY + contentHeight + (5f / 25.4f) * dpiY; // 5mm below content
|
||||||
|
float barcodeWidth = contentWidth;
|
||||||
|
float barcodeHeight = (10f / 25.4f) * dpiY; // 10mm height
|
||||||
|
|
||||||
|
// Draw barcode representation (simple lines)
|
||||||
|
DrawSimpleBarcode(g, contentX, barcodeY, barcodeWidth, barcodeHeight, prodOrder);
|
||||||
|
|
||||||
|
// Barcode text
|
||||||
|
SizeF barcodeTextSize = g.MeasureString(prodOrder, barcodeFont);
|
||||||
|
float barcodeTextX = contentX + (contentWidth - barcodeTextSize.Width) / 2;
|
||||||
|
g.DrawString(prodOrder, barcodeFont, textBrush, barcodeTextX, barcodeY + barcodeHeight + 5);
|
||||||
|
|
||||||
|
// Vertical barcode on the right side
|
||||||
|
float verticalBarcodeX = contentX + contentWidth + (5f / 25.4f) * dpiX; // 5mm to the right
|
||||||
|
float verticalBarcodeWidth = (8f / 25.4f) * dpiX; // 8mm width
|
||||||
|
DrawSimpleVerticalBarcode(g, verticalBarcodeX, contentY + rowHeight * 2,
|
||||||
|
verticalBarcodeWidth, contentHeight - rowHeight * 2, customerOrder);
|
||||||
|
|
||||||
|
// Dispose resources
|
||||||
|
companyFont.Dispose();
|
||||||
|
headerFont.Dispose();
|
||||||
|
dataFont.Dispose();
|
||||||
|
labelFont.Dispose();
|
||||||
|
barcodeFont.Dispose();
|
||||||
|
borderPen.Dispose();
|
||||||
|
dividerPen.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error in PrintPage event: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSimpleBarcode(Graphics g, float x, float y, float width, float height, string data)
|
||||||
|
{
|
||||||
|
// Simple barcode representation using alternating lines
|
||||||
|
float barWidth = 2f;
|
||||||
|
bool drawBar = true;
|
||||||
|
|
||||||
|
for (float currentX = x; currentX < x + width; currentX += barWidth)
|
||||||
|
{
|
||||||
|
if (drawBar)
|
||||||
|
{
|
||||||
|
g.FillRectangle(Brushes.Black, currentX, y, barWidth, height * 0.8f);
|
||||||
|
}
|
||||||
|
drawBar = !drawBar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSimpleVerticalBarcode(Graphics g, float x, float y, float width, float height, string data)
|
||||||
|
{
|
||||||
|
// Simple vertical barcode representation
|
||||||
|
float barHeight = 2f;
|
||||||
|
bool drawBar = true;
|
||||||
|
|
||||||
|
for (float currentY = y; currentY < y + height; currentY += barHeight)
|
||||||
|
{
|
||||||
|
if (drawBar)
|
||||||
|
{
|
||||||
|
g.FillRectangle(Brushes.Black, x, currentY, width * 0.8f, barHeight);
|
||||||
|
}
|
||||||
|
drawBar = !drawBar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
recticel_print_service/RecticelPrintService/PrintData.cs
Normal file
49
recticel_print_service/RecticelPrintService/PrintData.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace RecticelPrintService
|
||||||
|
{
|
||||||
|
public class PrintData
|
||||||
|
{
|
||||||
|
[JsonProperty("order_id")]
|
||||||
|
public int OrderId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("comanda_productie")]
|
||||||
|
public string ComandaProductie { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("customer_name")]
|
||||||
|
public string CustomerName { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("cantitate")]
|
||||||
|
public int Cantitate { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("com_achiz_client")]
|
||||||
|
public string ComAchizClient { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("nr_linie_com_client")]
|
||||||
|
public string NrLinieComClient { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("data_livrare")]
|
||||||
|
public string DataLivrare { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("dimensiune")]
|
||||||
|
public string Dimensiune { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("descr_com_prod")]
|
||||||
|
public string DescrComProd { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("customer_article_number")]
|
||||||
|
public string CustomerArticleNumber { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("cod_articol")]
|
||||||
|
public string CodArticol { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("sequential_number")]
|
||||||
|
public string SequentialNumber { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("current_label")]
|
||||||
|
public int CurrentLabel { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("total_labels")]
|
||||||
|
public int TotalLabels { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
81
recticel_print_service/RecticelPrintService/Program.cs
Normal file
81
recticel_print_service/RecticelPrintService/Program.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
|
namespace RecticelPrintService
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Recticel Print Service - No arguments provided");
|
||||||
|
Console.WriteLine("Usage: RecticelPrintService.exe \"recticel-print://printer/data\"");
|
||||||
|
Console.ReadKey();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string url = args[0];
|
||||||
|
Console.WriteLine($"Received print request: {url}");
|
||||||
|
|
||||||
|
// Parse the custom protocol URL
|
||||||
|
// Format: recticel-print://printer_name/base64_encoded_json_data
|
||||||
|
if (!url.StartsWith("recticel-print://"))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Invalid protocol. Expected: recticel-print://");
|
||||||
|
Console.ReadKey();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove protocol prefix
|
||||||
|
string data = url.Substring("recticel-print://".Length);
|
||||||
|
|
||||||
|
// Split printer name and data
|
||||||
|
string[] parts = data.Split('/');
|
||||||
|
if (parts.Length < 2)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Invalid URL format. Expected: recticel-print://printer_name/data");
|
||||||
|
Console.ReadKey();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string printerName = HttpUtility.UrlDecode(parts[0]);
|
||||||
|
string encodedData = HttpUtility.UrlDecode(parts[1]);
|
||||||
|
|
||||||
|
Console.WriteLine($"Target Printer: {printerName}");
|
||||||
|
Console.WriteLine($"Data Length: {encodedData.Length}");
|
||||||
|
|
||||||
|
// Decode base64 JSON data
|
||||||
|
byte[] dataBytes = Convert.FromBase64String(encodedData);
|
||||||
|
string jsonData = System.Text.Encoding.UTF8.GetString(dataBytes);
|
||||||
|
|
||||||
|
Console.WriteLine($"Decoded JSON: {jsonData}");
|
||||||
|
|
||||||
|
// Parse and print the label
|
||||||
|
var printer = new LabelPrinter();
|
||||||
|
bool success = printer.PrintLabel(printerName, jsonData);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Console.WriteLine("✅ Label printed successfully!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("❌ Failed to print label!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep console open for debugging (remove in production)
|
||||||
|
Console.WriteLine("Press any key to exit...");
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
|
Console.WriteLine(ex.StackTrace);
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("RecticelPrintService")]
|
||||||
|
[assembly: AssemblyDescription("Direct label printing service for Recticel Quality System")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Recticel")]
|
||||||
|
[assembly: AssemblyProduct("Recticel Print Service")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Recticel 2025")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
[assembly: Guid("41ed6235-3c76-4723-a5f6-02d2fa51e677")]
|
||||||
|
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{41ED6235-3C76-4723-A5F6-02D2FA51E677}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>RecticelPrintService</RootNamespace>
|
||||||
|
<AssemblyName>RecticelPrintService</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Drawing.Printing" />
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="LabelPrinter.cs" />
|
||||||
|
<Compile Include="PrintData.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
|
||||||
|
</packages>
|
||||||
50
recticel_print_service/install.bat
Normal file
50
recticel_print_service/install.bat
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
@echo off
|
||||||
|
echo Installing Recticel Print Service...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Check if running as Administrator
|
||||||
|
net session >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo ERROR: This script must be run as Administrator.
|
||||||
|
echo Right-click and select "Run as administrator"
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Create installation directory
|
||||||
|
echo Creating installation directory...
|
||||||
|
if not exist "C:\RecticelPrintService" (
|
||||||
|
mkdir "C:\RecticelPrintService"
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Copy files (assuming this script is in the same directory as the built application)
|
||||||
|
echo Copying application files...
|
||||||
|
copy "RecticelPrintService\bin\Release\*.*" "C:\RecticelPrintService\" /Y
|
||||||
|
|
||||||
|
REM Register custom protocol
|
||||||
|
echo Registering custom protocol...
|
||||||
|
reg import "recticel-print-protocol.reg"
|
||||||
|
|
||||||
|
if %errorlevel% equ 0 (
|
||||||
|
echo.
|
||||||
|
echo ✅ Installation completed successfully!
|
||||||
|
echo.
|
||||||
|
echo Service installed to: C:\RecticelPrintService\
|
||||||
|
echo Protocol registered: recticel-print://
|
||||||
|
echo.
|
||||||
|
echo Next steps:
|
||||||
|
echo 1. Configure your thermal label printer in Windows
|
||||||
|
echo 2. Set label size to 80mm x 110mm
|
||||||
|
echo 3. Test printing from the web interface
|
||||||
|
echo.
|
||||||
|
echo Press any key to exit...
|
||||||
|
pause >nul
|
||||||
|
) else (
|
||||||
|
echo.
|
||||||
|
echo ❌ Installation failed!
|
||||||
|
echo Please check if you're running as Administrator.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
)
|
||||||
|
|
||||||
|
exit /b 0
|
||||||
14
recticel_print_service/recticel-print-protocol.reg
Normal file
14
recticel_print_service/recticel-print-protocol.reg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Windows Registry Editor Version 5.00
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\recticel-print]
|
||||||
|
@="URL:Recticel Print Protocol"
|
||||||
|
"URL Protocol"=""
|
||||||
|
"EditFlags"=dword:00000002
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\recticel-print\shell]
|
||||||
|
@="open"
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\recticel-print\shell\open]
|
||||||
|
|
||||||
|
[HKEY_CLASSES_ROOT\recticel-print\shell\open\command]
|
||||||
|
@="\"C:\\RecticelPrintService\\RecticelPrintService.exe\" \"%1\""
|
||||||
Reference in New Issue
Block a user