Spec de M7 — Retornables
Dominio: Botellones y bases — 19 reglas, 13 confirmadas.
Estado: 📝 Diseñado — por planificar.
M7 llena las tres cuentas que faltan
Sección titulada «M7 llena las tres cuentas que faltan»La ficha del cliente lleva cuatro saldos (RN-CLI-06). M6 llenó la deuda; las
otras tres —botellones en su poder, bases prestadas y cargos
pendientes— siguen diciendo «sin registrar todavía». Las tres son de acá.
El milestone es un contraste
Sección titulada «El milestone es un contraste»Dos activos retornables, dos modelos opuestos, y la diferencia no es un detalle de implementación: es la razón de ser de cada uno.
| Botellón | Base | |
|---|---|---|
| Identidad | Ninguna (RN-ENV-01) |
ID único en un sticker (RN-BAS-01) |
| Se rastrea por | Cantidad | Unidad |
| Saldo a nivel | Cliente (RN-ENV-04) |
Dirección (RN-BAS-03) |
| Si se daña | Nada — sin depósito ni recargo | Recargo (RN-BAS-08) |
Por qué el botellón no tiene ID: el intercambio tiene que seguir siendo de baja fricción. Identificar cada envase agregaría un paso a cada visita sin responder ninguna pregunta nueva — para reclamar ocho botellones no hace falta saber cuáles ocho.
Por qué la base sí: hay que ir a buscarla a un lugar concreto. Sin saber en
cuál de los tres locales está la base 0913, el préstamo deja de ser
reclamable.
La compuerta es la ley de conservación
Sección titulada «La compuerta es la ley de conservación»RN-ENV-02 no es una regla más — es el invariante del módulo, y el propio
dominio dice qué hacer con él:
«Este invariante es un test. Escribilo temprano, corrélo seguido, y hacelo fallar ruidosamente.»
Σ(saldos de todos los tenedores) = Σ compras − Σ descartesSin ID individual, esa igualdad es lo único que avisa que algo se perdió. Un botellón que desaparece no deja hueco en ninguna tabla: deja la suma descuadrada, y nada más.
Por eso el libro es de deltas con signo sobre un tenedor, y una entrega escribe dos filas —una que resta de la bodega y otra que suma al cliente— en la misma transacción. Así el invariante se verifica con una consulta, y una transferencia mal escrita lo rompe de inmediato en vez de esconderse.
La contradicción entre dos reglas confirmadas
Sección titulada «La contradicción entre dos reglas confirmadas»RN-BAS-08 dice que el recargo por daño es una venta —para preservar la
auditoría unificada— y que puede ser a crédito.
RN-CLI-06 dice que los cargos pendientes son distintos de la deuda,
«porque no nacen de una venta a crédito».
Las dos están confirmadas y se contradicen: si el recargo es una venta a crédito, cae en la deuda; si es un cargo aparte, no es una venta.
Cómo se resuelve
Sección titulada «Cómo se resuelve»Las dos cosas a la vez, y se puede. El recargo se registra como una venta con
tipo = 'dano_base', así que hereda toda la auditoría del módulo de ventas: es
inmutable, se anula con motivo, queda con su autor. Y deudaDe excluye ese
tipo, mientras una consulta nueva lo cuenta como cargos pendientes.
Cada regla obtiene lo que pedía:
RN-BAS-08quería auditoría unificada → la tiene, es una venta de verdad.RN-CLI-06quería que no se mezcle con la deuda → no se mezcla, porque el saldo filtra por tipo.
Lo que se agrega es una columna tipo en ventas, y la obligación de que
todas las consultas de deuda la respeten. Eso lo vuelve un invariante nuevo:
un deudaDe que se olvide del filtro le cobraría al cliente un daño como si
fuera producto.
El modelo
Sección titulada «El modelo»movimientos_botellon bases id id cliente_id → clientes NULL id_sticker UNIQUE (NULL = bodega de la empresa) estado sana|danada cantidad ± enteros, nunca 0 direccion_id → direcciones NULL tipo compra|entrega|retorno| (NULL = en la bodega) descarte|ajuste danada_por / danada_en motivo recargo_venta_id → ventas NULL documento_id → ventas NULL registrado_por movimientos_base (historial, RN-BAS-05) base_id → basesventas tipo prestamo|retorno|dano|descarte + tipo producto|dano_base direccion_id NULL CHECK: dano_base ⟹ sin líneas motivo · registrado_porEl botellón no tiene tabla propia, y es correcto
Sección titulada «El botellón no tiene tabla propia, y es correcto»No hay una tabla botellones. No hay nada que guardar de un botellón: no
tiene identidad, no tiene estado, no tiene historia propia. Lo único que existe
son los movimientos, y los saldos se derivan de ellos.
Crear una tabla con una fila por botellón físico sería inventar la identidad que
RN-ENV-01 decidió no tener.
Lo que M7 NO construye
Sección titulada «Lo que M7 NO construye»- Estado lleno/vacío del botellón.
RN-ENV-07lo pone explícitamente fuera de alcance: «no se modela». Adelantarlo es el error que la propia documentación cita como ejemplo cuando descarta otras cosas. - Tope de botellones por cliente.
RN-BAS-11: sin tope duro; eladminaprueba casos atípicos. Sin un número que el negocio haya decidido, no hay con qué bloquear. - Rutas. El
direccion_idde una base ya existe desde M5; qué ruta la visita es M8.
Definition of Done
Sección titulada «Definition of Done»- La ley de conservación es un test que corre en cada suite y falla
ruidosamente:
Σ saldos = Σ compras − Σ descartes. - Entregar botellones escribe dos filas y el invariante sigue cerrando.
- El saldo de botellones de un cliente sale de sus movimientos, nunca de una columna editable.
- Una base está en exactamente un lugar: prestarla mientras ya está prestada se rechaza.
- Un
id_stickerno se repite. - Entregar una base a un cliente sin verificar se rechaza (
RN-BAS-07). - Marcar una base como dañada genera una venta
dano_basecon su motivo. - Esa venta no aparece en la deuda y sí en los cargos pendientes.
- Una venta
dano_baseno puede tener líneas, y una deproductono puede estar sin ellas — las dos sostenidas por la base. - La ficha del cliente muestra las tres cuentas que faltaban, con números.
