Files
quality_recticel/py_app/app/templates/upload_orders.html
Quality System Admin d264bcdca9 feat: Major system improvements and production deployment
 New Features:
- Added view_orders route with proper table display
- Implemented CSV upload with preview workflow and date parsing
- Added production WSGI server configuration with Gunicorn
- Created comprehensive production management scripts

🔧 Bug Fixes:
- Fixed upload_data route column mapping for actual CSV structure
- Resolved print module database queries and template rendering
- Fixed view orders navigation routing (was pointing to JSON API)
- Corrected barcode display width constraints in print module
- Added proper date format parsing for MySQL compatibility

🎨 UI/UX Improvements:
- Updated view_orders template with theme-compliant styling
- Hidden barcode text in print module preview for cleaner display
- Enhanced CSV upload with two-step preview-then-save workflow
- Improved error handling and debugging throughout upload process

🚀 Production Infrastructure:
- Added Gunicorn WSGI server with proper configuration
- Created systemd service for production deployment
- Implemented production management scripts (start/stop/status)
- Added comprehensive logging setup
- Updated requirements.txt with production dependencies

📊 Database & Data:
- Enhanced order_for_labels table compatibility
- Fixed column mappings for real CSV data structure
- Added proper date parsing and validation
- Improved error handling with detailed debugging

🔧 Technical Debt:
- Reorganized database setup documentation
- Added proper error handling throughout upload workflow
- Enhanced debugging capabilities for troubleshooting
- Improved code organization and documentation
2025-10-11 23:31:32 +03:00

282 lines
11 KiB
HTML
Executable File

