Dashboard
Resumen general del sistema de bodegas, inventario y colaboradores.
Bodegas registradas
0
Colaboradores activos
0
Productos con stock bajo
0
Valor total inventario
$0
Colaboradores del sistema
El administrador puede activar o deshabilitar el acceso al inventario.
IDNombreEstadoBodegas asignadasProductos a cargoAcceso inventarioAcciones
Mejoras incorporadas

Esta vista incluye ajustes contables por producto, ingresos, egresos y traslados entre bodegas con flujo simplificado por lista.

Empleados
Listado general de colaboradores registrados en el sistema.
IDNombreEstadoBodegas asignadasProductos a cargoAcción
Módulo de Bodegas
Administra bodegas, empleados encargados y productos por sucursal.
Listado de Bodegas
Vista general de bodegas y responsables.
N° BodegaNombreTipoEmpleado a cargoTotal artículosEstadoAcciones
Control de Stock
Inventario seleccionado
Total artículos
Vista simplificada para conteo físico, ajuste contable y búsqueda por categoría o tipo.
CódigoProductoEmpleado a cargoInventario actualInventario realPrecio ventaTotalEstado stockAjuste contableAcciones
Reportes
Vista rápida de indicadores del inventario.
Productos totales
0
Bodega con más productos
-
Colaborador con más productos
-
fillProductFilterSelects(); selectedBodegaId = bodegaId; this.reset(); document.getElementById("productoEditId").value = ""; modalProducto.hide(); if (inventarioModo === "empleado") selectedEmpleadoId = encargadoId; else { inventarioModo = "bodega"; selectedBodegaId = bodegaId; } renderInventario(searchProducto.value); renderBodegas(searchBodega.value); renderEmpleados(); renderDashboardColaboradores(); renderSidebarColaboradores(); renderKPIs(); showPage("page-inventario"); setActiveMainMenu("page-inventario"); }); document.getElementById("formOperacion").addEventListener("submit", function(e) { e.preventDefault(); const modo = document.getElementById("operacionModo").value; const seleccionados = getOperacionSeleccionados(); if (!seleccionados.length) { showToast("Agrega al menos un producto a la lista."); return; } const mensajeConfirmacion = modo === "traslado" ? "¿Está seguro de guardar el traslado?" : modo === "egreso" ? "¿Está seguro de guardar el egreso?" : "¿Está seguro de guardar el ingreso?"; if (!confirm(mensajeConfirmacion)) return; if (modo === "traslado") { const destinoId = Number(document.getElementById("trasladoDestino").value); if (!destinoId) { showToast("Selecciona una bodega destino."); return; } const destino = getBodegaById(destinoId); seleccionados.forEach(({ producto, cantidad }) => { const qty = Number(cantidad || 0); if (!qty || qty > producto.cantidad) return; producto.cantidad -= qty; producto.inventarioReal = Math.min(Number(producto.inventarioReal ?? producto.cantidad), producto.cantidad); producto.movimientos = producto.movimientos || []; producto.movimientos.push({ tipo: "salida", fecha: nowString(), detalle: `Traslado de ${qty} unidades hacia ${destino.nombre}` }); const existente = productos.find(x => x.bodegaId === destinoId && x.codigo === producto.codigo); if (existente) { existente.cantidad += qty; existente.inventarioReal = Number(existente.inventarioReal ?? existente.cantidad) + qty; existente.movimientos = existente.movimientos || []; existente.movimientos.push({ tipo: "entrada", fecha: nowString(), detalle: `Ingreso por traslado desde ${getBodegaNombre(producto.bodegaId)}` }); } else { productos.push({ id: Date.now() + Math.floor(Math.random()*1000), bodegaId: destinoId, encargadoId: destino.encargadoId, codigo: producto.codigo, nombre: producto.nombre, cantidad: qty, inventarioReal: qty, precioCompra: producto.precioCompra || 0, precio: producto.precio1 || producto.precio || 0, precio1: producto.precio1 || producto.precio || 0, precio2: producto.precio2 || 0, precio3: producto.precio3 || 0, minimo: producto.minimo, categoria: producto.categoria, tipoProducto: producto.tipoProducto || '', descripcion: producto.descripcion, movimientos: [{ tipo: "registro", fecha: nowString(), detalle: `Creado en destino por traslado desde ${getBodegaNombre(producto.bodegaId)}` }, { tipo: "entrada", fecha: nowString(), detalle: `Ingreso por traslado desde ${getBodegaNombre(producto.bodegaId)}` }] }); } }); productos = productos.filter(p => p.cantidad > 0); showToast(`Traslado guardado correctamente hacia ${destino.nombre}.`); } else { const motivo = document.getElementById("operacionMotivo").value; if (!motivo) { showToast("Selecciona un motivo."); return; } seleccionados.forEach(({ producto, cantidad }) => { const qty = Number(cantidad || 0); if (!qty) return; if (modo === "egreso") { if (qty > producto.cantidad) return; producto.cantidad -= qty; producto.inventarioReal = Math.min(Number(producto.inventarioReal ?? producto.cantidad), producto.cantidad); producto.movimientos = producto.movimientos || []; producto.movimientos.push({ tipo: "salida", fecha: nowString(), detalle: `Egreso por ${motivo}: ${qty} unidades` }); } else { producto.cantidad += qty; producto.inventarioReal = Number(producto.inventarioReal ?? producto.cantidad) + qty; producto.movimientos = producto.movimientos || []; producto.movimientos.push({ tipo: "entrada", fecha: nowString(), detalle: `Ingreso por ${motivo}: ${qty} unidades` }); } }); productos = productos.filter(p => p.cantidad > 0); showToast(modo === "egreso" ? `Egreso guardado correctamente por motivo: ${motivo}.` : `Ingreso guardado correctamente por motivo: ${motivo}.`); } fillProductFilterSelects(); resetOperacionEstado(); modalOperaciones.hide(); renderInventario(searchProducto.value); renderBodegas(searchBodega.value); renderEmpleados(); renderDashboardColaboradores(); renderSidebarColaboradores(); renderKPIs(); }); searchBodega.addEventListener("input", function() { renderBodegas(this.value); }); searchProducto.addEventListener("input", function() { renderInventario(this.value); }); document.getElementById("filterCategoriaProducto").addEventListener("change", function() { renderInventario(searchProducto.value); }); document.getElementById("filterTipoProducto").addEventListener("change", function() { renderInventario(searchProducto.value); }); document.getElementById("operacionSearch").addEventListener("input", renderOperacionLista); document.getElementById("operacionCategoria").addEventListener("change", renderOperacionLista); document.getElementById("operacionTipo").addEventListener("change", renderOperacionLista); document.getElementById("modalProducto").addEventListener("show.bs.modal", function() { if (!document.getElementById("productoEditId").value) { if (inventarioModo === "bodega") { document.getElementById("productoBodega").value = selectedBodegaId || ""; const b = getBodegaById(selectedBodegaId); if (b) document.getElementById("productoEncargado").value = b.encargadoId; } } }); document.querySelectorAll(".nav-main-link").forEach(link => { link.addEventListener("click", function() { const pageId = this.dataset.page; if (pageId === "page-inventario") { openInventarioGeneral(); return; } showMainPage(pageId); }); }); document.getElementById("submenuBodegasGeneral").addEventListener("click", function() { showPage("page-bodegas"); setActiveMainMenu("page-bodegas"); activateSubmenuGeneral(); }); document.getElementById("toggleBodegasMenu").addEventListener("click", function() { const submenu = document.getElementById("bodegasSubmenu"); const arrow = document.getElementById("bodegasArrow"); submenu.classList.toggle("show"); arrow.classList.toggle("open"); }); function init() { fillEmployeeSelects(); fillBodegaSelect(); fillProductFilterSelects(); renderSidebarColaboradores(); renderKPIs(); renderBodegas(); renderEmpleados(); renderDashboardColaboradores(); renderInventario(); showPage("page-dashboard"); setActiveMainMenu("page-dashboard"); } init();