feat(pos): filtrar modelos a solo Norteamerica — elimina modelos de otros mercados

Lista de modelos por marca para Mexico/USA/Canada (36 marcas).
Toyota: 625 → 236, Nissan: 499 → 138, Ford: 288 → 114,
Chevrolet: 470 → 207, VW: 283 → 143, Honda: 223 → 117.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 08:12:02 +00:00
parent 10e318bfd7
commit 97704fd804
2 changed files with 522 additions and 4 deletions

View File

@@ -12,6 +12,8 @@ PERFORMANCE: vehicle_parts has 14B+ rows. Every query MUST:
import re
from services.na_models import is_na_model
# ─────────────────────────────────────────────────────────────────────────────
# VEHICLE HIERARCHY NAVIGATION
@@ -54,10 +56,18 @@ def get_brands(master_conn, year_id=None):
return [{'id_brand': r[0], 'name_brand': r[1]} for r in rows]
def get_models(master_conn, brand_id, year_id=None):
"""Get models for a brand that have MYE entries.
If year_id is provided, only models available for that year."""
def get_models(master_conn, brand_id, year_id=None, brand_name=None):
"""Get models for a brand that have MYE entries, filtered to North America.
If year_id is provided, only models available for that year.
brand_name is used for NA filtering; looked up from DB if not provided."""
cur = master_conn.cursor()
# Resolve brand_name for NA filter if not provided
if not brand_name:
cur.execute("SELECT name_brand FROM brands WHERE id_brand = %s", (brand_id,))
row = cur.fetchone()
brand_name = row[0] if row else ''
if year_id:
cur.execute("""
SELECT DISTINCT m.id_model, m.name_model
@@ -76,7 +86,13 @@ def get_models(master_conn, brand_id, year_id=None):
""", (brand_id,))
rows = cur.fetchall()
cur.close()
return [{'id_model': r[0], 'name_model': r[1]} for r in rows]
# Filter to North America models only
return [
{'id_model': r[0], 'name_model': r[1]}
for r in rows
if is_na_model(brand_name, r[1])
]
def get_years(master_conn, model_id):

502
pos/services/na_models.py Normal file
View File

