feat(pos): add plate lookup (#8), 326 translations (#12), bulk image import (#11)

- 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:
2026-04-05 04:17:55 +00:00
parent 1bea31e83f
commit 4cc2c66208
8 changed files with 917 additions and 43 deletions

View File

@@ -1019,6 +1019,75 @@
});
}
// ─── PLATE LOOKUP ───
var plateInputWrap = document.getElementById('plateInputWrap');
var plateInput = document.getElementById('plateInput');
var plateStatus = document.getElementById('plateStatus');
var plateToggle = document.getElementById('plateToggle');
function togglePlate() {
var isVisible = plateInputWrap.style.display !== 'none';
plateInputWrap.style.display = isVisible ? 'none' : '';
plateToggle.textContent = isVisible ? 'Tienes las placas?' : 'Ocultar placas';
if (!isVisible && plateInput) plateInput.focus();
}
function showPlateStatus(msg, isError) {
plateStatus.style.display = msg ? '' : 'none';
plateStatus.textContent = msg;
plateStatus.style.color = isError ? 'var(--color-error)' : 'var(--color-text-muted)';
}
function lookupPlate() {
var plate = (plateInput.value || '').trim().toUpperCase();
if (!plate || plate.length < 5) {
showPlateStatus('Ingresa una placa valida (Ej: ABC-1234).', true);
return;
}
showPlateStatus('Buscando placa...', false);
apiFetch(API + '/plate/' + encodeURIComponent(plate)).then(function (data) {
if (!data) {
showPlateStatus('Error de conexion al buscar placa.', true);
return;
}
if (data.error) {
showPlateStatus(data.error, true);
return;
}
if (!data.found) {
plateStatus.style.display = '';
plateStatus.innerHTML = 'Placa no registrada. <a href="/pos/customers" style="color:var(--color-primary);">Registrar vehiculo</a>';
plateStatus.style.color = 'var(--color-warning, #e6a700)';
return;
}
var parts = [];
if (data.year) parts.push(data.year);
if (data.make) parts.push(data.make);
if (data.model) parts.push(data.model);
var label = parts.join(' ') || 'Vehiculo encontrado';
// If we got a catalog match, auto-fill the dropdowns
var match = data.catalog_match;
if (match && match.brand_id) {
showPlateStatus(label + ' — Cargando catalogo...', false);
_autoFillFromVin(match, data);
} else {
showPlateStatus(label + ' — No encontrado en el catalogo TecDoc.', false);
}
});
}
if (plateInput) {
plateInput.addEventListener('keydown', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
lookupPlate();
}
});
}
// ─── VIN DECODER ───
var vinInputWrap = document.getElementById('vinInputWrap');
var vinInput = document.getElementById('vinInput');
@@ -1160,6 +1229,8 @@
startBarcodeScan: startBarcodeScan,
toggleVin: toggleVin,
decodeVin: decodeVin,
togglePlate: togglePlate,
lookupPlate: lookupPlate,
};
// ─── INIT ───