';
}
// =====================================================================
// HISTORY MODAL
// =====================================================================
function viewHistory(itemId) {
apiFetch(API + '/items/' + itemId + '/history').then(function (data) {
if (!data) return;
var history = data.data || [];
var html = '';
if (!history.length) {
html = '
Sin movimientos
';
} else {
html = '
Fecha
Tipo
Cantidad
Costo
Empleado
Notas
';
history.forEach(function (h) {
var qtyColor = h.quantity > 0 ? 'var(--color-success)' : 'var(--color-error)';
html += '
' +
'
' + esc(h.date) + '
' +
'
' + esc(h.type) + '
' +
'
' + (h.quantity > 0 ? '+' : '') + h.quantity + '
' +
'
' + (h.cost ? '$' + fmt(h.cost) : '—') + '
' +
'
' + esc(h.employee) + '
' +
'
' + esc(h.notes) + '
' +
'
';
});
html += '
';
}
document.getElementById('historyContent').innerHTML = html;
document.getElementById('historyModal').classList.add('is-open');
});
}
function closeHistoryModal() {
document.getElementById('historyModal').classList.remove('is-open');
}
// =====================================================================
// BARCODE LABEL PRINT
// =====================================================================
function printBarcode(barcode, partNumber, name) {
var w = window.open('', '_blank', 'width=400,height=250');
w.document.write('Etiqueta');
w.document.write('
' + barcode + '
');
w.document.write('
' + partNumber + '
');
w.document.write('
' + name + '
');
w.document.write('');
w.document.close();
w.print();
}
// =====================================================================
// PRODUCT DETAIL MODAL (shows item info + movement history)
// =====================================================================
function uploadItemImage(itemId) {
var input = document.createElement('input');
input.type = 'file';
input.accept = 'image/jpeg,image/png,image/webp';
input.onchange = function () {
if (!input.files || !input.files[0]) return;
var file = input.files[0];
if (file.size > 5 * 1024 * 1024) {
alert('Imagen demasiado grande (max 5 MB)');
return;
}
var fd = new FormData();
fd.append('file', file);
var statusEl = document.getElementById('imgUploadStatus');
if (statusEl) statusEl.textContent = 'Subiendo...';
fetch(API + '/items/' + itemId + '/image', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + token },
body: fd
})
.then(function (r) { return r.json(); })
.then(function (result) {
if (result.image_url) {
// Refresh detail view
viewProductDetail(itemId);
} else {
if (statusEl) statusEl.textContent = result.error || 'Error';
}
})
.catch(function () {
if (statusEl) statusEl.textContent = 'Error de red';
});
};
input.click();
}
function deleteItemImage(itemId) {
if (!confirm('Eliminar imagen de este producto?')) return;
fetch(API + '/items/' + itemId + '/image', {
method: 'DELETE',
headers: { 'Authorization': 'Bearer ' + token }
})
.then(function (r) { return r.json(); })
.then(function (result) {
if (result.message) {
viewProductDetail(itemId);
} else {
alert(result.error || 'Error');
}
})
.catch(function () { alert('Error de red'); });
}
function viewProductDetail(itemId) {
apiFetch(API + '/items/' + itemId).then(function (data) {
if (!data || data.error) {
alert(data ? data.error : 'Error de red');
return;
}
var history = data.history || [];
var html = '';
// Product image section
html += '
';
if (data.image_url) {
html += '';
html += '
';
html += '';
html += '';
html += '
';
} else {
html += '
';
html += '';
html += '
Sin imagen
';
html += '
';
html += '';
}
html += '';
html += '
';
// Product info header
html += '
';
html += '
No. Parte' + esc(data.part_number) + '
';
html += '
Nombre' + esc(data.name) + '
';
html += '
Marca' + esc(data.brand) + '
';
html += '
Codigo de Barras' + esc(data.barcode) + '
';
html += '
Ubicacion' + esc(data.location || '-') + '
';
html += '
Stock' + (data.stock || 0) + '
';
html += '
';
// Prices
html += '
';
html += '
Costo$' + fmt(data.cost) + '
';
html += '
Precio 1$' + fmt(data.price_1) + '
';
html += '
Precio 2$' + fmt(data.price_2) + '
';
html += '
Precio 3$' + fmt(data.price_3) + '
';
html += '
';
// Cross-references section
html += '
Cross-References / Equivalencias
';
html += '
';
html += '
Cargando equivalencias...
';
html += '
';
// Load cross-references from catalog API
var partNumber = data.part_number;
var catalogPartId = data.catalog_part_id;
(function loadCrossRefs() {
// Try catalog part detail if we have catalog_part_id
var url = catalogPartId
? '/pos/api/catalog/part/' + catalogPartId
: '/pos/api/catalog/search?q=' + encodeURIComponent(partNumber);
fetch(url, { headers: { 'Authorization': 'Bearer ' + token } })
.then(function(r) { return r.json(); })
.then(function(d) {
var el = document.getElementById('crossRefContent');
if (!el) return;
var alternatives = d.alternatives || [];
var bodegas = d.bodegas || [];
// If it was a search, get alternatives from first result
if (!catalogPartId && d.data && d.data.length > 0) {
// Fetch detail for first match
fetch('/pos/api/catalog/part/' + d.data[0].id_part, { headers: { 'Authorization': 'Bearer ' + token } })
.then(function(r2) { return r2.json(); })
.then(function(d2) {
renderCrossRefs(el, d2.alternatives || [], d2.bodegas || []);
})
.catch(function() { el.innerHTML = '
Sin conexion al catalogo.
'; });
return;
}
renderCrossRefs(el, alternatives, bodegas);
})
.catch(function() {
var el = document.getElementById('crossRefContent');
if (el) el.innerHTML = '
Sin conexion al catalogo central.
';
});
})();
function renderCrossRefs(el, alternatives, bodegas) {
var html2 = '';
if (bodegas && bodegas.length > 0) {
html2 += '