@@ -0,0 +1,502 @@
# /home/Autopartes/pos/services/na_models.py
"""North America model filter -- models sold in Mexico, USA, and Canada.
TecDoc includes models from all global markets (Europe, Asia, Middle East, etc.)
but our catalog only needs models actually sold in North America.
Usage:
from services.na_models import is_na_model
if is_na_model('TOYOTA', 'AGYA (B1_)'): # False -- not sold in NA
if is_na_model('TOYOTA', 'Corolla (_E21_)'): # True -- sold in NA
if is_na_model('NISSAN', 'TSURU'): # True -- Mexico-specific
Matching logic:
- Case-insensitive
- TecDoc model name must START WITH one of the listed base names
- e.g. base "COROLLA" matches "Corolla (_E21_)", "Corolla Hatchback", etc.
- Unknown brands (not in NA_MODELS) pass through unfiltered
"""
# ────────────────────────────────────────────────────────────────────────────
# Base model names sold in North America (case-insensitive prefix matching)
# Includes: current (2020-2026), recent discontinued (2010-2019),
# classic/legacy still serviced (2000-2009),
# and Mexico-specific models.
# ────────────────────────────────────────────────────────────────────────────
NA_MODELS = {
# ── TOYOTA ──────────────────────────────────────────────────────────────
'TOYOTA': [
'4 RUNNER', '86', 'AVALON', 'BZ4X',
'C-HR', 'CAMRY', 'CELICA', 'COROLLA', 'CORONA', 'CRESSIDA',
'ECHO', 'FJ CRUISER',
'GR86', 'GR SUPRA', 'GRAND HIGHLANDER',
'HIGHLANDER',
'LAND CRUISER',
'MATRIX', 'MIRAI', 'MR2',
'PASEO', 'PICKUP', 'PRIUS',
'RAV4', 'RAV 4',
'SEQUOIA', 'SIENNA', 'SOLARA', 'SUPRA',
'TACOMA', 'TERCEL', 'T100', 'TUNDRA',
'VENZA',
'YARIS',
],
# ── NISSAN ──────────────────────────────────────────────────────────────
'NISSAN': [
'200SX', '240SX', '300ZX', '350Z', '370Z',
'ALTIMA', 'APRIO', 'ARIYA', 'ARMADA',
'FRONTIER',
'GT-R',
'JUKE',
'KICKS',
'LEAF',
'MARCH', 'MAXIMA', 'MURANO',
'NOTE', 'NP300', 'NV',
'PATHFINDER', 'PLATINA',
'QUEST',
'ROGUE', 'ROGUE SPORT',
'SENTRA',
'TIIDA', 'TITAN', 'TSURU',
'V-DRIVE', 'VERSA',
'X-TRAIL', 'XTERRA',
'Z',
],
# ── FORD ────────────────────────────────────────────────────────────────
'FORD': [
'BRONCO', 'BRONCO SPORT',
'CONTOUR', 'CROWN VICTORIA',
'ECOSPORT', 'EDGE', 'ESCAPE', 'ESCORT', 'EXCURSION', 'EXPEDITION',
'EXPLORER',
'F 150', 'F-150', 'F 250', 'F-250', 'F 350', 'F-350', 'F 450', 'F-450',
'F 550', 'F-550', 'FIESTA', 'FIGO', 'FIVE HUNDRED', 'FLEX', 'FOCUS',
'FREESTAR', 'FREESTYLE', 'FUSION',
'IKON',
'LOBO',
'MAVERICK', 'MUSTANG',
'PROBE',
'RANGER',
'TAURUS', 'THUNDERBIRD', 'TRANSIT', 'TRANSIT CONNECT',
'WINDSTAR',
],
# ── CHEVROLET ───────────────────────────────────────────────────────────
'CHEVROLET': [
'ASTRA', 'ASTRO', 'AVALANCHE', 'AVEO',
'BEAT', 'BLAZER', 'BOLT',
'CAMARO', 'CAPTIVA', 'CAVALIER', 'CHEVY', 'COBALT', 'COLORADO',
'CORSA', 'CORVETTE', 'CRUZE',
'EQUINOX', 'EXPRESS',
'GROVE',
'HHR',
'IMPALA',
'LUMINA',
'MALIBU', 'MERIVA', 'MONTE CARLO',
'ONIX', 'ORLANDO',
'PRIZM',
'S-10', 'S10', 'SILVERADO', 'SONIC', 'SPARK', 'SPIN', 'SUBURBAN',
'TAHOE', 'TORNADO', 'TRACKER', 'TRAIL', 'TRAILBLAZER', 'TRAVERSE',
'TRAX',
'VENTURE',
'ZAFIRA',
],
# ── VW (VOLKSWAGEN) ────────────────────────────────────────────────────
'VW': [
'ATLAS',
'BEETLE', 'BORA',
'CABRIO', 'CC', 'CLASICO', 'CROSSFOX',
'DERBY',
'EOS', 'EUROVAN',
'GLI', 'GOL', 'GOLF', 'GTI',
'ID.4', 'ID.BUZZ',
'JETTA',
'LUPO',
'NEW BEETLE', 'NIVUS',
'PASSAT', 'POINTER', 'POLO',
'RABBIT', 'ROUTAN',
'SAVEIRO', 'SEDAN', 'SPORTVAN', 'SURAN',
'T-CROSS', 'TAOS', 'TIGUAN', 'TOUAREG',
'UP',
'VENTO', 'VIRTUS',
],
# ── HONDA ───────────────────────────────────────────────────────────────
'HONDA': [
'ACCORD',
'BR-V',
'CITY', 'CIVIC', 'CR-V', 'CR-Z', 'CROSSTOUR',
'DEL SOL',
'ELEMENT',
'FIT',
'HR-V',
'INSIGHT',
'ODYSSEY',
'PASSPORT', 'PILOT', 'PRELUDE', 'PROLOGUE',
'RIDGELINE',
'S2000',
],
# ── HYUNDAI ─────────────────────────────────────────────────────────────
'HYUNDAI': [
'ACCENT', 'AZERA',
'CRETA',
'ELANTRA', 'ENTOURAGE',
'GENESIS',
'IONIQ',
'KONA',
'NEXO',
'PALISADE',
'SANTA CRUZ', 'SANTA FE', 'SONATA', 'STAREX',
'TIBURON', 'TUCSON',
'VELOSTER', 'VENUE', 'VERACRUZ',
'XG',
],
# ── KIA ─────────────────────────────────────────────────────────────────
'KIA': [
'AMANTI',
'CARNIVAL', 'CERATO',
'EV6', 'EV9',
'FORTE',
'K5',
'NIRO',
'OPTIMA',
'RIO',
'SEDONA', 'SELTOS', 'SORENTO', 'SOUL', 'SPECTRA', 'SPORTAGE',
'STINGER',
'TELLURIDE',
],
# ── MAZDA ───────────────────────────────────────────────────────────────
'MAZDA': [
'2', '3', '5', '6',
'323', '626', '929',
'B-SERIE', 'B2300', 'B2500', 'B3000', 'B4000',
'CX-3', 'CX-30', 'CX-5', 'CX-50', 'CX-7', 'CX-70', 'CX-9', 'CX-90',
'MIATA', 'MILLENIA', 'MPV', 'MX-3', 'MX-5', 'MX-30',
'PROTEGE',
'RX-7', 'RX-8',
'TRIBUTE',
],
# ── BMW ─────────────────────────────────────────────────────────────────
'BMW': [
'1', '2', '3', '4', '5', '6', '7', '8',
'I3', 'I4', 'I7', 'I8', 'IX', 'IX3',
'M2', 'M3', 'M4', 'M5', 'M6', 'M8',
'X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'XM',
'Z3', 'Z4', 'Z8',
],
# ── MERCEDES-BENZ ──────────────────────────────────────────────────────
'MERCEDES-BENZ': [
'A', 'AMG GT',
'B',
'C', 'CL', 'CLA', 'CLK', 'CLS',
'E', 'EQB', 'EQE', 'EQS',
'G', 'GL', 'GLA', 'GLB', 'GLC', 'GLE', 'GLK', 'GLS',
'MAYBACH', 'METRIS', 'ML',
'R',
'S', 'SL', 'SLC', 'SLK', 'SPRINTER',
],
# ── AUDI ────────────────────────────────────────────────────────────────
'AUDI': [
'A1', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8',
'E-TRON', 'ETRON',
'Q3', 'Q4', 'Q5', 'Q7', 'Q8',
'R8', 'RS', 'RS3', 'RS4', 'RS5', 'RS6', 'RS7',
'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'SQ5', 'SQ7', 'SQ8',
'TT',
],
# ── ACURA ───────────────────────────────────────────────────────────────
'ACURA': [
'CL', 'CSX',
'EL',
'ILX', 'INTEGRA', 'INTEGRA (2023)',
'MDX',
'NSX',
'RDX', 'RL', 'RLX', 'RSX',
'TL', 'TLX', 'TSX',
'ZDX',
],
# ── LEXUS ───────────────────────────────────────────────────────────────
'LEXUS': [
'CT',
'ES',
'GS', 'GX',
'IS',
'LC', 'LFA', 'LS', 'LX',
'NX',
'RC', 'RX', 'RZ',
'SC',
'TX',
'UX',
],
# ── INFINITI ────────────────────────────────────────────────────────────
'INFINITI': [
'EX', 'FX',
'G', 'I',
'JX',
'M',
'Q40', 'Q50', 'Q60', 'Q70', 'QX30', 'QX50', 'QX55', 'QX56',
'QX60', 'QX70', 'QX80',
],
# ── CHRYSLER ────────────────────────────────────────────────────────────
'CHRYSLER': [
'200', '300',
'ASPEN',
'CIRRUS', 'CONCORDE', 'CROSSFIRE',
'GRAND VOYAGER',
'NEON',
'PACIFICA', 'PT CRUISER',
'SEBRING',
'TOWN', 'TOWN & COUNTRY',
'VOYAGER',
],
# ── DODGE ───────────────────────────────────────────────────────────────
'DODGE': [
'ATOS', 'ATTITUDE', 'AVENGER',
'CALIBER', 'CARAVAN', 'CHALLENGER', 'CHARGER',
'DAKOTA', 'DART', 'DURANGO',
'GRAND CARAVAN',
'HORNET',
'I10',
'JOURNEY',
'MAGNUM',
'NEON', 'NITRO',
'RAM', 'STRATUS',
'VIPER', 'VISION',
],
# ── JEEP ────────────────────────────────────────────────────────────────
'JEEP': [
'CHEROKEE', 'COMMANDER', 'COMPASS',
'GLADIATOR', 'GRAND CHEROKEE', 'GRAND WAGONEER',
'LIBERTY',
'PATRIOT',
'RENEGADE',
'WAGONEER', 'WRANGLER',
],
# ── RAM ─────────────────────────────────────────────────────────────────
'RAM': [
'1500', '2500', '3500', '4500', '5500',
'700',
'PROMASTER',
],
# ── GMC ─────────────────────────────────────────────────────────────────
'GMC': [
'ACADIA',
'CANYON',
'ENVOY',
'HUMMER EV',
'JIMMY',
'SAFARI', 'SAVANA', 'SIERRA', 'SONOMA',
'TERRAIN',
'YUKON',
],
# ── BUICK ───────────────────────────────────────────────────────────────
'BUICK': [
'CENTURY',
'ENCLAVE', 'ENCORE', 'ENVISION', 'ENVISTA',
'LACROSSE', 'LESABRE', 'LUCERNE',
'PARK AVENUE',
'RAINIER', 'REGAL', 'RENDEZVOUS', 'RIVIERA',
'TERRAZA',
'VERANO',
],
# ── CADILLAC ────────────────────────────────────────────────────────────
'CADILLAC': [
'ATS',
'CT4', 'CT5', 'CT6', 'CTS',
'DEVILLE', 'DTS',
'ELDORADO', 'ESCALADE',
'LYRIQ',
'SEVILLE', 'SRX', 'STS',
'XT4', 'XT5', 'XT6', 'XTS',
],
# ── LINCOLN ─────────────────────────────────────────────────────────────
'LINCOLN': [
'AVIATOR',
'CONTINENTAL', 'CORSAIR',
'LS',
'MKC', 'MKS', 'MKT', 'MKX', 'MKZ',
'NAUTILUS', 'NAVIGATOR',
'TOWN CAR',
'ZEPHYR',
],
# ── SUBARU ──────────────────────────────────────────────────────────────
'SUBARU': [
'ASCENT',
'BAJA', 'BRZ',
'CROSSTREK',
'FORESTER',
'IMPREZA',
'LEGACY',
'OUTBACK',
'SOLTERRA',
'TRIBECA',
'WRX',
'XV',
],
# ── MITSUBISHI ──────────────────────────────────────────────────────────
'MITSUBISHI': [
'ECLIPSE', 'ECLIPSE CROSS', 'ENDEAVOR',
'GALANT',
'L200', 'LANCER',
'MIRAGE', 'MONTERO',
'OUTLANDER',
'RAIDER', 'RVR',
],
# ── SUZUKI ──────────────────────────────────────────────────────────────
'SUZUKI': [
'AERIO',
'CIAZ',
'EQUATOR',
'FORENZA',
'GRAND VITARA',
'IGNIS',
'KIZASHI',
'RENO',
'S-CROSS', 'SWIFT', 'SX4',
'VITARA',
'XL-7', 'XL7',
],
# ── RENAULT ─────────────────────────────────────────────────────────────
'RENAULT': [
'CAPTUR', 'CLIO', 'COLEOS',
'DUSTER',
'FLUENCE',
'KANGOO', 'KOLEOS', 'KWID',
'LOGAN',
'MEGANE',
'OROCH',
'SAFRANE', 'SANDERO', 'SCENIC', 'STEPWAY',
],
# ── PEUGEOT ─────────────────────────────────────────────────────────────
'PEUGEOT': [
'2008', '206', '207', '208', '3008', '301', '306', '307', '308',
'405', '5008', '508',
'MANAGER', 'PARTNER', 'RCZ', 'RIFTER',
],
# ── SEAT ────────────────────────────────────────────────────────────────
'SEAT': [
'ARONA', 'ATECA',
'CORDOBA',
'IBIZA',
'LEON',
'TARRACO', 'TOLEDO',
],
# ── FIAT ────────────────────────────────────────────────────────────────
'FIAT': [
'124', '500', '500L', '500X',
'DUCATO',
'FREEMONT',
'LINEA',
'MOBI',
'PALIO', 'PUNTO', 'PULSE',
'TIPO', 'TORO',
'UNO',
],
# ── MINI ────────────────────────────────────────────────────────────────
'MINI': [
'CLUBMAN', 'CONVERTIBLE', 'COUNTRYMAN', 'COUPE',
'HARDTOP', 'MINI',
'PACEMAN',
],
# ── VOLVO ───────────────────────────────────────────────────────────────
'VOLVO': [
'C30', 'C40', 'C70',
'EX30', 'EX90',
'S40', 'S60', 'S70', 'S80', 'S90',
'V40', 'V50', 'V60', 'V70', 'V90',
'XC40', 'XC60', 'XC70', 'XC90',
],
# ── PORSCHE ─────────────────────────────────────────────────────────────
'PORSCHE': [
'718', '911',
'BOXSTER',
'CAYENNE', 'CAYMAN',
'MACAN',
'PANAMERA',
'TAYCAN',
],
# ── JAGUAR ──────────────────────────────────────────────────────────────
'JAGUAR': [
'E-PACE',
'F-PACE', 'F-TYPE',
'I-PACE',
'S-TYPE',
'X-TYPE', 'XE', 'XF', 'XJ', 'XK',
],
# ── LAND ROVER ──────────────────────────────────────────────────────────
'LAND ROVER': [
'DEFENDER', 'DISCOVERY', 'DISCOVERY SPORT',
'FREELANDER',
'LR2', 'LR3', 'LR4',
'RANGE ROVER',
],
# ── TESLA ───────────────────────────────────────────────────────────────
'TESLA': [
'CYBERTRUCK',
'MODEL 3', 'MODEL S', 'MODEL X', 'MODEL Y',
],
}
# Pre-compute upper-cased sets for fast lookup
_NA_MODELS_UPPER = {
brand: [m.upper() for m in models]
for brand, models in NA_MODELS.items()
}
def is_na_model(brand_name, model_name):
"""Check if a TecDoc model is sold in North America.
Args:
brand_name: Brand name (e.g. 'TOYOTA', 'VW')
model_name: TecDoc model name (e.g. 'Corolla (_E21_)', 'AGYA (B1_)')
Returns:
True if the model is sold in NA, or if the brand is not in our list
(unknown brands pass through unfiltered).
"""
brand_upper = brand_name.upper().strip()
model_upper = model_name.upper().strip()
# If brand not in our list, allow all models (don't filter unknown brands)
if brand_upper not in _NA_MODELS_UPPER:
return True
# Check if model name starts with any known NA model
for na_model in _NA_MODELS_UPPER[brand_upper]:
if model_upper.startswith(na_model):
return True
return False