(function() {
'use strict';
const API = '/pos/api/supplier-catalog';
const VEHICLE_API = '/pos/api/inventory/vehicles';
const token = localStorage.getItem('pos_token') || '';
let state = {
q: '',
category: '',
make: '',
model: '',
year: '',
engine: '',
myeId: null,
page: 1,
perPage: 30,
totalPages: 1,
categories: [],
items: []
};
function headers() {
return { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' };
}
let scAbort = null;
let scSeq = 0;
async function apiFetch(url) {
if (scAbort) {
scAbort.abort();
scAbort = null;
}
const ctrl = new AbortController();
scAbort = ctrl;
try {
const resp = await fetch(url, { headers: headers(), signal: ctrl.signal });
if (resp.status === 401) { window.location.href = '/pos/login'; return null; }
if (!resp.ok) { console.error('API error', url, resp.status); return null; }
return resp.json();
} catch (e) {
if (e.name === 'AbortError') return null;
console.error('API error', url, e);
return null;
}
}
async function apiFetchSeq(url) {
const mySeq = ++scSeq;
const data = await apiFetch(url);
if (!data || scSeq !== mySeq) return null;
return data;
}
// ─── Categories ─────────────────────────────────────────────
async function loadCategories() {
const data = await apiFetch(API + '/categories');
if (!data) return;
state.categories = data.categories || [];
renderCategories();
}
function renderCategories() {
const el = document.getElementById('categoriesGrid');
if (!el) return;
let html = '
' +
'
Todas
' + state.categories.reduce((a,c)=>a+c.count,0) + ' items
';
state.categories.forEach(function(c) {
html += '' +
'
' + escapeHtml(c.name) + '
' + c.count + ' items
';
});
el.innerHTML = html;
}
window.selectCategory = function(name) {
state.category = name;
state.page = 1;
renderCategories();
doSearch();
};
// ─── Vehicle filters ────────────────────────────────────────
async function loadMakes() {
const data = await apiFetch(VEHICLE_API + '/makes');
if (!data) return;
const sel = document.getElementById('filterMake');
sel.innerHTML = '';
(data.data || []).forEach(function(m) {
sel.innerHTML += '';
});
}
window.onMakeChange = async function() {
const sel = document.getElementById('filterMake');
state.make = sel.value;
state.model = ''; state.year = ''; state.engine = ''; state.myeId = null;
document.getElementById('filterModel').disabled = true;
document.getElementById('filterYear').disabled = true;
document.getElementById('filterEngine').disabled = true;
if (!state.make) { doSearch(); return; }
const makes = await apiFetchSeq(VEHICLE_API + '/makes');
if (!makes) return;
const brand = (makes.data || []).find(function(m) { return m.name_brand === state.make; });
if (!brand) { doSearch(); return; }
const models = await apiFetchSeq(VEHICLE_API + '/models?brand_id=' + brand.id_brand);
if (!models) return;
const msel = document.getElementById('filterModel');
msel.innerHTML = '';
(models.data || []).forEach(function(m) {
msel.innerHTML += '';
});
msel.disabled = false;
doSearch();
};
window.onModelChange = async function() {
const sel = document.getElementById('filterModel');
const modelId = sel.value;
state.model = modelId ? sel.options[sel.selectedIndex].text : '';
state.year = ''; state.engine = ''; state.myeId = null;
document.getElementById('filterYear').disabled = true;
document.getElementById('filterEngine').disabled = true;
if (!modelId) { doSearch(); return; }
const years = await apiFetchSeq(VEHICLE_API + '/years?model_id=' + modelId);
if (!years) return;
const ysel = document.getElementById('filterYear');
ysel.innerHTML = '';
(years.data || []).forEach(function(y) {
ysel.innerHTML += '';
});
ysel.disabled = false;
doSearch();
};
window.onYearChange = async function() {
const sel = document.getElementById('filterYear');
const yearId = sel.value;
const modelId = document.getElementById('filterModel').value;
state.year = yearId ? sel.options[sel.selectedIndex].text : '';
state.engine = ''; state.myeId = null;
document.getElementById('filterEngine').disabled = true;
if (!yearId || !modelId) { doSearch(); return; }
const engines = await apiFetchSeq(VEHICLE_API + '/engines?model_id=' + modelId + '&year_id=' + yearId);
if (!engines) return;
const esel = document.getElementById('filterEngine');
esel.innerHTML = '';
(engines.data || []).forEach(function(e) {
const label = escapeHtml(e.name_engine) + (e.trim_level ? ' (' + escapeHtml(e.trim_level) + ')' : '');
esel.innerHTML += '';
});
esel.disabled = false;
doSearch();
};
// ─── Search ─────────────────────────────────────────────────
window.doSearch = async function() {
state.q = document.getElementById('searchInput').value.trim();
const engineSel = document.getElementById('filterEngine');
state.myeId = engineSel.value || null;
let url = API + '/search?page=' + state.page + '&per_page=' + state.perPage;
if (state.q) url += '&q=' + encodeURIComponent(state.q);
if (state.category) url += '&category=' + encodeURIComponent(state.category);
if (state.myeId) {
url += '&mye_id=' + state.myeId;
} else {
if (state.make) url += '&make=' + encodeURIComponent(state.make);
if (state.model) url += '&model=' + encodeURIComponent(state.model);
if (state.year) url += '&year=' + encodeURIComponent(state.year);
}
const data = await apiFetch(url);
if (!data) return;
state.items = data.data || [];
state.totalPages = (data.pagination || {}).total_pages || 1;
renderItems();
renderPagination();
};
window.clearFilters = function() {
document.getElementById('searchInput').value = '';
document.getElementById('filterMake').value = '';
document.getElementById('filterModel').innerHTML = ''; document.getElementById('filterModel').disabled = true;
document.getElementById('filterYear').innerHTML = ''; document.getElementById('filterYear').disabled = true;
document.getElementById('filterEngine').innerHTML = ''; document.getElementById('filterEngine').disabled = true;
state.q = ''; state.category = ''; state.make = ''; state.model = ''; state.year = ''; state.engine = ''; state.myeId = null; state.page = 1;
renderCategories();
doSearch();
};
// ─── Render results ─────────────────────────────────────────
function renderItems() {
const el = document.getElementById('partsGrid');
if (!el) return;
if (!state.items.length) {
el.innerHTML = '🔍
Sin resultados
Intenta con otros filtros o terminos de busqueda.
';
return;
}
el.innerHTML = state.items.map(function(it) {
return '' +
'
' + escapeHtml(it.sku) + '
' +
'
' + escapeHtml(it.name) + '
' +
'
' +
'' + escapeHtml(it.category || 'SIN CATEGORIA') + '' +
' ' + escapeHtml(it.supplier_name) + '' +
'
' +
'
';
}).join('');
}
function renderPagination() {
const el = document.getElementById('pagination');
if (!el) return;
if (state.totalPages <= 1) { el.innerHTML = ''; return; }
let html = '';
html += 'Pagina ' + state.page + ' de ' + state.totalPages + '';
html += '';
el.innerHTML = html;
}
window.goPage = function(p) {
state.page = p;
doSearch();
};
// ─── Detail modal ───────────────────────────────────────────
window.openDetail = async function(id) {
const data = await apiFetch(API + '/items/' + id);
if (!data) return;
document.getElementById('modalTitle').textContent = escapeHtml(data.sku);
let html = '';
html += '' + escapeHtml(data.name) + '
';
html += 'Informacion
' +
'
Proveedor: ' + escapeHtml(data.supplier_name) + '
Categoria: ' + escapeHtml(data.category || 'N/A') + '
';
if (data.interchanges && data.interchanges.length) {
html += 'Intercambios
' +
data.interchanges.map(function(ix) {
return '' + escapeHtml(ix.brand) + ' — ' + escapeHtml(ix.part_number) + '';
}).join('') + '
';
}
if (data.compatibilities && data.compatibilities.length) {
var seenCompat = {};
var uniqCompat = data.compatibilities.filter(function(c) {
var key = (c.make || '') + '|' + (c.model || '') + '|' + (c.year || '') + '|' + (c.engine || '');
if (seenCompat[key]) return false;
seenCompat[key] = true;
return true;
});
html += 'Vehiculos compatibles (' + uniqCompat.length + ')
' +
'
' +
uniqCompat.slice(0, 50).map(function(c) {
return '
' +
'' + escapeHtml(c.make || '') + ' ' + escapeHtml(c.model || '') + '
' +
(c.year || '') + ' ' + escapeHtml(c.engine || '') +
'
';
}).join('') +
(uniqCompat.length > 50 ? '
... y ' + (uniqCompat.length - 50) + ' mas
' : '') +
'
';
}
document.getElementById('modalBody').innerHTML = html;
document.getElementById('detailModal').classList.add('open');
};
window.closeModal = function() {
document.getElementById('detailModal').classList.remove('open');
};
// ─── Utils ──────────────────────────────────────────────────
function escapeHtml(s) {
if (s == null) return '';
return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"');
}
// ─── Init ───────────────────────────────────────────────────
function init() {
if (!token) { window.location.href = '/pos/login'; return; }
loadCategories();
loadMakes();
doSearch().then(function() {
var params = new URLSearchParams(window.location.search);
var id = params.get('id');
if (id) { openDetail(parseInt(id)); }
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();