Ir al contenido

Stock de producto

Esta página cubre el producto — lo que se vende y no vuelve.

El sistema controla cuatro tipos de existencia. Confundirlas es el error más caro que se puede cometer en este dominio.

Producto Insumo Botellón Base
Ejemplo Paca de agua Tapa, sello Envase de 20 L Soporte
Se vende Sí No No No
Vuelve No No Se espera que sí Sí, es un préstamo
Se identifica Por producto Por tipo Solo cantidad ID individual
Al salir Baja por venta Baja por producción Cambia de ubicación Cambia de ubicación

RN-STK-01 — El producto vive en un solo lugar: la bodega de la planta

Sección titulada «RN-STK-01 — El producto vive en un solo lugar: la bodega de la planta»

Estado: ✅ Confirmada — 22-ago-2026. Corrige la versión anterior de esta regla, que suponía dos ubicaciones.

Todo el producto terminado está en la bodega de la planta. No hay stock en otro lado, y por lo tanto el stock no lleva ubicación: es cantidad por producto y lote, y nada más.

Por qué no se modela una ubicación con un solo valor posible: una columna que hoy solo puede valer BODEGA la arrastra cada consulta, la repite cada test y no permite verificar que el filtrado funcione, porque no hay contra qué comparar. Es complejidad que se paga durante meses a cambio de una migración que tal vez nunca haga falta.


RN-STK-02 — Todo movimiento de stock queda registrado con motivo y responsable

Sección titulada «RN-STK-02 — Todo movimiento de stock queda registrado con motivo y responsable»

Estado: 🟡 Supuesto

El stock nunca se edita directamente. Se mueve mediante documentos:

Documento Efecto Módulo
Cierre de producción ➕ Producto · ➖ Tapas y sellos M4
Compra recibida ➕ Insumos, no producto terminado M9
Venta ➖ Producto M6
Devolución sana ➕ Producto, al mismo lote M6
Descarte ➖ Producto, con causa M2
Ajuste de inventario ± con motivo obligatorio M2

Los tres documentos de ruta —carga, venta en ruta y devolución de ruta— ya no existen: dependían de una segunda ubicación que RN-STK-01 descartó.

Por qué: un stock editable a mano es un stock que nadie cree. El ajuste existe —el inventario físico siempre difiere— pero es un documento con nombre, fecha y motivo, no un UPDATE.


RN-STK-03 — No se puede vender lo que no hay

Sección titulada «RN-STK-03 — No se puede vender lo que no hay»

Estado: ✅ Confirmada — 22-ago-2026. Se simplifica junto con RN-STK-01.

Una venta solo puede despachar producto que exista y no esté vencido. No hay venta con stock negativo.

Por qué: permitir negativo convierte el inventario en una sugerencia. Y un inventario que es una sugerencia no sirve para pedir insumos, ni para detectar un faltante, ni para cerrar el día.

Dónde se hace cumplir: en la base, no solo en el servicio (ADR-0006). Un saldo que no puede ser negativo es exactamente el tipo de invariante que un CHECK garantiza aunque un endpoint nuevo se olvide de validarlo.



RN-STK-04 — Los insumos de empaque son stock, y se consumen por producción

Sección titulada «RN-STK-04 — Los insumos de empaque son stock, y se consumen por producción»

Estado: ✅ Confirmada

Tapas y sellos termoencogibles forman parte del stock y se controlan por cantidad, igual que el producto.

Insumo Se consume cuando
Tapa para botellón Se llena y sella un botellón
Sello termoencogible Se llena y sella un botellón

La diferencia con el producto: el insumo no sale por venta, sale por producción (RN-PRD-09).

Por qué: una planta sin tapas no produce, por más agua que tenga en los tanques. Si el insumo no está en el sistema, nadie se entera de que se está acabando hasta que se acabó.


RN-STK-08 — Cada cierre de producción genera un lote, vencimiento automático a 30 días

Sección titulada «RN-STK-08 — Cada cierre de producción genera un lote, vencimiento automático a 30 días»

RN-STK-11 — El aviso de vencimiento próximo se configura, no se codifica

Sección titulada «RN-STK-11 — El aviso de vencimiento próximo se configura, no se codifica»

Estado: ✅ Confirmada — cierra la pregunta 36 (22-ago-2026).

Un lote se marca «vence pronto» cuando le quedan 7 días o menos de vida.

Ese número es el valor inicial, no una constante del negocio: tiene que poder ajustarse desde la administración sin tocar código. Va con los demás umbrales configurables de M12 · Alertas.

Por qué 7 para empezar: la vida útil son 30 días (RN-STK-08), así que siete deja una cuarta parte para reaccionar — y «lo que vence esta semana» se dice fácil en la planta.

Por qué configurable: el número correcto depende de la rotación real, y esa todavía no se midió. Un umbral que avisa tarde no sirve; uno que avisa demasiado pronto entrena a ignorar el aviso, que es peor. Cuando haya datos de venta se va a querer moverlo, y eso no puede exigir un despliegue.

Entregado en M12 (7-sep-2026). Vive en la tabla parametros, clave dias_aviso_vencimiento, y se mueve desde Alertas en la administración. La constante DIAS_DE_AVISO_DE_VENCIMIENTO se borró — no quedó como default, porque un default en el código más una fila en la base son dos lugares donde configurar lo mismo.

