Implementación AnomalIA - Fix de dropdowns y permisos.
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 5m17s

This commit is contained in:
2025-06-30 15:26:14 -03:00
parent 95aa09d62a
commit c96d259892
59 changed files with 1430 additions and 337 deletions

View File

@@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using GestionIntegral.Api.Data;
using GestionIntegral.Api.Dtos.Anomalia;
using Microsoft.Extensions.Logging;
namespace GestionIntegral.Api.Services.Anomalia
{
public class AlertaService : IAlertaService
{
private readonly DbConnectionFactory _dbConnectionFactory;
private readonly ILogger<AlertaService> _logger;
public AlertaService(DbConnectionFactory dbConnectionFactory, ILogger<AlertaService> logger)
{
_dbConnectionFactory = dbConnectionFactory;
_logger = logger;
}
public async Task<IEnumerable<AlertaGenericaDto>> ObtenerAlertasNoLeidasAsync()
{
// Apunta a la nueva tabla genérica 'Sistema_Alertas'
var query = "SELECT * FROM Sistema_Alertas WHERE Leida = 0 ORDER BY FechaDeteccion DESC";
try
{
using (var connection = _dbConnectionFactory.CreateConnection())
{
var alertas = await connection.QueryAsync<AlertaGenericaDto>(query);
return alertas ?? Enumerable.Empty<AlertaGenericaDto>();
}
}
catch (System.Exception ex)
{
_logger.LogError(ex, "Error al obtener las alertas no leídas desde Sistema_Alertas.");
return Enumerable.Empty<AlertaGenericaDto>();
}
}
public async Task<(bool Exito, string? Error)> MarcarComoLeidaAsync(int idAlerta)
{
var query = "UPDATE Sistema_Alertas SET Leida = 1 WHERE IdAlerta = @IdAlerta";
try
{
using (var connection = _dbConnectionFactory.CreateConnection())
{
var result = await connection.ExecuteAsync(query, new { IdAlerta = idAlerta });
if (result > 0)
{
return (true, null);
}
return (false, "La alerta no fue encontrada o ya estaba marcada.");
}
}
catch (System.Exception ex)
{
_logger.LogError(ex, "Error al marcar la alerta {IdAlerta} como leída.", idAlerta);
return (false, "Error interno del servidor.");
}
}
public async Task<(bool Exito, string? Error)> MarcarGrupoComoLeidoAsync(string tipoAlerta, int idEntidad)
{
var query = "UPDATE Sistema_Alertas SET Leida = 1 WHERE TipoAlerta = @TipoAlerta AND IdEntidad = @IdEntidad AND Leida = 0";
try
{
using (var connection = _dbConnectionFactory.CreateConnection())
{
var result = await connection.ExecuteAsync(query, new { TipoAlerta = tipoAlerta, IdEntidad = idEntidad });
// No es un error si no se actualizan filas (puede que no hubiera ninguna para ese grupo)
_logger.LogInformation("Marcadas como leídas {Count} alertas para Tipo: {Tipo}, EntidadID: {IdEntidad}", result, tipoAlerta, idEntidad);
return (true, null);
}
}
catch (System.Exception ex)
{
_logger.LogError(ex, "Error al marcar grupo de alertas como leídas. Tipo: {Tipo}, EntidadID: {IdEntidad}", tipoAlerta, idEntidad);
return (false, "Error interno del servidor.");
}
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using GestionIntegral.Api.Dtos.Anomalia;
namespace GestionIntegral.Api.Services.Anomalia
{
public interface IAlertaService
{
/// <summary>
/// Obtiene todas las alertas que no han sido marcadas como leídas.
/// </summary>
/// <returns>Una colección de DTOs de alertas genéricas.</returns>
Task<IEnumerable<AlertaGenericaDto>> ObtenerAlertasNoLeidasAsync();
/// <summary>
/// Marca una alerta específica como leída.
/// </summary>
/// <param name="idAlerta">El ID de la alerta a marcar.</param>
/// <returns>Una tupla indicando si la operación fue exitosa y un mensaje de error si falló.</returns>
Task<(bool Exito, string? Error)> MarcarComoLeidaAsync(int idAlerta);
/// <summary>
/// Marca como leídas todas las alertas de un mismo tipo y para una misma entidad.
/// (Ej: todas las alertas de "DevolucionAnomala" para el Canillita ID 45).
/// </summary>
/// <param name="tipoAlerta">El tipo de alerta a marcar (ej. "DevolucionAnomala").</param>
/// <param name="idEntidad">El ID de la entidad afectada (ej. el IdCanilla).</param>
/// <returns>Una tupla indicando si la operación fue exitosa y un mensaje de error si falló.</returns>
Task<(bool Exito, string? Error)> MarcarGrupoComoLeidoAsync(string tipoAlerta, int idEntidad);
}
}

View File

@@ -33,7 +33,6 @@ namespace GestionIntegral.Api.Services.Distribucion
_logger = logger;
}
// CORREGIDO: MapToDto ahora acepta una tupla con tipos anulables
private CanillaDto? MapToDto((Canilla? Canilla, string? NombreZona, string? NombreEmpresa) data)
{
if (data.Canilla == null) return null;
@@ -62,10 +61,14 @@ namespace GestionIntegral.Api.Services.Distribucion
return data.Select(MapToDto).Where(dto => dto != null).Select(dto => dto!);
}
public async Task<IEnumerable<CanillaDropdownDto>> ObtenerTodosDropdownAsync(bool? esAccionista, bool? soloActivos)
{
return await _canillaRepository.GetAllDropdownAsync(esAccionista, soloActivos) ?? Enumerable.Empty<CanillaDropdownDto>();
}
public async Task<CanillaDto?> ObtenerPorIdAsync(int id)
{
var data = await _canillaRepository.GetByIdAsync(id);
// MapToDto ahora devuelve CanillaDto? así que esto es correcto
return MapToDto(data);
}
@@ -89,7 +92,6 @@ namespace GestionIntegral.Api.Services.Distribucion
}
}
// CORREGIDO: Usar directamente el valor booleano
if (createDto.Accionista == true && createDto.Empresa != 0)
{
return (null, "Un canillita accionista no debe tener una empresa asignada (Empresa debe ser 0).");
@@ -287,6 +289,6 @@ namespace GestionIntegral.Api.Services.Distribucion
FechaMod = h.Historial.FechaMod,
TipoMod = h.Historial.TipoMod
}).ToList();
}
}
}
}

