brand-catalog.js was missing Authorization header on fetch calls,
causing 401 Unauthorized errors. Now reads pos_token from localStorage
and includes Bearer token in every request. Also handles 401 responses
by redirecting to /pos/login. Bump JS cache bust to v=2.
Backend:
- Add 'search' param to /brand-parts endpoint (filters oem_part_number and name via ILIKE)
- Keep count query accurate with search filter
Frontend (brand-catalog.js):
- Brand search input: filters 619 brands locally while typing
- Parts pagination: Previous/Next buttons with page counter (50 per page)
- Parts search within category: search input + Enter key triggers backend search
- Visual polish: stock badges, empty-state messages, responsive layout
- Loading states and breadcrumbs improved
- Add QWEN (qwen3.6) as primary AI backend with short system prompt
- Hermes remains as fallback with 45s timeout
- Increase QWEN timeout to 35s, max_tokens to 4000
- Add conversation history loading from whatsapp_messages (last 4 msgs)
- Persist detected vehicle in whatsapp_sessions table
- Add 'limpiar chat' / 'nuevo chat' / 'reset' commands to clear history
- Fix CSS conflict: rename whatsapp chat-panel classes to wa-chat-panel
- Fix JS ID conflicts with chat.js widget (waChatPanel, waChatMessages, etc.)
- Improve no-stock response: conversational with alternatives
- Split search_query by | for multi-part lookups
- Add DEMO_PROMPTS.md and DEMO_PROMPTS_V2.md
- Added save_qwen_fitment() in inventory_vehicle_compat.py to centralize
inserting QWEN results into inventory_vehicle_compat
- Simplified inventory_bp.py create_item() and auto_match_item_vehicles()
to use the centralized function, removing duplicated INSERT logic
inventory_vehicle_compat.get_compatibility was trying to JOIN tenant
inventory_vehicle_compat with master tables (model_year_engine, brands,
models, years, engines) on a single tenant connection. Those tables only
exist in the master DB, causing the query to fail silently.
Fix: split into two queries:
1. Fetch MYE IDs from tenant's inventory_vehicle_compat
2. Resolve vehicle details from master DB via ANY(%s)
3. Merge results
Also fixes the argument mismatch: inventory_bp passed (tenant, master,
item_id) but the function only accepted 2 args.
Replaced simple exact-match with 8-layer fallback strategy:
1. Exact normalized part number (parts.oem_part_number)
2. Exact normalized aftermarket part number
3. Exact normalized cross-reference number
4. Partial ILIKE match on OEM numbers
5. Partial ILIKE match on aftermarket numbers
6. Partial ILIKE match on cross-reference numbers
7. Separator-stripped fallback (KYB-343412 → KYB343412)
8. Name-based search on parts.name_part / parts.name_es
and aftermarket_parts.name_aftermarket_parts when no part_number hit
Brand-aware filtering: when brand hint is provided and not 'GENERAL',
only returns MYEs for vehicles of that brand.
Limits: max 20 part IDs per layer, max 200 MYEs total.
Test: BPR5ES + TOYOTA → matched True, 2 parts, 200 MYEs inserted.
- tenant_db.py: add rollback() before returning conn to pool to prevent
'idle in transaction (aborted)' state that exhausts the pool
- tenant_db.py: increase pool maxconn from 10 to 20 for better concurrency
- inventory_vehicle_compat.py: fix column name cross_ref_number ->
cross_reference_number to match actual schema
Nginx auto-serves .min.js when .js is requested with try_files.
The browser had the old file cached with 6M expiry. Adding ?v=2
forces clients to fetch the new version with autoMatchCompat exposed.
- catalog_bp.py: /search and /part/<id> no longer blocked by CATALOG_OEM_ENABLED
These endpoints query the master parts DB and enrich with local stock;
they should work in both local and OEM modes.
- inventory.js: expose autoMatchCompat and removeCompat to window for
onclick handlers in dynamically generated HTML.
- Regenerated inventory.min.js
- Added all brands with vehicles >= 1980 relevant to Mexico-USA-Canada
- Covers: American, Japanese, Korean, German, UK, Italian, French,
Swedish, Spanish, Chinese (with MX presence), Indian, and commercial
- All 96 brands verified against master DB with year >= 1980
- Fixed column names: brands.name_brand, models.name_model, engines.name_engine
- Added fuzzy model matching with ILIKE %%pattern%% for TecDoc-style names
- Removed erroneous double cur.fetchone() that always returned None
- Added retry logic (3 attempts) for QWEN API empty responses
- Added fallback engine-less query when engine description doesn't match DB
- Protected _extract_json against None input
- bnpl_bp.py: APLAZO/Kueski/Clip application workflow (mock)
- erp_bp.py: Aspel/CONTPAQi/SAP/Odoo sync jobs (mock)
- whatsapp_cloud_bp.py: Meta Cloud API webhook, messages, templates
- supplier_portal_bp.py: demand by zone/branch and top-parts analytics
- app.py: register all new blueprints
The chat.js init() template did not include #chatTtsToggle, causing
a runtime TypeError when hasTTS was true. Added the toggle button
inside .chat-header-actions, matching chat-public.js structure.
Regenerated chat.min.js.
- Agrega TTS (speechSynthesis) a chat.js del POS para leer respuestas IA
- Copia lógica de voz completa (STT + TTS) a dashboard/chat-public.js
- Extiende estilos TTS en chat.css y chat-public.css
- Agrega chat widget a 13 templates POS que no lo tenían
- Corrige duplicado de chat.css en diagrams.html
- Minifica assets actualizados
- 73/73 tests pasan
Cambios implementados:
1. Lazy loading de imágenes:
- catalog.js: loading="lazy" decoding="async" en part cards y detail panel
- inventory.js: lazy loading en imagen de detalle de item
2. Minificación de assets:
- scripts/minify-assets.sh: minifica JS (terser) y CSS para POS y Dashboard
- 25 archivos .min.js + 5 .min.css generados en pos/static/
- 14 archivos .min.js + 8 .min.css generados en dashboard/
3. Nginx auto-serve minified:
- try_files $1.min.js antes de servir .js original
- try_files $1.min.css antes de servir .css original
- Transparente para los templates HTML (cero cambios en HTML)
4. Cache warming script:
- scripts/warm_vehicle_cache.py: pobla Redis con vehicle info por batches
- Mitiga DISTINCT ON + 4 JOINs sobre 2B filas
- Corre en background, procesa ~1.5M parts
Tests: 73/73 pasando
Cambios implementados:
1. Redis cache para _classify_cache (catalog_service.py):
- Reemplaza dict in-memory por Redis compartido entre workers
- TTL 5 minutos para clasificación Nexpart
- classify_cache_clear() y classify_cache_stats() actualizados
- Hit rate pasa de ~6% (15 cachés separados) a ~80%+ (cache unificado)
2. Redis cache para vehicle info en smart_search():
- Verifica Redis antes de ejecutar DISTINCT ON + 4 JOINs sobre 2B filas
- Cache miss: query solo para los part_ids faltantes
- TTL 1 hora por part_id
- Impacto: búsquedas repetidas pasan de 500ms–2s a < 50ms
3. Gunicorn gthread (gunicorn.conf.py):
- worker_class = 'gthread' con 4 threads por worker
- 4 workers × 4 threads = 16 requests concurrentes
- max_requests = 1000 para reciclar workers y prevenir memory leaks
Tests: 73/73 pasando
Cambios implementados:
1. Connection pooling (tenant_db.py):
- psycopg2.pool.ThreadedConnectionPool para master y tenants
- Wrapper _PooledConnection que devuelve al pool en .close()
- Cero cambios en blueprints (backward compatible)
2. Tabla inventory_stock_summary + triggers (v3.2):
- O(1) stock lookup en vez de SUM() sobre historial completo
- Trigger AFTER INSERT en inventory_operations recalcula stock
- Poblada inicialmente en ambos tenants
- Refactor en 6 archivos de servicios para usar la nueva tabla
3. Fix N+1 en process_sale (pos_engine.py):
- Precarga retail_price en bulk query FOR UPDATE
- Elimina SELECT individual por item en loop
4. Índices críticos:
- idx_parts_name_part + pattern_ops (master)
- idx_inv_ops_inventory_branch_created (tenants)
- idx_wi_part_stock_positive (master, ya existía desde Fase 1)
Tests: 73/73 pasando (compat + fase3 + fase5 + fase6)
Migración: v3.2_db_performance.sql
- Nueva tabla inventory_vehicle_compat (v3.1)
- Motor inventory_vehicle_compat.py: auto-match + gestión manual
- catalog_service.get_parts_local() ahora incluye piezas locales vinculadas
- inventory_bp: auto-match en create/update + endpoints REST /vehicles
- Frontend catalog.js: badge 'Stock Local' para piezas nativas del tenant
- Frontend inventory.js: panel de vehículos compatibles con auto-match
- Tests: test_compatibility.py (9/9 pasan)
Piezas locales aparecen en navegación por vehículo aunque no estén en TecDoc.
Auto-match busca part_number en parts/aftermarket_parts y copia MYEs compatibles.
Replaced hardcoded values (4,817 SKUs, $2.4M, 1,284 clients, $842,190
invoiced, $2,847,320 assets, etc.) with $0 / 0 placeholders with IDs
so the JS can populate them from real API data.
Affected: inventory.html, customers.html, invoicing.html, accounting.html
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Eliminado: diagrams_bp, ruta /pos/diagrams, link en sidebar,
boton "Ver diagramas" en catalogo. Los archivos SVG y blueprint
se mantienen en el repo por si se reactivan en el futuro.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Blueprint with API endpoints: list, detail, SVG serve, vehicle-linked diagrams
- Interactive SVG viewer with zoom/pan (mouse wheel, drag, touch, keyboard)
- Clickable hotspots that highlight on hover and show part detail panel
- Parts sidebar listing all callout numbers with catalog search integration
- 3 placeholder SVG diagrams: braking system, suspension, engine components
- Seeded diagrams, hotspots, and vehicle_diagrams in DB
- Added to sidebar nav, i18n (ES/EN), and "Ver diagramas" link in catalog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Kiosk mode: fullscreen, wake lock, auto-login, context menu block, PWA/Capacitor detection
- AI vision: camera photos analyzed by Gemma 3 27B vision model via OpenRouter
- AI part classification: auto-suggest name/brand/category when entering part number
- Public catalog chatbot: /api/chat endpoint with rate limiting, chat widget on catalog page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reemplaza /instance/status → /status, /instance/create → /connect, etc.
Lee QR de data.qr (formato del bridge) ademas de data.base64 (Evolution).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reemplaza Evolution API con bridge Node.js propio usando Baileys.
QR se genera en ~10 segundos. Auto-reply con chatbot IA.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch from Meta Business Cloud API to Evolution API for WhatsApp integration.
Evolution API is self-hosted, free, and connects via WhatsApp Web QR code scan.
- Add docker-compose for Evolution API deployment
- Rewrite whatsapp_service.py for Evolution API endpoints
- Add instance management (create, QR, status, logout) to blueprint
- Add QR code scanning UI with connection status indicator
- Add duplicate message prevention in webhook handler
- Update config.py with EVOLUTION_API_URL/KEY (remove old Meta vars)
- Add setup documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Demo/sample rows in HTML tables were visible on first render before JS
populated real data. Replaced all hardcoded tbody rows and finance cards
with empty containers that JS populates from API on load.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- i18n.js with 130+ translation keys for es/en, loaded in all 11 templates
- sidebar.js uses t() for all nav labels, adds MX/US language toggle
- app-init.js role labels use i18n
- currency.py service with convert() and format_currency()
- config.py adds DEFAULT_CURRENCY and EXCHANGE_RATE_USD_MXN settings
- config_bp.py adds GET/PUT /pos/api/config/currency endpoints
- config.html adds currency/exchange-rate section (Section 8)
- config.js adds loadCurrency/saveCurrency with localStorage sync
- pos.js fmt() reads pos_currency from localStorage for USD/MXN display
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Gunicorn production server with auto-scaled workers, run.sh, updated systemd service
- Marketplace B2B: cross-tenant inventory search, ordering, seller management with full UI
- Subscription billing: plan limits enforced on products/employees/branches, billing API + upgrade flow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add thermal_printer.py service generating raw ESC/POS bytes for 58mm/80mm printers
- Add /pos/api/sales/<id>/print endpoint (escpos_raw or browser mode)
- Add printer.js with WebUSB and Web Serial support for direct browser-to-printer
- Add thermal print button in ticket modal with connect/print workflow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chat now fetches tenant inventory summary (brands, counts, low-stock)
and injects it into the AI system prompt so responses prioritize local
stock. VIN decoder uses free NHTSA vPIC API to decode 17-char VINs and
auto-fills the vehicle selector dropdowns when a catalog match is found.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>