- Plate lookup: new plate_vehicles table (v1.7 migration), plate_lookup service with Mexican plate validation, GET/POST endpoints on catalog_bp, plate search UI in catalog vehicle selector - Translations: extend PART_TRANSLATIONS from ~80 to 326 entries covering brake, engine, fuel, cooling, electrical, drivetrain, suspension, steering, exhaust, A/C, lighting, body, interior, fluids, and category translations - Bulk images: image_scraper service with download+resize+placeholder generation, bulk-images and auto-image endpoints on inventory_bp Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ from middleware import require_auth
|
||||
from tenant_db import get_master_conn, get_tenant_conn
|
||||
from services import catalog_service
|
||||
from services.vin_decoder import decode_vin
|
||||
from services.plate_lookup import search_plate, register_plate, is_valid_mexican_plate, normalize_plate
|
||||
|
||||
catalog_bp = Blueprint('catalog', __name__, url_prefix='/pos/api/catalog')
|
||||
|
||||
@@ -227,6 +228,113 @@ def decode_vin_route(vin):
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
# ─── Plate Lookup ───
|
||||
|
||||
@catalog_bp.route('/plate/<plate>', methods=['GET'])
|
||||
@require_auth('catalog.view')
|
||||
def plate_lookup(plate):
|
||||
"""Look up a vehicle by Mexican license plate in the local plate_vehicles table.
|
||||
If found, also tries to match the vehicle to the catalog DB.
|
||||
"""
|
||||
plate = (plate or '').strip()
|
||||
if not plate:
|
||||
return jsonify({'error': 'Placa requerida.'}), 400
|
||||
|
||||
if not is_valid_mexican_plate(plate):
|
||||
return jsonify({'error': 'Formato de placa no valido. Ej: ABC-1234 o AB-123-C'}), 400
|
||||
|
||||
tenant = None
|
||||
master = None
|
||||
try:
|
||||
tenant = get_tenant_conn(g.tenant_id)
|
||||
result = search_plate(tenant, plate)
|
||||
|
||||
if not result:
|
||||
return jsonify({
|
||||
'found': False,
|
||||
'plate': normalize_plate(plate),
|
||||
'message': 'Placa no registrada.'
|
||||
})
|
||||
|
||||
# Try to match to catalog
|
||||
catalog_match = None
|
||||
try:
|
||||
master = get_master_conn()
|
||||
catalog_match = _match_plate_to_catalog(master, result)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
if master:
|
||||
try: master.close()
|
||||
except: pass
|
||||
master = None
|
||||
|
||||
response = {
|
||||
'found': True,
|
||||
'plate': result['plate'],
|
||||
'make': result['make'],
|
||||
'model': result['model'],
|
||||
'year': result['year'],
|
||||
'vin': result['vin'],
|
||||
'customer_id': result['customer_id'],
|
||||
}
|
||||
if catalog_match:
|
||||
response['catalog_match'] = catalog_match
|
||||
|
||||
return jsonify(response)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
if tenant:
|
||||
try: tenant.close()
|
||||
except: pass
|
||||
if master:
|
||||
try: master.close()
|
||||
except: pass
|
||||
|
||||
|
||||
@catalog_bp.route('/plate', methods=['POST'])
|
||||
@require_auth('catalog.view')
|
||||
def plate_register():
|
||||
"""Register or update a plate-to-vehicle mapping."""
|
||||
data = request.get_json() or {}
|
||||
plate = (data.get('plate') or '').strip()
|
||||
if not plate:
|
||||
return jsonify({'error': 'plate required'}), 400
|
||||
|
||||
if not is_valid_mexican_plate(plate):
|
||||
return jsonify({'error': 'Formato de placa no valido.'}), 400
|
||||
|
||||
tenant = None
|
||||
try:
|
||||
tenant = get_tenant_conn(g.tenant_id)
|
||||
rec_id = register_plate(
|
||||
tenant, plate,
|
||||
make=data.get('make'),
|
||||
model=data.get('model'),
|
||||
year=data.get('year'),
|
||||
vin=data.get('vin'),
|
||||
customer_id=data.get('customer_id'),
|
||||
)
|
||||
return jsonify({'id': rec_id, 'message': 'Placa registrada.'})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
finally:
|
||||
if tenant:
|
||||
try: tenant.close()
|
||||
except: pass
|
||||
|
||||
|
||||
def _match_plate_to_catalog(master_conn, plate_info):
|
||||
"""Try to match plate vehicle info to the catalog DB (same logic as VIN)."""
|
||||
return _match_vin_to_catalog(master_conn, {
|
||||
'make': plate_info.get('make'),
|
||||
'model': plate_info.get('model'),
|
||||
'year': plate_info.get('year'),
|
||||
})
|
||||
|
||||
|
||||
def _match_vin_to_catalog(master_conn, vin_info):
|
||||
"""Try to find brand_id, model_id, year_id, mye_id from decoded VIN info."""
|
||||
make = (vin_info.get('make') or '').upper().strip()
|
||||
|
||||
Reference in New Issue
Block a user