Se introduce un sistema completo para auditar los envíos masivos de correos durante el cierre mensual y se refactoriza la interfaz de usuario de procesos para una mayor claridad y escalabilidad. Además, se mejora la lógica de negocio para la gestión de bajas de suscripciones. ### ✨ Nuevas Características - **Auditoría de Envíos Masivos (Cierre Mensual):** - Se crea una nueva tabla `com_LotesDeEnvio` para registrar cada ejecución del proceso de facturación mensual. - El `FacturacionService` ahora crea un "lote" al iniciar el cierre, registra el resultado de cada envío de email individual asociándolo a dicho lote, y actualiza las estadísticas finales (enviados, fallidos) al terminar. - Se implementa un nuevo `LotesEnvioController` con un endpoint para consultar los detalles de cualquier lote de envío histórico. ### 🔄 Refactorización y Mejoras - **Rediseño de la Página de Procesos:** - La antigua página "Facturación" se renombra a `CierreYProcesosPage` y se rediseña completamente utilizando una interfaz de Pestañas (Tabs). - **Pestaña "Procesos Mensuales":** Aisla las acciones principales (Generar Cierre, Archivo de Débito, Procesar Respuesta), mostrando un resumen del resultado del último envío. - **Pestaña "Historial de Cierres":** Muestra una tabla con todos los lotes de envío pasados y permite al usuario ver los detalles de cada uno en un modal. - **Filtros para el Historial de Cierres:** - Se añaden filtros por Mes y Año a la pestaña de "Historial de Cierres", permitiendo al usuario buscar y auditar procesos pasados de manera eficiente. El filtrado se realiza en el backend para un rendimiento óptimo. - **Lógica de `FechaFin` Obligatoria para Bajas:** - Se implementa una regla de negocio crucial: al cambiar el estado de una suscripción a "Pausada" o "Cancelada", ahora es obligatorio establecer una `FechaFin`. - **Frontend:** El modal de suscripciones ahora gestiona esto automáticamente, haciendo el campo `FechaFin` requerido y visible según el estado seleccionado. - **Backend:** Se añade una validación en `SuscripcionService` como segunda capa de seguridad para garantizar la integridad de los datos. ### 🐛 Corrección de Errores - **Reporte de Distribución:** Se corrigió un bug en la generación del PDF donde la columna de fecha no mostraba la "Fecha de Baja" para las suscripciones finalizadas. Ahora se muestra la fecha correcta según la sección (Altas o Bajas). - **Errores de Compilación y Dependencias:** Se solucionaron varios errores de compilación en el backend, principalmente relacionados con la falta de registro de los nuevos repositorios (`ILoteDeEnvioRepository`, `IEmailLogService`, etc.) en el contenedor de inyección de dependencias (`Program.cs`). - **Errores de Tipado en Frontend:** Se corrigieron múltiples errores de TypeScript en `CierreYProcesosPage` debidos a la inconsistencia entre `PascalCase` (C#) y `camelCase` (JSON/TypeScript), asegurando un mapeo correcto de los datos de la API.
578 lines
33 KiB
C#
578 lines
33 KiB
C#
using GestionIntegral.Api.Data.Repositories.Distribucion;
|
|
using GestionIntegral.Api.Data.Repositories.Reportes;
|
|
using GestionIntegral.Api.Data.Repositories.Suscripciones;
|
|
using GestionIntegral.Api.Dtos.Reportes;
|
|
|
|
namespace GestionIntegral.Api.Services.Reportes
|
|
{
|
|
public class ReportesService : IReportesService
|
|
{
|
|
private readonly IReportesRepository _reportesRepository;
|
|
private readonly IFacturaRepository _facturaRepository;
|
|
private readonly IFacturaDetalleRepository _facturaDetalleRepository;
|
|
private readonly IPublicacionRepository _publicacionRepository;
|
|
private readonly IEmpresaRepository _empresaRepository;
|
|
private readonly ISuscriptorRepository _suscriptorRepository;
|
|
private readonly ISuscripcionRepository _suscripcionRepository;
|
|
private readonly ILogger<ReportesService> _logger;
|
|
|
|
public ReportesService(IReportesRepository reportesRepository, IFacturaRepository facturaRepository, IFacturaDetalleRepository facturaDetalleRepository, IPublicacionRepository publicacionRepository, IEmpresaRepository empresaRepository
|
|
, ISuscriptorRepository suscriptorRepository, ISuscripcionRepository suscripcionRepository, ILogger<ReportesService> logger)
|
|
{
|
|
_reportesRepository = reportesRepository;
|
|
_facturaRepository = facturaRepository;
|
|
_facturaDetalleRepository = facturaDetalleRepository;
|
|
_publicacionRepository = publicacionRepository;
|
|
_empresaRepository = empresaRepository;
|
|
_suscriptorRepository = suscriptorRepository;
|
|
_suscripcionRepository = suscripcionRepository;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<(IEnumerable<ExistenciaPapelDto> Data, string? Error)> ObtenerExistenciaPapelAsync(
|
|
DateTime fechaDesde, DateTime fechaHasta, int? idPlanta, bool consolidado)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
{
|
|
return (Enumerable.Empty<ExistenciaPapelDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
}
|
|
|
|
if (!consolidado && !idPlanta.HasValue)
|
|
{
|
|
return (Enumerable.Empty<ExistenciaPapelDto>(), "Se requiere un ID de planta para reportes no consolidados.");
|
|
}
|
|
|
|
try
|
|
{
|
|
var dataFromRepo = await _reportesRepository.GetExistenciaPapelAsync(fechaDesde, fechaHasta, idPlanta, consolidado);
|
|
var dataWithUtcDates = dataFromRepo.Select(dto =>
|
|
{
|
|
if (dto.FechaEstimacionFinStock.HasValue)
|
|
{
|
|
dto.FechaEstimacionFinStock = DateTime.SpecifyKind(dto.FechaEstimacionFinStock.Value.Date, DateTimeKind.Utc);
|
|
}
|
|
return dto;
|
|
}).ToList();
|
|
return (dataWithUtcDates, null);
|
|
}
|
|
catch (ArgumentNullException ex) when (ex.ParamName == "idPlanta")
|
|
{
|
|
_logger.LogWarning(ex, "ArgumentNullException para idPlanta en ObtenerExistenciaPapelAsync.");
|
|
return (Enumerable.Empty<ExistenciaPapelDto>(), ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Existencia de Papel.");
|
|
return (Enumerable.Empty<ExistenciaPapelDto>(), "Error interno al generar el reporte de existencia de papel.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<MovimientoBobinasDto> Data, string? Error)> ObtenerMovimientoBobinasAsync(DateTime fechaDesde, DateTime fechaHasta, int idPlanta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
{
|
|
return (Enumerable.Empty<MovimientoBobinasDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
}
|
|
int diasPeriodo = (fechaHasta.Date - fechaDesde.Date).Days + 1;
|
|
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetMovimientoBobinasAsync(fechaDesde.Date, diasPeriodo, idPlanta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Movimiento de Bobinas.");
|
|
return (Enumerable.Empty<MovimientoBobinasDto>(), "Error interno al generar el reporte de movimiento de bobinas.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<MovimientoBobinaEstadoDetalleDto> Detalle, IEnumerable<MovimientoBobinaEstadoTotalDto> Totales, string? Error)> ObtenerMovimientoBobinasPorEstadoAsync(DateTime fechaDesde, DateTime fechaHasta, int idPlanta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
{
|
|
return (Enumerable.Empty<MovimientoBobinaEstadoDetalleDto>(), Enumerable.Empty<MovimientoBobinaEstadoTotalDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
}
|
|
|
|
try
|
|
{
|
|
var detalle = await _reportesRepository.GetMovimientoBobinasEstadoDetalleAsync(fechaDesde.Date, fechaHasta.Date, idPlanta);
|
|
var totales = await _reportesRepository.GetMovimientoBobinasEstadoTotalesAsync(fechaDesde.Date, fechaHasta.Date, idPlanta);
|
|
|
|
var detalleUtc = detalle.Select(d =>
|
|
{
|
|
d.FechaMovimiento = DateTime.SpecifyKind(d.FechaMovimiento, DateTimeKind.Utc);
|
|
return d;
|
|
}).ToList();
|
|
|
|
return (detalleUtc, totales, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Movimiento de Bobinas por Estado.");
|
|
return (Enumerable.Empty<MovimientoBobinaEstadoDetalleDto>(), Enumerable.Empty<MovimientoBobinaEstadoTotalDto>(), "Error interno al generar el reporte de movimiento de bobinas por estado.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ListadoDistribucionGeneralResumenDto> Resumen, IEnumerable<ListadoDistribucionGeneralPromedioDiaDto> Promedios, string? Error)> ObtenerListadoDistribucionGeneralAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
return (Enumerable.Empty<ListadoDistribucionGeneralResumenDto>(), Enumerable.Empty<ListadoDistribucionGeneralPromedioDiaDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
|
|
try
|
|
{
|
|
// El SP SP_DistObtenerResumenMensual usa Mes y Año de fechaDesde.
|
|
// El SP SP_DistObtenerResumenMensualPorDiaSemana también.
|
|
var resumenData = await _reportesRepository.GetListadoDistribucionGeneralResumenAsync(idPublicacion, fechaDesde, fechaHasta);
|
|
var promediosData = await _reportesRepository.GetListadoDistribucionGeneralPromedioDiaAsync(idPublicacion, fechaDesde, fechaHasta);
|
|
|
|
var resumenUtc = resumenData.Select(r => { r.Fecha = DateTime.SpecifyKind(r.Fecha, DateTimeKind.Utc); return r; }).ToList();
|
|
|
|
return (resumenUtc, promediosData, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Listado Distribucion General.");
|
|
return (Enumerable.Empty<ListadoDistribucionGeneralResumenDto>(), Enumerable.Empty<ListadoDistribucionGeneralPromedioDiaDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ListadoDistribucionCanillasSimpleDto> Simple, IEnumerable<ListadoDistribucionCanillasPromedioDiaDto> Promedios, string? Error)> ObtenerListadoDistribucionCanillasAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
return (Enumerable.Empty<ListadoDistribucionCanillasSimpleDto>(), Enumerable.Empty<ListadoDistribucionCanillasPromedioDiaDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
|
|
try
|
|
{
|
|
var simpleData = await _reportesRepository.GetListadoDistribucionCanillasSimpleAsync(idPublicacion, fechaDesde, fechaHasta);
|
|
var promediosData = await _reportesRepository.GetListadoDistribucionCanillasPromedioDiaAsync(idPublicacion, fechaDesde, fechaHasta);
|
|
return (simpleData, promediosData, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Listado Distribucion Canillas.");
|
|
return (Enumerable.Empty<ListadoDistribucionCanillasSimpleDto>(), Enumerable.Empty<ListadoDistribucionCanillasPromedioDiaDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ListadoDistribucionCanillasImporteDto> Data, string? Error)> ObtenerListadoDistribucionCanillasConImporteAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
return (Enumerable.Empty<ListadoDistribucionCanillasImporteDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetListadoDistribucionCanillasImporteAsync(idPublicacion, fechaDesde, fechaHasta, esAccionista);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Listado Distribucion Canillas con Importe.");
|
|
return (Enumerable.Empty<ListadoDistribucionCanillasImporteDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<VentaMensualSecretariaElDiaDto> Data, string? Error)> ObtenerVentaMensualSecretariaElDiaAsync(DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<VentaMensualSecretariaElDiaDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetVentaMensualSecretariaElDiaAsync(fechaDesde, fechaHasta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Venta Mensual Secretaria El Dia.");
|
|
return (Enumerable.Empty<VentaMensualSecretariaElDiaDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<VentaMensualSecretariaElPlataDto> Data, string? Error)> ObtenerVentaMensualSecretariaElPlataAsync(DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<VentaMensualSecretariaElPlataDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetVentaMensualSecretariaElPlataAsync(fechaDesde, fechaHasta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Venta Mensual Secretaria El Plata.");
|
|
return (Enumerable.Empty<VentaMensualSecretariaElPlataDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<VentaMensualSecretariaTirDevoDto> Data, string? Error)> ObtenerVentaMensualSecretariaTirDevoAsync(DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<VentaMensualSecretariaTirDevoDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetVentaMensualSecretariaTirDevoAsync(fechaDesde, fechaHasta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Venta Mensual Secretaria Tirada/Devolucion.");
|
|
return (Enumerable.Empty<VentaMensualSecretariaTirDevoDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(
|
|
IEnumerable<DetalleDistribucionCanillaDto> Canillas,
|
|
IEnumerable<DetalleDistribucionCanillaDto> CanillasAcc,
|
|
IEnumerable<DetalleDistribucionCanillaAllDto> CanillasAll,
|
|
IEnumerable<DetalleDistribucionCanillaDto> CanillasFechaLiq,
|
|
IEnumerable<DetalleDistribucionCanillaDto> CanillasAccFechaLiq,
|
|
IEnumerable<ObtenerCtrlDevolucionesDto> CtrlDevolucionesRemitos,
|
|
IEnumerable<ControlDevolucionesReporteDto> CtrlDevolucionesParaDistCan,
|
|
IEnumerable<DevueltosOtrosDiasDto> CtrlDevolucionesOtrosDias,
|
|
string? Error
|
|
)> ObtenerReporteDistribucionCanillasAsync(DateTime fecha, int idEmpresa)
|
|
{
|
|
try
|
|
{
|
|
var canillasTask = _reportesRepository.GetDetalleDistribucionCanillasPubliAsync(fecha, idEmpresa);
|
|
var canillasAccTask = _reportesRepository.GetDetalleDistribucionCanillasAccPubliAsync(fecha, idEmpresa);
|
|
var canillasAllTask = _reportesRepository.GetDetalleDistribucionCanillasAllPubliAsync(fecha, idEmpresa);
|
|
var canillasFechaLiqTask = _reportesRepository.GetDetalleDistribucionCanillasPubliFechaLiqAsync(fecha, idEmpresa);
|
|
var canillasAccFechaLiqTask = _reportesRepository.GetDetalleDistribucionCanillasAccPubliFechaLiqAsync(fecha, idEmpresa);
|
|
var ctrlDevolucionesRemitosTask = _reportesRepository.GetReporteObtenerCtrlDevolucionesAsync(fecha, idEmpresa); // SP_ObtenerCtrlDevoluciones
|
|
var ctrlDevolucionesParaDistCanTask = _reportesRepository.GetReporteCtrlDevolucionesParaDistCanAsync(fecha, idEmpresa); // SP_DistCanillasCantidadEntradaSalida
|
|
var ctrlDevolucionesOtrosDiasTask = _reportesRepository.GetEntradaSalidaOtrosDiasAsync(fecha, idEmpresa); // SP_DistCanillasCantidadEntradaSalidaOtrosDias
|
|
|
|
await Task.WhenAll(
|
|
canillasTask, canillasAccTask, canillasAllTask,
|
|
canillasFechaLiqTask, canillasAccFechaLiqTask,
|
|
ctrlDevolucionesRemitosTask, ctrlDevolucionesParaDistCanTask,
|
|
ctrlDevolucionesOtrosDiasTask
|
|
);
|
|
|
|
var detallesOriginales = await ctrlDevolucionesParaDistCanTask ?? Enumerable.Empty<ControlDevolucionesReporteDto>();
|
|
var detallesOrdenados = detallesOriginales.OrderBy(d => d.Tipo).ToList();
|
|
|
|
Func<IEnumerable<DetalleDistribucionCanillaDto>, IEnumerable<DetalleDistribucionCanillaDto>> toUtc =
|
|
items => items?.Select(c => { if (c.Fecha.HasValue) c.Fecha = DateTime.SpecifyKind(c.Fecha.Value.Date, DateTimeKind.Utc); return c; }).ToList()
|
|
?? Enumerable.Empty<DetalleDistribucionCanillaDto>();
|
|
|
|
return (
|
|
toUtc(await canillasTask),
|
|
toUtc(await canillasAccTask),
|
|
await canillasAllTask ?? Enumerable.Empty<DetalleDistribucionCanillaAllDto>(),
|
|
toUtc(await canillasFechaLiqTask),
|
|
toUtc(await canillasAccFechaLiqTask),
|
|
await ctrlDevolucionesRemitosTask ?? Enumerable.Empty<ObtenerCtrlDevolucionesDto>(),
|
|
detallesOrdenados,
|
|
await ctrlDevolucionesOtrosDiasTask ?? Enumerable.Empty<DevueltosOtrosDiasDto>(),
|
|
null
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Reporte Distribucion Canillas para fecha {Fecha} y empresa {IdEmpresa}.", fecha, idEmpresa);
|
|
return (
|
|
Enumerable.Empty<DetalleDistribucionCanillaDto>(),
|
|
Enumerable.Empty<DetalleDistribucionCanillaDto>(),
|
|
Enumerable.Empty<DetalleDistribucionCanillaAllDto>(),
|
|
Enumerable.Empty<DetalleDistribucionCanillaDto>(),
|
|
Enumerable.Empty<DetalleDistribucionCanillaDto>(),
|
|
Enumerable.Empty<ObtenerCtrlDevolucionesDto>(),
|
|
Enumerable.Empty<ControlDevolucionesReporteDto>(),
|
|
Enumerable.Empty<DevueltosOtrosDiasDto>(),
|
|
"Error interno al generar el reporte de distribución de canillas."
|
|
);
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<TiradasPublicacionesSeccionesDto> Data, string? Error)> ObtenerTiradasPublicacionesSeccionesAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta, int idPlanta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<TiradasPublicacionesSeccionesDto>(), "Fecha 'Desde' no puede ser mayor que 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetTiradasPublicacionesSeccionesAsync(idPublicacion, fechaDesde, fechaHasta, idPlanta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Tiradas por Publicación y Secciones.");
|
|
return (Enumerable.Empty<TiradasPublicacionesSeccionesDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<TiradasPublicacionesSeccionesDto> Data, string? Error)> ObtenerTiradasPublicacionesSeccionesConsolidadoAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<TiradasPublicacionesSeccionesDto>(), "Fecha 'Desde' no puede ser mayor que 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetTiradasPublicacionesSeccionesConsolidadoAsync(idPublicacion, fechaDesde, fechaHasta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Tiradas por Publicación y Secciones (Consolidado).");
|
|
return (Enumerable.Empty<TiradasPublicacionesSeccionesDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ConsumoBobinasSeccionDto> Data, string? Error)> ObtenerConsumoBobinasPorSeccionAsync(DateTime fechaDesde, DateTime fechaHasta, int idPlanta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<ConsumoBobinasSeccionDto>(), "Fecha 'Desde' no puede ser mayor que 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetConsumoBobinasPorSeccionAsync(fechaDesde, fechaHasta, idPlanta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Consumo de Bobinas por Sección.");
|
|
return (Enumerable.Empty<ConsumoBobinasSeccionDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ConsumoBobinasSeccionDto> Data, string? Error)> ObtenerConsumoBobinasPorSeccionConsolidadoAsync(DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<ConsumoBobinasSeccionDto>(), "Fecha 'Desde' no puede ser mayor que 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetConsumoBobinasPorSeccionConsolidadoAsync(fechaDesde, fechaHasta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Consumo de Bobinas por Sección (Consolidado).");
|
|
return (Enumerable.Empty<ConsumoBobinasSeccionDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ConsumoBobinasPublicacionDto> Data, string? Error)> ObtenerConsumoBobinasPorPublicacionAsync(DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta) return (Enumerable.Empty<ConsumoBobinasPublicacionDto>(), "Fecha 'Desde' no puede ser mayor que 'Hasta'.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetConsumoBobinasPorPublicacionAsync(fechaDesde, fechaHasta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Consumo de Bobinas por Publicación.");
|
|
return (Enumerable.Empty<ConsumoBobinasPublicacionDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ComparativaConsumoBobinasDto> Data, string? Error)> ObtenerComparativaConsumoBobinasAsync(DateTime fechaInicioMesA, DateTime fechaFinMesA, DateTime fechaInicioMesB, DateTime fechaFinMesB, int idPlanta)
|
|
{
|
|
if (fechaInicioMesA > fechaFinMesA || fechaInicioMesB > fechaFinMesB) return (Enumerable.Empty<ComparativaConsumoBobinasDto>(), "Fechas de inicio no pueden ser mayores que las de fin para los meses.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetComparativaConsumoBobinasAsync(fechaInicioMesA, fechaFinMesA, fechaInicioMesB, fechaFinMesB, idPlanta);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Comparativa de Consumo de Bobinas.");
|
|
return (Enumerable.Empty<ComparativaConsumoBobinasDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ComparativaConsumoBobinasDto> Data, string? Error)> ObtenerComparativaConsumoBobinasConsolidadoAsync(DateTime fechaInicioMesA, DateTime fechaFinMesA, DateTime fechaInicioMesB, DateTime fechaFinMesB)
|
|
{
|
|
if (fechaInicioMesA > fechaFinMesA || fechaInicioMesB > fechaFinMesB) return (Enumerable.Empty<ComparativaConsumoBobinasDto>(), "Fechas de inicio no pueden ser mayores que las de fin para los meses.");
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetComparativaConsumoBobinasConsolidadoAsync(fechaInicioMesA, fechaFinMesA, fechaInicioMesB, fechaFinMesB);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Comparativa de Consumo de Bobinas (Consolidado).");
|
|
return (Enumerable.Empty<ComparativaConsumoBobinasDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
// Implementación para ReporteCuentasDistribuidores
|
|
public async Task<(
|
|
IEnumerable<BalanceCuentaDistDto> EntradasSalidas,
|
|
IEnumerable<BalanceCuentaDebCredDto> DebitosCreditos,
|
|
IEnumerable<BalanceCuentaPagosDto> Pagos,
|
|
IEnumerable<SaldoDto> Saldos,
|
|
string? Error
|
|
)> ObtenerReporteCuentasDistribuidorAsync(int idDistribuidor, int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
return (Enumerable.Empty<BalanceCuentaDistDto>(), Enumerable.Empty<BalanceCuentaDebCredDto>(), Enumerable.Empty<BalanceCuentaPagosDto>(), Enumerable.Empty<SaldoDto>(), "Fecha 'Desde' no puede ser mayor que 'Hasta'.");
|
|
|
|
try
|
|
{
|
|
var esTask = _reportesRepository.GetBalanceCuentaDistEntradaSalidaPorEmpresaAsync(idDistribuidor, idEmpresa, fechaDesde, fechaHasta);
|
|
var dcTask = _reportesRepository.GetBalanceCuentDistDebCredEmpresaAsync(idDistribuidor, idEmpresa, fechaDesde, fechaHasta);
|
|
var paTask = _reportesRepository.GetBalanceCuentDistPagosEmpresaAsync(idDistribuidor, idEmpresa, fechaDesde, fechaHasta);
|
|
var saTask = _reportesRepository.GetBalanceCuentSaldosEmpresasAsync("Distribuidores", idDistribuidor, idEmpresa);
|
|
|
|
await Task.WhenAll(esTask, dcTask, paTask, saTask);
|
|
|
|
Func<IEnumerable<BalanceCuentaDistDto>, IEnumerable<BalanceCuentaDistDto>> esToUtc =
|
|
items => items?.Select(i => { i.Fecha = DateTime.SpecifyKind(i.Fecha.Date, DateTimeKind.Utc); return i; }).ToList()
|
|
?? Enumerable.Empty<BalanceCuentaDistDto>();
|
|
Func<IEnumerable<BalanceCuentaDebCredDto>, IEnumerable<BalanceCuentaDebCredDto>> dcToUtc =
|
|
items => items?.Select(i => { i.Fecha = DateTime.SpecifyKind(i.Fecha.Date, DateTimeKind.Utc); return i; }).ToList()
|
|
?? Enumerable.Empty<BalanceCuentaDebCredDto>();
|
|
Func<IEnumerable<BalanceCuentaPagosDto>, IEnumerable<BalanceCuentaPagosDto>> paToUtc =
|
|
items => items?.Select(i => { i.Fecha = DateTime.SpecifyKind(i.Fecha.Date, DateTimeKind.Utc); return i; }).ToList()
|
|
?? Enumerable.Empty<BalanceCuentaPagosDto>();
|
|
|
|
return (
|
|
esToUtc(await esTask),
|
|
dcToUtc(await dcTask),
|
|
paToUtc(await paTask),
|
|
await saTask ?? Enumerable.Empty<SaldoDto>(),
|
|
null
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Reporte Cuentas Distribuidor.");
|
|
return (
|
|
Enumerable.Empty<BalanceCuentaDistDto>(),
|
|
Enumerable.Empty<BalanceCuentaDebCredDto>(),
|
|
Enumerable.Empty<BalanceCuentaPagosDto>(),
|
|
Enumerable.Empty<SaldoDto>(),
|
|
"Error interno al generar el reporte."
|
|
);
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ListadoDistribucionDistSimpleDto> Simple, IEnumerable<ListadoDistribucionDistPromedioDiaDto> Promedios, string? Error)> ObtenerListadoDistribucionDistribuidoresAsync(int idDistribuidor, int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
return (Enumerable.Empty<ListadoDistribucionDistSimpleDto>(), Enumerable.Empty<ListadoDistribucionDistPromedioDiaDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
|
|
try
|
|
{
|
|
// Llamar a los métodos específicos del repositorio
|
|
var simpleDataTask = _reportesRepository.GetListadoDistribucionDistSimpleAsync(idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
|
|
var promediosDataTask = _reportesRepository.GetListadoDistribucionDistPromedioDiaAsync(idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
|
|
|
|
await Task.WhenAll(simpleDataTask, promediosDataTask);
|
|
|
|
return (await simpleDataTask, await promediosDataTask, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener Listado Distribucion (Distribuidores). Params: Dist={idDistribuidor}, Pub={idPublicacion}, Desde={fechaDesde}, Hasta={fechaHasta}", idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
|
|
return (Enumerable.Empty<ListadoDistribucionDistSimpleDto>(), Enumerable.Empty<ListadoDistribucionDistPromedioDiaDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(
|
|
IEnumerable<LiquidacionCanillaDetalleDto> Detalles,
|
|
IEnumerable<LiquidacionCanillaGananciaDto> Ganancias,
|
|
string? Error
|
|
)> ObtenerDatosTicketLiquidacionAsync(DateTime fecha, int idCanilla)
|
|
{
|
|
try
|
|
{
|
|
var detallesTask = _reportesRepository.GetLiquidacionCanillaDetalleAsync(fecha, idCanilla);
|
|
var gananciasTask = _reportesRepository.GetLiquidacionCanillaGananciasAsync(fecha, idCanilla);
|
|
|
|
await Task.WhenAll(detallesTask, gananciasTask);
|
|
|
|
var detalles = await detallesTask;
|
|
var ganancias = await gananciasTask;
|
|
|
|
if ((detalles == null || !detalles.Any()) && (ganancias == null || !ganancias.Any()))
|
|
{
|
|
// Podrías optar por no devolver error aquí si es válido que uno de los dos esté vacío
|
|
// y manejarlo en el controlador o el RDLC.
|
|
}
|
|
|
|
// Convertir fechas a UTC si es necesario para el RDLC (aunque estos DTOs no tienen fechas)
|
|
|
|
return (
|
|
detalles ?? Enumerable.Empty<LiquidacionCanillaDetalleDto>(),
|
|
ganancias ?? Enumerable.Empty<LiquidacionCanillaGananciaDto>(),
|
|
null
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en ReportesService al obtener datos para Ticket Liquidación Canilla. Fecha: {Fecha}, Canilla: {IdCanilla}", fecha, idCanilla);
|
|
return (
|
|
Enumerable.Empty<LiquidacionCanillaDetalleDto>(),
|
|
Enumerable.Empty<LiquidacionCanillaGananciaDto>(),
|
|
"Error interno al obtener los datos para el ticket de liquidación."
|
|
);
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ListadoDistCanMensualDiariosDto> Data, string? Error)> ObtenerReporteMensualDiariosAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
|
|
{
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetReporteMensualDiariosAsync(fechaDesde, fechaHasta, esAccionista);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error al obtener reporte mensual canillitas (diarios).");
|
|
return (Enumerable.Empty<ListadoDistCanMensualDiariosDto>(), "Error al obtener datos del reporte (diarios).");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<ListadoDistCanMensualPubDto> Data, string? Error)> ObtenerReporteMensualPorPublicacionAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
|
|
{
|
|
try
|
|
{
|
|
var data = await _reportesRepository.GetReporteMensualPorPublicacionAsync(fechaDesde, fechaHasta, esAccionista);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error al obtener reporte mensual canillitas (por publicación).");
|
|
return (Enumerable.Empty<ListadoDistCanMensualPubDto>(), "Error al obtener datos del reporte (por publicación).");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<FacturasParaReporteDto> Data, string? Error)> ObtenerFacturasParaReportePublicidad(int anio, int mes)
|
|
{
|
|
if (anio < 2020 || mes < 1 || mes > 12)
|
|
{
|
|
return (Enumerable.Empty<FacturasParaReporteDto>(), "Período no válido.");
|
|
}
|
|
var periodo = $"{anio}-{mes:D2}";
|
|
try
|
|
{
|
|
// Llamada directa al nuevo método del repositorio
|
|
var data = await _reportesRepository.GetDatosReportePublicidadAsync(periodo);
|
|
return (data, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en servicio al obtener datos para reporte de publicidad para el período {Periodo}", periodo);
|
|
return (new List<FacturasParaReporteDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
|
|
public async Task<(IEnumerable<DistribucionSuscripcionDto> Altas, IEnumerable<DistribucionSuscripcionDto> Bajas, string? Error)> ObtenerReporteDistribucionSuscripcionesAsync(DateTime fechaDesde, DateTime fechaHasta)
|
|
{
|
|
if (fechaDesde > fechaHasta)
|
|
{
|
|
return (Enumerable.Empty<DistribucionSuscripcionDto>(), Enumerable.Empty<DistribucionSuscripcionDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");
|
|
}
|
|
|
|
try
|
|
{
|
|
// Ejecutamos ambas consultas en paralelo para mayor eficiencia
|
|
var altasTask = _reportesRepository.GetDistribucionSuscripcionesActivasAsync(fechaDesde, fechaHasta);
|
|
var bajasTask = _reportesRepository.GetDistribucionSuscripcionesBajasAsync(fechaDesde, fechaHasta);
|
|
|
|
await Task.WhenAll(altasTask, bajasTask);
|
|
|
|
return (await altasTask, await bajasTask, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error en servicio al obtener datos para reporte de distribución de suscripciones.");
|
|
return (Enumerable.Empty<DistribucionSuscripcionDto>(), Enumerable.Empty<DistribucionSuscripcionDto>(), "Error interno al generar el reporte.");
|
|
}
|
|
}
|
|
}
|
|
} |