El umbral viaja con los lotes (/stock/:id/lotes devuelve diasDeAvisoDeVencimiento): configurarlo es de admin, pero mirarlo es de quien ve stock, y el pos no tiene configuracion:ver.

Estado: ✅ Confirmada — cerrá la pregunta 🟢 “¿Hay control de lotes o vencimiento?” de Qué falta preguntar.

cierre_produccion_diario = {
...,
lote_generado: "YYYY-MM-DD-L1", // generado por el sistema al cerrar
fecha_empaque: date,
...
}
producto_unidad = {
sku: ...,
lote_id: lote_id,
fecha_empaque: date,
fecha_vencimiento: date, // = fecha_empaque + 30 días
...
}

Reglas:

  • Vencimiento automático: vencimiento = empaque + 30 días. No se tipea a mano — lo calcula el sistema.
  • Lote generado al cerrar la producción: el formato YYYY-MM-DD-L1 (fecha + secuencia) sale del sistema y se imprime en la bolsa física por el pos.
  • Trazabilidad: cada venta registra el lote_id vendido. Si hay recall o producto defectuoso, se identifica a qué clientes se les vendió.
  • FIFO en bodega: las ventas sacan primero el producto con vencimiento más próximo (lote más viejo).
  • Vencidos se bloquean automáticamente: el stock con fecha_vencimiento < hoy no se ofrece para la venta.

Por qué importa: anticipar la trazabilidad desde el MVP. Si en el futuro hay un recall, poder decir “esta venta se hizo con el lote X, esos clientes son los afectados” es invaluable.


RN-STK-05 — Devoluciones vuelven al stock si están sanas; vencidas o dañadas se descartan

Sección titulada «RN-STK-05 — Devoluciones vuelven al stock si están sanas; vencidas o dañadas se descartan»

Estado: ✅ Confirmada — cerrá la pregunta 🟢 “¿Se aceptan devoluciones de producto, o solo anulación de la venta completa?” de Qué falta preguntar.

Ver RN-VEN-10 para el flujo de la venta con devolución. Esta regla cubre el lado del stock:

Estado del producto devuelto Acción de stock
sano Vuelve al mismo lote en BODEGA. Sigue su vida normal.
vencido Descarte directo sin clasificar causa (vencimiento es objetivo).
danado Dispara el flujo de descarte con clasificación de causa (RN-STK-06).

RN-STK-06 — Descarte de producto: selectivo por unidad, causa obligatoria, sin castigo automático

Sección titulada «RN-STK-06 — Descarte de producto: selectivo por unidad, causa obligatoria, sin castigo automático»

Estado: ✅ Confirmada — cerrá la pregunta 🟢 “¿Puede descartarse producto ya envasado por calidad?” de Qué falta preguntar.

Una unidad dañada o vencida se puede descartar sin destruir el lote entero. Solo las unidades afectadas.

descarte = {
id: uuid,
unidades: [{ sku, lote_id, fecha_vencimiento, ... }, ...],
causa: "falla_produccion" | "mal_manejo_cliente" | "otro" | "vencido",
registrado_por: user_id, // pos o admin
registrado_en: timestamp,
observaciones: string,
reemplazo_generado_id: venta_id | null, // si causa == falla_produccion
cliente_afectado_id: cliente_id | null, // si aplica
}

Política por causa:

Causa ¿Reemplazo al cliente? ¿Quién paga? Sistema registra
falla_produccion ✅ sí Aquazaku Descarte + reposición
mal_manejo_cliente ❌ no Cliente asume Descarte + entrada al historial del cliente
vencido ❌ no Nadie Descarte (sin clasificar)
otro depende de revisión admin depende Descarte + flag para revisión

El pos o admin debe clasificar la causa obligatoriamente al registrar. Sin clasificar, no se descarta.

Patrón compartido con RN-BAS-08 (recargo por daño de base):

  • El sistema hace visible el historial de descarte por mal_manejo_cliente per cliente.
  • El admin decide si inactiva al cliente. NO es castigo automático.
  • Visibilidad sin automatización: el poder de decisión queda en el humano.

RN-STK-07 — La planta de Campo de la Cruz es la única bodega y el único punto de venta

Sección titulada «RN-STK-07 — La planta de Campo de la Cruz es la única bodega y el único punto de venta»

Estado: ✅ Confirmada — cerrá las preguntas 🟢 “¿Hay más de un punto de venta?” y “¿Hay más de una bodega?” de Qué falta preguntar.

stock_locations = ["BODEGA"] // una sola

Implicaciones:

  • No hay modelo multi-bodega. No hay transferencias entre bodegas.
  • No hay stock itinerante (porque no hay seller con carga de camión — el seller solo contacta, ver modelo operativo).
  • pos vende directo desde BODEGA (RN-STK-01).
  • Si en algún momento Aquazaku abre una segunda planta o vende en otra ciudad, esta regla se reabre como decisión explícita — no es un toggle.

  • ¿Se controlan las bolsas como insumo, además de tapas y sellos?
  • ¿Se define stock mínimo de tapas y sellos que dispare alerta de reposición?
  • ¿Se compran insumos de tratamiento de agua? ¿Se controlan o son gasto?
  • ¿Se lleva cuenta corriente con proveedores o se paga contra entrega?
  • ¿Cada cuánto se hace inventario físico? — consolidada como pregunta 31.