// 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 _logger; public NovedadCanillaService( INovedadCanillaRepository novedadRepository, ICanillaRepository canillaRepository, DbConnectionFactory connectionFactory, ILogger 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> ObtenerPorCanillaAsync(int idCanilla, DateTime? fechaDesde, DateTime? fechaHasta) { var data = await _novedadRepository.GetByCanillaAsync(idCanilla, fechaDesde, fechaHasta); return data.Select(MapToDto); } public async Task 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> 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> 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> 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(); } } }