View File

@@ -8,6 +8,7 @@ namespace GestionIntegral.Api.Services.Distribucion
public interface ICanillaService
{
Task<IEnumerable<CanillaDto>> ObtenerTodosAsync(string? nomApeFilter, int? legajoFilter, bool? esAccionista, bool? soloActivos);
Task<IEnumerable<CanillaDropdownDto>> ObtenerTodosDropdownAsync(bool? esAccionista, bool? soloActivos);
Task<CanillaDto?> ObtenerPorIdAsync(int id);
Task<(CanillaDto? Canilla, string? Error)> CrearAsync(CreateCanillaDto createDto, int idUsuario);
Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateCanillaDto updateDto, int idUsuario);

View File

@@ -8,6 +8,7 @@ namespace GestionIntegral.Api.Services.Distribucion
public interface IOtroDestinoService
{
Task<IEnumerable<OtroDestinoDto>> ObtenerTodosAsync(string? nombreFilter);
Task<IEnumerable<OtroDestinoDropdownDto>> ObtenerTodosDropdownAsync();
Task<OtroDestinoDto?> ObtenerPorIdAsync(int id);
Task<(OtroDestinoDto? Destino, string? Error)> CrearAsync(CreateOtroDestinoDto createDto, int idUsuario);
Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateOtroDestinoDto updateDto, int idUsuario);

View File

@@ -37,6 +37,11 @@ namespace GestionIntegral.Api.Services.Distribucion
return destinos.Select(MapToDto);
}
public async Task<IEnumerable<OtroDestinoDropdownDto>> ObtenerTodosDropdownAsync()
{
return await _otroDestinoRepository.GetAllDropdownAsync();
}
public async Task<OtroDestinoDto?> ObtenerPorIdAsync(int id)
{
var destino = await _otroDestinoRepository.GetByIdAsync(id);

View File

@@ -86,6 +86,7 @@ namespace GestionIntegral.Api.Services.Distribucion
{
IdPublicacion = d.Publicacion!.IdPublicacion, // Usar ! si estás seguro que no es null después del Where
Nombre = d.Publicacion!.Nombre,
NombreEmpresa = d.NombreEmpresa ?? "Empresa Desconocida",
Habilitada = d.Publicacion!.Habilitada ?? true // Si necesitas filtrar por esto
})
.OrderBy(p => p.Nombre)

View File

@@ -37,6 +37,12 @@ namespace GestionIntegral.Api.Services.Impresion
return estadosBobina.Select(MapToDto);
}
public async Task<IEnumerable<EstadoBobinaDropdownDto>> ObtenerTodosDropdownAsync()
{
var estadosBobina = await _estadoBobinaRepository.GetAllDropdownAsync();
return estadosBobina;
}
public async Task<EstadoBobinaDto?> ObtenerPorIdAsync(int id)
{
var estadoBobina = await _estadoBobinaRepository.GetByIdAsync(id);

View File

@@ -8,6 +8,7 @@ namespace GestionIntegral.Api.Services.Impresion
public interface IEstadoBobinaService
{
Task<IEnumerable<EstadoBobinaDto>> ObtenerTodosAsync(string? denominacionFilter);
Task<IEnumerable<EstadoBobinaDropdownDto>> ObtenerTodosDropdownAsync();
Task<EstadoBobinaDto?> ObtenerPorIdAsync(int id);
Task<(EstadoBobinaDto? EstadoBobina, string? Error)> CrearAsync(CreateEstadoBobinaDto createDto, int idUsuario);
Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateEstadoBobinaDto updateDto, int idUsuario);

View File

@@ -8,6 +8,7 @@ namespace GestionIntegral.Api.Services.Impresion
public interface ITipoBobinaService
{
Task<IEnumerable<TipoBobinaDto>> ObtenerTodosAsync(string? denominacionFilter);
Task<IEnumerable<TipoBobinaDto>> ObtenerTodosDropdownAsync();
Task<TipoBobinaDto?> ObtenerPorIdAsync(int id);
Task<(TipoBobinaDto? TipoBobina, string? Error)> CrearAsync(CreateTipoBobinaDto createDto, int idUsuario);
Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateTipoBobinaDto updateDto, int idUsuario);

View File

@@ -36,6 +36,12 @@ namespace GestionIntegral.Api.Services.Impresion
return tiposBobina.Select(MapToDto);
}
public async Task<IEnumerable<TipoBobinaDto>> ObtenerTodosDropdownAsync()
{
var tiposBobina = await _tipoBobinaRepository.GetAllDropdownAsync();
return tiposBobina.Select(MapToDto);
}
public async Task<TipoBobinaDto?> ObtenerPorIdAsync(int id)
{
var tipoBobina = await _tipoBobinaRepository.GetByIdAsync(id);