1738 lines
		
	
	
		
			93 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1738 lines
		
	
	
		
			93 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using GestionIntegral.Api.Services.Reportes;
 | |
| using Microsoft.AspNetCore.Authorization;
 | |
| using Microsoft.AspNetCore.Mvc;
 | |
| using Microsoft.Reporting.NETCore;
 | |
| using Microsoft.Extensions.Logging;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Threading.Tasks;
 | |
| using GestionIntegral.Api.Dtos.Reportes;
 | |
| using GestionIntegral.Api.Data.Repositories.Impresion;
 | |
| using System.IO;
 | |
| using System.Linq;
 | |
| using GestionIntegral.Api.Data.Repositories.Distribucion;
 | |
| using GestionIntegral.Api.Services.Distribucion;
 | |
| 
 | |
| namespace GestionIntegral.Api.Controllers
 | |
| {
 | |
|     [Route("api/[controller]")]
 | |
|     [ApiController]
 | |
|     [Authorize]
 | |
|     public class ReportesController : ControllerBase
 | |
|     {
 | |
|         private readonly IReportesService _reportesService;
 | |
|         private readonly ILogger<ReportesController> _logger;
 | |
|         private readonly IPlantaRepository _plantaRepository;
 | |
|         private readonly IPublicacionRepository _publicacionRepository;
 | |
|         private readonly IEmpresaRepository _empresaRepository;
 | |
|         private readonly IDistribuidorRepository _distribuidorRepository; // Para obtener el nombre del distribuidor
 | |
|         private readonly INovedadCanillaService _novedadCanillaService;
 | |
| 
 | |
| 
 | |
|         // Permisos
 | |
|         private const string PermisoVerReporteExistenciaPapel = "RR005";
 | |
|         private const string PermisoVerReporteMovimientoBobinas = "RR006";
 | |
|         private const string PermisoVerListadoDistribucion = "RR002";
 | |
|         private const string PermisoVerControlDevoluciones = "RR003";
 | |
|         private const string PermisoVerComprobanteLiquidacionCanilla = "MC005";
 | |
|         private const string PermisoVerBalanceCuentas = "RR001";
 | |
|         private const string PermisoVerReporteTiradas = "RR008";
 | |
|         private const string PermisoVerReporteConsumoBobinas = "RR007";
 | |
|         private const string PermisoVerReporteNovedadesCanillas = "RR004";
 | |
|         private const string PermisoVerReporteListadoDistMensual = "RR009";
 | |
| 
 | |
|         public ReportesController(
 | |
|             IReportesService reportesService,
 | |
|             INovedadCanillaService novedadCanillaService,
 | |
|             ILogger<ReportesController> logger,
 | |
|             IPlantaRepository plantaRepository,
 | |
|             IPublicacionRepository publicacionRepository,
 | |
|             IEmpresaRepository empresaRepository,
 | |
|             IDistribuidorRepository distribuidorRepository)
 | |
|         {
 | |
|             _reportesService = reportesService;
 | |
|             _novedadCanillaService = novedadCanillaService;
 | |
|             _logger = logger;
 | |
|             _plantaRepository = plantaRepository;
 | |
|             _publicacionRepository = publicacionRepository;
 | |
|             _empresaRepository = empresaRepository;
 | |
|             _distribuidorRepository = distribuidorRepository;
 | |
|         }
 | |
| 
 | |
|         private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
 | |
| 
 | |
|         // GET: api/reportes/existencia-papel
 | |
|         [HttpGet("existencia-papel")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ExistenciaPapelDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status500InternalServerError)]
 | |
|         public async Task<IActionResult> GetReporteExistenciaPapel(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteExistenciaPapel))
 | |
|             {
 | |
|                 _logger.LogWarning("Acceso denegado a GetReporteExistenciaPapel. Usuario: {User}", User.Identity?.Name ?? "Desconocido");
 | |
|                 return Forbid();
 | |
|             }
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerExistenciaPapelAsync(fechaDesde, fechaHasta, idPlanta, consolidado); // <--- CORREGIDO
 | |
| 
 | |
|             if (error != null)
 | |
|             {
 | |
|                 return BadRequest(new { message = error });
 | |
|             }
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("existencia-papel/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status500InternalServerError)]
 | |
|         public async Task<IActionResult> GetReporteExistenciaPapelPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteExistenciaPapel)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerExistenciaPapelAsync(fechaDesde, fechaHasta, idPlanta, consolidado); // <--- CORREGIDO
 | |
| 
 | |
|             if (error != null)
 | |
|             {
 | |
|                 return BadRequest(new { message = error });
 | |
|             }
 | |
