Commit Graph

45 Commits

Author SHA1 Message Date
Claude Agent
89c3d1d07f feat(partner): detect and resync partner mismatches on already-imported orders
Detects PF↔PJ transitions and CUI changes after import; auto-resyncs
uninvoiced orders (max 5/cycle) and shows visual alert for invoiced ones.
- SQLite: partner_mismatch column + batch helpers
- sync_service: detection loop + _resync_partner_for_order
- dashboard: red dot + attention card indicator
- modal: alert with contextual message and resync button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:19:26 +00:00
Claude Agent
bf194eb088 fix(price): remove baseprice detection, use directional price match
baseprice > price was wrongly treated as "quantity discount" — it's just
GoMag's promotional price. Now: price_gomag <= pret_roa is always OK,
only flag when GoMag charges MORE than ROA. Reset cached price_match
at startup for re-evaluation. Fix dashboard dot color for mismatches.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-07 20:41:54 +00:00
Claude Agent
057e62fc04 feat(price): detect quantity discounts via baseprice, show Disc. badge
GoMag sends baseprice (catalog price) alongside price (discounted).
When baseprice > price, the item is volume-discounted — skip ROA
price comparison and show amber "Disc." badge instead of false
mismatch. Strikethrough baseprice in price column for transparency.

Pipeline: parse baseprice → store in SQLite → skip in validation →
pass flag to frontend → render badge (desktop + mobile pill badge
with aria-label, opacity 0.6 for dark mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 17:06:37 +00:00
Claude Agent
0f817b2130 fix(address): normalize SECTORUL + etaj in addr_match, fix Oracle duplicate addrs
- _addr_match / addrMatch: add SECTORUL\s*\d* branch to strip sector
  number; add (?:\b|(?=\d)) to catch glued keywords (sc1, ap94);
  include etaj field in rStreet concat
- database.py: replace duplicate addr_match impl with import from sync_service
- import_service.py: short-circuit billing addr Oracle call when
  billing == shipping (avoids duplicate address creation)
- PL/SQL: normalize MUNICIPIUL BUCURESTI → BUCURESTI SECTORUL X before
  TIER 1; resolve id_localitate before search; TIER 1 now matches on
  id_loc instead of text locality
- Add scripts/cleanup_duplicate_addresses.sql for manual prod cleanup
- Add 5 new tests: sectorul, keyword+digit gluing, etaj, short-circuit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:48:49 +00:00
Claude Agent
ecde7fe440 feat(address): ROA address cache refresh — 8-field format + manual refresh endpoint
Phase 5 address format upgrade (pre-existing working tree changes):
- import_service: extend vadrese_parteneri query to 8 fields (strada/numar/bloc/scara/apart/etaj/localitate/judet); strip trailing city name from address string passed to Oracle
- sync_service: extend _addr_match to compare bloc/scara/apart in addition to strada/numar
- 05_pack_import_parteneri.pck: updated PL/SQL package

New: address cache refresh mechanism:
- sqlite_service: add get_order_address_ids(), update_order_address_cache() (targeted 3-column update, no ANAF fields touched), get_orders_with_address_ids()
- sync.py: POST /api/orders/{order_number}/refresh-address endpoint (404/422/503/200); batch Oracle address refresh in refresh_invoices (single IN roundtrip, per-order mismatch recomputed)
- UI: refresh button (⟳) in ADRESE modal header (base.html); refreshOrderAddress() with loading state + toast (dashboard.js v43); window._detailOrderNumber global (shared.js v32)
- tests: TestRefreshOrderAddress — 4 tests (404, 422, 503, 200 with 8-field assert)

Oracle prod fix applied directly: ADRESE_PARTENERI id_adresa=4116 STRADA VASILE→VASILE GOLDIS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 12:35:18 +00:00
Claude Agent
51910148ef refactor(ui): remove redundant price badge from order detail modal
Header diff badges already show price mismatches, making the Status-line
badge duplicative.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-06 16:11:49 +00:00
Claude Agent
c8e3a4e8d1 refactor(ui): separate diff dots with distinct colors, align modal badges
Replace 2 combined dots with 4 individual dots per diff type:
- CUI/TVA (red), Denumire (orange), Adresa (blue), Pret (green)
- Remove redundant price column from dashboard table
- Add --compare design token (orange) for denomination mismatches
- Align modal badge colors with table dot colors (4 separate CSS classes)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-06 15:40:53 +00:00
Claude Agent
4bff1aada1 fix(anaf): deduplicate TVA/CUI badges, remove address from DIFFS filter
CUI adjustment (RO prefix change) already implies TVA mismatch, so
suppress redundant TVA badge when CUI badge is shown. Remove
address_mismatch from DIFFS pill count since it's not an ANAF difference.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-06 14:56:04 +00:00
Claude Agent
2b212b933e fix(anaf): show TVA badge only on GoMag vs ANAF mismatch
Previously the TVA badge/dot appeared whenever ANAF reported neplatitor.
Now it only appears when GoMag CUI prefix (RO=platitor) disagrees with
ANAF status — aligned across JS badges, red dots, SQL filter and count.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-06 14:49:30 +00:00
Claude Agent
31095c07f7 fix(address+ui): remove TIER 2 reuse, typed diff badges, false positive reduction
- Remove TIER 2 address lookup (county+city without street) from PL/SQL — creates
  new address when street differs instead of reusing wrong one
- Replace generic "N diferente" badge with typed micro-badges (CUI, Denumire, TVA,
  Adr. livr., Adr. fact., Preturi) with red/amber semantic colors
- Extend addrMatch() regex to strip full Romanian address words (STRADA, NUMAR, BLOC,
  COMUNA, SAT, MUNICIPIUL, etc.) — fixes "Strada X" vs "X" false positives
- Extend normalize_company_name() for II, PFA, INTREPRINDERE INDIVIDUALA legal forms
- Persist address_mismatch to SQLite so "Dif." filter includes address-only diffs
- Add red/amber indicator dots to desktop table and mobile list rows
- 12 unit tests for normalization and server-side address matching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:28:57 +00:00
Claude Agent
e75d40fcde fix(address+ui): parse embedded AP/SC/ET from street + show PF partner name
Address parser: extract APARTAMENT/SCARA/ETAJ embedded in street text
(previously only NR and BLOC were extracted). Two-tier matching:
separator-required for short prefixes (avoids "APATEULUI" false-positive)
and direct-digit fallback for "ap14", "sc1", "et2" patterns.

UI: show denumire_roa for PF orders too, not just PJ.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:07:57 +00:00
Claude Agent
e8c5398499 style(design): FINDING-003 — replace transition:all with explicit props
DESIGN.md motion rules: never use transition:all, list properties
explicitly. Changed preset-btn from transition:all to
background/color/border-color transitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:15:59 +00:00
Claude Agent
388bb8544a style(design): FINDING-002 — fix H5 heading size (20px → 16px)
H5 was using Bootstrap default (1.25rem = 20px), larger than the H4
page title (18px). This inverted the heading hierarchy. Set H5 to
16px/600 per DESIGN.md section title spec.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:15:14 +00:00
Claude Agent
a5548f9c14 style(design): FINDING-001 — table font-size 16px → 14px per DESIGN.md
DESIGN.md type scale specifies 14px body / 13px data for table cells.
The table was using 1rem (16px), which is Bootstrap's default. This
reduces data density on the most visible component (the order table).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:14:42 +00:00
Claude Agent
84c38e3641 style(ui): design polish + replace CUI badge with +RO/−RO
6 design review fixes: diff summary badge in modal header, PF indicator,
eFactura risk icon (octagon vs triangle for colorblind), aria labels,
extract .denom-mismatch CSS class, remove dead .addr-table CSS.

Replace vague "Corectat" badge with directional +RO (green, prefix added)
or −RO (orange, prefix removed). Kit items show "Kit" badge instead of
price match dot. Cache-bust shared.js v24, style.css v31.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:01:50 +00:00
Claude Agent
b6a265dee6 style(design): FINDING-003+004 — fix touch targets and page title size
- Preset buttons: add min-height 32px desktop, 44px mobile
- btn-sm: add min-height 44px on mobile
- Checkbox: increase min-size on mobile
- Mobile overrides placed AFTER base rules for correct cascade
- Page title h4: override Bootstrap default (24px/500) to match
  DESIGN.md spec (18px/600/Display)
- Cache-bust style.css v30

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:28:08 +00:00
Claude Agent
7079e7a66a chore: cache-bust style.css v28, dashboard.js v36
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:22:01 +00:00
Claude Agent
e8b42088e3 fix(anaf-dedup): fix ANAF parsing, facturare addr, compact modal layout
- Fix ANAF API: extract CUI from date_generale (not top-level), fix
  notFound casing (capital F)
- Fix missing facturare address when same ID as livrare (copy instead
  of skip)
- Replace ANAF cache pre-population stub with real logic (3-month CUIs)
- Restructure order detail modal: inline 2-col GOMAG|ROA layout with
  compact address lines replacing collapsed sections
- Fix addrMatch() to use field-level comparison with Romanian
  abbreviation stripping (STR, NR, BL, SC, AP, ET, ETAJ, APART)
- Add dashboard "Diferente" filter pill for ANAF-adjusted orders
- Update e2e test for new modal structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:07:37 +00:00
Claude Agent
2f593c30f6 feat(anaf-dedup): ANAF partner dedup + address fix + UI enrichment
Prevent partner duplicates via ANAF CUI verification and dual PL/SQL
search. Fix address matching with street-level comparison and diacritics
normalization. Show partner/address comparison in order detail modal.

- New anaf_service.py: batch ANAF API client with chunking, retry, cache
- PL/SQL: dual CUI search (bare/RO+bare/RO space+bare), 3-tier address
  search (street+city+id_loc → city+id_loc → create), strip_diacritics
  at storage for addresses and partner names
- SQLite: anaf_cache table, 12 new order columns for partner/address data
- import_service: cod_fiscal_override param, return partner/address from Oracle
- sync_service: ANAF batch integration, denomination mismatch detection,
  cache pre-population trigger
- Router: enriched order_detail with partner_info + addresses JSON
- UI: collapsible Detalii Partener + Adrese Comparativ sections in modal,
  auto-expand on mismatch, ANAF badges, mobile address cards
- Dashboard: address quality attention indicator
- New scan_duplicate_partners.py script for one-time duplicate audit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:36:52 +00:00
Claude Agent
b2745a9a64 fix(flow): replace duplicate period dropdown with preset buttons
Period selector had both preset buttons (3/7/30 zile) and a dropdown
with overlapping options. Per plan Commit 6, preset buttons are the
single control: Azi / 3 zile / 7 zile / 30 zile / Custom. Visible
on all screen sizes with horizontal scroll on mobile.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-27 13:54:04 +00:00
Claude Agent
efb055c2be fix(qa): ISSUE-002 — ROA prices not showing in order detail modal
The JS read pret_roa from order.price_check.items[idx] which doesn't
exist. The backend puts pret_roa and price_match directly on each item
in the items array. Fixed both desktop table and mobile view to read
from item.pret_roa and item.price_match instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:25:07 +00:00
Claude Agent
d3d1905b18 feat(simplify): simplified logs view
Default to showing problem orders (ERROR/SKIPPED) first. Imported
orders collapsed behind "X comenzi importate cu succes" toggle.
Reduces noise for operators scanning for issues.

Cache-bust: logs.js?v=14, style.css?v=23

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:42:29 +00:00
Claude Agent
b52313faf6 feat(flow): map SKU + auto-retry consolidated banner
After saving a SKU mapping, check for SKIPPED orders containing that
SKU and show a floating banner with count + "Importa" button. Batch
retries up to 20 orders and shows result feedback.

Backend:
- get_skipped_orders_with_sku() in sqlite_service.py
- GET /api/orders/by-sku/{sku}/pending endpoint
- POST /api/orders/batch-retry endpoint (max 20, sequential)

Frontend:
- Auto-retry banner after quickMap save with batch import button
- Success/error feedback, auto-dismiss after 15s

Cache-bust: shared.js?v=19

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:38:10 +00:00
Claude Agent
7a789b4fe7 feat(flow): retry failed orders
Add ability to re-import individual ERROR/SKIPPED orders directly from
the order detail modal. Downloads narrow date range from GoMag API,
finds the specific order, and re-runs import_single_order().

Backend:
- New retry_service.py with retry_single_order() — downloads order_date
  ±1 day from GoMag, finds order by number, imports via import_service
- Guard: blocks retry during active sync (_sync_lock check)
- POST /api/orders/{order_number}/retry endpoint

Frontend:
- "Reimporta" button in modal footer (visible only for ERROR/SKIPPED)
- Spinner during retry, success/error feedback with auto-refresh

Cache-bust: shared.js?v=18

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:34:51 +00:00
Claude Agent
1b2b1d8b24 feat(safety): invoice reconciliation on order detail
Add invoice total comparison in the order detail modal. When an order
has been invoiced, shows whether the invoice total matches the order
total — green badge if OK, red badge with difference amount if not.

Backend: compute reconciliation (difference, match) from existing
invoice.total_cu_tva vs order_total in order_detail endpoint.

Frontend: reconciliation badge below invoice info in modal, hidden
when no invoice exists.

Cache-bust: shared.js?v=17

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:30:21 +00:00
Claude Agent
a10a00aa4d feat(safety): needs attention card on dashboard
Add a "Needs Attention" card above the orders table that surfaces:
- Import errors count (click → ERROR filter)
- Unmapped SKUs count (click → Missing SKUs page)
- Uninvoiced orders >3 days (click → UNINVOICED filter)
Shows green "Totul in ordine" when all metrics are zero.

Backend: add uninvoiced_old count to get_orders() and unresolved_skus
from get_dashboard_stats() to dashboard/orders API response.

Cache-bust: style.css?v=21, dashboard.js?v=29

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:28:18 +00:00
Claude Agent
3bd0556f73 feat(safety): price comparison on order detail
Add ROA price comparison to order detail modal — operators can now see
if GoMag prices match Oracle before invoicing. Eliminates the #1 risk
of invoicing with wrong prices.

Backend:
- New get_prices_for_order() in validation_service.py — batch Oracle
  query with dual-policy routing (sales/production by cont 341/345),
  PRETURI_CU_TVA handling, kit total calculation
- Extend GET /api/sync/order/{orderNumber} with per-item pret_roa and
  order-level price_check summary
- GET /api/dashboard/orders returns price_match=null (lightweight)

Frontend:
- Modal: price check badge (green/red/grey), "Pret GoMag" + "Pret ROA"
  columns, match dot per row, mismatch rows highlighted
- Dashboard: price dot column (₽) in orders table
- Mobile: inline mismatch indicator

Cache-bust: shared.js?v=16, dashboard.js?v=28

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:25:02 +00:00
Claude Agent
f6b6b863bd fix(dark): mobile order values invisible — Bootstrap card color override
Bootstrap's .card sets color: var(--bs-body-color) which stays #212529 in
dark mode since we use data-theme="dark" not data-bs-theme. Added explicit
card dark override and color: var(--text-primary) on .flat-row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:14:44 +00:00
Claude Agent
aacca13b85 style(design): FINDING-001 — mobile segmented control uses amber accent
Mobile segmented filter buttons used Bootstrap btn-primary (blue) for
active state. Per DESIGN.md two-accent system, state indicators use
amber. Added .seg-active class with --accent color.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:52:15 +00:00
Claude Agent
a8292c2ef2 style(design): migrate to DESIGN.md system
Full visual migration: Space Grotesk + DM Sans + JetBrains Mono fonts,
warm amber two-accent system (amber=state, blue=action), dark mode with
CSS vars + localStorage + FOUC prevention, mobile bottom nav (5 tabs),
full-width tables, error/skipped dot glow, ~13 hardcoded hex replaced
with CSS vars in 4 JS files, 5 new E2E tests.

Files: style.css (full rewrite), base.html (fonts, theme script, dark
toggle, bottom nav), settings.html (dark toggle card), dashboard.js,
logs.js, mappings.js, settings.js (color vars), 5 templates (bnav
active blocks), test_design_system_e2e.py (NEW).

Cache-bust: style.css?v=18, shared.js?v=14, dashboard.js?v=27,
logs.js?v=13, mappings.js?v=12, settings.js?v=8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:36:07 +00:00
Claude Agent
c5757b8322 refactor(modal): extract order detail to shared.js
Move duplicated order detail modal logic from dashboard.js and logs.js
into a shared renderOrderDetailModal() function in shared.js. Move
modal HTML from dashboard.html and logs.html into base.html.

Shared functions: renderCodmatCell, orderStatusBadge, fmtCost, fmtNum,
computeDiscountSplit, renderReceipt. Both pages now call the shared
modal with page-specific quick map callbacks.

Net -152 lines. Logs page gains invoice info, TVA column, and receipt
footer that were previously dashboard-only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:19:42 +00:00
Claude Agent
f68adbb072 chore: bump CSS cache version to v=17 2026-03-19 23:29:25 +00:00
Claude Agent
eccd9dd753 style(design): FINDING-008 — add color-scheme: light declaration 2026-03-19 23:29:17 +00:00
Claude Agent
327f0e6ea2 refactor(ui): unify mapping form into single shared component
Extract the SKU mapping modal (HTML + JS) from dashboard, logs, and
missing_skus into a shared component in base.html + shared.js. All pages
now use the same compact layout with CODMAT/Cant. column headers.

- Fix missing_skus backdrop bug: event.stopPropagation() on icon click
  prevents double modal open from <a> + <tr> event bubbling
- Shrink mappings addModal from modal-lg to regular size with compact layout
- Remove ~500 lines of duplicated modal HTML and JS across 4 pages
- Each page keeps a thin wrapper (openDashQuickMap, openLogsQuickMap,
  openMapModal) that calls shared openQuickMap() with an onSave callback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:21:43 +00:00
Claude Agent
69a3088579 refactor(dashboard): move search box to filter bar after period dropdown
Search was hidden in card header — now inline with filters for better
discoverability. Compact refresh button to icon-only. On mobile, search
and period dropdown share the same row via flex.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 16:08:58 +00:00
Claude Agent
3d212979d9 refactor(dashboard): move search box from filter bar to card header
Reduces vertical space by eliminating the second row in the filter bar.
Search input is now next to the "Comenzi" title, hidden on mobile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 14:04:10 +00:00
Claude Agent
5e01fefd4c feat(sync): handle cancelled GoMag orders (status Anulata / statusId 7)
- Add web_status column to orders table (generic name for platform status)
- Filter cancelled orders during sync, record as CANCELLED in SQLite
- Soft-delete previously-imported cancelled orders in Oracle (if not invoiced)
- Add CANCELLED filter pill + badge in dashboard UI
- New soft_delete_order_in_roa() and mark_order_cancelled() functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:50:38 +00:00
Claude Agent
84b24b1434 feat(invoice+import): refresh facturi, detalii factura, fix duplicate CODMAT + rollback
- PL/SQL: handle duplicate CODMAT in nom_articole with MAX(id_articol)
- import_service: add explicit conn.rollback() on Oracle errors
- sync_service: auto-fix stale ERROR orders that exist in Oracle
- invoice_service: add data_act (invoice date) from vanzari table
- sync router: new POST /api/dashboard/refresh-invoices endpoint
- order detail: enrich with invoice data (serie, numar, data factura)
- dashboard: refresh invoices button (desktop + mobile icon)
- quick map modal: compact single-row layout, pre-populate existing mappings
- quick map: link on SKU column instead of CODMAT

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 17:30:23 +00:00
Claude Agent
49471e9f34 fix(js): patch fetch to prepend ROOT_PATH for IIS reverse proxy
All relative /api/... calls automatically get /gomag prefix via
global fetch wrapper in shared.js. ROOT_PATH injected from template.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 15:19:50 +00:00
Claude Agent
ced6c0a2d4 fix(templates): use root_path for static assets instead of url_for
url_for generates absolute URLs with internal host (localhost:5003)
which browsers block via ERR_BLOCKED_BY_ORB. Using root_path prefix
generates correct relative paths (/gomag/static/...).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 15:15:56 +00:00
Claude Agent
ee60a17f00 fix(templates): use url_for for static assets and root_path for nav links
Fixes 404 errors for CSS/JS when served behind IIS reverse proxy with
/gomag prefix. Replaces hardcoded /static/ paths with request.url_for()
and nav links with request.scope root_path prefix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 15:04:03 +00:00
Claude Agent
680f670037 feat(ui): mobile UI polish with segmented controls and responsive navbar
- Replace filter pills with btn-group segmented controls on mobile (all pages)
- Add renderMobileSegmented() shared utility with colored count badges
- Compact sync card and logs run selector on mobile
- Unified flat-row format: dot + date + name + count (0.875rem throughout)
- Responsive navbar with short labels on mobile (Acasa/Mapari/Lipsa/Jurnale)
- Vertical dots icon (bi-three-dots-vertical) without dropdown caret
- Shorter "Mapare" button text on mobile, Re-scan in context menu
- Top pagination on logs page, hide per-page selector on mobile
- Cache-bust static assets to v=5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:20:24 +00:00
650e98539e feat(sync): add SSE live feed, unified logs page, fix Oracle connection
- Add SSE event bus in sync_service (subscribe/unsubscribe/_emit)
- Add GET /api/sync/stream SSE endpoint for real-time sync progress
- Rewrite logs.html: unified runs table + live feed + summary + filters
- Rewrite logs.js: SSE EventSource client, run selection, pagination
- Dashboard: clickable runs navigate to /logs?run=, sync started banner
- Remove "Import Comenzi" nav item, delete sync_detail.html
- Add error_message column to sync_runs table with migration
- Fix: export TNS_ADMIN as OS env var so oracledb finds tnsnames.ora
- Fix: use get_oracle_connection() instead of direct pool.acquire()
- Fix: CRM_POLITICI_PRET_ART INSERT to match actual table schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:08:09 +02:00
97699fa0e5 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>
2026-03-11 16:59:08 +02:00
9c42187f02 feat: add FastAPI admin dashboard with sync orchestration and test suite
Replace Flask admin with FastAPI app (api/app/) featuring:
- Dashboard with stat cards, sync control, and history
- Mappings CRUD for ARTICOLE_TERTI with CSV import/export
- Article autocomplete from NOM_ARTICOLE
- SKU pre-validation before import
- Sync orchestration: read JSONs -> validate -> import -> log to SQLite
- APScheduler for periodic sync from UI
- File logging to logs/sync_comenzi_YYYYMMDD_HHMMSS.log
- Oracle pool None guard (503 vs 500 on unavailable)

Test suite:
- test_app_basic.py: 30 tests (imports + routes) without Oracle
- test_integration.py: 9 integration tests with Oracle

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:35:16 +02:00