Extract shared setupAutocomplete() into shared.js so all three autocomplete
instances (mappings modal, inline add, quick-map modal) get keyboard nav
(ArrowDown/Up/Enter/Escape), scroll-safe blur handling, and capture-phase
keydown to prevent browser interception. Remove old onmousedown inline
handlers, use data-codmat/data-label attributes instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Kebab dropdown delete/resync used inlineConfirmAction which breaks inside
Bootstrap dropdowns (dropdown closes on click, hiding confirm state).
Replaced with confirm() dialog + direct async action with row feedback.
Detail modal resync/delete/retry now trigger onStatusChange callback to
refresh the orders table, so status dots update without page reload.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Bug 1: hover actions covered total column; replaced with kebab dropdown in dedicated 44px column
- Bug 2: resync/delete buttons kept stale state across modal opens; reset in modal init block
- Bug 3: delete success button was green (btn-success); changed to red (btn-danger)
- Dropdown styled per DESIGN.md: warm shadow, 8px radius, dark mode tokens
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resync soft-deletes from Oracle then re-imports from GoMag with fresh
article data. Delete soft-deletes and marks DELETED_IN_ROA. Both have
invoice safety gates (refuse if invoiced or Oracle unavailable).
UI: split modal footer (Delete left, Resync+Close right), inline
confirm pattern (no native confirm()), dashboard row hover action
icons, disabled+tooltip for invoiced orders. 8 unit tests for safety
gates and happy paths.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes false negatives where city spellings differ slightly (e.g.
"Sfântu Ilie" vs "SFINTU ILIE") or ROA stores "BUCURESTI SECTORUL 1"
while GoMag sends "Municipiul București". Both backend (_addr_match)
and frontend (addrMatch) now use identical SOUNDEX logic mirroring
Oracle's implementation.
Also fixes field order: etaj before apart in r_street concatenation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Oracle parser failed to extract sc/ap/et when GoMag addresses had no
commas. Added REGEXP_REPLACE to insert commas before address keywords
in v_strada before the comma-split, ensuring the token parser always
fires. Also added 5 Oracle integration tests calling
parseaza_adresa_semicolon directly, and improved diacritics handling
in addr_match (Python + JS).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GoMag vs ROA price comparison generated too many false positives
(kits, volume discounts, special prices). Removes comparison columns,
dots, badges, catalog sync endpoints, and ~950 lines of dead code.
Keeps WRITE path (sync_prices_from_order) for kit pricing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- diff dot for partner_mismatch uses --warning (orange) instead of --error
to distinguish from price mismatch (also red)
- modal ROA column shows "necunoscut - se va actualiza la urmatorul sync"
when denumire_roa is null but partner_mismatch=1 (orders imported before
the column existed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
- 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>
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>
When no sync run is selected, the logs page was completely blank
below the controls. Added a guidance message with icon explaining
what to do. Hides automatically when a run is selected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
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>
- 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>
The billing/shipping diff triangle used inline style="color:#6b7280"
which doesn't adapt to dark mode. Now uses a CSS class with
var(--text-muted) for proper theming.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Colored left-border on cards is AI Slop blacklist item #8.
Use warning-light background tint instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
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>
updateSchedulerInterval() only saved when enabled=true, so changing
the dropdown with auto off was lost on refresh. Now always persists.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: GET /api/sync/schedule returned interval_minutes=null when
scheduler was stopped, causing dropdown to stay on first HTML option
(1 min). Setting .value programmatically could trigger onchange, sending
a second PUT with interval=1 right after the user's intended interval.
- GET schedule falls back to DB/default (10 min) when scheduler is off
- Add _schedulerLoading flag to block onchange during loadSchedulerStatus
- Default interval 10 min everywhere (was 5 in backend)
- Cache bust dashboard.js v=33
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add price_match column to SQLite, cached on order detail view
- Background backfill on startup checks all unchecked imported orders
- Extract _enrich_items_with_codmat() helper to deduplicate SKU enrichment
- Attention card now shows same nefacturate count as filter pill
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
SKUs with forward slashes (e.g. 0V2071/250159/250158) caused a 404
on /api/mappings/{sku}/prices because path separators in the SKU
were interpreted as URL path segments. Changed to query parameter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show a welcome card on the dashboard when no sync runs exist yet.
Guides new users: 1. Check Settings → 2. Start Sync → 3. Map SKUs.
Card auto-hides after first successful sync.
Cache-bust: dashboard.js?v=31, style.css?v=24
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Change default period from 7 to 3 days. Add quick-select preset
buttons (3 zile / 7 zile / 30 zile) that sync with the dropdown.
Reduces noise for daily operators who only need recent orders.
Cache-bust: style.css?v=22, dashboard.js?v=30
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
Bootstrap --bs-table-bg defaults to white, not overridden in dark mode.
Added --bs-table-bg: var(--surface) and explicit td background for odd
rows. Zebra now alternates #1E1E1E / #2A2A2A in dark mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DESIGN.md specifies box-shadow glow for SKIPPED status dots:
0 0 6px 2px rgba(202,138,4,0.3). Was missing from .dot-yellow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>