feat: importar csv y auditar ediciones

This commit is contained in:
mono
2026-10-25 18:20:04 -05:00
parent 8e286d6fec
commit 01b5ee64cc
23 changed files with 483 additions and 19 deletions

View File

@@ -0,0 +1,29 @@
import { db } from '@toldo/data';
import type { Auditoria, EntidadAuditada } from '@toldo/core';
export interface DatosEdicion {
modificadoPor: string;
motivo: string;
}
export function validarEdicion(datos: DatosEdicion) {
if (!datos.modificadoPor.trim()) throw new Error('Indica quién realiza el cambio.');
if (!datos.motivo.trim()) throw new Error('Indica el motivo del cambio.');
}
export class AuditoriaService {
async registrar(entidad: EntidadAuditada, registroId: string, anteriores: unknown | undefined, nuevos: unknown, datos: DatosEdicion) {
validarEdicion(datos);
const auditoria: Auditoria = {
id: crypto.randomUUID(), entidad, registroId, operacion: anteriores ? 'EDITAR' : 'CREAR',
modificadoPor: datos.modificadoPor.trim(), motivo: datos.motivo.trim(),
valoresAnteriores: anteriores ? JSON.stringify(anteriores) : undefined,
valoresNuevos: JSON.stringify(nuevos), fecha: new Date(), createdAt: new Date(),
};
return db.auditorias.add(auditoria);
}
async listar(entidad?: EntidadAuditada) {
return entidad ? db.auditorias.where('entidad').equals(entidad).reverse().sortBy('fecha') : db.auditorias.orderBy('fecha').reverse().toArray();
}
}

View File

@@ -0,0 +1,37 @@
import { db } from '@toldo/data';
import type { Producto, Productor, Venta, VentaLinea } from '@toldo/core';
import { validarEdicion, type DatosEdicion } from './AuditoriaService';
export class EdicionService {
async editarProductor(productor: Productor, anterior: Productor, datos: DatosEdicion) {
validarEdicion(datos);
return db.transaction('rw', db.productores, db.auditorias, async () => {
await db.productores.put(productor);
await db.auditorias.add({ id: crypto.randomUUID(), entidad: 'PRODUCTOR', registroId: productor.id, operacion: 'EDITAR', ...datos, modificadoPor: datos.modificadoPor.trim(), motivo: datos.motivo.trim(), valoresAnteriores: JSON.stringify(anterior), valoresNuevos: JSON.stringify(productor), fecha: new Date(), createdAt: new Date() } as any);
});
}
async editarProducto(producto: Producto, anterior: Producto, datos: DatosEdicion) {
validarEdicion(datos);
return db.transaction('rw', db.productos, db.auditorias, async () => {
await db.productos.put(producto);
await db.auditorias.add({ id: crypto.randomUUID(), entidad: 'PRODUCTO', registroId: producto.id, operacion: 'EDITAR', ...datos, modificadoPor: datos.modificadoPor.trim(), motivo: datos.motivo.trim(), valoresAnteriores: JSON.stringify(anterior), valoresNuevos: JSON.stringify(producto), fecha: new Date(), createdAt: new Date() } as any);
});
}
async editarVenta(venta: Venta, anterior: Venta, lineasAnteriores: VentaLinea[], datos: DatosEdicion) {
validarEdicion(datos);
return db.transaction('rw', db.ventas, db.ventaLineas, db.movimientosInventario, db.auditorias, async () => {
const lineasNuevas = venta.lineas;
for (const anteriorLinea of lineasAnteriores) {
const nueva = lineasNuevas.find((linea) => linea.id === anteriorLinea.id);
if (!nueva) continue;
const diferencia = nueva.cantidad - anteriorLinea.cantidad;
if (diferencia) await db.movimientosInventario.add({ id: crypto.randomUUID(), fecha: new Date(), tipo: 'VENTA', productoId: nueva.productoId, cantidad: -diferencia, referenciaId: venta.id, motivo: `Corrección de venta: ${datos.motivo}`, createdAt: new Date() } as any);
await db.ventaLineas.put(nueva);
}
await db.ventas.put(venta);
await db.auditorias.add({ id: crypto.randomUUID(), entidad: 'VENTA', registroId: venta.id, operacion: 'EDITAR', ...datos, modificadoPor: datos.modificadoPor.trim(), motivo: datos.motivo.trim(), valoresAnteriores: JSON.stringify({ venta: anterior, lineas: lineasAnteriores }), valoresNuevos: JSON.stringify({ venta, lineas: lineasNuevas }), fecha: new Date(), createdAt: new Date() } as any);
});
}
}