Compare commits
5 Commits
134fc73f9c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd6db40339 | ||
|
|
e2a6553fe9 | ||
|
|
6029a2b98e | ||
|
|
2b6be2ba49 | ||
|
|
d5b043c762 |
@@ -11,8 +11,11 @@ ENV PYTHONUNBUFFERED=1 \
|
|||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
python3-dev \
|
||||||
mariadb-client \
|
mariadb-client \
|
||||||
curl \
|
curl \
|
||||||
|
libpq-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Create application directory
|
# Create application directory
|
||||||
|
|||||||
0
app/__init__.py
Normal file → Executable file
0
app/__init__.py
Normal file → Executable file
0
app/access_control.py
Normal file → Executable file
0
app/access_control.py
Normal file → Executable file
0
app/auth.py
Normal file → Executable file
0
app/auth.py
Normal file → Executable file
0
app/config.py
Normal file → Executable file
0
app/config.py
Normal file → Executable file
0
app/database.py
Normal file → Executable file
0
app/database.py
Normal file → Executable file
0
app/db_migrations/add_warehouse_roles_and_bindings.sql
Normal file → Executable file
0
app/db_migrations/add_warehouse_roles_and_bindings.sql
Normal file → Executable file
2
app/db_schema_verifier.py
Normal file → Executable file
2
app/db_schema_verifier.py
Normal file → Executable file
@@ -389,7 +389,7 @@ class SchemaVerifier:
|
|||||||
open_for_order TINYINT(1) DEFAULT 1,
|
open_for_order TINYINT(1) DEFAULT 1,
|
||||||
line_number INT,
|
line_number INT,
|
||||||
printed_labels TINYINT(1) DEFAULT 0,
|
printed_labels TINYINT(1) DEFAULT 0,
|
||||||
data_livrara DATE,
|
data_livrare DATE,
|
||||||
dimensiune VARCHAR(50),
|
dimensiune VARCHAR(50),
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|||||||
0
app/models/__init__.py
Normal file → Executable file
0
app/models/__init__.py
Normal file → Executable file
0
app/modules/labels/__init__.py
Normal file → Executable file
0
app/modules/labels/__init__.py
Normal file → Executable file
0
app/modules/labels/import_labels.py
Normal file → Executable file
0
app/modules/labels/import_labels.py
Normal file → Executable file
47
app/modules/labels/pdf_generator.py
Normal file → Executable file
47
app/modules/labels/pdf_generator.py
Normal file → Executable file
@@ -87,8 +87,8 @@ class LabelPDFGenerator:
|
|||||||
if printer_optimized:
|
if printer_optimized:
|
||||||
self._optimize_for_label_printer(c)
|
self._optimize_for_label_printer(c)
|
||||||
|
|
||||||
# Create sequential label number: CP00000711/001, CP00000711/002, etc.
|
# Create sequential label number: CP00000711-0001, CP00000711-0002, etc.
|
||||||
sequential_number = f"{prod_order}/{i:03d}"
|
sequential_number = f"{prod_order}-{i:04d}"
|
||||||
|
|
||||||
# Draw single label
|
# Draw single label
|
||||||
self._draw_label(c, order_data, sequential_number, i, quantity)
|
self._draw_label(c, order_data, sequential_number, i, quantity)
|
||||||
@@ -116,7 +116,7 @@ class LabelPDFGenerator:
|
|||||||
prod_order = order_data.get('comanda_productie', 'CP00000000')
|
prod_order = order_data.get('comanda_productie', 'CP00000000')
|
||||||
|
|
||||||
# Create sequential label number with specific piece number
|
# Create sequential label number with specific piece number
|
||||||
sequential_number = f"{prod_order}/{piece_number:03d}"
|
sequential_number = f"{prod_order}-{piece_number:04d}"
|
||||||
|
|
||||||
print(f"DEBUG: Generating label {sequential_number} (piece {piece_number} of {total_pieces})")
|
print(f"DEBUG: Generating label {sequential_number} (piece {piece_number} of {total_pieces})")
|
||||||
|
|
||||||
@@ -301,7 +301,7 @@ class LabelPDFGenerator:
|
|||||||
canvas.setFont("Helvetica-Bold", 10)
|
canvas.setFont("Helvetica-Bold", 10)
|
||||||
# Match HTML: comanda_productie + "-" + sequential number (not quantity!)
|
# Match HTML: comanda_productie + "-" + sequential number (not quantity!)
|
||||||
comanda_productie = str(order_data.get('comanda_productie', 'N/A'))
|
comanda_productie = str(order_data.get('comanda_productie', 'N/A'))
|
||||||
prod_order = f"{comanda_productie}-{current_num:03d}" # Sequential number for this specific label
|
prod_order = f"{comanda_productie}-{current_num:04d}" # Sequential number for this specific label
|
||||||
po_text_width = canvas.stringWidth(prod_order, "Helvetica-Bold", 10)
|
po_text_width = canvas.stringWidth(prod_order, "Helvetica-Bold", 10)
|
||||||
po_x_centered = vertical_x + (self.right_column_width - po_text_width) / 2
|
po_x_centered = vertical_x + (self.right_column_width - po_text_width) / 2
|
||||||
canvas.drawString(po_x_centered, row_y + self.row_height/3, prod_order)
|
canvas.drawString(po_x_centered, row_y + self.row_height/3, prod_order)
|
||||||
@@ -321,17 +321,23 @@ class LabelPDFGenerator:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Create barcode for sequential number
|
# Create barcode for sequential number
|
||||||
|
# OPTIMIZED FOR SCANNING: 0.30mm bar width for reliable readability
|
||||||
barcode = code128.Code128(sequential_number,
|
barcode = code128.Code128(sequential_number,
|
||||||
barWidth=0.25*mm, # Adjust bar width for better fit
|
barWidth=0.30*mm, # Increased from 0.25mm for better scanning
|
||||||
barHeight=mm_to_points(10)) # Increase height to 10mm
|
barHeight=mm_to_points(10)) # 10mm height
|
||||||
|
|
||||||
# Always scale to fit the full allocated width
|
# Only scale if barcode is too wide, otherwise use natural size
|
||||||
scale_factor = barcode_width / barcode.width
|
if barcode.width > barcode_width:
|
||||||
canvas.saveState()
|
scale_factor = barcode_width / barcode.width
|
||||||
canvas.translate(barcode_x, barcode_y)
|
canvas.saveState()
|
||||||
canvas.scale(scale_factor, 1)
|
canvas.translate(barcode_x, barcode_y)
|
||||||
barcode.drawOn(canvas, 0, 0)
|
canvas.scale(scale_factor, 1)
|
||||||
canvas.restoreState()
|
barcode.drawOn(canvas, 0, 0)
|
||||||
|
canvas.restoreState()
|
||||||
|
else:
|
||||||
|
# Use natural size - center it in available space
|
||||||
|
x_offset = (barcode_width - barcode.width) / 2
|
||||||
|
barcode.drawOn(canvas, barcode_x + x_offset, barcode_y)
|
||||||
|
|
||||||
# NO TEXT BELOW BARCODE - Remove all text rendering for horizontal barcode
|
# NO TEXT BELOW BARCODE - Remove all text rendering for horizontal barcode
|
||||||
|
|
||||||
@@ -362,18 +368,21 @@ class LabelPDFGenerator:
|
|||||||
vertical_code = "000000/00"
|
vertical_code = "000000/00"
|
||||||
|
|
||||||
# Create a vertical barcode using Code128
|
# Create a vertical barcode using Code128
|
||||||
|
# OPTIMIZED FOR SCANNING: 0.30mm bar width for reliable readability
|
||||||
v_barcode = code128.Code128(vertical_code,
|
v_barcode = code128.Code128(vertical_code,
|
||||||
barWidth=0.15*mm, # Thinner bars for better fit
|
barWidth=0.30*mm, # Increased from 0.15mm for better scanning
|
||||||
barHeight=mm_to_points(8)) # Increased bar height
|
barHeight=mm_to_points(10)) # Increased bar height
|
||||||
|
|
||||||
# Draw rotated barcode - fill the entire frame height
|
# Draw rotated barcode - fit naturally without aggressive scaling
|
||||||
canvas.saveState()
|
canvas.saveState()
|
||||||
canvas.translate(vertical_barcode_x + mm_to_points(6), vertical_barcode_y)
|
canvas.translate(vertical_barcode_x + mm_to_points(6), vertical_barcode_y)
|
||||||
canvas.rotate(90)
|
canvas.rotate(90)
|
||||||
|
|
||||||
# Always scale to fill the frame height
|
# Only scale if barcode is too wide for frame, otherwise use natural size
|
||||||
scale_factor = vertical_barcode_height / v_barcode.width
|
if v_barcode.width > vertical_barcode_height:
|
||||||
canvas.scale(scale_factor, 1)
|
scale_factor = vertical_barcode_height / v_barcode.width
|
||||||
|
canvas.scale(scale_factor, 1)
|
||||||
|
# else: use natural size for best scanning quality
|
||||||
|
|
||||||
v_barcode.drawOn(canvas, 0, 0)
|
v_barcode.drawOn(canvas, 0, 0)
|
||||||
canvas.restoreState()
|
canvas.restoreState()
|
||||||
|
|||||||
0
app/modules/labels/print_module.py
Normal file → Executable file
0
app/modules/labels/print_module.py
Normal file → Executable file
35
app/modules/labels/routes.py
Normal file → Executable file
35
app/modules/labels/routes.py
Normal file → Executable file
@@ -487,4 +487,39 @@ def api_generate_batch_pdf(order_id):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error generating batch PDF: {e}")
|
logger.error(f"Error generating batch PDF: {e}")
|
||||||
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@labels_bp.route('/api/pairing-keys', methods=['GET'], endpoint='api_pairing_keys')
|
||||||
|
def api_pairing_keys():
|
||||||
|
"""Get QZ Tray pairing keys for printer selection"""
|
||||||
|
if 'user_id' not in session:
|
||||||
|
return jsonify({'error': 'Unauthorized'}), 401
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = get_db()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT id, printer_name, pairing_key, valid_until
|
||||||
|
FROM qz_pairing_keys
|
||||||
|
WHERE valid_until >= CURDATE()
|
||||||
|
ORDER BY printer_name ASC
|
||||||
|
""")
|
||||||
|
|
||||||
|
pairing_keys = []
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
pairing_keys.append({
|
||||||
|
'id': row[0],
|
||||||
|
'printer_name': row[1],
|
||||||
|
'pairing_key': row[2]
|
||||||
|
})
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
logger.info(f"Retrieved {len(pairing_keys)} valid pairing keys")
|
||||||
|
return jsonify(pairing_keys), 200
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error fetching pairing keys: {e}")
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
0
app/modules/quality/__init__.py
Normal file → Executable file
0
app/modules/quality/__init__.py
Normal file → Executable file
0
app/modules/quality/quality.py
Normal file → Executable file
0
app/modules/quality/quality.py
Normal file → Executable file
0
app/modules/quality/routes.py
Normal file → Executable file
0
app/modules/quality/routes.py
Normal file → Executable file
0
app/modules/settings/__init__.py
Normal file → Executable file
0
app/modules/settings/__init__.py
Normal file → Executable file
0
app/modules/settings/logs.py
Normal file → Executable file
0
app/modules/settings/logs.py
Normal file → Executable file
0
app/modules/settings/routes.py
Normal file → Executable file
0
app/modules/settings/routes.py
Normal file → Executable file
0
app/modules/settings/stats.py
Normal file → Executable file
0
app/modules/settings/stats.py
Normal file → Executable file
0
app/modules/settings/warehouse_worker_management.py
Normal file → Executable file
0
app/modules/settings/warehouse_worker_management.py
Normal file → Executable file
0
app/modules/warehouse/__init__.py
Normal file → Executable file
0
app/modules/warehouse/__init__.py
Normal file → Executable file
0
app/modules/warehouse/boxes.py
Normal file → Executable file
0
app/modules/warehouse/boxes.py
Normal file → Executable file
0
app/modules/warehouse/boxes_routes.py
Normal file → Executable file
0
app/modules/warehouse/boxes_routes.py
Normal file → Executable file
0
app/modules/warehouse/routes.py
Normal file → Executable file
0
app/modules/warehouse/routes.py
Normal file → Executable file
0
app/modules/warehouse/warehouse.py
Normal file → Executable file
0
app/modules/warehouse/warehouse.py
Normal file → Executable file
0
app/modules/warehouse/warehouse_orders.py
Normal file → Executable file
0
app/modules/warehouse/warehouse_orders.py
Normal file → Executable file
0
app/routes.py
Normal file → Executable file
0
app/routes.py
Normal file → Executable file
0
app/scheduler.py
Normal file → Executable file
0
app/scheduler.py
Normal file → Executable file
0
app/static/css/base.css
Normal file → Executable file
0
app/static/css/base.css
Normal file → Executable file
0
app/static/css/database_management.css
Normal file → Executable file
0
app/static/css/database_management.css
Normal file → Executable file
0
app/static/css/fg_scan.css
Normal file → Executable file
0
app/static/css/fg_scan.css
Normal file → Executable file
0
app/static/css/login.css
Normal file → Executable file
0
app/static/css/login.css
Normal file → Executable file
0
app/static/css/print_module.css
Normal file → Executable file
0
app/static/css/print_module.css
Normal file → Executable file
0
app/static/css/scan.css
Normal file → Executable file
0
app/static/css/scan.css
Normal file → Executable file
0
app/static/css/theme.css
Normal file → Executable file
0
app/static/css/theme.css
Normal file → Executable file
0
app/static/js/base.js
Normal file → Executable file
0
app/static/js/base.js
Normal file → Executable file
0
app/static/js/qz-printer.js
Normal file → Executable file
0
app/static/js/qz-printer.js
Normal file → Executable file
0
app/static/js/qz-tray.js
Normal file → Executable file
0
app/static/js/qz-tray.js
Normal file → Executable file
0
app/static/js/theme.js
Normal file → Executable file
0
app/static/js/theme.js
Normal file → Executable file
0
app/static/style.css
Normal file → Executable file
0
app/static/style.css
Normal file → Executable file
0
app/templates/base.html
Normal file → Executable file
0
app/templates/base.html
Normal file → Executable file
0
app/templates/base_print.html
Normal file → Executable file
0
app/templates/base_print.html
Normal file → Executable file
0
app/templates/dashboard.html
Normal file → Executable file
0
app/templates/dashboard.html
Normal file → Executable file
0
app/templates/errors/403.html
Normal file → Executable file
0
app/templates/errors/403.html
Normal file → Executable file
0
app/templates/errors/404.html
Normal file → Executable file
0
app/templates/errors/404.html
Normal file → Executable file
0
app/templates/errors/500.html
Normal file → Executable file
0
app/templates/errors/500.html
Normal file → Executable file
0
app/templates/login.html
Normal file → Executable file
0
app/templates/login.html
Normal file → Executable file
0
app/templates/modules/labels/import_labels.html
Normal file → Executable file
0
app/templates/modules/labels/import_labels.html
Normal file → Executable file
0
app/templates/modules/labels/index.html
Normal file → Executable file
0
app/templates/modules/labels/index.html
Normal file → Executable file
38
app/templates/modules/labels/print_labels.html
Normal file → Executable file
38
app/templates/modules/labels/print_labels.html
Normal file → Executable file
@@ -290,8 +290,11 @@
|
|||||||
<!-- Add html2canvas library for capturing preview as image -->
|
<!-- Add html2canvas library for capturing preview as image -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||||
<!-- PATCHED QZ Tray library - works with custom server using pairing key authentication -->
|
<!-- PATCHED QZ Tray library - works with custom server using pairing key authentication -->
|
||||||
|
<script src="{{ url_for('static', filename='js/qz-tray.js') }}"></script>
|
||||||
|
<!-- CDN versions (disabled):
|
||||||
<script src="https://qz.glyphtree.com/api/latest/qz-tray.js"></script>
|
<script src="https://qz.glyphtree.com/api/latest/qz-tray.js"></script>
|
||||||
<!-- Original CDN version (disabled): <script src="https://cdn.jsdelivr.net/npm/qz-tray@2.2.4/qz-tray.js"></script> -->
|
<script src="https://cdn.jsdelivr.net/npm/qz-tray@2.2.4/qz-tray.js"></script>
|
||||||
|
-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Simplified notification system
|
// Simplified notification system
|
||||||
@@ -492,9 +495,9 @@ function updateLabelPreview(order) {
|
|||||||
const prodOrder = comandaProductie && cantitate ? `${comandaProductie}-${cantitate}` : 'N/A';
|
const prodOrder = comandaProductie && cantitate ? `${comandaProductie}-${cantitate}` : 'N/A';
|
||||||
document.getElementById('prod-order-value').textContent = prodOrder;
|
document.getElementById('prod-order-value').textContent = prodOrder;
|
||||||
|
|
||||||
// Update horizontal barcode with CP format (e.g., CP00000711/001)
|
// Update horizontal barcode with correct format (e.g., TEST-ORD-006-0001)
|
||||||
// Show the first piece number (001) in preview
|
// Show the first piece number (0001) in preview
|
||||||
const horizontalBarcodeData = comandaProductie ? `${comandaProductie}/001` : 'SAMPLE001';
|
const horizontalBarcodeData = comandaProductie ? `${comandaProductie}-${String(1).padStart(4, '0')}` : 'SAMPLE-0001';
|
||||||
document.getElementById('barcode-text').textContent = horizontalBarcodeData;
|
document.getElementById('barcode-text').textContent = horizontalBarcodeData;
|
||||||
|
|
||||||
// Generate horizontal barcode visual using JsBarcode
|
// Generate horizontal barcode visual using JsBarcode
|
||||||
@@ -530,8 +533,9 @@ function updateLabelPreview(order) {
|
|||||||
horizontalBarcodeData === 'N/A' ? 'No data' : 'JsBarcode not loaded');
|
horizontalBarcodeData === 'N/A' ? 'No data' : 'JsBarcode not loaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update vertical barcode with client order format (e.g., Abcderd65)
|
// Update vertical barcode with client order format (e.g., CLIENT001/65)
|
||||||
const verticalBarcodeData = comAchizClient && nrLinie ? `${comAchizClient}${nrLinie}` : 'SAMPLE00';
|
// Must match PDF generator format: com_achiz_client/nr_linie_com_client
|
||||||
|
const verticalBarcodeData = comAchizClient && nrLinie ? `${comAchizClient}/${nrLinie}` : '000000/00';
|
||||||
document.getElementById('vertical-barcode-text').textContent = verticalBarcodeData;
|
document.getElementById('vertical-barcode-text').textContent = verticalBarcodeData;
|
||||||
|
|
||||||
// Generate vertical barcode visual using JsBarcode (will be rotated by CSS)
|
// Generate vertical barcode visual using JsBarcode (will be rotated by CSS)
|
||||||
@@ -577,8 +581,8 @@ function clearLabelPreview() {
|
|||||||
document.getElementById('description-value').textContent = 'N/A';
|
document.getElementById('description-value').textContent = 'N/A';
|
||||||
document.getElementById('article-code-value').textContent = 'N/A';
|
document.getElementById('article-code-value').textContent = 'N/A';
|
||||||
document.getElementById('prod-order-value').textContent = 'N/A';
|
document.getElementById('prod-order-value').textContent = 'N/A';
|
||||||
document.getElementById('barcode-text').textContent = 'SAMPLE001';
|
document.getElementById('barcode-text').textContent = 'SAMPLE-0001';
|
||||||
document.getElementById('vertical-barcode-text').textContent = 'SAMPLE00';
|
document.getElementById('vertical-barcode-text').textContent = '000000/00';
|
||||||
|
|
||||||
// Generate sample barcodes instead of clearing
|
// Generate sample barcodes instead of clearing
|
||||||
generateSampleBarcodes();
|
generateSampleBarcodes();
|
||||||
@@ -602,8 +606,8 @@ function generateSampleBarcodes() {
|
|||||||
horizontalElement.innerHTML = '';
|
horizontalElement.innerHTML = '';
|
||||||
console.log('🔍 Horizontal element cleared, generating barcode...');
|
console.log('🔍 Horizontal element cleared, generating barcode...');
|
||||||
|
|
||||||
// Generate horizontal sample barcode with simpler parameters first
|
// Generate horizontal sample barcode with correct format (dash and 4-digit padding)
|
||||||
JsBarcode(horizontalElement, "SAMPLE001", {
|
JsBarcode(horizontalElement, "SAMPLE-0001", {
|
||||||
format: "CODE128",
|
format: "CODE128",
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 40,
|
height: 40,
|
||||||
@@ -620,8 +624,8 @@ function generateSampleBarcodes() {
|
|||||||
verticalElement.innerHTML = '';
|
verticalElement.innerHTML = '';
|
||||||
console.log('🔍 Vertical element cleared, generating barcode...');
|
console.log('🔍 Vertical element cleared, generating barcode...');
|
||||||
|
|
||||||
// Generate vertical sample barcode
|
// Generate vertical sample barcode with correct format (slash separator)
|
||||||
JsBarcode(verticalElement, "SAMPLE00", {
|
JsBarcode(verticalElement, "000000/00", {
|
||||||
format: "CODE128",
|
format: "CODE128",
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 35,
|
height: 35,
|
||||||
@@ -1081,8 +1085,9 @@ function updatePreview(orderData, pieceNumber, totalPieces) {
|
|||||||
|
|
||||||
const deliveryDate = data_livrare ? new Date(data_livrare).toLocaleDateString() : 'N/A';
|
const deliveryDate = data_livrare ? new Date(data_livrare).toLocaleDateString() : 'N/A';
|
||||||
const clientOrder = com_achiz_client && nr_linie_com_client ? `${com_achiz_client}-${nr_linie_com_client}` : 'N/A';
|
const clientOrder = com_achiz_client && nr_linie_com_client ? `${com_achiz_client}-${nr_linie_com_client}` : 'N/A';
|
||||||
const horizontalBarcode = comanda_productie ? `${comanda_productie}-${String(pieceNumber).padStart(3, '0')}` : 'N/A';
|
const horizontalBarcode = comanda_productie ? `${comanda_productie}-${String(pieceNumber).padStart(4, '0')}` : 'N/A';
|
||||||
const verticalBarcode = clientOrder;
|
// Vertical barcode uses slash separator to match PDF generator
|
||||||
|
const verticalBarcode = com_achiz_client && nr_linie_com_client ? `${com_achiz_client}/${nr_linie_com_client}` : '000000/00';
|
||||||
const prodOrder = comanda_productie && cantitate ? `${comanda_productie}-${cantitate}` : 'N/A';
|
const prodOrder = comanda_productie && cantitate ? `${comanda_productie}-${cantitate}` : 'N/A';
|
||||||
|
|
||||||
// Update preview elements with correct IDs
|
// Update preview elements with correct IDs
|
||||||
@@ -1132,8 +1137,9 @@ function generateHTMLLabel(orderData, pieceNumber, totalPieces) {
|
|||||||
// Format data for label (matching preview format)
|
// Format data for label (matching preview format)
|
||||||
const deliveryDate = data_livrare ? new Date(data_livrare).toLocaleDateString() : 'N/A';
|
const deliveryDate = data_livrare ? new Date(data_livrare).toLocaleDateString() : 'N/A';
|
||||||
const clientOrder = com_achiz_client && nr_linie_com_client ? `${com_achiz_client}-${nr_linie_com_client}` : 'N/A';
|
const clientOrder = com_achiz_client && nr_linie_com_client ? `${com_achiz_client}-${nr_linie_com_client}` : 'N/A';
|
||||||
const horizontalBarcode = comanda_productie ? `${comanda_productie}-${String(pieceNumber).padStart(3, '0')}` : 'N/A';
|
const horizontalBarcode = comanda_productie ? `${comanda_productie}-${String(pieceNumber).padStart(4, '0')}` : 'N/A';
|
||||||
const verticalBarcode = clientOrder;
|
// Vertical barcode uses slash separator to match PDF generator
|
||||||
|
const verticalBarcode = com_achiz_client && nr_linie_com_client ? `${com_achiz_client}/${nr_linie_com_client}` : '000000/00';
|
||||||
const prodOrder = comanda_productie && cantitate ? `${comanda_productie}-${cantitate}` : 'N/A';
|
const prodOrder = comanda_productie && cantitate ? `${comanda_productie}-${cantitate}` : 'N/A';
|
||||||
|
|
||||||
const htmlContent = `
|
const htmlContent = `
|
||||||
|
|||||||
12
app/templates/modules/labels/print_lost_labels.html
Normal file → Executable file
12
app/templates/modules/labels/print_lost_labels.html
Normal file → Executable file
@@ -237,7 +237,7 @@
|
|||||||
<!-- Add html2canvas library for capturing preview as image -->
|
<!-- Add html2canvas library for capturing preview as image -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||||
<!-- PATCHED QZ Tray library - works with custom server using pairing key authentication -->
|
<!-- PATCHED QZ Tray library - works with custom server using pairing key authentication -->
|
||||||
<script src="https://qz.glyphtree.com/api/latest/qz-tray.js"></script>
|
<script src="{{ url_for('static', filename='js/qz-tray.js') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// Store all orders data for searching (will be populated by API fetch on page load)
|
// Store all orders data for searching (will be populated by API fetch on page load)
|
||||||
@@ -559,7 +559,7 @@ async function handleQZTrayPrint(selectedRow) {
|
|||||||
labelNumbers.push(i);
|
labelNumbers.push(i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert(`Invalid range. Please use format "001-${String(orderData.cantitate).padStart(3, '0')}" or single number.`);
|
alert(`Invalid range. Please use format "0001-${String(orderData.cantitate).padStart(4, '0')}" or single number.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -592,8 +592,8 @@ async function handleQZTrayPrint(selectedRow) {
|
|||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
const rangeText = labelsRangeInput ?
|
const rangeText = labelsRangeInput ?
|
||||||
(labelNumbers.length === 1 ? `label ${String(labelNumbers[0]).padStart(3, '0')}` :
|
(labelNumbers.length === 1 ? `label ${String(labelNumbers[0]).padStart(4, '0')}` :
|
||||||
`labels ${String(labelNumbers[0]).padStart(3, '0')}-${String(labelNumbers[labelNumbers.length-1]).padStart(3, '0')}`) :
|
`labels ${String(labelNumbers[0]).padStart(4, '0')}-${String(labelNumbers[labelNumbers.length-1]).padStart(4, '0')}`) :
|
||||||
`all ${orderData.cantitate} labels`;
|
`all ${orderData.cantitate} labels`;
|
||||||
alert(`Successfully printed ${rangeText} for order ${orderData.comanda_productie}`);
|
alert(`Successfully printed ${rangeText} for order ${orderData.comanda_productie}`);
|
||||||
|
|
||||||
@@ -736,10 +736,10 @@ function updatePreviewCard(order) {
|
|||||||
set('size-value', order.dimensiune || '');
|
set('size-value', order.dimensiune || '');
|
||||||
set('article-code-value', order.cod_articol || '');
|
set('article-code-value', order.cod_articol || '');
|
||||||
set('prod-order-value', (order.comanda_productie && order.cantitate) ? `${order.comanda_productie}-${order.cantitate}` : '');
|
set('prod-order-value', (order.comanda_productie && order.cantitate) ? `${order.comanda_productie}-${order.cantitate}` : '');
|
||||||
set('barcode-text', order.comanda_productie ? `${order.comanda_productie}/001` : '');
|
set('barcode-text', order.comanda_productie ? `${order.comanda_productie}-0001` : '');
|
||||||
set('vertical-barcode-text', (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '');
|
set('vertical-barcode-text', (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '');
|
||||||
// Generate barcodes if JsBarcode is available (with debugging like print_module.html)
|
// Generate barcodes if JsBarcode is available (with debugging like print_module.html)
|
||||||
const horizontalBarcodeData = order.comanda_productie ? `${order.comanda_productie}/001` : 'N/A';
|
const horizontalBarcodeData = order.comanda_productie ? `${order.comanda_productie}-0001` : 'N/A';
|
||||||
const verticalBarcodeData = (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '000000/00';
|
const verticalBarcodeData = (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '000000/00';
|
||||||
|
|
||||||
console.log('🔍 BARCODE DEBUG - Order data:', order);
|
console.log('🔍 BARCODE DEBUG - Order data:', order);
|
||||||
|
|||||||
12
app/templates/modules/labels/print_lost_labels_new.html
Normal file → Executable file
12
app/templates/modules/labels/print_lost_labels_new.html
Normal file → Executable file
@@ -230,7 +230,7 @@
|
|||||||
<!-- Add html2canvas library for capturing preview as image -->
|
<!-- Add html2canvas library for capturing preview as image -->
|
||||||
<script src="{{ url_for('static', filename='html2canvas.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='html2canvas.min.js') }}"></script>
|
||||||
<!-- PATCHED QZ Tray library - works with custom server using pairing key authentication -->
|
<!-- PATCHED QZ Tray library - works with custom server using pairing key authentication -->
|
||||||
<script src="{{ url_for('static', filename='qz-tray.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/qz-tray.js') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// Store all orders data for searching
|
// Store all orders data for searching
|
||||||
@@ -542,7 +542,7 @@ async function handleQZTrayPrint(selectedRow) {
|
|||||||
labelNumbers.push(i);
|
labelNumbers.push(i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert(`Invalid range. Please use format "001-${String(orderData.cantitate).padStart(3, '0')}" or single number.`);
|
alert(`Invalid range. Please use format "0001-${String(orderData.cantitate).padStart(4, '0')}" or single number.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -575,8 +575,8 @@ async function handleQZTrayPrint(selectedRow) {
|
|||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
const rangeText = labelsRangeInput ?
|
const rangeText = labelsRangeInput ?
|
||||||
(labelNumbers.length === 1 ? `label ${String(labelNumbers[0]).padStart(3, '0')}` :
|
(labelNumbers.length === 1 ? `label ${String(labelNumbers[0]).padStart(4, '0')}` :
|
||||||
`labels ${String(labelNumbers[0]).padStart(3, '0')}-${String(labelNumbers[labelNumbers.length-1]).padStart(3, '0')}`) :
|
`labels ${String(labelNumbers[0]).padStart(4, '0')}-${String(labelNumbers[labelNumbers.length-1]).padStart(4, '0')}`) :
|
||||||
`all ${orderData.cantitate} labels`;
|
`all ${orderData.cantitate} labels`;
|
||||||
alert(`Successfully printed ${rangeText} for order ${orderData.comanda_productie}`);
|
alert(`Successfully printed ${rangeText} for order ${orderData.comanda_productie}`);
|
||||||
|
|
||||||
@@ -719,10 +719,10 @@ function updatePreviewCard(order) {
|
|||||||
set('size-value', order.dimensiune || '');
|
set('size-value', order.dimensiune || '');
|
||||||
set('article-code-value', order.cod_articol || '');
|
set('article-code-value', order.cod_articol || '');
|
||||||
set('prod-order-value', (order.comanda_productie && order.cantitate) ? `${order.comanda_productie}-${order.cantitate}` : '');
|
set('prod-order-value', (order.comanda_productie && order.cantitate) ? `${order.comanda_productie}-${order.cantitate}` : '');
|
||||||
set('barcode-text', order.comanda_productie ? `${order.comanda_productie}/001` : '');
|
set('barcode-text', order.comanda_productie ? `${order.comanda_productie}-0001` : '');
|
||||||
set('vertical-barcode-text', (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '');
|
set('vertical-barcode-text', (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '');
|
||||||
// Generate barcodes if JsBarcode is available (with debugging like print_module.html)
|
// Generate barcodes if JsBarcode is available (with debugging like print_module.html)
|
||||||
const horizontalBarcodeData = order.comanda_productie ? `${order.comanda_productie}/001` : 'N/A';
|
const horizontalBarcodeData = order.comanda_productie ? `${order.comanda_productie}-0001` : 'N/A';
|
||||||
const verticalBarcodeData = (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '000000/00';
|
const verticalBarcodeData = (order.com_achiz_client && order.nr_linie_com_client) ? `${order.com_achiz_client}/${order.nr_linie_com_client}` : '000000/00';
|
||||||
|
|
||||||
console.log('🔍 BARCODE DEBUG - Order data:', order);
|
console.log('🔍 BARCODE DEBUG - Order data:', order);
|
||||||
|
|||||||
0
app/templates/modules/labels/print_module.html
Normal file → Executable file
0
app/templates/modules/labels/print_module.html
Normal file → Executable file
0
app/templates/modules/quality/fg_reports.html
Normal file → Executable file
0
app/templates/modules/quality/fg_reports.html
Normal file → Executable file
2
app/templates/modules/quality/fg_scan.html
Normal file → Executable file
2
app/templates/modules/quality/fg_scan.html
Normal file → Executable file
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fg_scan.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/fg_scan.css') }}">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/qz-tray@2.1.0/qz-tray.js"></script>
|
<script src="{{ url_for('static', filename='js/qz-tray.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
0
app/templates/modules/quality/index.html
Normal file → Executable file
0
app/templates/modules/quality/index.html
Normal file → Executable file
0
app/templates/modules/quality/inspections.html
Normal file → Executable file
0
app/templates/modules/quality/inspections.html
Normal file → Executable file
0
app/templates/modules/quality/reports.html
Normal file → Executable file
0
app/templates/modules/quality/reports.html
Normal file → Executable file
0
app/templates/modules/settings/app_keys.html
Normal file → Executable file
0
app/templates/modules/settings/app_keys.html
Normal file → Executable file
0
app/templates/modules/settings/database.html
Normal file → Executable file
0
app/templates/modules/settings/database.html
Normal file → Executable file
65
app/templates/modules/settings/database_management.html
Normal file → Executable file
65
app/templates/modules/settings/database_management.html
Normal file → Executable file
@@ -477,7 +477,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
alert('Cleanup completed! ' + (data.deleted_count || 0) + ' old backups deleted.');
|
alert('Cleanup completed! ' + (data.deleted_count || 0) + ' old backups deleted.');
|
||||||
@@ -512,7 +515,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
alert('Backup created successfully: ' + data.file);
|
alert('Backup created successfully: ' + data.file);
|
||||||
@@ -677,7 +683,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({ table: table })
|
body: JSON.stringify({ table: table })
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
if (response.status === 401) {
|
||||||
|
throw new Error('Unauthorized. Please log in again.');
|
||||||
|
}
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
// Hide modal
|
// Hide modal
|
||||||
@@ -701,16 +715,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
} else {
|
} else {
|
||||||
alert('Error: ' + data.error);
|
alert('Error: ' + data.error);
|
||||||
// Re-enable button
|
// Re-enable button
|
||||||
this.disabled = false;
|
confirmBtn.disabled = false;
|
||||||
this.innerHTML = '<i class="fas fa-trash"></i> Yes, Clear All Data';
|
confirmBtn.innerHTML = '<i class="fas fa-trash"></i> Yes, Clear All Data';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
alert('Error clearing table: ' + error);
|
alert('Error clearing table: ' + error.message);
|
||||||
// Re-enable button
|
// Re-enable button
|
||||||
this.disabled = false;
|
confirmBtn.disabled = false;
|
||||||
this.innerHTML = '<i class="fas fa-trash"></i> Yes, Clear All Data';
|
confirmBtn.innerHTML = '<i class="fas fa-trash"></i> Yes, Clear All Data';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -739,7 +753,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({ backup: backup })
|
body: JSON.stringify({ backup: backup })
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
alert('Database restored successfully!');
|
alert('Database restored successfully!');
|
||||||
@@ -758,7 +775,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
function loadBackupsList() {
|
function loadBackupsList() {
|
||||||
fetch('{{ url_for("settings.get_backups_list") }}')
|
fetch('{{ url_for("settings.get_backups_list") }}')
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.backups && data.backups.length > 0) {
|
if (data.backups && data.backups.length > 0) {
|
||||||
const tbody = document.getElementById('backups-list');
|
const tbody = document.getElementById('backups-list');
|
||||||
@@ -837,7 +857,10 @@ function toggleDayOfWeek() {
|
|||||||
|
|
||||||
function loadBackupSchedules() {
|
function loadBackupSchedules() {
|
||||||
fetch('{{ url_for("settings.get_backup_schedules") }}')
|
fetch('{{ url_for("settings.get_backup_schedules") }}')
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const tbody = document.getElementById('schedules-list');
|
const tbody = document.getElementById('schedules-list');
|
||||||
|
|
||||||
@@ -925,7 +948,10 @@ function saveBackupSchedule() {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
alert('Backup schedule created successfully!');
|
alert('Backup schedule created successfully!');
|
||||||
@@ -949,7 +975,10 @@ function deleteSchedule(scheduleId) {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
alert('Schedule deleted successfully!');
|
alert('Schedule deleted successfully!');
|
||||||
@@ -972,7 +1001,10 @@ function toggleSchedule(scheduleId) {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
loadBackupSchedules();
|
loadBackupSchedules();
|
||||||
@@ -1010,7 +1042,10 @@ function uploadBackupFile() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
statusDiv.innerHTML = '<div class="alert alert-success"><i class="fas fa-check-circle"></i> File uploaded successfully: ' + data.filename + ' (' + data.size + ' bytes)</div>';
|
statusDiv.innerHTML = '<div class="alert alert-success"><i class="fas fa-check-circle"></i> File uploaded successfully: ' + data.filename + ' (' + data.size + ' bytes)</div>';
|
||||||
|
|||||||
0
app/templates/modules/settings/general.html
Normal file → Executable file
0
app/templates/modules/settings/general.html
Normal file → Executable file
0
app/templates/modules/settings/index.html
Normal file → Executable file
0
app/templates/modules/settings/index.html
Normal file → Executable file
0
app/templates/modules/settings/logs_explorer.html
Normal file → Executable file
0
app/templates/modules/settings/logs_explorer.html
Normal file → Executable file
0
app/templates/modules/settings/search_logs.html
Normal file → Executable file
0
app/templates/modules/settings/search_logs.html
Normal file → Executable file
0
app/templates/modules/settings/user_form.html
Normal file → Executable file
0
app/templates/modules/settings/user_form.html
Normal file → Executable file
0
app/templates/modules/settings/users.html
Normal file → Executable file
0
app/templates/modules/settings/users.html
Normal file → Executable file
0
app/templates/modules/settings/view_log.html
Normal file → Executable file
0
app/templates/modules/settings/view_log.html
Normal file → Executable file
0
app/templates/modules/warehouse/boxes.html
Normal file → Executable file
0
app/templates/modules/warehouse/boxes.html
Normal file → Executable file
0
app/templates/modules/warehouse/index.html
Normal file → Executable file
0
app/templates/modules/warehouse/index.html
Normal file → Executable file
0
app/templates/modules/warehouse/inventory.html
Normal file → Executable file
0
app/templates/modules/warehouse/inventory.html
Normal file → Executable file
0
app/templates/modules/warehouse/locations.html
Normal file → Executable file
0
app/templates/modules/warehouse/locations.html
Normal file → Executable file
0
app/templates/modules/warehouse/reports.html
Normal file → Executable file
0
app/templates/modules/warehouse/reports.html
Normal file → Executable file
0
app/templates/modules/warehouse/set_boxes_locations.html
Normal file → Executable file
0
app/templates/modules/warehouse/set_boxes_locations.html
Normal file → Executable file
0
app/templates/modules/warehouse/set_orders_on_boxes.html
Normal file → Executable file
0
app/templates/modules/warehouse/set_orders_on_boxes.html
Normal file → Executable file
0
app/templates/modules/warehouse/test_barcode.html
Normal file → Executable file
0
app/templates/modules/warehouse/test_barcode.html
Normal file → Executable file
0
app/templates/profile.html
Normal file → Executable file
0
app/templates/profile.html
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
version: '3.8'
|
#version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# MariaDB Database Service
|
# MariaDB Database Service
|
||||||
|
|||||||
260
documentation/add_labels_test_data.py
Normal file
260
documentation/add_labels_test_data.py
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Add Example/Test Data for Labels Module
|
||||||
|
Creates sample orders in order_for_labels table for testing printing functionality via QZ Tray
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
from app.database import get_db
|
||||||
|
import logging
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def add_sample_labels_data():
|
||||||
|
"""Add sample order data for testing labels/printing functionality"""
|
||||||
|
try:
|
||||||
|
conn = get_db()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Check if table exists
|
||||||
|
cursor.execute("SHOW TABLES LIKE 'order_for_labels'")
|
||||||
|
if not cursor.fetchone():
|
||||||
|
logger.error("order_for_labels table does not exist. Please run initialize_db.py first.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Clear existing test data (optional - comment out if you want to keep existing data)
|
||||||
|
logger.info("Clearing existing test data...")
|
||||||
|
cursor.execute("DELETE FROM order_for_labels WHERE comanda_productie LIKE 'TEST%'")
|
||||||
|
|
||||||
|
# Sample test data for different scenarios
|
||||||
|
test_orders = [
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-001',
|
||||||
|
'cod_articol': 'ART001',
|
||||||
|
'descr_com_prod': 'Electronic Component Type A - High Performance',
|
||||||
|
'cantitate': 150,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-001',
|
||||||
|
'nr_linie_com_client': '01',
|
||||||
|
'customer_name': 'TechCorp Industries',
|
||||||
|
'customer_article_number': 'TC-COMP-A001',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 1,
|
||||||
|
'printed_labels': 0, # Not printed - will show in unprinted list
|
||||||
|
'data_livrara': '2024-03-15', # Fixed field name to match DB schema
|
||||||
|
'dimensiune': 'Standard-Large'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-002',
|
||||||
|
'cod_articol': 'ART002',
|
||||||
|
'descr_com_prod': 'Mechanical Part B - Precision Machined',
|
||||||
|
'cantitate': 75,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-002',
|
||||||
|
'nr_linie_com_client': '02',
|
||||||
|
'customer_name': 'MechParts Ltd',
|
||||||
|
'customer_article_number': 'MP-PART-B002',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 2,
|
||||||
|
'printed_labels': 0, # Not printed
|
||||||
|
'data_livrara': '2024-03-18',
|
||||||
|
'dimensiune': 'Medium'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-003',
|
||||||
|
'cod_articol': 'ART003',
|
||||||
|
'descr_com_prod': 'Plastic Housing C - UV Resistant',
|
||||||
|
'cantitate': 200,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-003',
|
||||||
|
'nr_linie_com_client': '03',
|
||||||
|
'customer_name': 'PlasticWorks Inc',
|
||||||
|
'customer_article_number': 'PW-HOUSE-C003',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 3,
|
||||||
|
'printed_labels': 1, # Already printed - will show in printed list
|
||||||
|
'data_livrara': '2024-03-20',
|
||||||
|
'dimensiune': 'Large'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-004',
|
||||||
|
'cod_articol': 'ART004',
|
||||||
|
'descr_com_prod': 'Metal Bracket D - Galvanized Steel',
|
||||||
|
'cantitate': 300,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-004',
|
||||||
|
'nr_linie_com_client': '04',
|
||||||
|
'customer_name': 'MetalCraft Solutions',
|
||||||
|
'customer_article_number': 'MC-BRACK-D004',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 4,
|
||||||
|
'printed_labels': 0, # Not printed
|
||||||
|
'data_livrara': '2024-03-22',
|
||||||
|
'dimensiune': 'Small'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-005',
|
||||||
|
'cod_articol': 'ART005',
|
||||||
|
'descr_com_prod': 'Circuit Board E - Multi-layer PCB',
|
||||||
|
'cantitate': 50,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-005',
|
||||||
|
'nr_linie_com_client': '05',
|
||||||
|
'customer_name': 'CircuitTech Systems',
|
||||||
|
'customer_article_number': 'CT-PCB-E005',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 5,
|
||||||
|
'printed_labels': 0, # Not printed
|
||||||
|
'data_livrara': '2024-03-25',
|
||||||
|
'dimensiune': 'Standard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-006',
|
||||||
|
'cod_articol': 'ART006',
|
||||||
|
'descr_com_prod': 'Rubber Gasket F - High Temperature',
|
||||||
|
'cantitate': 500,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-006',
|
||||||
|
'nr_linie_com_client': '06',
|
||||||
|
'customer_name': 'RubberPro Manufacturing',
|
||||||
|
'customer_article_number': 'RP-GASKET-F006',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 6,
|
||||||
|
'printed_labels': 1, # Already printed
|
||||||
|
'data_livrara': '2024-03-28',
|
||||||
|
'dimensiune': 'Extra-Small'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-007',
|
||||||
|
'cod_articol': 'ART007',
|
||||||
|
'descr_com_prod': 'Glass Panel G - Tempered Safety Glass',
|
||||||
|
'cantitate': 25,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-007',
|
||||||
|
'nr_linie_com_client': '07',
|
||||||
|
'customer_name': 'GlassTech Innovations',
|
||||||
|
'customer_article_number': 'GT-PANEL-G007',
|
||||||
|
'open_for_order': 1,
|
||||||
|
'line_number': 7,
|
||||||
|
'printed_labels': 0, # Not printed - urgent order
|
||||||
|
'data_livrara': '2024-03-12', # Past due date for testing
|
||||||
|
'dimensiune': 'Extra-Large'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'comanda_productie': 'TEST-ORD-008',
|
||||||
|
'cod_articol': 'ART008',
|
||||||
|
'descr_com_prod': 'Fabric Cover H - Water-Resistant Canvas',
|
||||||
|
'cantitate': 120,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-008',
|
||||||
|
'nr_linie_com_client': '08',
|
||||||
|
'customer_name': 'FabricWorks Design',
|
||||||
|
'customer_article_number': 'FW-COVER-H008',
|
||||||
|
'open_for_order': 0, # Not open for order - for testing
|
||||||
|
'line_number': 8,
|
||||||
|
'printed_labels': 0,
|
||||||
|
'data_livrara': '2024-04-01',
|
||||||
|
'dimensiune': 'Custom'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Insert test data
|
||||||
|
logger.info(f"Inserting {len(test_orders)} test orders...")
|
||||||
|
|
||||||
|
for order in test_orders:
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO order_for_labels (
|
||||||
|
comanda_productie, cod_articol, descr_com_prod, cantitate,
|
||||||
|
com_achiz_client, nr_linie_com_client, customer_name,
|
||||||
|
customer_article_number, open_for_order, line_number,
|
||||||
|
printed_labels, data_livrara, dimensiune
|
||||||
|
) VALUES (
|
||||||
|
%(comanda_productie)s, %(cod_articol)s, %(descr_com_prod)s, %(cantitate)s,
|
||||||
|
%(com_achiz_client)s, %(nr_linie_com_client)s, %(customer_name)s,
|
||||||
|
%(customer_article_number)s, %(open_for_order)s, %(line_number)s,
|
||||||
|
%(printed_labels)s, %(data_livrara)s, %(dimensiune)s
|
||||||
|
)
|
||||||
|
""", order)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
logger.info("✅ Successfully added test data for labels module!")
|
||||||
|
logger.info("Test data summary:")
|
||||||
|
logger.info(f" - Total orders: {len(test_orders)}")
|
||||||
|
logger.info(f" - Unprinted orders: {sum(1 for o in test_orders if o['printed_labels'] == 0)}")
|
||||||
|
logger.info(f" - Printed orders: {sum(1 for o in test_orders if o['printed_labels'] == 1)}")
|
||||||
|
logger.info(" - Test order codes: TEST-ORD-001 through TEST-ORD-008")
|
||||||
|
logger.info("\nYou can now test:")
|
||||||
|
logger.info(" 1. Navigate to /labels/print-module")
|
||||||
|
logger.info(" 2. View unprinted orders (should show 6 orders)")
|
||||||
|
logger.info(" 3. Generate PDF labels and test QZ Tray printing")
|
||||||
|
logger.info(" 4. Mark orders as printed and verify status updates")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error adding test data: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def verify_test_data():
|
||||||
|
"""Verify that test data was added correctly"""
|
||||||
|
try:
|
||||||
|
conn = get_db()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Count total test orders
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM order_for_labels WHERE comanda_productie LIKE 'TEST%'")
|
||||||
|
total_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# Count unprinted test orders
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM order_for_labels WHERE comanda_productie LIKE 'TEST%' AND printed_labels = 0")
|
||||||
|
unprinted_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# Count printed test orders
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM order_for_labels WHERE comanda_productie LIKE 'TEST%' AND printed_labels = 1")
|
||||||
|
printed_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
logger.info(f"\n📋 Test Data Verification:")
|
||||||
|
logger.info(f" - Total test orders: {total_count}")
|
||||||
|
logger.info(f" - Unprinted orders: {unprinted_count}")
|
||||||
|
logger.info(f" - Printed orders: {printed_count}")
|
||||||
|
|
||||||
|
# List some sample orders
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT comanda_productie, descr_com_prod, cantitate, printed_labels, data_livrara
|
||||||
|
FROM order_for_labels
|
||||||
|
WHERE comanda_productie LIKE 'TEST%'
|
||||||
|
ORDER BY comanda_productie
|
||||||
|
LIMIT 5
|
||||||
|
""")
|
||||||
|
|
||||||
|
orders = cursor.fetchall()
|
||||||
|
if orders:
|
||||||
|
logger.info(f"\n🏷️ Sample Test Orders:")
|
||||||
|
for order in orders:
|
||||||
|
status = "✅ Printed" if order[3] else "⏳ Unprinted"
|
||||||
|
logger.info(f" - {order[0]}: {order[1][:50]}... (Qty: {order[2]}, {status})")
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error verifying test data: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logger.info("🏷️ Adding Labels Module Test Data...")
|
||||||
|
|
||||||
|
if add_sample_labels_data():
|
||||||
|
verify_test_data()
|
||||||
|
logger.info("\n🎉 Test data successfully added!")
|
||||||
|
logger.info("\nNext steps:")
|
||||||
|
logger.info("1. Start the application: docker compose up -d")
|
||||||
|
logger.info("2. Navigate to: http://localhost:8080/labels/print-module")
|
||||||
|
logger.info("3. Test QZ Tray printing functionality")
|
||||||
|
else:
|
||||||
|
logger.error("❌ Failed to add test data")
|
||||||
|
sys.exit(1)
|
||||||
149
documentation/add_labels_test_data_direct.py
Normal file
149
documentation/add_labels_test_data_direct.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Add Example/Test Data for Labels Module - Direct Database Version
|
||||||
|
Creates sample orders in order_for_labels table for testing printing functionality via QZ Tray
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pymysql
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Database connection parameters
|
||||||
|
DB_CONFIG = {
|
||||||
|
'host': 'localhost',
|
||||||
|
'port': 3306,
|
||||||
|
'user': 'quality_user',
|
||||||
|
'password': 'qualitypass',
|
||||||
|
'database': 'quality_db',
|
||||||
|
'charset': 'utf8mb4'
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_sample_labels_data():
|
||||||
|
"""Add sample order data for testing labels/printing functionality"""
|
||||||
|
try:
|
||||||
|
# Connect to database
|
||||||
|
conn = pymysql.connect(**DB_CONFIG)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Check if table exists
|
||||||
|
cursor.execute("SHOW TABLES LIKE 'order_for_labels'")
|
||||||
|
if not cursor.fetchone():
|
||||||
|
logger.error("order_for_labels table does not exist. Please run initialize_db.py first.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Clear existing test data (optional - comment out if you want to keep existing data)
|
||||||
|
logger.info("Clearing existing test data...")
|
||||||
|
cursor.execute("DELETE FROM order_for_labels WHERE comanda_productie LIKE 'TEST%'")
|
||||||
|
|
||||||
|
# Sample test data for different scenarios
|
||||||
|
test_orders = [
|
||||||
|
('TEST-ORD-001', 'ART001', 'Electronic Component Type A - High Performance', 150, 'CLIENT-PO-2024-001', '01', 'TechCorp Industries', 'TC-COMP-A001', 1, 1, 0, '2024-03-15', 'Standard-Large'),
|
||||||
|
('TEST-ORD-002', 'ART002', 'Mechanical Part B - Precision Machined', 75, 'CLIENT-PO-2024-002', '02', 'MechParts Ltd', 'MP-PART-B002', 1, 2, 0, '2024-03-18', 'Medium'),
|
||||||
|
('TEST-ORD-003', 'ART003', 'Plastic Housing C - UV Resistant', 200, 'CLIENT-PO-2024-003', '03', 'PlasticWorks Inc', 'PW-HOUSE-C003', 1, 3, 1, '2024-03-20', 'Large'),
|
||||||
|
('TEST-ORD-004', 'ART004', 'Metal Bracket D - Galvanized Steel', 300, 'CLIENT-PO-2024-004', '04', 'MetalCraft Solutions', 'MC-BRACK-D004', 1, 4, 0, '2024-03-22', 'Small'),
|
||||||
|
('TEST-ORD-005', 'ART005', 'Circuit Board E - Multi-layer PCB', 50, 'CLIENT-PO-2024-005', '05', 'CircuitTech Systems', 'CT-PCB-E005', 1, 5, 0, '2024-03-25', 'Standard'),
|
||||||
|
('TEST-ORD-006', 'ART006', 'Rubber Gasket F - High Temperature', 500, 'CLIENT-PO-2024-006', '06', 'RubberPro Manufacturing', 'RP-GASKET-F006', 1, 6, 1, '2024-03-28', 'Extra-Small'),
|
||||||
|
('TEST-ORD-007', 'ART007', 'Glass Panel G - Tempered Safety Glass', 25, 'CLIENT-PO-2024-007', '07', 'GlassTech Innovations', 'GT-PANEL-G007', 1, 7, 0, '2024-03-12', 'Extra-Large'),
|
||||||
|
('TEST-ORD-008', 'ART008', 'Fabric Cover H - Water-Resistant Canvas', 120, 'CLIENT-PO-2024-008', '08', 'FabricWorks Design', 'FW-COVER-H008', 0, 8, 0, '2024-04-01', 'Custom'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Insert test data
|
||||||
|
logger.info(f"Inserting {len(test_orders)} test orders...")
|
||||||
|
|
||||||
|
cursor.executemany("""
|
||||||
|
INSERT INTO order_for_labels (
|
||||||
|
comanda_productie, cod_articol, descr_com_prod, cantitate,
|
||||||
|
com_achiz_client, nr_linie_com_client, customer_name,
|
||||||
|
customer_article_number, open_for_order, line_number,
|
||||||
|
printed_labels, data_livrara, dimensiune
|
||||||
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
""", test_orders)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
logger.info("✅ Successfully added test data for labels module!")
|
||||||
|
logger.info("Test data summary:")
|
||||||
|
logger.info(f" - Total orders: {len(test_orders)}")
|
||||||
|
logger.info(f" - Unprinted orders: {sum(1 for o in test_orders if o[10] == 0)}") # printed_labels is index 10
|
||||||
|
logger.info(f" - Printed orders: {sum(1 for o in test_orders if o[10] == 1)}")
|
||||||
|
logger.info(" - Test order codes: TEST-ORD-001 through TEST-ORD-008")
|
||||||
|
logger.info("\nYou can now test:")
|
||||||
|
logger.info(" 1. Navigate to /labels/print-module")
|
||||||
|
logger.info(" 2. View unprinted orders (should show 6 orders)")
|
||||||
|
logger.info(" 3. Generate PDF labels and test QZ Tray printing")
|
||||||
|
logger.info(" 4. Mark orders as printed and verify status updates")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error adding test data: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def verify_test_data():
|
||||||
|
"""Verify that test data was added correctly"""
|
||||||
|
try:
|
||||||
|
conn = pymysql.connect(**DB_CONFIG)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Count total test orders
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM order_for_labels WHERE comanda_productie LIKE 'TEST%'")
|
||||||
|
total_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# Count unprinted test orders
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM order_for_labels WHERE comanda_productie LIKE 'TEST%' AND printed_labels = 0")
|
||||||
|
unprinted_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# Count printed test orders
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM order_for_labels WHERE comanda_productie LIKE 'TEST%' AND printed_labels = 1")
|
||||||
|
printed_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
logger.info(f"\n📋 Test Data Verification:")
|
||||||
|
logger.info(f" - Total test orders: {total_count}")
|
||||||
|
logger.info(f" - Unprinted orders: {unprinted_count}")
|
||||||
|
logger.info(f" - Printed orders: {printed_count}")
|
||||||
|
|
||||||
|
# List some sample orders
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT comanda_productie, descr_com_prod, cantitate, printed_labels, data_livrara
|
||||||
|
FROM order_for_labels
|
||||||
|
WHERE comanda_productie LIKE 'TEST%'
|
||||||
|
ORDER BY comanda_productie
|
||||||
|
LIMIT 5
|
||||||
|
""")
|
||||||
|
|
||||||
|
orders = cursor.fetchall()
|
||||||
|
if orders:
|
||||||
|
logger.info(f"\n🏷️ Sample Test Orders:")
|
||||||
|
for order in orders:
|
||||||
|
status = "✅ Printed" if order[3] else "⏳ Unprinted"
|
||||||
|
desc = order[1][:50] + "..." if len(order[1]) > 50 else order[1]
|
||||||
|
logger.info(f" - {order[0]}: {desc} (Qty: {order[2]}, {status})")
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error verifying test data: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logger.info("🏷️ Adding Labels Module Test Data...")
|
||||||
|
|
||||||
|
if add_sample_labels_data():
|
||||||
|
verify_test_data()
|
||||||
|
logger.info("\n🎉 Test data successfully added!")
|
||||||
|
logger.info("\nNext steps:")
|
||||||
|
logger.info("1. Navigate to: http://localhost:8781/labels/print-module")
|
||||||
|
logger.info("2. Test QZ Tray printing functionality")
|
||||||
|
logger.info("3. Use test orders TEST-ORD-001 through TEST-ORD-008")
|
||||||
|
else:
|
||||||
|
logger.error("❌ Failed to add test data")
|
||||||
25
init_db.py
25
init_db.py
@@ -408,6 +408,31 @@ def create_tables():
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
""", description="Table 'cp_location_history'")
|
""", description="Table 'cp_location_history'")
|
||||||
|
|
||||||
|
# Order For Labels table (for printing module)
|
||||||
|
execute_sql(conn, """
|
||||||
|
CREATE TABLE IF NOT EXISTS order_for_labels (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
comanda_productie VARCHAR(50) NOT NULL,
|
||||||
|
cod_articol VARCHAR(50),
|
||||||
|
descr_com_prod TEXT,
|
||||||
|
cantitate DECIMAL(10, 2),
|
||||||
|
com_achiz_client VARCHAR(50),
|
||||||
|
nr_linie_com_client VARCHAR(50),
|
||||||
|
customer_name VARCHAR(255),
|
||||||
|
customer_article_number VARCHAR(100),
|
||||||
|
open_for_order TINYINT(1) DEFAULT 1,
|
||||||
|
line_number INT,
|
||||||
|
printed_labels TINYINT(1) DEFAULT 0,
|
||||||
|
data_livrare DATE,
|
||||||
|
dimensiune VARCHAR(50),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_comanda_productie (comanda_productie),
|
||||||
|
INDEX idx_printed_labels (printed_labels),
|
||||||
|
INDEX idx_created_at (created_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
""", description="Table 'order_for_labels'")
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
logger.info("✓ All tables created successfully")
|
logger.info("✓ All tables created successfully")
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ def create_tables():
|
|||||||
open_for_order TINYINT(1) DEFAULT 1,
|
open_for_order TINYINT(1) DEFAULT 1,
|
||||||
line_number INT,
|
line_number INT,
|
||||||
printed_labels TINYINT(1) DEFAULT 0,
|
printed_labels TINYINT(1) DEFAULT 0,
|
||||||
data_livrara DATE,
|
data_livrare DATE,
|
||||||
dimensiune VARCHAR(50),
|
dimensiune VARCHAR(50),
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ Markdown==3.5.1
|
|||||||
APScheduler==3.10.4
|
APScheduler==3.10.4
|
||||||
reportlab==4.0.7
|
reportlab==4.0.7
|
||||||
python-barcode==0.15.1
|
python-barcode==0.15.1
|
||||||
Flask-Session==0.8.0openpyxl==3.10.0
|
Flask-Session==0.8.0
|
||||||
|
openpyxl==3.1.5
|
||||||
70
test_barcode_format.py
Normal file
70
test_barcode_format.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify barcode format in generated PDFs
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, '/srv/quality_app-v2')
|
||||||
|
|
||||||
|
from app.modules.labels.pdf_generator import LabelPDFGenerator
|
||||||
|
|
||||||
|
# Test order data
|
||||||
|
test_order = {
|
||||||
|
'comanda_productie': 'TEST-ORD-004',
|
||||||
|
'cod_articol': 'ART004',
|
||||||
|
'descr_com_prod': 'Metal Bracket D - Galvanized Steel',
|
||||||
|
'cantitate': 300,
|
||||||
|
'com_achiz_client': 'CLIENT-PO-2024-004',
|
||||||
|
'nr_linie_com_client': '04',
|
||||||
|
'customer_name': 'MetalCraft Solutions',
|
||||||
|
'customer_article_number': 'MC-BRACK-D004',
|
||||||
|
'data_livrara': '2024-03-22',
|
||||||
|
'dimensiune': 'Small'
|
||||||
|
}
|
||||||
|
|
||||||
|
print("="*70)
|
||||||
|
print("BARCODE FORMAT TEST")
|
||||||
|
print("="*70)
|
||||||
|
|
||||||
|
# Test what sequential number will be generated
|
||||||
|
prod_order = test_order['comanda_productie']
|
||||||
|
piece_number = 1
|
||||||
|
|
||||||
|
# This is how the PDF generator creates the sequential number
|
||||||
|
sequential_number = f"{prod_order}-{piece_number:04d}"
|
||||||
|
|
||||||
|
print(f"\n📦 Production Order: {prod_order}")
|
||||||
|
print(f"🔢 Piece Number: {piece_number}")
|
||||||
|
print(f"📊 Sequential Number (Horizontal Barcode): {sequential_number}")
|
||||||
|
|
||||||
|
# Check vertical barcode format
|
||||||
|
com_achiz_client = test_order['com_achiz_client']
|
||||||
|
nr_linie = test_order['nr_linie_com_client']
|
||||||
|
vertical_code = f"{com_achiz_client}/{nr_linie}"
|
||||||
|
|
||||||
|
print(f"📐 Vertical Barcode: {vertical_code}")
|
||||||
|
|
||||||
|
print("\n" + "="*70)
|
||||||
|
print("EXPECTED vs ACTUAL")
|
||||||
|
print("="*70)
|
||||||
|
print(f"✅ CORRECT Horizontal: {sequential_number}")
|
||||||
|
print(f"❌ WRONG Format: TEST/ORD/004/0001")
|
||||||
|
print(f"")
|
||||||
|
print("If you're seeing TEST/ORD/004/0001, possible causes:")
|
||||||
|
print("1. Data in database has slashes instead of hyphens")
|
||||||
|
print("2. Barcode scanner is configured to translate hyphens to slashes")
|
||||||
|
print("3. Looking at wrong barcode (there are 2 barcodes on each label)")
|
||||||
|
print("="*70)
|
||||||
|
|
||||||
|
# Generate actual PDF to verify
|
||||||
|
print("\n🔧 Generating test PDF...")
|
||||||
|
pdf_gen = LabelPDFGenerator(paper_saving_mode=True)
|
||||||
|
pdf_buffer = pdf_gen.generate_single_label_pdf(test_order, 1, 300, printer_optimized=True)
|
||||||
|
|
||||||
|
# Save test PDF
|
||||||
|
output_file = '/srv/quality_app-v2/test_label_output.pdf'
|
||||||
|
with open(output_file, 'wb') as f:
|
||||||
|
f.write(pdf_buffer.read())
|
||||||
|
|
||||||
|
print(f"✅ Test PDF saved to: {output_file}")
|
||||||
|
print(f"📄 Open this PDF to verify the barcode format visually")
|
||||||
|
print("\nThe barcode should encode: TEST-ORD-004-0001 (with hyphens)")
|
||||||
74
test_label.pdf
Normal file
74
test_label.pdf
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document http://www.reportlab.com
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 8 0 R /MediaBox [ 0 0 226.7717 297.6378 ] /Parent 7 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Author (anonymous) /CreationDate (D:20260215130816+00'00') /Creator (Recticel Label System) /Keywords () /ModDate (D:20260215130816+00'00') /Producer (Optimized for Epson TM-T20 / Citizen CTS-310)
|
||||||
|
/Subject (Production Label) /Title (Thermal Label - Optimized for Label Printers) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1821
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gat=-gMRrh&:N/3n?EFq$&<^g3d)DUc.1AU#kf05/)-&XUe&87LYQ1kCsLUd+N*?ec5[>91M:B%)BZ+HYO@^%ZV[iTA&UnhDA>6RC@PWD?-IDu\9p4klCZbC@O>lS:F[3e_&1-gPE%(AcA&(f=`$3B26607<*+9UE/%42ioWKa`pAt1L.mD#/V%=#C+q.kkPD?Yo_<9A-lD.:[P=#QiUZ[q+1gi[ID/k@DUm:TqYPI/E<#<,[J4f^bJuCm*6<nseXb^<j>bllfG\fj['cKg1]GI=*:%HO`e:]_o",h[ZaCiQ_^^r)AI=JGa,tI<WR7"U#@AkQjnnUt]A!6`&"B&+e(l!;CeQb=KNWUFh/&Gek7aIglVfbB$Q(7-&>sSlErQ$lp>N1/oY@&Ke_C6u;t,k'^&S&ua2RuJVn(3pc*_^JK,?`0l`/9hDS>noD18LSjgKLG_NM?pm"r?8YKpO0a_#S0K`TZ3lcn_`Z:Q,_'"37tP`c8bQ\giurQ\J_2TtF$\uiP?o4+-!G9)]<49>"j\c/kH?iAa8W2jdeX^<tD*Qq=E4^PtXZa*ikG^J`;DRk36R$:,HPPb<#[b7gdf:=sP\9Si<d$YBAc9@cEhcubDs"V8J3]SS3!ept=VF.X+LRq!9+^t,aIYg:-*cBK*B-/kP_OYpT]Y.Lm5@%T[Z\>UF",@,f!*bQ,C_*GK)a!"KNlVk1G[rmrS_ABtES;DcNanuq7MD[EMB7OZDQ,L%$LYuW*%SI)BD=VtFPNEs&TFPPEuFW`2IhL=!a5Z$nosb>:`U2%HGiViDdVIC!FpL07MKtPJY0/4.J/=j,o]W.Rq<jH,SWZ\?tB,<m]hnnU\_P5c!'[@HS=(U65_U(+IgH!Ao[MSM+4)=kf<c9r3/.:(PVr>)X&t3MnqLel%m2%"nNd6b?>>:"6CB$3.500g]e?f5T)N&H4a"n'Pi[EU4l-(#:oY%Zn#_@M27n*C.DU<(l2t4&eN#QhF'$c=\+8sU]`nAdm[B]J<D9a&h,k6"T!/uU1I'gioENq.4Jtq(G1!NZ&[g%b,K,m-T]t$R08A)%$[[0)Z"V4<\!Q.3>NI]4"DriUZX$/;?BgN[C5X?ABqlAO;pR:%J1bC16q^smDpDR[M=r:X`C%r*SI%^W_r&R4^mD:lWN@$[REmc.AI:dRH5X0kfb6^X9kXoIhUc\fHtms`bQK-T9(C\)B:)I'$)tBq&gEc@<hnc\998j![)H!^m^(q6I1*IZnM3%SX&@b6_FZAY6@[6W`<PF*sLU(W&P]u8-h'$*;@i:RG+"F`qAWVOU\\>Xu\LY`W=3$%8FNH'6YAH`/IW+#KCHSa`X'lacAlu5QU=4B?^KB@0DGBmtJ1l\$#od4QSK:-R7aY8uZ\@d3e7<72o#Ta%8A7c[hO"gH]Zejg:R#k@eVDTXXb=8[=2*N##o'>)Hd@^_:Ar=LKrloam>ND/EjS#RKFmSljYO7:<#>Rmr64ksbeD5n=EZ0Jeg=?N.EC"\UJ'?BR4!*JhXG0W_=57U19Ga\bV9J23@"9&a9=9FTEk(8IF4Zfq+R<mq9=>+8GF=PP@r2JOf/'R`6Rp.qJlWEa0"Ca@L:lWU$>_>Ms;[,%B`X#H7eSi"];$-QKX<l+rm4E=ai=RJV=\/DX-oal^"YjbJ)gPFjlKkpue,O)UG'qmduW<%]":488aK,/7>.9aAj5K\3nHpSD-<GpHD;_L/RrQVd(H8"R<_:X^:-No(k+7D>G_#i=s4TVM<Gt\3)O.@XVI^qA*W^6;a=?[\#Ijgg7@Q"eDK:fR]<il306,oF/W[9LN:k)3gLfHjARf*JEJpT$~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 9
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000073 00000 n
|
||||||
|
0000000114 00000 n
|
||||||
|
0000000221 00000 n
|
||||||
|
0000000333 00000 n
|
||||||
|
0000000536 00000 n
|
||||||
|
0000000604 00000 n
|
||||||
|
0000000924 00000 n
|
||||||
|
0000000983 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<ea57d8511a72770d9c6e1dd29826f00c><ea57d8511a72770d9c6e1dd29826f00c>]
|
||||||
|
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||||
|
|
||||||
|
/Info 6 0 R
|
||||||
|
/Root 5 0 R
|
||||||
|
/Size 9
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
2895
|
||||||
|
%%EOF
|
||||||
Reference in New Issue
Block a user