feat(sqlite): refactor orders schema + dashboard period filter

Replace import_orders (insert-per-run) with orders table (one row per
order, upsert on conflict). Eliminates dedup CTE on every dashboard
query and prevents unbounded row growth at 4-500 orders/sync.

Key changes:
- orders table: PK order_number, upsert via ON CONFLICT DO UPDATE;
  COALESCE preserves id_comanda once set; times_skipped auto-increments
- sync_run_orders: lightweight junction (sync_run_id, order_number)
  replaces sync_run_id column on orders
- order_items: PK changed to (order_number, sku), INSERT OR IGNORE
- Auto-migration in init_sqlite(): import_orders → orders on first boot,
  old table renamed to import_orders_bak
- /api/dashboard/orders: period_days param (3/7/30/0=all, default 7)
- Dashboard: period selector buttons in orders card header
- start.sh: stop existing process on port 5003 before restart;
  remove --reload (broken on WSL2 /mnt/e/)
- Add invoice_service, E2E Playwright tests, Oracle package updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 16:18:57 +02:00
parent 650e98539e
commit 82196b9dc0
32 changed files with 4164 additions and 1192 deletions

View File

@@ -111,25 +111,6 @@ body {
.badge-pending { background-color: #94a3b8; }
.badge-ready { background-color: #3b82f6; }
/* Stat cards */
.stat-card {
text-align: center;
padding: 1rem;
}
.stat-card .stat-value {
font-size: 1.75rem;
font-weight: 700;
line-height: 1.2;
}
.stat-card .stat-label {
font-size: 0.8rem;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Tables */
.table {
font-size: 0.875rem;
@@ -213,65 +194,20 @@ body {
justify-content: center;
}
/* Live Feed */
.live-feed {
max-height: 300px;
overflow-y: auto;
/* Log viewer */
.log-viewer {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.8125rem;
scroll-behavior: smooth;
}
.feed-entry {
padding: 0.35rem 0.75rem;
border-bottom: 1px solid #f1f5f9;
display: flex;
align-items: baseline;
gap: 0.5rem;
}
.feed-entry:last-child {
border-bottom: none;
}
.feed-entry.phase {
background-color: #eff6ff;
color: #1e40af;
}
.feed-entry.error {
background-color: #fef2f2;
color: #991b1b;
}
.feed-entry.success {
color: #166534;
}
.feed-entry .feed-time {
color: #94a3b8;
white-space: nowrap;
min-width: 5rem;
}
.feed-entry .feed-icon {
min-width: 1.25rem;
text-align: center;
}
.feed-entry .feed-msg {
flex: 1;
word-break: break-word;
}
/* Live pulse animation */
.live-pulse {
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
line-height: 1.5;
max-height: 600px;
overflow-y: auto;
padding: 1rem;
margin: 0;
background-color: #1e293b;
color: #e2e8f0;
white-space: pre-wrap;
word-wrap: break-word;
border-radius: 0 0 0.5rem 0.5rem;
}
/* Clickable table rows */
@@ -282,3 +218,87 @@ body {
.table-hover tbody tr[data-href]:hover {
background-color: #e2e8f0;
}
/* Sortable table headers (R7) */
.sortable {
cursor: pointer;
user-select: none;
}
.sortable:hover {
background-color: #f1f5f9;
}
.sort-icon {
font-size: 0.75rem;
margin-left: 0.25rem;
color: #3b82f6;
}
/* SKU group visual grouping (R6) */
.sku-group-even {
/* default background */
}
.sku-group-odd {
background-color: #f8fafc;
}
/* Editable cells */
.editable {
cursor: pointer;
}
.editable:hover {
background-color: #e2e8f0;
}
/* Order detail modal items */
.modal-lg .table-sm td,
.modal-lg .table-sm th {
font-size: 0.8125rem;
padding: 0.35rem 0.5rem;
}
/* Filter button badges */
#orderFilterBtns .badge {
font-size: 0.7rem;
}
/* Modal stacking for quickMap over orderDetail */
#quickMapModal {
z-index: 1060;
}
#quickMapModal + .modal-backdrop,
.modal-backdrop ~ .modal-backdrop {
z-index: 1055;
}
/* Deleted mapping rows */
tr.mapping-deleted td {
text-decoration: line-through;
opacity: 0.5;
}
/* Map icon button (minimal, no border) */
.btn-map-icon {
color: #3b82f6;
padding: 0.1rem 0.25rem;
cursor: pointer;
font-size: 1rem;
text-decoration: none;
}
.btn-map-icon:hover {
color: #1d4ed8;
}
/* Last sync summary card columns */
.last-sync-col {
border-right: 1px solid #e2e8f0;
}
/* Dashboard filter badges */
#dashFilterBtns .badge {
font-size: 0.7rem;
}
/* Cursor pointer utility */
.cursor-pointer {
cursor: pointer;
}