|             if (data == null || !data.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF con los parámetros seleccionados." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = consolidado ? "Controllers/Reportes/RDLC/ReporteExistenciaPapelConsolidado.rdlc" : "Controllers/Reportes/RDLC/ReporteExistenciaPapel.rdlc";
 | |
| 
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSConsumoBobinas", data));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>();
 | |
|                 parameters.Add(new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")));
 | |
|                 parameters.Add(new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")));
 | |
| 
 | |
|                 string nombrePlantaParam = "Consolidado";
 | |
|                 if (!consolidado && idPlanta.HasValue)
 | |
|                 {
 | |
|                     var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
 | |
|                     nombrePlantaParam = planta?.Nombre ?? "N/A";
 | |
|                 }
 | |
|                 else if (consolidado)
 | |
|                 {
 | |
|                     // Para el consolidado, el RDLC ReporteExistenciaPapelConsolidado.txt NO espera NomPlanta
 | |
|                 }
 | |
|                 else
 | |
|                 { // No consolidado pero idPlanta es NULL (aunque el servicio ya valida esto)
 | |
|                     nombrePlantaParam = "N/A";
 | |
|                 }
 | |
|                 // Solo añadir NomPlanta si NO es consolidado, porque el RDLC consolidado no lo tiene.
 | |
|                 if (!consolidado)
 | |
|                 {
 | |
|                     parameters.Add(new ReportParameter("NomPlanta", nombrePlantaParam));
 | |
|                 }
 | |
| 
 | |
| 
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ExistenciaPapel_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}_{(consolidado ? "Consolidado" : $"Planta{idPlanta}")}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Existencia de Papel.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         [HttpGet("movimiento-bobinas")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<MovimientoBobinasDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         public async Task<IActionResult> GetReporteMovimientoBobinas(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int idPlanta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteMovimientoBobinas)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerMovimientoBobinasAsync(fechaDesde, fechaHasta, idPlanta); // <--- CORREGIDO
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("movimiento-bobinas/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteMovimientoBobinasPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int idPlanta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteMovimientoBobinas)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerMovimientoBobinasAsync(fechaDesde, fechaHasta, idPlanta); // <--- CORREGIDO
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF del movimiento de bobinas con los parámetros seleccionados." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteMovimientoBobinas.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSMovimientoBobinas", data)); // El RDLC usa "DSMovimientoBobinas"
 | |
| 
 | |
|                 var planta = await _plantaRepository.GetByIdAsync(idPlanta);
 | |
|                 var parameters = new List<ReportParameter>();
 | |
|                 parameters.Add(new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")));
 | |
|                 parameters.Add(new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")));
 | |
|                 parameters.Add(new ReportParameter("NomPlanta", planta?.Nombre ?? "N/A"));
 | |
| 
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"MovimientoBobinas_Planta{idPlanta}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Movimiento de Bobinas.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/movimiento-bobinas-estado
 | |
|         [HttpGet("movimiento-bobinas-estado")] // Endpoint para los datos JSON
 | |
|         [ProducesResponseType(typeof(MovimientoBobinasPorEstadoResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteMovimientoBobinasPorEstado(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int idPlanta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteMovimientoBobinas)) return Forbid(); // Reutilizar permiso
 | |
| 
 | |
|             var (detalle, totales, error) = await _reportesService.ObtenerMovimientoBobinasPorEstadoAsync(fechaDesde, fechaHasta, idPlanta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             if ((detalle == null || !detalle.Any()) && (totales == null || !totales.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para el reporte de movimiento de bobinas por estado." });
 | |
|             }
 | |
| 
 | |
|             var response = new MovimientoBobinasPorEstadoResponseDto
 | |
|             {
 | |
|                 Detalle = detalle ?? Enumerable.Empty<MovimientoBobinaEstadoDetalleDto>(),
 | |
|                 Totales = totales ?? Enumerable.Empty<MovimientoBobinaEstadoTotalDto>()
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("movimiento-bobinas-estado/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteMovimientoBobinasEstadoPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int idPlanta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteMovimientoBobinas)) return Forbid();
 | |
| 
 | |
|             var (detalle, totales, error) = await _reportesService.ObtenerMovimientoBobinasPorEstadoAsync(fechaDesde, fechaHasta, idPlanta); // <--- CORREGIDO
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if ((detalle == null || !detalle.Any()) && (totales == null || !totales.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF del movimiento de bobinas por estado con los parámetros seleccionados." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteMovimientoBobinasEstado.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSMovimientoBobinasEstado", detalle ?? new List<MovimientoBobinaEstadoDetalleDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSMovimientoBobinasEstadoTotales", totales ?? new List<MovimientoBobinaEstadoTotalDto>()));
 | |
| 
 | |
|                 var planta = await _plantaRepository.GetByIdAsync(idPlanta);
 | |
|                 var parameters = new List<ReportParameter>();
 | |
|                 parameters.Add(new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")));
 | |
|                 parameters.Add(new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")));
 | |
|                 parameters.Add(new ReportParameter("NomPlanta", planta?.Nombre ?? "N/A"));
 | |
| 
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"MovimientoBobinasEstado_Planta{idPlanta}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Movimiento de Bobinas por Estado.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/listado-distribucion-general
 | |
|         [HttpGet("listado-distribucion-general")]
 | |
|         [ProducesResponseType(typeof(ListadoDistribucionGeneralResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionGeneral(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (resumen, promedios, error) = await _reportesService.ObtenerListadoDistribucionGeneralAsync(idPublicacion, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if ((resumen == null || !resumen.Any()) && (promedios == null || !promedios.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para el listado de distribución general." });
 | |
|             }
 | |
| 
 | |
|             var response = new ListadoDistribucionGeneralResponseDto
 | |
|             {
 | |
|                 Resumen = resumen ?? Enumerable.Empty<ListadoDistribucionGeneralResumenDto>(),
 | |
|                 PromediosPorDia = promedios ?? Enumerable.Empty<ListadoDistribucionGeneralPromedioDiaDto>()
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("listado-distribucion-general/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionGeneralPdf(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde, // Usado para Mes y Año en el SP
 | |
|             [FromQuery] DateTime fechaHasta) // Usado para el nombre del archivo y potencialmente como parámetro si el SP cambia
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (resumen, promedios, error) = await _reportesService.ObtenerListadoDistribucionGeneralAsync(idPublicacion, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if ((resumen == null || !resumen.Any()) && (promedios == null || !promedios.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteListadoDistribucionGeneral.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 // Los nombres de DataSet deben coincidir con los del RDLC. Basado en DSListadoDistribucion.txt
 | |
|                 report.DataSources.Add(new ReportDataSource("DSResumenMensual", resumen ?? new List<ListadoDistribucionGeneralResumenDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSResumenMensualPorDiaSemana", promedios ?? new List<ListadoDistribucionGeneralPromedioDiaDto>()));
 | |
| 
 | |
|                 var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("NomPubli", publicacion?.Nombre ?? "N/A"),
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("MMMM 'de' yyyy")) // El RDLC espera un parámetro FechaDesde
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ListadoDistribucionGeneral_Pub{idPublicacion}_{fechaDesde:yyyyMM}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Listado Distribucion General.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/listado-distribucion-canillas
 | |
|         [HttpGet("listado-distribucion-canillas")]
 | |
|         [ProducesResponseType(typeof(ListadoDistribucionCanillasResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionCanillas(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (simple, promedios, error) = await _reportesService.ObtenerListadoDistribucionCanillasAsync(idPublicacion, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if ((simple == null || !simple.Any()) && (promedios == null || !promedios.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para el listado de distribución de canillas." });
 | |
|             }
 | |
| 
 | |
|             var response = new ListadoDistribucionCanillasResponseDto
 | |
|             {
 | |
|                 DetalleSimple = simple ?? Enumerable.Empty<ListadoDistribucionCanillasSimpleDto>(),
 | |
|                 PromediosPorDia = promedios ?? Enumerable.Empty<ListadoDistribucionCanillasPromedioDiaDto>()
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("listado-distribucion-canillas/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionCanillasPdf(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (simple, promedios, error) = await _reportesService.ObtenerListadoDistribucionCanillasAsync(idPublicacion, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if ((simple == null || !simple.Any()) && (promedios == null || !promedios.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteListadoDistribucionCanillas.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucion", simple ?? new List<ListadoDistribucionCanillasSimpleDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionAgDias", promedios ?? new List<ListadoDistribucionCanillasPromedioDiaDto>()));
 | |
| 
 | |
|                 var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("NomPubli", publicacion?.Nombre ?? "N/A"),
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ListadoDistribucionCanillas_Pub{idPublicacion}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Listado Distribucion Canillas.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/listado-distribucion-canillas-importe
 | |
|         [HttpGet("listado-distribucion-canillas-importe")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ListadoDistribucionCanillasImporteDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionCanillasConImporte(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] bool esAccionista)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerListadoDistribucionCanillasConImporteAsync(idPublicacion, fechaDesde, fechaHasta, esAccionista);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para el listado de distribución de canillas con importe." });
 | |
|             }
 | |
| 
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("listado-distribucion-canillas-importe/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionCanillasConImportePdf(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] bool esAccionista)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerListadoDistribucionCanillasConImporteAsync(idPublicacion, fechaDesde, fechaHasta, esAccionista);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteListadoDistribucionCanImp.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCan", data));
 | |
| 
 | |
|                 var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("NomPubli", publicacion?.Nombre ?? "N/A"),
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("CanAcc", esAccionista ? "1" : "0")
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string tipoVendedor = esAccionista ? "Accionistas" : "Canillitas";
 | |
|                 string fileName = $"ListadoDistCanImp_Pub{idPublicacion}_{tipoVendedor}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Listado Distribucion Canillas con Importe.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/venta-mensual-secretaria/el-dia
 | |
|         [HttpGet("venta-mensual-secretaria/el-dia")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<VentaMensualSecretariaElDiaDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetVentaMensualSecretariaElDia([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // Asumiendo RR002 para todos estos
 | |
|             var (data, error) = await _reportesService.ObtenerVentaMensualSecretariaElDiaAsync(fechaDesde, fechaHasta);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para el reporte de ventas 'El Día'." });
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("venta-mensual-secretaria/el-dia/pdf")]
 | |
|         public async Task<IActionResult> GetVentaMensualSecretariaElDiaPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // Asumiendo RR002
 | |
|             var (data, error) = await _reportesService.ObtenerVentaMensualSecretariaElDiaAsync(fechaDesde, fechaHasta);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteVentaMensualSecretariaElDia.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucion", data)); // Basado en el RDLC
 | |
|                 report.SetParameters(new[] {
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 });
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 return File(pdfBytes, "application/pdf", $"VentaMensualSecretaria_ElDia_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF VentaMensualSecretariaElDia."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/venta-mensual-secretaria/el-plata
 | |
|         [HttpGet("venta-mensual-secretaria/el-plata")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<VentaMensualSecretariaElPlataDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetVentaMensualSecretariaElPlata([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // Asumiendo RR002
 | |
|             var (data, error) = await _reportesService.ObtenerVentaMensualSecretariaElPlataAsync(fechaDesde, fechaHasta);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para el reporte de ventas 'El Plata'." });
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("venta-mensual-secretaria/el-plata/pdf")]
 | |
|         public async Task<IActionResult> GetVentaMensualSecretariaElPlataPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // Asumiendo RR002
 | |
|             var (data, error) = await _reportesService.ObtenerVentaMensualSecretariaElPlataAsync(fechaDesde, fechaHasta);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteVentaMensualSecretariaElPlata.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucion", data)); // Basado en el RDLC
 | |
|                 report.SetParameters(new[] {
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 });
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 return File(pdfBytes, "application/pdf", $"VentaMensualSecretaria_ElPlata_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF VentaMensualSecretariaElPlata."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/venta-mensual-secretaria/tirada-devolucion
 | |
|         [HttpGet("venta-mensual-secretaria/tirada-devolucion")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<VentaMensualSecretariaTirDevoDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetVentaMensualSecretariaTirDevo([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // Asumiendo RR002
 | |
|             var (data, error) = await _reportesService.ObtenerVentaMensualSecretariaTirDevoAsync(fechaDesde, fechaHasta);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para el reporte de tirada/devolución." });
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("venta-mensual-secretaria/tirada-devolucion/pdf")]
 | |
|         public async Task<IActionResult> GetVentaMensualSecretariaTirDevoPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // Asumiendo RR002
 | |
|             var (data, error) = await _reportesService.ObtenerVentaMensualSecretariaTirDevoAsync(fechaDesde, fechaHasta);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteVentaMensualSecretariaTirDevo.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucion", data)); // Basado en el RDLC
 | |
|                 report.SetParameters(new[] {
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 });
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 return File(pdfBytes, "application/pdf", $"VentaMensualSecretaria_TirDevo_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF VentaMensualSecretariaTirDevo."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/distribucion-canillas
 | |
|         [HttpGet("distribucion-canillas")] // Endpoint para los datos JSON
 | |
|         [ProducesResponseType(typeof(ReporteDistribucionCanillasResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteDistribucionCanillasData([FromQuery] DateTime fecha, [FromQuery] int idEmpresa)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerComprobanteLiquidacionCanilla)) return Forbid();
 | |
| 
 | |
|             var (canillas, canillasAcc, canillasAll, canillasFechaLiq, canillasAccFechaLiq,
 | |
|                  ctrlDevolucionesRemitos, ctrlDevolucionesParaDistCan, ctrlDevolucionesOtrosDias, error) =
 | |
|                 await _reportesService.ObtenerReporteDistribucionCanillasAsync(fecha, idEmpresa);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             // Una validación simple, podrías hacerla más granular si es necesario
 | |
|             bool noHayDatos = (canillas == null || !canillas.Any()) &&
 | |
|                               (canillasAcc == null || !canillasAcc.Any()) &&
 | |
|                               (canillasAll == null || !canillasAll.Any()) &&
 | |
|                               (ctrlDevolucionesParaDistCan == null || !ctrlDevolucionesParaDistCan.Any()); // Podrías añadir más aquí
 | |
| 
 | |
|             if (noHayDatos)
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para el reporte de distribución de canillas." });
 | |
|             }
 | |
| 
 | |
|             var response = new ReporteDistribucionCanillasResponseDto
 | |
|             {
 | |
|                 Canillas = canillas ?? Enumerable.Empty<DetalleDistribucionCanillaDto>(),
 | |
|                 CanillasAccionistas = canillasAcc ?? Enumerable.Empty<DetalleDistribucionCanillaDto>(),
 | |
|                 CanillasTodos = canillasAll ?? Enumerable.Empty<DetalleDistribucionCanillaAllDto>(),
 | |
|                 CanillasLiquidadasOtraFecha = canillasFechaLiq ?? Enumerable.Empty<DetalleDistribucionCanillaDto>(),
 | |
|                 CanillasAccionistasLiquidadasOtraFecha = canillasAccFechaLiq ?? Enumerable.Empty<DetalleDistribucionCanillaDto>(),
 | |
|                 ControlDevolucionesRemitos = ctrlDevolucionesRemitos ?? Enumerable.Empty<ObtenerCtrlDevolucionesDto>(),
 | |
|                 ControlDevolucionesDetalle = ctrlDevolucionesParaDistCan ?? Enumerable.Empty<ControlDevolucionesReporteDto>(),
 | |
|                 ControlDevolucionesOtrosDias = ctrlDevolucionesOtrosDias ?? Enumerable.Empty<DevueltosOtrosDiasDto>()
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("distribucion-canillas/pdf")]
 | |
|         public async Task<IActionResult> GetReporteDistribucionCanillasPdf([FromQuery] DateTime fecha, [FromQuery] int idEmpresa, [FromQuery] bool soloTotales = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerComprobanteLiquidacionCanilla)) return Forbid();
 | |
| 
 | |
|             // CORRECCIÓN AQUÍ: Añadir la variable para el nuevo elemento de la tupla
 | |
|             var (
 | |
|                 canillas,
 | |
|                 canillasAcc,
 | |
|                 canillasAll,
 | |
|                 canillasFechaLiq,
 | |
|                 canillasAccFechaLiq,
 | |
|                 ctrlDevolucionesRemitos,        // Renombrado para claridad
 | |
|                 ctrlDevolucionesParaDistCan,
 | |
|                 _,                             // Descartamos ctrlDevolucionesOtrosDias si no se usa aquí
 | |
|                 error
 | |
|             ) = await _reportesService.ObtenerReporteDistribucionCanillasAsync(fecha, idEmpresa);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             // La lógica de noHayDatosParaTotales y noHayDatosParaDetalle debería usar los nombres correctos
 | |
|             bool noHayDatosParaTotales = (canillasAll == null || !canillasAll.Any()) &&
 | |
|                                          (ctrlDevolucionesRemitos == null || !ctrlDevolucionesRemitos.Any()) && // Usar ctrlDevolucionesRemitos o ctrlDevolucionesParaDistCan según el RDLC
 | |
|                                          (ctrlDevolucionesParaDistCan == null || !ctrlDevolucionesParaDistCan.Any());
 | |
| 
 | |
|             bool noHayDatosParaDetalle = noHayDatosParaTotales &&
 | |
|                                          (canillas == null || !canillas.Any()) &&
 | |
|                                          (canillasAcc == null || !canillasAcc.Any()) &&
 | |
|                                          (canillasFechaLiq == null || !canillasFechaLiq.Any()) &&
 | |
|                                          (canillasAccFechaLiq == null || !canillasAccFechaLiq.Any());
 | |
| 
 | |
|             if ((soloTotales && noHayDatosParaTotales) || (!soloTotales && noHayDatosParaDetalle))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF del reporte de distribución de canillas." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = soloTotales ? "Controllers/Reportes/RDLC/ReporteDistribucionCanillasTotales.rdlc" : "Controllers/Reportes/RDLC/ReporteDistribucionCanillas.rdlc";
 | |
| 
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
| 
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCan", canillas ?? new List<DetalleDistribucionCanillaDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanAcc", canillasAcc ?? new List<DetalleDistribucionCanillaDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanALL", canillasAll ?? new List<DetalleDistribucionCanillaAllDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanFechaLiq", canillasFechaLiq ?? new List<DetalleDistribucionCanillaDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanAccFechaLiq", canillasAccFechaLiq ?? new List<DetalleDistribucionCanillaDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSObtenerCtrlDevoluciones", ctrlDevolucionesRemitos ?? new List<ObtenerCtrlDevolucionesDto>())); // Usa el renombrado
 | |
|                 report.DataSources.Add(new ReportDataSource("DSCtrlDevoluciones", ctrlDevolucionesParaDistCan ?? new List<ControlDevolucionesReporteDto>()));
 | |
| 
 | |
|                 var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("FechaConsultada", fecha.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("Empresa", empresa?.Nombre ?? "N/A")
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string tipoReporte = soloTotales ? "Totales" : "Detalle";
 | |
|                 string fileName = $"DistribucionCanillas_{tipoReporte}_Emp{idEmpresa}_{fecha:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Reporte Distribucion Canillas.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/control-devoluciones
 | |
|         [HttpGet("control-devoluciones")]
 | |
|         [ProducesResponseType(typeof(ControlDevolucionesDataResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetControlDevolucionesData([FromQuery] DateTime fecha, [FromQuery] int idEmpresa)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerControlDevoluciones)) return Forbid();
 | |
| 
 | |
|             var (
 | |
|                 _, // canillas
 | |
|                 _, // canillasAcc
 | |
|                 _, // canillasAll
 | |
|                 _, // canillasFechaLiq
 | |
|                 _, // canillasAccFechaLiq
 | |
|                 ctrlDevolucionesRemitosData,         // Para SP_ObtenerCtrlDevoluciones -> DataSet "DSObtenerCtrlDevoluciones"
 | |
|                 ctrlDevolucionesParaDistCanData,   // Para SP_DistCanillasCantidadEntradaSalida -> DataSet "DSCtrlDevoluciones"
 | |
|                 ctrlDevolucionesOtrosDiasData,     // Para SP_DistCanillasCantidadEntradaSalidaOtrosDias -> DataSet "DSCtrlDevolucionesOtrosDias"
 | |
|                 error
 | |
|             ) = await _reportesService.ObtenerReporteDistribucionCanillasAsync(fecha, idEmpresa); // Reutilizamos este método
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             // Adaptar la condición de "no hay datos" a los DataSets que realmente usa este reporte
 | |
|             if ((ctrlDevolucionesParaDistCanData == null || !ctrlDevolucionesParaDistCanData.Any()) &&
 | |
|                 (ctrlDevolucionesOtrosDiasData == null || !ctrlDevolucionesOtrosDiasData.Any()) &&
 | |
|                 (ctrlDevolucionesRemitosData == null || !ctrlDevolucionesRemitosData.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el reporte de control de devoluciones." });
 | |
|             }
 | |
| 
 | |
|             var response = new ControlDevolucionesDataResponseDto
 | |
|             {
 | |
|                 DetallesCtrlDevoluciones = ctrlDevolucionesParaDistCanData ?? Enumerable.Empty<ControlDevolucionesReporteDto>(),
 | |
|                 DevolucionesOtrosDias = ctrlDevolucionesOtrosDiasData ?? Enumerable.Empty<DevueltosOtrosDiasDto>(),
 | |
|                 RemitosIngresados = ctrlDevolucionesRemitosData ?? Enumerable.Empty<ObtenerCtrlDevolucionesDto>()
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("control-devoluciones/pdf")]
 | |
|         public async Task<IActionResult> GetReporteControlDevolucionesPdf([FromQuery] DateTime fecha, [FromQuery] int idEmpresa)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerControlDevoluciones)) return Forbid();
 | |
| 
 | |
|             // La tupla ahora devuelve un campo más
 | |
|             var (
 | |
|                 _, _, _, _, _,
 | |
|                 ctrlDevolucionesRemitosData,      // Para DSObtenerCtrlDevoluciones
 | |
|                 ctrlDevolucionesParaDistCanData,  // Para DSCtrlDevoluciones
 | |
|                 ctrlDevolucionesOtrosDiasData,    // <--- NUEVO: Para DSCtrlDevolucionesOtrosDias
 | |
|                 error
 | |
|             ) = await _reportesService.ObtenerReporteDistribucionCanillasAsync(fecha, idEmpresa);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             // Ajustamos la condición para verificar los DataSets que realmente usa este reporte específico
 | |
|             if ((ctrlDevolucionesRemitosData == null || !ctrlDevolucionesRemitosData.Any()) &&
 | |
|                 (ctrlDevolucionesParaDistCanData == null || !ctrlDevolucionesParaDistCanData.Any()) &&
 | |
|                 (ctrlDevolucionesOtrosDiasData == null || !ctrlDevolucionesOtrosDiasData.Any()) // <--- AÑADIDO A LA VERIFICACIÓN
 | |
|                )
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF para control de devoluciones." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteCtrlDevoluciones.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
| 
 | |
|                 // DataSet que usa SP_DistCanillasCantidadEntradaSalida
 | |
|                 report.DataSources.Add(new ReportDataSource("DSCtrlDevoluciones", ctrlDevolucionesParaDistCanData ?? new List<ControlDevolucionesReporteDto>()));
 | |
| 
 | |
|                 // DataSet que usa SP_DistCanillasCantidadEntradaSalidaOtrosDias
 | |
|                 report.DataSources.Add(new ReportDataSource("DSCtrlDevolucionesOtrosDias", ctrlDevolucionesOtrosDiasData ?? new List<DevueltosOtrosDiasDto>())); // <--- CORREGIDO
 | |
| 
 | |
|                 // DataSet que usa SP_ObtenerCtrlDevoluciones
 | |
|                 report.DataSources.Add(new ReportDataSource("DSObtenerCtrlDevoluciones", ctrlDevolucionesRemitosData ?? new List<ObtenerCtrlDevolucionesDto>()));
 | |
| 
 | |
| 
 | |
|                 var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("FechaConsultada", fecha.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("NomEmp", empresa?.Nombre ?? "N/A")
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ControlDevoluciones_Emp{idEmpresa}_{fecha:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Control Devoluciones.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/cuentas-distribuidores
 | |
|         [HttpGet("cuentas-distribuidores")]
 | |
|         [ProducesResponseType(typeof(ReporteCuentasDistribuidorResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteCuentasDistribuidoresData(
 | |
|             [FromQuery] int idDistribuidor,
 | |
|             [FromQuery] int idEmpresa,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerBalanceCuentas)) return Forbid();
 | |
| 
 | |
|             var (entradasSalidas, debitosCreditos, pagos, saldos, error) =
 | |
|                 await _reportesService.ObtenerReporteCuentasDistribuidorAsync(idDistribuidor, idEmpresa, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (!entradasSalidas.Any() && !debitosCreditos.Any() && !pagos.Any() && !saldos.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el reporte de cuenta del distribuidor." });
 | |
|             }
 | |
| 
 | |
|             var distribuidor = await _distribuidorRepository.GetByIdAsync(idDistribuidor);
 | |
|             var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
 | |
| 
 | |
|             var response = new ReporteCuentasDistribuidorResponseDto
 | |
|             {
 | |
|                 EntradasSalidas = entradasSalidas ?? Enumerable.Empty<BalanceCuentaDistDto>(),
 | |
|                 DebitosCreditos = debitosCreditos ?? Enumerable.Empty<BalanceCuentaDebCredDto>(),
 | |
|                 Pagos = pagos ?? Enumerable.Empty<BalanceCuentaPagosDto>(),
 | |
|                 Saldos = saldos ?? Enumerable.Empty<SaldoDto>(),
 | |
|                 NombreDistribuidor = distribuidor.Distribuidor?.Nombre,
 | |
|                 NombreEmpresa = empresa?.Nombre
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("cuentas-distribuidores/pdf")]
 | |
|         public async Task<IActionResult> GetReporteCuentasDistribuidoresPdf(
 | |
|             [FromQuery] int idDistribuidor,
 | |
|             [FromQuery] int idEmpresa,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerBalanceCuentas)) return Forbid();
 | |
| 
 | |
|             var (entradasSalidas, debitosCreditos, pagos, saldos, error) =
 | |
|                 await _reportesService.ObtenerReporteCuentasDistribuidorAsync(idDistribuidor, idEmpresa, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (!entradasSalidas.Any() && !debitosCreditos.Any() && !pagos.Any() && !saldos.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el reporte de cuenta del distribuidor." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteCuentasDistribuidores.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
| 
 | |
|                 report.DataSources.Add(new ReportDataSource("DSDistribuidoresEntradasSalidas", entradasSalidas ?? new List<BalanceCuentaDistDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSDistribuidoresDebCred", debitosCreditos ?? new List<BalanceCuentaDebCredDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSDistribuidoresPagos", pagos ?? new List<BalanceCuentaPagosDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSDistribuidoresSaldos", saldos ?? new List<SaldoDto>()));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"CuentaDistribuidor_{idDistribuidor}_Emp{idEmpresa}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Cuentas Distribuidores.");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/tiradas-publicaciones-secciones
 | |
|         [HttpGet("tiradas-publicaciones-secciones")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<TiradasPublicacionesSeccionesDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteTiradasPublicacionesSeccionesData(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteTiradas)) return Forbid();
 | |
| 
 | |
|             IEnumerable<TiradasPublicacionesSeccionesDto> data;
 | |
|             string? errorMsg;
 | |
| 
 | |
|             if (consolidado)
 | |
|             {
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerTiradasPublicacionesSeccionesConsolidadoAsync(idPublicacion, fechaDesde, fechaHasta);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (!idPlanta.HasValue) return BadRequest(new { message = "Se requiere IdPlanta para reportes no consolidados." });
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerTiradasPublicacionesSeccionesAsync(idPublicacion, fechaDesde, fechaHasta, idPlanta.Value);
 | |
|             }
 | |
| 
 | |
|             if (errorMsg != null) return BadRequest(new { message = errorMsg });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("tiradas-publicaciones-secciones/pdf")]
 | |
|         public async Task<IActionResult> GetReporteTiradasPublicacionesSeccionesPdf(
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteTiradas)) return Forbid();
 | |
| 
 | |
|             IEnumerable<TiradasPublicacionesSeccionesDto> data;
 | |
|             string? errorMsg; // Para recibir el mensaje de error
 | |
| 
 | |
|             if (consolidado)
 | |
|             {
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerTiradasPublicacionesSeccionesConsolidadoAsync(idPublicacion, fechaDesde, fechaHasta);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (!idPlanta.HasValue) return BadRequest(new { message = "Se requiere IdPlanta para reportes no consolidados." });
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerTiradasPublicacionesSeccionesAsync(idPublicacion, fechaDesde, fechaHasta, idPlanta.Value);
 | |
|             }
 | |
| 
 | |
|             if (errorMsg != null) return BadRequest(new { message = errorMsg });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = consolidado ?
 | |
|                     "Controllers/Reportes/RDLC/ReporteTiradasPublicacionesSeccionesConsolidado.rdlc" :
 | |
|                     "Controllers/Reportes/RDLC/ReporteTiradasPublicacionesSecciones.rdlc";
 | |
| 
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSTiradasPublicacionesSecciones", data));
 | |
| 
 | |
|                 var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("Mes", fechaDesde.ToString("MMMM yyyy")),
 | |
|                     new ReportParameter("NomPubli", publicacion?.Nombre ?? "N/A")
 | |
|                 };
 | |
|                 if (!consolidado && idPlanta.HasValue)
 | |
|                 {
 | |
|                     var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
 | |
|                     parameters.Add(new ReportParameter("NomPlanta", planta?.Nombre ?? "N/A"));
 | |
|                 }
 | |
| 
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"TiradasSecciones_Pub{idPublicacion}_{(consolidado ? "Consolidado" : $"Planta{idPlanta}")}_{fechaDesde:yyyyMM}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF Tiradas Publicaciones Secciones."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/consumo-bobinas-seccion
 | |
|         [HttpGet("consumo-bobinas-seccion")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ConsumoBobinasSeccionDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteConsumoBobinasSeccionData(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteConsumoBobinas)) return Forbid();
 | |
| 
 | |
|             IEnumerable<ConsumoBobinasSeccionDto> data;
 | |
|             string? errorMsg;
 | |
| 
 | |
|             if (consolidado)
 | |
|             {
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerConsumoBobinasPorSeccionConsolidadoAsync(fechaDesde, fechaHasta);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (!idPlanta.HasValue) return BadRequest(new { message = "Se requiere IdPlanta para reportes no consolidados." });
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerConsumoBobinasPorSeccionAsync(fechaDesde, fechaHasta, idPlanta.Value);
 | |
|             }
 | |
| 
 | |
|             if (errorMsg != null) return BadRequest(new { message = errorMsg });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("consumo-bobinas-seccion/pdf")]
 | |
|         public async Task<IActionResult> GetReporteConsumoBobinasSeccionPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteConsumoBobinas)) return Forbid();
 | |
| 
 | |
|             IEnumerable<ConsumoBobinasSeccionDto> data;
 | |
|             string? errorMsg;
 | |
| 
 | |
|             if (consolidado)
 | |
|             {
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerConsumoBobinasPorSeccionConsolidadoAsync(fechaDesde, fechaHasta);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (!idPlanta.HasValue) return BadRequest(new { message = "Se requiere IdPlanta para reportes no consolidados." });
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerConsumoBobinasPorSeccionAsync(fechaDesde, fechaHasta, idPlanta.Value);
 | |
|             }
 | |
| 
 | |
|             if (errorMsg != null) return BadRequest(new { message = errorMsg });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = consolidado ?
 | |
|                    "Controllers/Reportes/RDLC/ReporteConsumoBobinasSeccionConsolidado.rdlc" :
 | |
|                    "Controllers/Reportes/RDLC/ReporteConsumoBobinasSeccion.rdlc";
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSConsumoBobinasSeccion", data));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 };
 | |
|                 if (!consolidado && idPlanta.HasValue)
 | |
|                 {
 | |
|                     var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
 | |
|                     parameters.Add(new ReportParameter("NomPlanta", planta?.Nombre ?? "N/A"));
 | |
|                 }
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ConsumoBobinasSeccion_{(consolidado ? "Consolidado" : $"Planta{idPlanta}")}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF Consumo Bobinas por Seccion."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/consumo-bobinas-publicacion
 | |
|         [HttpGet("consumo-bobinas-publicacion")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ConsumoBobinasPublicacionDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteConsumoBobinasPublicacionData(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteConsumoBobinas)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerConsumoBobinasPorPublicacionAsync(fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("consumo-bobinas-publicacion/pdf")]
 | |
|         public async Task<IActionResult> GetReporteConsumoBobinasPublicacionPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteConsumoBobinas)) return Forbid();
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerConsumoBobinasPorPublicacionAsync(fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteConsumoBobinasPublicacion.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSConsumoBobinasPublicacion", data));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ConsumoBobinasPublicacion_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF Consumo Bobinas por Publicacion."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/comparativa-consumo-bobinas
 | |
|         [HttpGet("comparativa-consumo-bobinas")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ComparativaConsumoBobinasDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteComparativaConsumoBobinasData(
 | |
|             [FromQuery] DateTime fechaInicioMesA, [FromQuery] DateTime fechaFinMesA,
 | |
|             [FromQuery] DateTime fechaInicioMesB, [FromQuery] DateTime fechaFinMesB,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteConsumoBobinas)) return Forbid();
 | |
| 
 | |
|             IEnumerable<ComparativaConsumoBobinasDto> data;
 | |
|             string? errorMsg;
 | |
| 
 | |
|             if (consolidado)
 | |
|             {
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerComparativaConsumoBobinasConsolidadoAsync(fechaInicioMesA, fechaFinMesA, fechaInicioMesB, fechaFinMesB);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (!idPlanta.HasValue) return BadRequest(new { message = "Se requiere IdPlanta para reportes no consolidados." });
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerComparativaConsumoBobinasAsync(fechaInicioMesA, fechaFinMesA, fechaInicioMesB, fechaFinMesB, idPlanta.Value);
 | |
|             }
 | |
| 
 | |
|             if (errorMsg != null) return BadRequest(new { message = errorMsg });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             return Ok(data);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("comparativa-consumo-bobinas/pdf")]
 | |
|         public async Task<IActionResult> GetReporteComparativaConsumoBobinasPdf(
 | |
|             [FromQuery] DateTime fechaInicioMesA, [FromQuery] DateTime fechaFinMesA,
 | |
|             [FromQuery] DateTime fechaInicioMesB, [FromQuery] DateTime fechaFinMesB,
 | |
|             [FromQuery] int? idPlanta,
 | |
|             [FromQuery] bool consolidado = false)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteConsumoBobinas)) return Forbid();
 | |
| 
 | |
|             IEnumerable<ComparativaConsumoBobinasDto> data;
 | |
|             string? errorMsg;
 | |
| 
 | |
|             if (consolidado)
 | |
|             {
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerComparativaConsumoBobinasConsolidadoAsync(fechaInicioMesA, fechaFinMesA, fechaInicioMesB, fechaFinMesB);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (!idPlanta.HasValue) return BadRequest(new { message = "Se requiere IdPlanta para reportes no consolidados." });
 | |
|                 (data, errorMsg) = await _reportesService.ObtenerComparativaConsumoBobinasAsync(fechaInicioMesA, fechaFinMesA, fechaInicioMesB, fechaFinMesB, idPlanta.Value);
 | |
|             }
 | |
| 
 | |
|             if (errorMsg != null) return BadRequest(new { message = errorMsg });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el reporte." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = consolidado ?
 | |
|                     "Controllers/Reportes/RDLC/ReporteConsumoBobinasMesesConsolidado.rdlc" :
 | |
|                     "Controllers/Reportes/RDLC/ReporteConsumoBobinasMeses.rdlc";
 | |
| 
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSConsumoBobinasMeses", data));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("MesA", fechaInicioMesA.ToString("MMMM yyyy")),
 | |
|                     new ReportParameter("MesB", fechaInicioMesB.ToString("MMMM yyyy"))
 | |
|                 };
 | |
|                 if (!consolidado && idPlanta.HasValue)
 | |
|                 {
 | |
|                     var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
 | |
|                     parameters.Add(new ReportParameter("NomPlanta", planta?.Nombre ?? "N/A"));
 | |
|                 }
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ComparativaConsumoBobinas_{(consolidado ? "Consolidado" : $"Planta{idPlanta}")}_{fechaInicioMesA:yyyyMM}_vs_{fechaInicioMesB:yyyyMM}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF Comparativa Consumo Bobinas."); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/listado-distribucion-distribuidores
 | |
|         [HttpGet("listado-distribucion-distribuidores")]
 | |
|         [ProducesResponseType(typeof(ListadoDistribucionDistribuidoresResponseDto), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionDistribuidores(
 | |
|             [FromQuery] int idDistribuidor,
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid(); // RR002
 | |
| 
 | |
|             (IEnumerable<ListadoDistribucionDistSimpleDto> simple, IEnumerable<ListadoDistribucionDistPromedioDiaDto> promedios, string? error) result =
 | |
|     await _reportesService.ObtenerListadoDistribucionDistribuidoresAsync(idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (result.error != null) return BadRequest(new { message = result.error });
 | |
|             if ((result.simple == null || !result.simple.Any()) && (result.promedios == null || !result.promedios.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para el listado de distribución de distribuidores." });
 | |
|             }
 | |
| 
 | |
|             var response = new ListadoDistribucionDistribuidoresResponseDto
 | |
|             {
 | |
|                 DetalleSimple = result.simple ?? Enumerable.Empty<ListadoDistribucionDistSimpleDto>(),
 | |
|                 PromediosPorDia = result.promedios ?? Enumerable.Empty<ListadoDistribucionDistPromedioDiaDto>()
 | |
|             };
 | |
| 
 | |
|             return Ok(response);
 | |
|         }
 | |
| 
 | |
|         [HttpGet("listado-distribucion-distribuidores/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetListadoDistribucionDistribuidoresPdf(
 | |
|             [FromQuery] int idDistribuidor,
 | |
|             [FromQuery] int idPublicacion,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
 | |
| 
 | |
|             var (simple, promedios, error) = await _reportesService.ObtenerListadoDistribucionDistribuidoresAsync(idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if ((simple == null || !simple.Any()) && (promedios == null || !promedios.Any()))
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay datos para generar el PDF." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 // USAREMOS EL MISMO RDLC QUE PARA CANILLITAS, YA QUE TIENE LA MISMA ESTRUCTURA DE DATASOURCES
 | |
|                 using (var fs = new FileStream("Controllers/Reportes/RDLC/ReporteListadoDistribucion.rdlc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 // Nombres de DataSources deben coincidir con los del RDLC
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucion", simple ?? new List<ListadoDistribucionDistSimpleDto>()));
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionAgDias", promedios ?? new List<ListadoDistribucionDistPromedioDiaDto>()));
 | |
| 
 | |
|                 var publicacionData = await _publicacionRepository.GetByIdAsync(idPublicacion);
 | |
|                 var distribuidorData = await _distribuidorRepository.GetByIdAsync(idDistribuidor);
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|                 {
 | |
|                     new ReportParameter("NomPubli", publicacionData.Publicacion?.Nombre ?? "N/A"),
 | |
|                     new ReportParameter("NomDist", distribuidorData.Distribuidor?.Nombre ?? "N/A"), // Parámetro para el RDLC
 | |
|                     new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                     new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|                 };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ListadoDistribucion_Dist{idDistribuidor}_Pub{idPublicacion}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Listado Distribucion (Distribuidores).");
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del reporte.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         [HttpGet("ticket-liquidacion-canilla/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetTicketLiquidacionCanillaPdf(
 | |
|         [FromQuery] DateTime fecha,
 | |
|         [FromQuery] int idCanilla,
 | |
|         [FromQuery] bool esAccionista = false) // Añadir esAccionista
 | |
|         {
 | |
|             // Usar PermisoVerComprobanteLiquidacionCanilla o uno específico si lo creas
 | |
|             if (!TienePermiso(PermisoVerComprobanteLiquidacionCanilla)) return Forbid();
 | |
| 
 | |
|             var (detalles, ganancias, error) = await _reportesService.ObtenerDatosTicketLiquidacionAsync(fecha, idCanilla);
 | |
| 
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
| 
 | |
|             // El PDF podría funcionar incluso si solo uno de los datasets tiene datos, 
 | |
|             // pero es bueno verificar si al menos hay detalles.
 | |
|             if (detalles == null || !detalles.Any())
 | |
|             {
 | |
|                 return NotFound(new { message = "No hay detalles de liquidación para generar el PDF." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = esAccionista ?
 | |
|                     "Controllers/Reportes/RDLC/ReporteLiquidacionCanillasAcc.rdlc" :
 | |
|                     "Controllers/Reportes/RDLC/ReporteLiquidacionCanillas.rdlc";
 | |
| 
 | |
|                 if (!System.IO.File.Exists(rdlcPath))
 | |
|                 {
 | |
|                     _logger.LogError("Archivo RDLC no encontrado: {Path}", rdlcPath);
 | |
|                     return StatusCode(StatusCodes.Status500InternalServerError, $"Archivo de reporte no encontrado: {System.IO.Path.GetFileName(rdlcPath)}");
 | |
|                 }
 | |
| 
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
| 
 | |
|                 report.DataSources.Add(new ReportDataSource("DSLiquidacionCanillas", detalles));
 | |
|                 if (!esAccionista) // El reporte de accionistas podría no usar el dataset de ganancias, o usar uno diferente
 | |
|                 {
 | |
|                     report.DataSources.Add(new ReportDataSource("DSLiquidacionCanillasGanancias", ganancias ?? new List<LiquidacionCanillaGananciaDto>()));
 | |
|                 }
 | |
| 
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|         {
 | |
|             // El RDLC espera "FechaLiqui"
 | |
|             new ReportParameter("FechaLiqui", fecha.ToString("dd/MM/yyyy"))
 | |
|         };
 | |
|                 // El nombre del canilla ya está en el DataSet "DSLiquidacionCanillas" (campo "Canilla")
 | |
|                 // Si el RDLC lo espera como parámetro, lo añadiríamos aquí.
 | |
|                 // var canilla = await _canillaRepository.GetByIdAsync(idCanilla);
 | |
|                 // parameters.Add(new ReportParameter("NombreCanillaParam", canilla?.NomApe ?? "N/A"));
 | |
| 
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string tipo = esAccionista ? "Accionista" : "Canillita";
 | |
|                 string fileName = $"TicketLiquidacion_{tipo}_{idCanilla}_{fecha:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para Ticket Liquidación Canilla. Fecha: {Fecha}, Canilla: {IdCanilla}", fecha, idCanilla);
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del ticket.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/novedades-canillas
 | |
|         // Obtiene los datos para el reporte de novedades de canillitas
 | |
|         [HttpGet("novedades-canillas")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<NovedadesCanillasReporteDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)] // Si no hay datos
 | |
|         [ProducesResponseType(StatusCodes.Status500InternalServerError)]
 | |
|         public async Task<IActionResult> GetReporteNovedadesCanillasData(
 | |
|             [FromQuery] int idEmpresa,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteNovedadesCanillas))
 | |
|             {
 | |
|                 _logger.LogWarning("Acceso denegado a GetReporteNovedadesCanillasData. Usuario: {User}", User.Identity?.Name ?? "Desconocido");
 | |
|                 return Forbid();
 | |
|             }
 | |
| 
 | |
|             if (fechaDesde > fechaHasta)
 | |
|             {
 | |
|                 return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 var reporteData = await _novedadCanillaService.ObtenerReporteNovedadesAsync(idEmpresa, fechaDesde, fechaHasta);
 | |
|                 if (reporteData == null || !reporteData.Any())
 | |
|                 {
 | |
|                     // Devolver Ok con array vacío en lugar de NotFound para que el frontend pueda manejarlo como "sin datos"
 | |
|                     return Ok(Enumerable.Empty<NovedadesCanillasReporteDto>());
 | |
|                 }
 | |
|                 return Ok(reporteData);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar datos para el reporte de novedades de canillitas. Empresa: {IdEmpresa}, Desde: {FechaDesde}, Hasta: {FechaHasta}", idEmpresa, fechaDesde, fechaHasta);
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, new { message = "Error interno al generar el reporte de novedades." });
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/novedades-canillas/pdf
 | |
|         // Genera el PDF del reporte de novedades de canillitas
 | |
|         [HttpGet("novedades-canillas/pdf")]
 | |
|         [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         [ProducesResponseType(StatusCodes.Status500InternalServerError)]
 | |
|         public async Task<IActionResult> GetReporteNovedadesCanillasPdf(
 | |
|             [FromQuery] int idEmpresa,
 | |
|         [FromQuery] DateTime fechaDesde,
 | |
|         [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteNovedadesCanillas)) // RR004
 | |
|             {
 | |
|                 _logger.LogWarning("Acceso denegado a GetReporteNovedadesCanillasPdf. Usuario: {User}", User.Identity?.Name ?? "Desconocido");
 | |
|                 return Forbid();
 | |
|             }
 | |
|             if (fechaDesde > fechaHasta)
 | |
|             {
 | |
|                 return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 // Obtener datos para AMBOS datasets
 | |
|                 var novedadesData = await _novedadCanillaService.ObtenerReporteNovedadesAsync(idEmpresa, fechaDesde, fechaHasta);
 | |
|                 var gananciasData = await _novedadCanillaService.ObtenerReporteGananciasAsync(idEmpresa, fechaDesde, fechaHasta); // << OBTENER DATOS DE GANANCIAS
 | |
| 
 | |
|                 // Verificar si hay datos en *alguno* de los datasets necesarios para el reporte
 | |
|                 if ((novedadesData == null || !novedadesData.Any()) && (gananciasData == null || !gananciasData.Any()))
 | |
|                 {
 | |
|                     return NotFound(new { message = "No hay datos para generar el PDF con los parámetros seleccionados." });
 | |
|                 }
 | |
| 
 | |
|                 var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
 | |
| 
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = Path.Combine("Controllers", "Reportes", "RDLC", "ReporteListadoNovedadesCanillas.rdlc");
 | |
|                 if (!System.IO.File.Exists(rdlcPath))
 | |
|                 {
 | |
|                     _logger.LogError("Archivo RDLC no encontrado en la ruta: {RdlcPath}", rdlcPath);
 | |
|                     return StatusCode(StatusCodes.Status500InternalServerError, "Archivo de definición de reporte no encontrado.");
 | |
|                 }
 | |
| 
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
| 
 | |
|                 // Nombre del DataSet en RDLC para SP_DistCanillasNovedades (detalles)
 | |
|                 report.DataSources.Add(new ReportDataSource("DSNovedadesCanillasDetalles", novedadesData ?? new List<NovedadesCanillasReporteDto>()));
 | |
| 
 | |
|                 // Nombre del DataSet en RDLC para SP_DistCanillasGanancias (ganancias/resumen)
 | |
|                 report.DataSources.Add(new ReportDataSource("DSNovedadesCanillas", gananciasData ?? new List<CanillaGananciaReporteDto>()));
 | |
| 
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|             {
 | |
|                 new ReportParameter("NomEmp", empresa?.Nombre ?? "N/A"),
 | |
|                 new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                 new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
 | |
|             };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string fileName = $"ReporteNovedadesCanillas_Emp{idEmpresa}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
 | |
|                 return File(pdfBytes, "application/pdf", fileName);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al generar PDF para el reporte de novedades de canillitas. Empresa: {IdEmpresa}", idEmpresa);
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, new { message = $"Error interno al generar el PDF: {ex.Message}" });
 | |
|             }
 | |
|         }
 | |
|         // GET: api/reportes/novedades-canillas-ganancias
 | |
|         [HttpGet("novedades-canillas-ganancias")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<CanillaGananciaReporteDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         [ProducesResponseType(StatusCodes.Status404NotFound)]
 | |
|         public async Task<IActionResult> GetReporteGananciasCanillasData(
 | |
|             [FromQuery] int idEmpresa,
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteNovedadesCanillas)) return Forbid(); // RR004
 | |
| 
 | |
|             if (fechaDesde > fechaHasta)
 | |
|             {
 | |
|                 return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
 | |
|             }
 | |
|             try
 | |
|             {
 | |
|                 var gananciasData = await _novedadCanillaService.ObtenerReporteGananciasAsync(idEmpresa, fechaDesde, fechaHasta);
 | |
|                 if (gananciasData == null || !gananciasData.Any())
 | |
|                 {
 | |
|                     return Ok(Enumerable.Empty<CanillaGananciaReporteDto>());
 | |
|                 }
 | |
|                 return Ok(gananciasData);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _logger.LogError(ex, "Error al obtener datos de ganancias para el reporte de novedades. Empresa: {IdEmpresa}", idEmpresa);
 | |
|                 return StatusCode(StatusCodes.Status500InternalServerError, new { message = "Error interno al obtener datos de ganancias." });
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // GET: api/reportes/listado-distribucion-mensual/diarios
 | |
|         [HttpGet("listado-distribucion-mensual/diarios")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ListadoDistCanMensualDiariosDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         public async Task<IActionResult> GetListadoDistMensualDiarios(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] bool esAccionista)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
 | |
|             if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerReporteMensualDiariosAsync(fechaDesde, fechaHasta, esAccionista);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             return Ok(data ?? Enumerable.Empty<ListadoDistCanMensualDiariosDto>());
 | |
|         }
 | |
| 
 | |
|         [HttpGet("listado-distribucion-mensual/diarios/pdf")]
 | |
|         public async Task<IActionResult> GetListadoDistMensualDiariosPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] bool esAccionista)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
 | |
|             if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerReporteMensualDiariosAsync(fechaDesde, fechaHasta, esAccionista);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el PDF." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = Path.Combine("Controllers", "Reportes", "RDLC", "ReporteListadoDistribucionCanMensualDiarios.rdlc");
 | |
|                 if (!System.IO.File.Exists(rdlcPath))
 | |
|                 {
 | |
|                     _logger.LogError("Archivo RDLC no encontrado: {Path}", rdlcPath);
 | |
|                     return StatusCode(StatusCodes.Status500InternalServerError, $"Archivo de reporte no encontrado: {Path.GetFileName(rdlcPath)}");
 | |
|                 }
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanMensualDiarios", data));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|             {
 | |
|                 new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                 new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")),
 | |
|                 new ReportParameter("CanAcc", esAccionista ? "1" : "0") // El RDLC espera un Integer para CanAcc
 | |
|             };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string tipoDesc = esAccionista ? "Accionistas" : "Canillitas";
 | |
|                 return File(pdfBytes, "application/pdf", $"ListadoDistMensualDiarios_{tipoDesc}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF ListadoDistMensualDiarios"); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         // GET: api/reportes/listado-distribucion-mensual/publicaciones
 | |
|         [HttpGet("listado-distribucion-mensual/publicaciones")]
 | |
|         [ProducesResponseType(typeof(IEnumerable<ListadoDistCanMensualPubDto>), StatusCodes.Status200OK)]
 | |
|         [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | |
|         [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | |
|         public async Task<IActionResult> GetListadoDistMensualPorPublicacion(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] bool esAccionista)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
 | |
|             if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerReporteMensualPorPublicacionAsync(fechaDesde, fechaHasta, esAccionista);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             return Ok(data ?? Enumerable.Empty<ListadoDistCanMensualPubDto>());
 | |
|         }
 | |
| 
 | |
|         [HttpGet("listado-distribucion-mensual/publicaciones/pdf")]
 | |
|         public async Task<IActionResult> GetListadoDistMensualPorPublicacionPdf(
 | |
|             [FromQuery] DateTime fechaDesde,
 | |
|             [FromQuery] DateTime fechaHasta,
 | |
|             [FromQuery] bool esAccionista)
 | |
|         {
 | |
|             if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
 | |
|             if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
 | |
| 
 | |
|             var (data, error) = await _reportesService.ObtenerReporteMensualPorPublicacionAsync(fechaDesde, fechaHasta, esAccionista);
 | |
|             if (error != null) return BadRequest(new { message = error });
 | |
|             if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el PDF." });
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 LocalReport report = new LocalReport();
 | |
|                 string rdlcPath = Path.Combine("Controllers", "Reportes", "RDLC", "ReporteListadoDistribucionCanMensual.rdlc");
 | |
|                 if (!System.IO.File.Exists(rdlcPath))
 | |
|                 {
 | |
|                     _logger.LogError("Archivo RDLC no encontrado: {Path}", rdlcPath);
 | |
|                     return StatusCode(StatusCodes.Status500InternalServerError, $"Archivo de reporte no encontrado: {Path.GetFileName(rdlcPath)}");
 | |
|                 }
 | |
|                 using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
 | |
|                 {
 | |
|                     report.LoadReportDefinition(fs);
 | |
|                 }
 | |
|                 report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanMensual", data));
 | |
| 
 | |
|                 var parameters = new List<ReportParameter>
 | |
|             {
 | |
|                 new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
 | |
|                 new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")),
 | |
|                 new ReportParameter("CanAcc", esAccionista ? "1" : "0")
 | |
|             };
 | |
|                 report.SetParameters(parameters);
 | |
| 
 | |
|                 byte[] pdfBytes = report.Render("PDF");
 | |
|                 string tipoDesc = esAccionista ? "Accionistas" : "Canillitas";
 | |
|                 return File(pdfBytes, "application/pdf", $"ListadoDistMensualPub_{tipoDesc}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
 | |
|             }
 | |
|             catch (Exception ex) { _logger.LogError(ex, "Error PDF ListadoDistMensualPorPublicacion"); return StatusCode(500, "Error interno."); }
 | |
|         }
 | |
|     }
 | |
| } |