La mayoría de los sistemas de inventario tiene un número que cambia. Quotery tiene un movimiento tipado para cada cambio — así '¿por qué este producto bajó 3?' no es un misterio, es un JOIN.
El enfoque de número único es seductor en su simplicidad. UPDATE stock_item SET quantity = quantity - 3 WHERE sku = 'AB-001'. Una consulta, listo. Pero esa consulta no te dice nada sobre por qué se movieron 3 unidades. ¿Fue una venta? ¿Una devolución? ¿Un ajuste de almacén? ¿Una corrección de un conteo equivocado del mes pasado? El número cambió, la razón se evaporó. Seis meses después, cuando el auditor pregunta, la respuesta es 'no sé — el sistema dice que lo despachamos.' El sistema es correcto pero inútil para entender.
Los seis tipos RESERVE (cotización cerrada), RELEASE (cotización cancelada desde closed), SHIP (nota de entrega posteada), RETURN (nota de devolución posteada), RECEIVE (recepción de proveedor posteada), ADJUSTMENT (corrección manual solo de admin). Cada tipo tiene signo esperado y documento fuente esperado.
El sistema de tipos es lo que le da al ledger su poder explicativo. Un movimiento RESERVE significa algo diferente de un movimiento SHIP, incluso si mueven la misma cantidad. El tipo te dice el evento de negocio que causó el movimiento. La FK del documento fuente te dice exactamente qué cotización, entrega, devolución o recepción lo disparó. El timestamp te dice cuándo. El usuario que inició la transacción te dice quién. Cada dimensión del 'por qué' está capturada en la fila.
Delta con signo
RESERVE escribe on_hand=0, reserved=+N. SHIP escribe on_hand=-N, reserved=-N. El ledger guarda el delta; el caché guarda el saldo corriente.
La separación de delta y total es lo que hace el ledger reconstruible. Cada fila es autocontenida: registra el cambio exacto en on_hand y reserved en ese momento. Para computar el estado en cualquier punto en el tiempo, suma todos los deltas hasta ese punto. No hay necesidad de confiar en el caché — el caché es solo una vista materializada del ledger, y cualquier discrepancia se resuelve re-sumando, nunca editando el ledger.
Un documento fuente, un movimiento Postear una DeliveryNote crea un movimiento SHIP con el id de la entrega. Cancelar un Quote cerrado crea un RELEASE con el id de la cotización. La FK es opcional solo para ADJUSTMENT — e incluso ahí requerimos una nota no vacía.
La nota obligatoria en ADJUSTMENT es la válvula de seguridad. Las correcciones manuales ocurren — los conteos de inventario varían, los productos se dañan, las muestras se toman para pruebas de calidad. Cuando un admin ajusta el inventario manualmente, el campo de nota captura la explicación humana: 'Conteo físico encontró 2 unidades menos que el sistema — probablemente dañadas durante la ola de calor de junio.' Esa nota es visible en el ledger y en la pista de auditoría. No es un sustituto de un proceso adecuado, pero es un registro durable de un evento excepcional.
