Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Carlos-Gnd/FERRED-Inventario-y-Ventas/llms.txt

Use this file to discover all available pages before exploring further.

El módulo de inventario de Ferred gestiona el stock de forma independiente por sucursal. Cada sede mantiene su propia tabla StockSucursal (par único productoId + sucursalId), lo que permite que el inventario refleje la realidad física de cada local sin interferir con las demás. Los administradores tienen visibilidad consolidada de todas las sucursales; los usuarios con rol BODEGA o CAJERO solo ven su sede asignada.

Stock por sucursal

El modelo StockSucursal almacena la cantidad disponible y el umbral mínimo para cada producto en cada sucursal:
model StockSucursal {
  id         Int      @id @default(autoincrement())
  productoId Int      @map("producto_id")
  sucursalId Int      @map("sucursal_id")
  cantidad   Int      @default(0)
  minimo     Int      @default(0)
  // ...
  @@unique([productoId, sucursalId])
  @@map("stock_sucursal")
}
Para consultar el stock de una sucursal:
GET /api/inventario/stock/:sucursalId
El servidor verifica la conectividad antes de responder:
  • Online: devuelve los datos de Prisma y los almacena en OfflineCache con TTL de 5 minutos.
  • Offline (o Prisma caído): devuelve los datos de obtenerStockSucursalSqlite(sucursalId) directamente desde SQLite.

Alertas de stock crítico

Un producto se considera en estado de alerta cuando su cantidad es menor o igual al minimo configurado para esa sucursal.
EstadoCondiciónDescripción
disponiblecantidad > minimoStock dentro del rango normal
bajocantidad <= minimo y cantidad > 0Por debajo del umbral mínimo
criticocantidad = 0Sin existencias en la sucursal
Este cálculo se aplica directamente en las consultas SQL y en el endpoint de stock comparativo:
estado:
  s.cantidad === 0       ? 'critico'   :
  s.cantidad <= s.minimo ? 'bajo'      :
                           'disponible'
El umbral minimo se configura por producto por sucursal, no de forma global. Una sucursal con mayor rotación puede tener un minimo más alto para el mismo artículo. Ajústalo con PATCH /api/inventario/:productoId/ajuste pasando el campo minimo en el cuerpo.

Ajuste de stock

Para corregir el stock de un producto en una sucursal (inventario físico, merma, donación, etc.):
PATCH /api/inventario/:productoId/ajuste
Roles permitidos: ADMIN, BODEGA. Cuerpo de la solicitud:
{
  "sucursalId": 1,
  "cantidad": 50,
  "minimo": 10,
  "motivo": "Conteo físico mensual"
}
CampoTipoObligatorioDescripción
sucursalIdnumberSucursal donde se ajusta el stock
cantidadnumberNueva cantidad absoluta (no es un incremento)
minimonumberNoNuevo umbral mínimo (default 0)
motivostringNoRazón del ajuste, queda en el log de sync
El ajuste usa upsert: crea el registro si no existía o lo actualiza si ya existía. Tras el ajuste, recalcula stockActual sumando todas las sucursales y actualiza el campo en Producto.

Transferencias entre sucursales

Para mover stock de una sucursal a otra sin pasar por una venta:
POST /api/inventario/transferencia
Rol permitido: solo ADMIN.
{
  "productoId": 5,
  "origenId": 1,
  "destinoId": 2,
  "cantidad": 20
}
La operación es atómica: el decremento en origen y el incremento en destino ocurren en la misma transacción de Prisma. Si el origen no tiene stock suficiente, la transacción falla con HTTP 409 antes de modificar nada.

Stock comparativo

Para ver todos los productos con su stock desglosado por sucursal en una sola consulta:
GET /api/inventario/stock-comparativo
Roles permitidos: ADMIN, BODEGA. La respuesta es un arreglo de productos, cada uno con un campo sucursales que incluye cantidad, minimo y estado por sede:
[
  {
    "id": 5,
    "nombre": "Pintura Blanca 1 galón",
    "stockTotal": 85,
    "sucursales": [
      { "sucursalId": 1, "sucursalNombre": "Central", "cantidad": 60, "minimo": 10, "estado": "disponible" },
      { "sucursalId": 2, "sucursalNombre": "Norte",   "cantidad": 25, "minimo": 30, "estado": "bajo" }
    ]
  }
]

Modo offline

El sistema implementa un caché de respaldo con OfflineCache (TTL de 5 minutos) y lectura directa desde SQLite cuando Prisma no está disponible.
OfflineCache.set(key, data) almacena la respuesta en memoria con marca de tiempo. Al recibir una petición, el servidor primero comprueba conectividad con SyncService.checkConnectivity(). Si la respuesta falla con un código Prisma de conexión (P1001, P1002, P1008, P1017) o con mensajes como ECONNREFUSED, el handler cae al bloque catch y devuelve los datos de SQLite sin propagar el error.
El caché se invalida automáticamente al realizar ajustes de stock (OfflineCache.invalidate('stock:<sucursalId>')) y transferencias (OfflineCache.invalidate('stock:<origenId>'), OfflineCache.invalidate('stock:<destinoId>')). También se invalida la clave productos: al crear o editar productos.

Build docs developers (and LLMs) love