Diseño de un AuditoriaController con un patrón para añadir endpoints de historial para diferentes entidades. Implementación de la lógica de servicio y repositorio para obtener datos de las tablas _H para: Usuarios (gral_Usuarios_H) Pagos de Distribuidores (cue_PagosDistribuidor_H) Notas de Crédito/Débito (cue_CreditosDebitos_H) Entradas/Salidas de Distribuidores (dist_EntradasSalidas_H) Entradas/Salidas de Canillitas (dist_EntradasSalidasCanillas_H) Novedades de Canillitas (dist_dtNovedadesCanillas_H) Ajustes Manuales de Saldo (cue_SaldoAjustesHistorial) Tipos de Pago (cue_dtTipopago_H) Canillitas (Maestro) (dist_dtCanillas_H) Distribuidores (Maestro) (dist_dtDistribuidores_H) Empresas (Maestro) (dist_dtEmpresas_H) DTOs específicos para cada tipo de historial, incluyendo NombreUsuarioModifico. Frontend: Servicio auditoriaService.ts con métodos para llamar a cada endpoint de historial. Página AuditoriaGeneralPage.tsx con: Selector de "Tipo de Entidad a Auditar". Filtros comunes (Fechas, Usuario Modificador, Tipo de Modificación, ID Entidad). Un DataGrid que muestra las columnas dinámicamente según el tipo de entidad seleccionada. Lógica para cargar los datos correspondientes. DTOs de historial en TypeScript. Actualizaciones en AppRoutes.tsx y MainLayout.tsx para la nueva sección de Auditoría (restringida a SuperAdmin).
139 lines
6.4 KiB
C#
139 lines
6.4 KiB
C#
using Dapper;
|
|
using GestionIntegral.Api.Models.Distribucion;
|
|
using Microsoft.Extensions.Logging; // Para ILogger
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Text; // Para StringBuilder
|
|
using System.Threading.Tasks;
|
|
|
|
namespace GestionIntegral.Api.Data.Repositories.Distribucion
|
|
{
|
|
public class CambioParadaRepository : ICambioParadaRepository
|
|
{
|
|
private readonly DbConnectionFactory _cf;
|
|
private readonly ILogger<CambioParadaRepository> _logger;
|
|
|
|
public CambioParadaRepository(DbConnectionFactory cf, ILogger<CambioParadaRepository> logger)
|
|
{
|
|
_cf = cf;
|
|
_logger = logger;
|
|
}
|
|
|
|
private async Task LogHistorialAsync(CambioParadaCanilla paradaOriginal, int idUsuario, string tipoMod, IDbConnection connection, IDbTransaction? transaction)
|
|
{
|
|
var historial = new CambioParadaCanillaHistorial
|
|
{
|
|
Id_Registro = paradaOriginal.IdRegistro,
|
|
Id_Canilla = paradaOriginal.IdCanilla,
|
|
Parada = paradaOriginal.Parada,
|
|
VigenciaD = paradaOriginal.VigenciaD,
|
|
VigenciaH = paradaOriginal.VigenciaH,
|
|
Id_Usuario = idUsuario,
|
|
FechaMod = DateTime.Now,
|
|
TipoMod = tipoMod
|
|
};
|
|
const string sqlHistorial = @"
|
|
INSERT INTO dbo.dist_CambiosParadasCanillas_H
|
|
(Id_Registro, Id_Canilla, Parada, VigenciaD, VigenciaH, Id_Usuario, FechaMod, TipoMod)
|
|
VALUES
|
|
(@Id_Registro, @Id_Canilla, @Parada, @VigenciaD, @VigenciaH, @Id_Usuario, @FechaMod, @TipoMod);";
|
|
await connection.ExecuteAsync(sqlHistorial, historial, transaction);
|
|
}
|
|
|
|
|
|
public async Task<IEnumerable<CambioParadaCanilla>> GetByCanillaAsync(int idCanilla)
|
|
{
|
|
using var connection = _cf.CreateConnection();
|
|
const string sql = @"
|
|
SELECT Id_Registro AS IdRegistro, Id_Canilla AS IdCanilla, Parada, VigenciaD, VigenciaH
|
|
FROM dbo.dist_CambiosParadasCanillas
|
|
WHERE Id_Canilla = @IdCanilla
|
|
ORDER BY VigenciaD DESC, Id_Registro DESC;";
|
|
return await connection.QueryAsync<CambioParadaCanilla>(sql, new { IdCanilla = idCanilla });
|
|
}
|
|
|
|
public async Task<CambioParadaCanilla?> GetByIdAsync(int idRegistro)
|
|
{
|
|
using var connection = _cf.CreateConnection();
|
|
const string sql = @"
|
|
SELECT Id_Registro AS IdRegistro, Id_Canilla AS IdCanilla, Parada, VigenciaD, VigenciaH
|
|
FROM dbo.dist_CambiosParadasCanillas
|
|
WHERE Id_Registro = @IdRegistro;";
|
|
return await connection.QuerySingleOrDefaultAsync<CambioParadaCanilla>(sql, new { IdRegistro = idRegistro });
|
|
}
|
|
|
|
public async Task<CambioParadaCanilla?> GetCurrentParadaAsync(int idCanilla, IDbTransaction? transaction = null)
|
|
{
|
|
const string sql = @"
|
|
SELECT TOP 1 Id_Registro AS IdRegistro, Id_Canilla AS IdCanilla, Parada, VigenciaD, VigenciaH
|
|
FROM dbo.dist_CambiosParadasCanillas
|
|
WHERE Id_Canilla = @IdCanilla AND VigenciaH IS NULL
|
|
ORDER BY VigenciaD DESC, Id_Registro DESC;"; // Por si hay un error y quedaron varias abiertas
|
|
|
|
var conn = transaction?.Connection ?? _cf.CreateConnection();
|
|
bool manageConnection = transaction == null;
|
|
if (manageConnection && conn.State != ConnectionState.Open) { if (conn is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else conn.Open(); }
|
|
try
|
|
{
|
|
return await conn.QuerySingleOrDefaultAsync<CambioParadaCanilla>(sql, new { IdCanilla = idCanilla }, transaction);
|
|
}
|
|
finally
|
|
{
|
|
if (manageConnection && conn.State == ConnectionState.Open) { if (conn is System.Data.Common.DbConnection dbConn) await dbConn.CloseAsync(); else conn.Close(); }
|
|
}
|
|
}
|
|
|
|
|
|
public async Task<CambioParadaCanilla?> CreateAsync(CambioParadaCanilla nuevaParada, int idUsuario, IDbTransaction transaction)
|
|
{
|
|
const string sqlInsert = @"
|
|
INSERT INTO dbo.dist_CambiosParadasCanillas (Id_Canilla, Parada, VigenciaD, VigenciaH)
|
|
OUTPUT INSERTED.Id_Registro AS IdRegistro, INSERTED.Id_Canilla AS IdCanilla, INSERTED.Parada, INSERTED.VigenciaD, INSERTED.VigenciaH
|
|
VALUES (@IdCanilla, @Parada, @VigenciaD, @VigenciaH);";
|
|
|
|
// VigenciaH es null al crear una nueva parada activa
|
|
var inserted = await transaction.Connection!.QuerySingleAsync<CambioParadaCanilla>(sqlInsert,
|
|
new { nuevaParada.IdCanilla, nuevaParada.Parada, nuevaParada.VigenciaD, VigenciaH = (DateTime?)null },
|
|
transaction);
|
|
|
|
if (inserted == null || inserted.IdRegistro == 0) throw new DataException("Error al crear cambio de parada o ID no generado.");
|
|
|
|
await LogHistorialAsync(inserted, idUsuario, "Creada", transaction.Connection!, transaction);
|
|
return inserted;
|
|
}
|
|
|
|
public async Task<bool> UpdateVigenciaHAsync(int idRegistro, DateTime vigenciaH, int idUsuario, IDbTransaction transaction)
|
|
{
|
|
var paradaOriginal = await GetByIdAsync(idRegistro); // Obtener para el log
|
|
if (paradaOriginal == null) throw new KeyNotFoundException("Registro de parada no encontrado para actualizar VigenciaH.");
|
|
|
|
// Loggear ANTES de actualizar
|
|
await LogHistorialAsync(paradaOriginal, idUsuario, "Cerrada", transaction.Connection!, transaction);
|
|
|
|
const string sqlUpdate = @"
|
|
UPDATE dbo.dist_CambiosParadasCanillas
|
|
SET VigenciaH = @VigenciaH
|
|
WHERE Id_Registro = @IdRegistro;";
|
|
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate,
|
|
new { VigenciaH = vigenciaH.Date, IdRegistro = idRegistro },
|
|
transaction);
|
|
|
|
return rowsAffected == 1;
|
|
}
|
|
|
|
public async Task<bool> DeleteAsync(int idRegistro, int idUsuario, IDbTransaction transaction)
|
|
{
|
|
var paradaOriginal = await GetByIdAsync(idRegistro);
|
|
if (paradaOriginal == null) throw new KeyNotFoundException("Registro de parada no encontrado para eliminar.");
|
|
|
|
// Loggear ANTES de eliminar
|
|
await LogHistorialAsync(paradaOriginal, idUsuario, "Eliminada", transaction.Connection!, transaction);
|
|
|
|
const string sqlDelete = "DELETE FROM dbo.dist_CambiosParadasCanillas WHERE Id_Registro = @IdRegistro;";
|
|
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdRegistro = idRegistro }, transaction);
|
|
return rowsAffected == 1;
|
|
}
|
|
}
|
|
} |