Add import labels functionality to labels module
- Created import_labels.py with CSV and Excel file processing - Implemented validation for order rows and date format handling - Added import-labels route with preview and save functionality - Created import_labels.html template with new app UI styling - Added import card to labels module index - Added openpyxl to requirements.txt for Excel support
This commit is contained in:
236
app/templates/modules/labels/import_labels.html
Normal file
236
app/templates/modules/labels/import_labels.html
Normal file
@@ -0,0 +1,236 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Import Labels Data - Quality App v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="mb-2">
|
||||
<i class="fas fa-file-import"></i> Import Labels Data
|
||||
</h1>
|
||||
<p class="text-muted">Upload CSV or Excel files with order data for label printing</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Form Card -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
{% if show_preview %}
|
||||
<!-- Preview Mode -->
|
||||
<h5 class="card-title mb-3">
|
||||
Preview: <strong>{{ filename }}</strong>
|
||||
</h5>
|
||||
<p class="text-muted mb-3">
|
||||
Showing first 10 rows of {{ total_orders }} records. Review the data below and click "Import to Database" to confirm.
|
||||
</p>
|
||||
|
||||
<form method="POST" id="import-form">
|
||||
<input type="hidden" name="action" value="save">
|
||||
|
||||
<div class="d-flex gap-2 mb-4">
|
||||
<button type="submit" class="btn btn-success" id="save-btn">
|
||||
<i class="fas fa-check"></i> Import to Database
|
||||
</button>
|
||||
<a href="{{ url_for('labels.import_labels') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-times"></i> Cancel
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<!-- Upload Mode -->
|
||||
<h5 class="card-title mb-3">
|
||||
<i class="fas fa-upload"></i> Upload File
|
||||
</h5>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data" id="upload-form">
|
||||
<input type="hidden" name="action" value="preview">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Choose CSV or Excel file:</label>
|
||||
<input class="form-control form-control-lg" type="file" id="file" name="file"
|
||||
accept=".csv,.xlsx,.xls" required>
|
||||
<small class="text-muted d-block mt-2">
|
||||
Supported formats: CSV (.csv), Excel (.xlsx, .xls)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-lg">
|
||||
<i class="fas fa-upload"></i> Upload & Preview
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File Format Information -->
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body" style="background: var(--bg-secondary); border-left: 4px solid var(--accent-color);">
|
||||
<h6 class="card-title mb-3">
|
||||
<i class="fas fa-info-circle"></i> Expected File Format
|
||||
</h6>
|
||||
<p class="mb-2">
|
||||
Your file should contain columns for order data. Required columns:
|
||||
</p>
|
||||
<ul class="mb-0" style="font-size: 0.9rem;">
|
||||
<li><strong>Comanda Productie</strong> - Production order number</li>
|
||||
<li><strong>Descr. Com. Prod</strong> - Order description</li>
|
||||
<li><strong>Cantitate</strong> - Quantity</li>
|
||||
</ul>
|
||||
<p class="mt-3 mb-0" style="font-size: 0.9rem; color: var(--text-secondary);">
|
||||
Optional columns: Cod Articol, Data Livrare, Dimensiune, Com. Achiz. Client, Nr. Linie Com. Client,
|
||||
Customer Name, Customer Article Number, Open for Order, Line Number
|
||||
</p>
|
||||
<p class="mt-2 mb-0" style="font-size: 0.85rem; color: var(--text-secondary);">
|
||||
Column names are case-insensitive and can have variations (spaces and dots are ignored).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Reference Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-3">
|
||||
<i class="fas fa-book"></i> Column Reference
|
||||
</h6>
|
||||
<table class="table table-sm table-borderless" style="font-size: 0.85rem;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Comanda Productie</strong></td>
|
||||
<td><span class="badge bg-danger">Required</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Descr. Com. Prod</strong></td>
|
||||
<td><span class="badge bg-danger">Required</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Cantitate</strong></td>
|
||||
<td><span class="badge bg-danger">Required</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Cod Articol</strong></td>
|
||||
<td><span class="badge bg-secondary">Optional</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Data Livrare</strong></td>
|
||||
<td><span class="badge bg-secondary">Optional</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Dimensiune</strong></td>
|
||||
<td><span class="badge bg-secondary">Optional</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Customer Name</strong></td>
|
||||
<td><span class="badge bg-secondary">Optional</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-3">
|
||||
<i class="fas fa-lightbulb"></i> Tips
|
||||
</h6>
|
||||
<ul class="small mb-0" style="font-size: 0.85rem; padding-left: 1.5rem;">
|
||||
<li>Make sure your file uses UTF-8 encoding</li>
|
||||
<li>Check that quantities are positive numbers</li>
|
||||
<li>Dates should be in YYYY-MM-DD or DD/MM/YYYY format</li>
|
||||
<li>Review the preview carefully before importing</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Preview Table -->
|
||||
{% if show_preview %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-3">
|
||||
Data Preview (First 10 rows of {{ total_orders }})
|
||||
</h5>
|
||||
|
||||
<div class="table-responsive" style="max-height: 500px; overflow-y: auto;">
|
||||
<table class="table table-sm table-hover table-striped">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
{% for header in headers %}
|
||||
<th style="font-size: 0.85rem; white-space: nowrap;">{{ header }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if preview_data %}
|
||||
{% for row in preview_data %}
|
||||
<tr>
|
||||
{% for header in headers %}
|
||||
<td style="font-size: 0.85rem;">{{ row.get(header, '-') }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="{{ headers|length }}" class="text-center text-muted py-4">
|
||||
No data to preview
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--bg-secondary: {% if request.cookies.get('theme') == 'dark' %}#1e293b{% else %}#f8f9fa{% endif %};
|
||||
--accent-color: {% if request.cookies.get('theme') == 'dark' %}#3b82f6{% else %}#007bff{% endif %};
|
||||
--text-secondary: {% if request.cookies.get('theme') == 'dark' %}#94a3b8{% else %}#6c757d{% endif %};
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: var(--accent-color);
|
||||
box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Handle form submission with loading state
|
||||
document.getElementById('import-form')?.addEventListener('submit', function(e) {
|
||||
const btn = document.getElementById('save-btn');
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Importing...';
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('upload-form')?.addEventListener('submit', function(e) {
|
||||
const fileInput = document.getElementById('file');
|
||||
if (!fileInput.files.length) {
|
||||
e.preventDefault();
|
||||
alert('Please select a file');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -30,6 +30,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Import Labels Card -->
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="card shadow-sm h-100 module-launcher">
|
||||
<div class="card-body text-center">
|
||||
<div class="launcher-icon mb-3">
|
||||
<i class="fas fa-file-import text-info"></i>
|
||||
</div>
|
||||
<h5 class="card-title">Import Labels Data</h5>
|
||||
<p class="card-text text-muted">Upload CSV or Excel files with order data for label printing.</p>
|
||||
<a href="{{ url_for('labels.import_labels') }}" class="btn btn-info btn-sm">
|
||||
<i class="fas fa-arrow-right"></i> Import Data
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Print Lost Labels Card -->
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="card shadow-sm h-100 module-launcher">
|
||||
|
||||
Reference in New Issue
Block a user