Files
GestionIntegralWeb/Backend/GestionIntegral.Api/Services/Reportes/ReportesService.cs
dmolinari 899e0a173f Refactor: Mejora la lógica de facturación y la UI
Este commit introduce una refactorización significativa en el módulo de
suscripciones para alinear el sistema con reglas de negocio clave:
facturación consolidada por empresa, cobro a mes adelantado con
imputación de ajustes diferida, y una interfaz de usuario más clara.

Backend:
- **Facturación por Empresa:** Se modifica `FacturacionService` para
  agrupar las suscripciones por cliente y empresa, generando una
  factura consolidada para cada combinación. Esto asegura la correcta
  separación fiscal.
- **Imputación de Ajustes:** Se ajusta la lógica para que la facturación
  de un período (ej. Septiembre) aplique únicamente los ajustes
  pendientes cuya fecha corresponde al período anterior (Agosto).
- **Cierre Secuencial:** Se implementa una validación en
  `GenerarFacturacionMensual` que impide generar la facturación de un
  período si el anterior no ha sido cerrado, garantizando el orden
  cronológico.
- **Emails Consolidados:** El proceso de notificación automática al
  generar el cierre ahora envía un único email consolidado por
  suscriptor, detallando los cargos de todas sus facturas/empresas.
- **Envío de PDF Individual:** Se refactoriza el endpoint de envío manual
  para que opere sobre una `idFactura` individual y adjunte el PDF
  correspondiente si existe.
- **Repositorios Mejorados:** Se optimizan y añaden métodos en
  `FacturaRepository` y `AjusteRepository` para soportar los nuevos
  requisitos de filtrado y consulta de datos consolidados.

Frontend:
- **Separación de Vistas:** La página de "Facturación" se divide en dos:
  - `ProcesosPage`: Para acciones masivas (generar cierre, archivo de
    débito, procesar respuesta).
  - `ConsultaFacturasPage`: Una nueva página dedicada a buscar,
    filtrar y gestionar facturas individuales con una interfaz de doble
    acordeón (Suscriptor -> Empresa).
- **Filtros Avanzados:** La página `ConsultaFacturasPage` ahora incluye
  filtros por nombre de suscriptor, estado de pago y estado de
  facturación.
- **Filtros de Fecha por Defecto:** La página de "Cuenta Corriente"
  ahora filtra por el mes actual por defecto para mejorar el rendimiento
  y la usabilidad.
- **Validación de Fechas:** Se añade lógica en los filtros de fecha para
  impedir la selección de rangos inválidos.
- **Validación de Monto de Pago:** El modal de pago manual ahora impide
  registrar un monto superior al saldo pendiente de la factura.
2025-08-08 09:48:15 -03:00

554 lines
31 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.");
}
}
}
}