Del CRUD al mantenimiento real
Publicado: Dom Sep 20, 2026 6:19 pm
trazabilidad, transacciones y auditoría con Delphi + SQLite
Durante las últimas sesiones de PC Shop he trabajado en algo que va más allá de añadir una nueva función: hacer evolucionar una aplicación que ya contiene datos sin romper su histórico.
Hasta ahora PRODUCTOS.Stock indicaba cuántas unidades quedaban, pero no explicaba cómo se había llegado hasta ese valor.
Para resolverlo se añadió MOVIMIENTOS_STOCK:
La regla utilizada es:
Además, modificación de stock y registro del movimiento forman una única transacción:
Si algo falla, se ejecuta ROLLBACK.
Integración con las ventas
Las ventas generan ahora automáticamente una SALIDA de stock:
El identificador se obtiene mediante:
y queda relacionado así:
Los movimientos manuales mantienen IdVenta = NULL.
Auditoría
Después se añadió una comprobación capaz de detectar:
- ventas sin movimiento;
- movimientos duplicados;
- movimientos asociados a ventas inexistentes;
- diferencias entre cantidad vendida y salida de stock.
La primera auditoría produjo:
Pero esas 8 ventas no eran errores: eran ventas históricas creadas antes de existir MOVIMIENTOS_STOCK.
Para distinguirlas se añadió:
De esta forma:
La migración se realiza sin borrar datos mediante:
Después del cambio:
Finalmente se añadió una protección adicional en SQLite:
Así una venta no puede terminar accidentalmente con dos movimientos asociados, mientras que los movimientos manuales pueden seguir utilizando IdVenta = NULL.
El resultado combina varias capas:
Este bloque me ha servido especialmente para trabajar mantenimiento de aplicaciones existentes, migraciones de esquema, compatibilidad con datos antiguos, FireDAC, SQLite, transacciones, logging, auditoría e integridad de datos.
Artículo completo en InformatOLI . org
[]
Durante las últimas sesiones de PC Shop he trabajado en algo que va más allá de añadir una nueva función: hacer evolucionar una aplicación que ya contiene datos sin romper su histórico.
Hasta ahora PRODUCTOS.Stock indicaba cuántas unidades quedaban, pero no explicaba cómo se había llegado hasta ese valor.
Para resolverlo se añadió MOVIMIENTOS_STOCK:
Código: Seleccionar todo
ENTRADA +5
SALIDA -2
AJUSTE +3
AJUSTE -1
Código: Seleccionar todo
StockNuevo = StockActual + Cantidad
Código: Seleccionar todo
BEGIN TRANSACTION
↓
UPDATE PRODUCTOS.Stock
↓
INSERT MOVIMIENTOS_STOCK
↓
COMMIT
Integración con las ventas
Las ventas generan ahora automáticamente una SALIDA de stock:
Código: Seleccionar todo
INSERT VENTA
↓
obtener IdVenta
↓
UPDATE STOCK
↓
INSERT MOVIMIENTO_STOCK
↓
COMMIT
Código: Seleccionar todo
SELECT last_insert_rowid();
Código: Seleccionar todo
VENTAS.Id = 37
MOVIMIENTOS_STOCK.IdVenta = 37
Auditoría
Después se añadió una comprobación capaz de detectar:
- ventas sin movimiento;
- movimientos duplicados;
- movimientos asociados a ventas inexistentes;
- diferencias entre cantidad vendida y salida de stock.
La primera auditoría produjo:
Código: Seleccionar todo
Ventas revisadas: 9
Sin movimiento: 8
Duplicados: 0
Huérfanos: 0
Cantidades incoherentes: 0
Para distinguirlas se añadió:
Código: Seleccionar todo
Trazable INTEGER NOT NULL DEFAULT 0
Código: Seleccionar todo
Trazable = 0 → venta histórica
Trazable = 1 → venta sometida a las reglas actuales
Código: Seleccionar todo
PRAGMA table_info(VENTAS)
ALTER TABLE VENTAS
ADD COLUMN Trazable INTEGER NOT NULL DEFAULT 0;
Código: Seleccionar todo
Ventas revisadas: 1
Sin movimiento: 0
Duplicados: 0
Huérfanos: 0
Cantidades incoherentes: 0
TRAZABILIDAD CORRECTA
Código: Seleccionar todo
CREATE UNIQUE INDEX IF NOT EXISTS UX_MOVIMIENTOS_STOCK_IdVenta
ON MOVIMIENTOS_STOCK(IdVenta)
WHERE IdVenta IS NOT NULL;
El resultado combina varias capas:
Código: Seleccionar todo
Lógica Delphi
+
Transacciones
+
Auditoría
+
Restricciones SQLite
↓
Mayor integridad de datos
Artículo completo en InformatOLI . org
[]