feat(inventory): show ID column, add quick-entry button, improve purchase UX

- Add ID column to stock table header and renderInventoryRow
- Add 'Entrada' button on each stock row to open purchase modal pre-filled
- Show inventory ID in product detail popup
- recordPurchase: close modal, clear form, reload stats and stock list on success
- Fix colspan 11 -> 12 for empty state rows
This commit is contained in:
2026-05-18 05:31:34 +00:00
parent 6196234d8b
commit bfa7bc2997
2 changed files with 23 additions and 5 deletions

View File

@@ -65,6 +65,7 @@
function renderInventoryRow(it) {
return '<tr style="cursor:pointer;" onclick="viewProductDetail(' + it.id + ')">' +
'<td class="td--mono" style="font-size:var(--text-caption);color:var(--color-text-muted);">' + it.id + '</td>' +
'<td class="td--mono">' + esc(it.barcode) + '</td>' +
'<td class="td--mono">' + esc(it.part_number) + '</td>' +
'<td class="td--primary">' + esc(it.name) + '</td>' +
@@ -77,6 +78,7 @@
'<td>' + esc(it.location) + '</td>' +
'<td>' +
'<button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();viewHistory(' + it.id + ')">Historial</button> ' +
'<button class="btn btn--ghost btn--sm" style="color:var(--color-accent);" onclick="event.stopPropagation();showPurchaseModalForItem(' + it.id + ')">Entrada</button> ' +
'<button class="btn btn--ghost btn--sm" onclick="event.stopPropagation();printBarcode(\'' + esc(it.barcode) + '\',\'' + esc(it.part_number) + '\',\'' + esc(it.name) + '\')">Etiqueta</button>' +
'</td></tr>';
}
@@ -93,7 +95,7 @@
var tbody = document.getElementById('productTableBody');
var items = data.data || [];
if (!items.length) {
tbody.innerHTML = '<tr><td colspan="11" style="text-align:center;padding:30px;color:var(--color-text-muted);">Sin productos</td></tr>';
tbody.innerHTML = '<tr><td colspan="12" style="text-align:center;padding:30px;color:var(--color-text-muted);">Sin productos</td></tr>';
document.getElementById('productPagination').innerHTML = '';
return;
}
@@ -104,7 +106,7 @@
rowHeight: 48,
buffer: 3,
renderRow: renderInventoryRow,
emptyHtml: '<tr><td colspan="11" style="text-align:center;padding:30px;color:var(--color-text-muted);">Sin productos</td></tr>'
emptyHtml: '<tr><td colspan="12" style="text-align:center;padding:30px;color:var(--color-text-muted);">Sin productos</td></tr>'
});
}
inventoryVS.setData(items);
@@ -236,6 +238,10 @@
function showPurchaseModal() {
document.getElementById('purchaseModal').classList.add('is-open');
}
function showPurchaseModalForItem(itemId) {
document.getElementById('purchaseItemId').value = itemId;
showPurchaseModal();
}
function closePurchaseModal() {
document.getElementById('purchaseModal').classList.remove('is-open');
document.getElementById('purchaseResult').innerHTML = '';
@@ -254,9 +260,18 @@
return;
}
apiFetch(API + '/purchase', { method: 'POST', body: JSON.stringify(data) }).then(function (result) {
document.getElementById('purchaseResult').innerHTML = result && result.operation_id
? '<span style="color:var(--color-success);">Compra registrada (op #' + result.operation_id + ')</span>'
: '<span style="color:var(--color-error);">' + (result ? result.error || 'Error' : 'Error de red') + '</span>';
if (result && result.operation_id) {
document.getElementById('purchaseResult').innerHTML = '<span style="color:var(--color-success);">Compra registrada (op #' + result.operation_id + ')</span>';
closePurchaseModal();
['purchaseItemId','purchaseQty','purchaseCost','purchaseInvoice','purchaseNotes'].forEach(function(id) {
var el = document.getElementById(id);
if (el) el.value = '';
});
if (window.loadInventoryStats) window.loadInventoryStats();
loadItems(currentPage);
} else {
document.getElementById('purchaseResult').innerHTML = '<span style="color:var(--color-error);">' + (result ? result.error || 'Error' : 'Error de red') + '</span>';
}
});
}
@@ -599,6 +614,7 @@
// Product info header
html += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">';
html += '<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">ID Inventario</span><strong style="font-family:var(--font-mono);">' + data.id + '</strong></div>';
html += '<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">No. Parte</span><strong>' + esc(data.part_number) + '</strong></div>';
html += '<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Nombre</span><strong>' + esc(data.name) + '</strong></div>';
html += '<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">Marca</span>' + esc(data.brand) + '</div>';
@@ -796,6 +812,7 @@
window.closeCreateModal = closeCreateModal;
window.createItem = createItem;
window.showPurchaseModal = showPurchaseModal;
window.showPurchaseModalForItem = showPurchaseModalForItem;
window.closePurchaseModal = closePurchaseModal;
window.recordPurchase = recordPurchase;
window.showAdjustmentModal = showAdjustmentModal;