feat(dashboard): add logs page, pagination, quick mapping modal, price pre-validation

- Add /logs page with per-order sync run details, filters (Toate/Importate/Fara Mapare/Erori)
- Add price pre-validation (validate_prices + ensure_prices) to prevent ORA-20000 on direct articles
- Add find_new_orders() to detect orders not yet in Oracle COMENZI
- Extend missing_skus table with order context (order_count, order_numbers, customers)
- Add server-side pagination on /api/validate/missing-skus and /missing-skus page
- Replace confusing "Skip"/"Err" with "Fara Mapare"/"Erori" terminology
- Add inline mapping modal on dashboard (replaces navigation to /mappings)
- Add 2-row stat cards: orders (Comenzi Noi/Ready/Importate/Fara Mapare/Erori) + articles
- Add ID_POL/ID_GESTIUNE/ID_SECTIE to config.py and .env
- Update .gitignore (venv, *.db, api/api/, logs/)
- 33/33 unit tests pass, E2E verified with Playwright

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 16:59:08 +02:00
parent 06daf24073
commit 97699fa0e5
17 changed files with 1050 additions and 93 deletions

101
api/app/templates/logs.html Normal file
View File

@@ -0,0 +1,101 @@
{% extends "base.html" %}
{% block title %}Jurnale Import - GoMag Import{% endblock %}
{% block nav_logs %}active{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="mb-0">Jurnale Import</h4>
<div class="d-flex align-items-center gap-2">
<select class="form-select form-select-sm" id="runSelector" style="min-width: 320px;">
<option value="">-- Selecteaza un sync run --</option>
</select>
<button class="btn btn-sm btn-outline-secondary" onclick="loadRuns()" title="Reincarca lista">
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
</div>
<!-- Filter buttons -->
<div class="mb-3" id="filterRow" style="display:none;">
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-secondary active" data-filter="all">
<i class="bi bi-list-ul"></i> Toate
</button>
<button type="button" class="btn btn-outline-success" data-filter="IMPORTED">
<i class="bi bi-check-circle"></i> Importate
</button>
<button type="button" class="btn btn-outline-warning" data-filter="SKIPPED">
<i class="bi bi-skip-forward"></i> Fara Mapare
</button>
<button type="button" class="btn btn-outline-danger" data-filter="ERROR">
<i class="bi bi-x-circle"></i> Erori
</button>
</div>
<small class="text-muted ms-3" id="filterCount"></small>
</div>
<!-- Run summary bar -->
<div class="row g-3 mb-3" id="runSummary" style="display:none;">
<div class="col-auto">
<div class="card stat-card px-3 py-2">
<div class="stat-value text-primary" id="sum-total" style="font-size:1.25rem;">-</div>
<div class="stat-label">Total</div>
</div>
</div>
<div class="col-auto">
<div class="card stat-card px-3 py-2">
<div class="stat-value text-success" id="sum-imported" style="font-size:1.25rem;">-</div>
<div class="stat-label">Importate</div>
</div>
</div>
<div class="col-auto">
<div class="card stat-card px-3 py-2">
<div class="stat-value text-warning" id="sum-skipped" style="font-size:1.25rem;">-</div>
<div class="stat-label">Omise</div>
</div>
</div>
<div class="col-auto">
<div class="card stat-card px-3 py-2">
<div class="stat-value text-danger" id="sum-errors" style="font-size:1.25rem;">-</div>
<div class="stat-label">Erori</div>
</div>
</div>
<div class="col-auto">
<div class="card stat-card px-3 py-2">
<div class="stat-value text-secondary" id="sum-duration" style="font-size:1.25rem;">-</div>
<div class="stat-label">Durata</div>
</div>
</div>
</div>
<!-- Orders table -->
<div class="card">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0" id="logsTable">
<thead>
<tr>
<th style="width:140px;">Nr. Comanda</th>
<th>Client</th>
<th style="width:100px;" class="text-center">Nr. Articole</th>
<th style="width:120px;">Status</th>
<th>Eroare / Detalii</th>
</tr>
</thead>
<tbody id="logsBody">
<tr id="emptyState">
<td colspan="5" class="text-center text-muted py-5">
<i class="bi bi-journal-text fs-2 d-block mb-2 text-muted opacity-50"></i>
Selecteaza un sync run din lista de sus
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="/static/js/logs.js"></script>
{% endblock %}