Files
GestionIntegralWeb/Backend/GestionIntegral.Api/Services/Distribucion/NovedadCanillaService.cs
eldiadmolinari 437b1e8864 Backend:
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).
2025-06-09 19:37:07 -03:00

276 lines
12 KiB
C#

// En Services/Distribucion (o donde corresponda)
using GestionIntegral.Api.Data; // Para DbConnectionFactory
using GestionIntegral.Api.Data.Repositories.Distribucion;
using GestionIntegral.Api.Dtos.Auditoria;
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Dtos.Reportes;
using GestionIntegral.Api.Models.Distribucion; // Asegúrate que el modelo Canilla tenga NomApe
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data; // Para IDbTransaction
using System.Linq;
using System.Threading.Tasks;
namespace GestionIntegral.Api.Services.Distribucion
{
public class NovedadCanillaService : INovedadCanillaService
{
private readonly INovedadCanillaRepository _novedadRepository;
private readonly ICanillaRepository _canillaRepository;
private readonly DbConnectionFactory _connectionFactory;
private readonly ILogger<NovedadCanillaService> _logger;
public NovedadCanillaService(
INovedadCanillaRepository novedadRepository,
ICanillaRepository canillaRepository,
DbConnectionFactory connectionFactory,
ILogger<NovedadCanillaService> logger)
{
_novedadRepository = novedadRepository;
_canillaRepository = canillaRepository;
_connectionFactory = connectionFactory;
_logger = logger;
}
private NovedadCanillaDto MapToDto((NovedadCanilla Novedad, string NombreCanilla) data)
{
return new NovedadCanillaDto
{
IdNovedad = data.Novedad.IdNovedad,
IdCanilla = data.Novedad.IdCanilla,
NombreCanilla = data.NombreCanilla, // Viene de la tupla en GetByCanillaAsync
Fecha = data.Novedad.Fecha,
Detalle = data.Novedad.Detalle
};
}
private NovedadCanillaDto MapToDto(NovedadCanilla data, string nombreCanilla)
{
return new NovedadCanillaDto
{
IdNovedad = data.IdNovedad,
IdCanilla = data.IdCanilla,
NombreCanilla = nombreCanilla,
Fecha = data.Fecha,
Detalle = data.Detalle
};
}
public async Task<IEnumerable<NovedadCanillaDto>> ObtenerPorCanillaAsync(int idCanilla, DateTime? fechaDesde, DateTime? fechaHasta)
{
var data = await _novedadRepository.GetByCanillaAsync(idCanilla, fechaDesde, fechaHasta);
return data.Select(MapToDto);
}
public async Task<NovedadCanillaDto?> ObtenerPorIdAsync(int idNovedad)
{
var novedad = await _novedadRepository.GetByIdAsync(idNovedad);
if (novedad == null) return null;
// Asumiendo que _canillaRepository.GetByIdAsync devuelve una tupla (Canilla? Canilla, ...)
// O un DTO CanillaDto que tiene NomApe
var canillaDataResult = await _canillaRepository.GetByIdAsync(novedad.IdCanilla);
// Ajusta esto según lo que realmente devuelva GetByIdAsync
// Si devuelve CanillaDto:
// string nombreCanilla = canillaDataResult?.NomApe ?? "Desconocido";
// Si devuelve la tupla (Canilla? Canilla, string? NombreZona, string? NombreEmpresa):
string nombreCanilla = canillaDataResult.Canilla?.NomApe ?? "Desconocido";
return MapToDto(novedad, nombreCanilla);
}
public async Task<(NovedadCanillaDto? Novedad, string? Error)> CrearAsync(CreateNovedadCanillaDto createDto, int idUsuario)
{
// Asegúrate que GetByIdSimpleAsync devuelva un objeto Canilla o algo con NomApe
var canilla = await _canillaRepository.GetByIdSimpleAsync(createDto.IdCanilla);
if (canilla == null)
{
return (null, "El canillita especificado no existe.");
}
var nuevaNovedad = new NovedadCanilla
{
IdCanilla = createDto.IdCanilla,
Fecha = createDto.Fecha.Date,
Detalle = createDto.Detalle
};
using var connection = _connectionFactory.CreateConnection();
// Abre la conexión explícitamente si no se usa una transacción externa
if (connection is System.Data.Common.DbConnection dbConn && connection.State != ConnectionState.Open)
{
await dbConn.OpenAsync();
}
else if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using var transaction = connection.BeginTransaction();
try
{
var creada = await _novedadRepository.CreateAsync(nuevaNovedad, idUsuario, transaction);
if (creada == null)
{
transaction.Rollback();
return (null, "Error al guardar la novedad en la base de datos.");
}
transaction.Commit();
_logger.LogInformation("Novedad ID {IdNovedad} para Canilla ID {IdCanilla} creada por Usuario ID {UserId}.", creada.IdNovedad, creada.IdCanilla, idUsuario);
// Asegúrate que 'canilla.NomApe' sea accesible. Si GetByIdSimpleAsync devuelve la entidad Canilla, esto está bien.
return (MapToDto(creada, canilla.NomApe ?? "Canilla sin nombre"), null);
}
catch (Exception ex)
{
try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error durante Rollback en CrearAsync NovedadCanilla."); }
_logger.LogError(ex, "Error CrearAsync NovedadCanilla para Canilla ID: {IdCanilla}", createDto.IdCanilla);
return (null, $"Error interno al crear la novedad: {ex.Message}");
}
finally
{
if (connection.State == ConnectionState.Open) connection.Close();
}
}
public async Task<(bool Exito, string? Error)> ActualizarAsync(int idNovedad, UpdateNovedadCanillaDto updateDto, int idUsuario)
{
var existente = await _novedadRepository.GetByIdAsync(idNovedad);
if (existente == null)
{
return (false, "Novedad no encontrada.");
}
existente.Detalle = updateDto.Detalle;
using var connection = _connectionFactory.CreateConnection();
if (connection is System.Data.Common.DbConnection dbConn && connection.State != ConnectionState.Open)
{
await dbConn.OpenAsync();
}
else if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using var transaction = connection.BeginTransaction();
try
{
var actualizado = await _novedadRepository.UpdateAsync(existente, idUsuario, transaction);
if (!actualizado)
{
transaction.Rollback();
return (false, "Error al actualizar la novedad en la base de datos.");
}
transaction.Commit();
_logger.LogInformation("Novedad ID {IdNovedad} actualizada por Usuario ID {UserId}.", idNovedad, idUsuario);
return (true, null);
}
catch (Exception ex)
{
try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error durante Rollback en ActualizarAsync NovedadCanilla."); }
_logger.LogError(ex, "Error ActualizarAsync NovedadCanilla ID: {IdNovedad}", idNovedad);
return (false, $"Error interno al actualizar la novedad: {ex.Message}");
}
finally
{
if (connection.State == ConnectionState.Open) connection.Close();
}
}
public async Task<(bool Exito, string? Error)> EliminarAsync(int idNovedad, int idUsuario)
{
var existente = await _novedadRepository.GetByIdAsync(idNovedad);
if (existente == null)
{
return (false, "Novedad no encontrada.");
}
using var connection = _connectionFactory.CreateConnection();
if (connection is System.Data.Common.DbConnection dbConn && connection.State != ConnectionState.Open)
{
await dbConn.OpenAsync();
}
else if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using var transaction = connection.BeginTransaction();
try
{
var eliminado = await _novedadRepository.DeleteAsync(idNovedad, idUsuario, transaction);
if (!eliminado)
{
transaction.Rollback();
return (false, "Error al eliminar la novedad de la base de datos.");
}
transaction.Commit();
_logger.LogInformation("Novedad ID {IdNovedad} eliminada por Usuario ID {UserId}.", idNovedad, idUsuario);
return (true, null);
}
catch (Exception ex)
{
try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error durante Rollback en EliminarAsync NovedadCanilla."); }
_logger.LogError(ex, "Error EliminarAsync NovedadCanilla ID: {IdNovedad}", idNovedad);
return (false, $"Error interno al eliminar la novedad: {ex.Message}");
}
finally
{
if (connection.State == ConnectionState.Open) connection.Close();
}
}
public async Task<IEnumerable<NovedadesCanillasReporteDto>> ObtenerReporteNovedadesAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
{
// Podría añadir validaciones o lógica de negocio adicional si fuera necesario
// antes de llamar al repositorio. Por ahora, es una llamada directa.
try
{
return await _novedadRepository.GetReporteNovedadesAsync(idEmpresa, fechaDesde, fechaHasta);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener datos para el reporte de novedades de canillitas. Empresa: {IdEmpresa}, Desde: {FechaDesde}, Hasta: {FechaHasta}", idEmpresa, fechaDesde, fechaHasta);
// Podría relanzar o devolver una lista vacía con un mensaje de error,
// dependiendo de cómo quiera manejar los errores en la capa de servicio.
// Por simplicidad, relanzamos para que el controlador lo maneje.
throw;
}
}
public async Task<IEnumerable<CanillaGananciaReporteDto>> ObtenerReporteGananciasAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
{
try
{
return await _novedadRepository.GetReporteGananciasAsync(idEmpresa, fechaDesde, fechaHasta);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener datos para el reporte de ganancias de canillitas. Empresa: {IdEmpresa}, Desde: {FechaDesde}, Hasta: {FechaHasta}", idEmpresa, fechaDesde, fechaHasta);
throw;
}
}
public async Task<IEnumerable<NovedadCanillaHistorialDto>> ObtenerHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idNovedadAfectada)
{
var historialData = await _novedadRepository.GetHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idNovedadAfectada);
return historialData.Select(h => new NovedadCanillaHistorialDto
{
Id_Novedad = h.Historial.Id_Novedad,
Id_Canilla = h.Historial.Id_Canilla,
Fecha = h.Historial.Fecha,
Detalle = h.Historial.Detalle,
Id_Usuario = h.Historial.Id_Usuario,
NombreUsuarioModifico = h.NombreUsuarioModifico,
FechaMod = h.Historial.FechaMod,
TipoMod = h.Historial.TipoMod
// Si decides traer NombreCanilla desde el repo, mapealo aquí.
}).ToList();
}
}
}