{% extends "base.html" %}
{% block title %}Upload Order Data for Labels{% endblock %}
{% block head %}
<style>
/* VIEW ORDERS TABLE - Specific styling (copied from view_orders.html) */
table.view-orders-table.scan-table {
margin: 0 !important;
border-spacing: 0 !important;
border-collapse: collapse !important;
width: 100% !important;
table-layout: fixed !important;
font-size: 11px !important;
}
table.view-orders-table.scan-table thead th {
height: 85px !important;
min-height: 85px !important;
max-height: 85px !important;
vertical-align: middle !important;
text-align: center !important;
white-space: normal !important;
word-wrap: break-word !important;
line-height: 1.3 !important;
padding: 6px 3px !important;
font-size: 11px !important;
background-color: #e9ecef !important;
font-weight: bold !important;
text-transform: none !important;
letter-spacing: 0 !important;
overflow: visible !important;
box-sizing: border-box !important;
border: 1px solid #ddd !important;
text-overflow: clip !important;
position: relative !important;
}
table.view-orders-table.scan-table tbody td {
padding: 4px 2px !important;
font-size: 10px !important;
text-align: center !important;
border: 1px solid #ddd !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
vertical-align: middle !important;
}
table.view-orders-table.scan-table td:nth-child(1) { width: 50px !important; }
table.view-orders-table.scan-table td:nth-child(2) { width: 80px !important; }
table.view-orders-table.scan-table td:nth-child(3) { width: 80px !important; }
table.view-orders-table.scan-table td:nth-child(4) { width: 150px !important; }
table.view-orders-table.scan-table td:nth-child(5) { width: 70px !important; }
table.view-orders-table.scan-table td:nth-child(6) { width: 80px !important; }
table.view-orders-table.scan-table td:nth-child(7) { width: 75px !important; }
table.view-orders-table.scan-table td:nth-child(8) { width: 90px !important; }
table.view-orders-table.scan-table td:nth-child(9) { width: 70px !important; }
table.view-orders-table.scan-table td:nth-child(10) { width: 100px !important; }
table.view-orders-table.scan-table td:nth-child(11) { width: 90px !important; }
table.view-orders-table.scan-table td:nth-child(12) { width: 70px !important; }
table.view-orders-table.scan-table td:nth-child(13) { width: 50px !important; }
table.view-orders-table.scan-table td:nth-child(14) { width: 70px !important; }
table.view-orders-table.scan-table td:nth-child(15) { width: 100px !important; }
table.view-orders-table.scan-table tbody tr:hover td {
background-color: #f8f9fa !important;
}
.report-table-card h3 {
margin: 0 0 15px 0 !important;
padding: 0 !important;
}
.report-table-card {
padding: 15px !important;
}
</style>
{% endblock %}
{% block content %}
<div class="scan-container">
<!-- Upload Orders Card (first, fixed position) -->
<div class="card scan-form-card" style="margin-bottom: 24px;">
{% if leftover_description %}
<h3>Left over orders</h3>
<div style="color: #dc3545; font-weight: bold; margin-bottom: 10px;">{{ leftover_description }}</div>
{% else %}
<h3>Upload Order Data for Labels</h3>
{% endif %}
<form method="POST" enctype="multipart/form-data" class="form-centered" id="csv-upload-form">
{% if show_preview %}
<!-- Show preview controls -->
<input type="hidden" name="action" value="save">
<label style="font-weight: bold;">Preview of: {{ filename }}</label><br>
<p style="color: #666; font-size: 14px; margin: 10px 0;">
Showing first 10 rows. Review the data below and click "Save to Database" to confirm.
</p>
<button type="submit" class="btn" style="background-color: #28a745;">Save to Database</button>
<a href="{{ url_for('main.upload_data') }}" class="btn" style="background-color: #6c757d; margin-left: 10px;">Cancel</a>
{% else %}
<!-- Show file upload -->
<input type="hidden" name="action" value="preview">
<label for="file">Choose CSV file:</label>
<input type="file" name="file" accept=".csv" required><br>
<button type="submit" class="btn">Upload & Preview</button>
<!-- CSV Format Information -->
<div style="margin-top: 20px; padding: 15px; background-color: var(--app-card-bg, #2a3441); border-radius: 5px; border-left: 4px solid var(--app-accent-color, #007bff); color: var(--app-text-color, #ffffff);">
<h5 style="margin-top: 0; color: var(--app-accent-color, #007bff);">Expected CSV Format</h5>
<p style="margin-bottom: 10px; color: var(--app-text-color, #ffffff);">Your CSV file should contain columns such as:</p>
<ul style="margin-bottom: 10px; color: var(--app-text-color, #ffffff);">
<li><strong>order_number</strong> - The order/production number</li>
<li><strong>quantity</strong> - Number of items</li>
<li><strong>warehouse_location</strong> - Storage location</li>
</ul>
<p style="color: var(--app-secondary-text, #b8c5d1); font-size: 14px; margin-bottom: 0;">
Column names are case-insensitive and can have variations like "Order Number", "Quantity", "Location", etc.
</p>
</div>
{% endif %}
</form>
<!-- Popup Modal -->
<div id="popup-modal" class="popup" style="display:none; position:fixed; top:0; left:0; width:100vw; height:100vh; background:var(--app-overlay-bg, rgba(30,41,59,0.85)); z-index:9999; align-items:center; justify-content:center;">
<div class="popup-content" style="margin:auto; padding:32px; border-radius:8px; box-shadow:0 2px 8px #333; min-width:320px; max-width:400px; text-align:center;">
<h3 style="color:var(--app-label-text);">Saving orders to database...</h3>
</div>
</div>
<script>
function showPopupAndSubmit() {
document.getElementById('popup-modal').style.display = 'flex';
// Submit the form after showing popup
setTimeout(function() {
var form = document.getElementById('csv-upload-form');
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'save_to_database';
input.value = '1';
form.appendChild(input);
form.submit();
}, 500);
}
window.onload = function() {
if (window.location.hash === '#saved') {
document.getElementById('popup-modal').style.display = 'none';
}
}
</script>
</div>
<!-- Preview Table Card (expandable height, scrollable) -->
<div class="card scan-table-card" style="margin-bottom: 24px; max-height: 480px; overflow-y: auto;">
{% if show_preview %}
<h3>CSV Data Preview - {{ filename }}</h3>
<table class="scan-table">
<thead>
<tr>
{% for header in headers %}
<th>{{ header }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% if preview_data %}
{% for row in preview_data %}
<tr>
{% for header in headers %}
<td>{{ row.get(header, '') }}</td>
{% endfor %}
</tr>
{% endfor %}
{% else %}
<tr><td colspan="{{ headers|length }}" style="text-align:center;">No data to preview</td></tr>
{% endif %}
</tbody>
</table>
{% else %}
<h3>CSV Data Preview</h3>
<table class="scan-table">
<thead>
<tr>
<th>Upload a CSV file to see preview</th>
</tr>
</thead>
<tbody>
<tr><td style="text-align:center; padding: 40px;">No CSV file uploaded yet. Use the form above to upload and preview your data.</td></tr>
</tbody>
</table>
{% endif %}
</div>
</div>
<style>
/* THESE STYLES ONLY APPLY TO OTHER TABLES, NOT UPLOAD ORDERS TABLE */
.scan-table:not(.upload-orders-table) {
font-size: 11px !important;
line-height: 1.2;
min-width: 800px;
width: 100%;
table-layout: fixed;
}
.scan-table:not(.upload-orders-table) th,
.scan-table:not(.upload-orders-table) td {
padding: 6px 4px !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scan-table:not(.upload-orders-table) th {
font-size: 10px !important;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.3px;
}
/* Column widths for NON-upload-orders tables only */
.scan-table:not(.upload-orders-table) th:nth-child(1),
.scan-table:not(.upload-orders-table) td:nth-child(1) {
max-width: 50px;
min-width: 30px;
}
.scan-table:not(.upload-orders-table) th:nth-child(2),
.scan-table:not(.upload-orders-table) td:nth-child(2) {
max-width: 70px;
min-width: 70px;
}
.scan-table:not(.upload-orders-table) th:nth-child(3),
.scan-table:not(.upload-orders-table) td:nth-child(3) {
max-width: 120px;
min-width: 120px;
}
.scan-table:not(.upload-orders-table) th:nth-child(4),
.scan-table:not(.upload-orders-table) td:nth-child(4) {
max-width: 60px;
min-width: 60px;
text-align: right;
}
.scan-table:not(.upload-orders-table) th:nth-child(5),
.scan-table:not(.upload-orders-table) td:nth-child(5) {
max-width: 90px;
min-width: 90px;
}
/* Ensure table container fits */
.scan-table-card {
overflow-x: auto;
}
/* Hover effects for NON-upload-orders tables */
.scan-table:not(.upload-orders-table) tbody tr:hover td {
background-color: #f8f9fa !important;
position: relative;
}
.scan-table:not(.upload-orders-table) td {
cursor: help;
}
.scan-table:not(.upload-orders-table) td:hover {
overflow: visible;
white-space: normal;
word-wrap: break-word;
z-index: 10;
position: relative;
background-color: #fff3cd !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
</style>
<style>
/* Special style for leftover orders table to match preview table height and appearance */
.leftover-table-card {
max-height: 480px !important;
overflow-y: auto !important;
border: 2px solid #dc3545 !important;
background: #fff6f6 !important;
}
.leftover-table thead th, .leftover-table td {
background: #fff6f6 !important;
}
</style>
{% endblock %}