Se introduce un sistema completo para auditar los envíos masivos de correos durante el cierre mensual y se refactoriza la interfaz de usuario de procesos para una mayor claridad y escalabilidad. Además, se mejora la lógica de negocio para la gestión de bajas de suscripciones. ### ✨ Nuevas Características - **Auditoría de Envíos Masivos (Cierre Mensual):** - Se crea una nueva tabla `com_LotesDeEnvio` para registrar cada ejecución del proceso de facturación mensual. - El `FacturacionService` ahora crea un "lote" al iniciar el cierre, registra el resultado de cada envío de email individual asociándolo a dicho lote, y actualiza las estadísticas finales (enviados, fallidos) al terminar. - Se implementa un nuevo `LotesEnvioController` con un endpoint para consultar los detalles de cualquier lote de envío histórico. ### 🔄 Refactorización y Mejoras - **Rediseño de la Página de Procesos:** - La antigua página "Facturación" se renombra a `CierreYProcesosPage` y se rediseña completamente utilizando una interfaz de Pestañas (Tabs). - **Pestaña "Procesos Mensuales":** Aisla las acciones principales (Generar Cierre, Archivo de Débito, Procesar Respuesta), mostrando un resumen del resultado del último envío. - **Pestaña "Historial de Cierres":** Muestra una tabla con todos los lotes de envío pasados y permite al usuario ver los detalles de cada uno en un modal. - **Filtros para el Historial de Cierres:** - Se añaden filtros por Mes y Año a la pestaña de "Historial de Cierres", permitiendo al usuario buscar y auditar procesos pasados de manera eficiente. El filtrado se realiza en el backend para un rendimiento óptimo. - **Lógica de `FechaFin` Obligatoria para Bajas:** - Se implementa una regla de negocio crucial: al cambiar el estado de una suscripción a "Pausada" o "Cancelada", ahora es obligatorio establecer una `FechaFin`. - **Frontend:** El modal de suscripciones ahora gestiona esto automáticamente, haciendo el campo `FechaFin` requerido y visible según el estado seleccionado. - **Backend:** Se añade una validación en `SuscripcionService` como segunda capa de seguridad para garantizar la integridad de los datos. ### 🐛 Corrección de Errores - **Reporte de Distribución:** Se corrigió un bug en la generación del PDF donde la columna de fecha no mostraba la "Fecha de Baja" para las suscripciones finalizadas. Ahora se muestra la fecha correcta según la sección (Altas o Bajas). - **Errores de Compilación y Dependencias:** Se solucionaron varios errores de compilación en el backend, principalmente relacionados con la falta de registro de los nuevos repositorios (`ILoteDeEnvioRepository`, `IEmailLogService`, etc.) en el contenedor de inyección de dependencias (`Program.cs`). - **Errores de Tipado en Frontend:** Se corrigieron múltiples errores de TypeScript en `CierreYProcesosPage` debidos a la inconsistencia entre `PascalCase` (C#) y `camelCase` (JSON/TypeScript), asegurando un mapeo correcto de los datos de la API.
1758 lines
88 KiB
C#
1758 lines
88 KiB
C#
using GestionIntegral.Api.Services.Reportes;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using GestionIntegral.Api.Dtos.Reportes;
|
|
using GestionIntegral.Api.Data.Repositories.Impresion;
|
|
using GestionIntegral.Api.Data.Repositories.Distribucion;
|
|
using GestionIntegral.Api.Services.Distribucion;
|
|
using GestionIntegral.Api.Services.Pdf;
|
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
|
using GestionIntegral.Api.Controllers.Reportes.PdfTemplates;
|
|
using QuestPDF.Infrastructure;
|
|
using System.Globalization;
|
|
|
|
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;
|
|
private readonly IQuestPdfGenerator _pdfGenerator;
|
|
|
|
// 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";
|
|
private const string PermisoVerReporteFacturasPublicidad = "RR010";
|
|
private const string PermisoVerReporteDistSuscripciones = "RR011";
|
|
|
|
public ReportesController(
|
|
IReportesService reportesService,
|
|
INovedadCanillaService novedadCanillaService,
|
|
ILogger<ReportesController> logger,
|
|
IPlantaRepository plantaRepository,
|
|
IPublicacionRepository publicacionRepository,
|
|
IEmpresaRepository empresaRepository,
|
|
IDistribuidorRepository distribuidorRepository,
|
|
IQuestPdfGenerator pdfGenerator)
|
|
{
|
|
_reportesService = reportesService;
|
|
_novedadCanillaService = novedadCanillaService;
|
|
_logger = logger;
|
|
_plantaRepository = plantaRepository;
|
|
_publicacionRepository = publicacionRepository;
|
|
_empresaRepository = empresaRepository;
|
|
_distribuidorRepository = distribuidorRepository;
|
|
_pdfGenerator = pdfGenerator;
|
|
}
|
|
|
|
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);
|
|
|
|
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
|
|
{
|
|
IDocument document; // Se declara aquí
|
|
|
|
if (consolidado)
|
|
{
|
|
var viewModel = new ExistenciaPapelConsolidadoViewModel
|
|
{
|
|
Existencias = data,
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
document = new ExistenciaPapelConsolidadoDocument(viewModel);
|
|
}
|
|
else
|
|
{
|
|
if (!idPlanta.HasValue)
|
|
{
|
|
return BadRequest(new { message = "El idPlanta es requerido para reportes no consolidados." });
|
|
}
|
|
|
|
var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
|
|
var viewModel = new ExistenciaPapelViewModel
|
|
{
|
|
Existencias = data,
|
|
NombrePlanta = planta?.Nombre ?? $"Planta ID {idPlanta.Value}", // Manejo por si no se encuentra
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
document = new ExistenciaPapelDocument(viewModel);
|
|
}
|
|
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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 con QuestPDF 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);
|
|
|
|
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." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var planta = await _plantaRepository.GetByIdAsync(idPlanta);
|
|
|
|
var viewModel = new MovimientoBobinasViewModel
|
|
{
|
|
Movimientos = data,
|
|
NombrePlanta = planta?.Nombre ?? $"Planta ID {idPlanta}",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new MovimientoBobinasDocument(viewModel);
|
|
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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);
|
|
|
|
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." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var planta = await _plantaRepository.GetByIdAsync(idPlanta);
|
|
|
|
var viewModel = new MovimientoBobinasEstadoViewModel
|
|
{
|
|
Detalles = detalle ?? Enumerable.Empty<MovimientoBobinaEstadoDetalleDto>(),
|
|
Totales = totales,
|
|
NombrePlanta = planta?.Nombre ?? $"Planta ID {idPlanta}",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new MovimientoBobinasEstadoDocument(viewModel);
|
|
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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,
|
|
[FromQuery] DateTime fechaHasta)
|
|
{
|
|
if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
|
|
|
|
// El servicio ya devuelve la tupla con los dos conjuntos de datos.
|
|
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
|
|
{
|
|
var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
|
|
|
|
var viewModel = new ListadoDistribucionGeneralViewModel
|
|
{
|
|
ResumenMensual = resumen ?? Enumerable.Empty<ListadoDistribucionGeneralResumenDto>(),
|
|
PromediosPorDia = promedios,
|
|
NombrePublicacion = publicacion?.Nombre ?? "N/A",
|
|
MesConsultado = fechaDesde.ToString("MMMM 'de' yyyy", new CultureInfo("es-ES"))
|
|
};
|
|
|
|
var document = new ListadoDistribucionGeneralDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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
|
|
{
|
|
var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
|
|
|
|
var viewModel = new ListadoDistribucionCanillasViewModel
|
|
{
|
|
DetalleDiario = simple ?? Enumerable.Empty<ListadoDistribucionCanillasSimpleDto>(),
|
|
PromediosPorDia = promedios,
|
|
NombrePublicacion = publicacion?.Nombre ?? "N/A",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ListadoDistribucionCanillasDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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
|
|
{
|
|
var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
|
|
|
|
var viewModel = new ListadoDistCanillasImporteViewModel
|
|
{
|
|
Detalles = data,
|
|
NombrePublicacion = publicacion?.Nombre ?? "N/A",
|
|
TipoDestinatario = esAccionista ? "Accionistas" : "Canillitas",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ListadoDistCanillasImporteDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<IActionResult> GetVentaMensualSecretariaElDiaPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
|
|
{
|
|
if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
|
|
|
|
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
|
|
{
|
|
var viewModel = new VentaMensualSecretariaElDiaViewModel
|
|
{
|
|
VentasDiarias = data,
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new VentaMensualSecretariaElDiaDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
string fileName = $"VentaMensualSecretaria_ElDia_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error PDF VentaMensualSecretariaElDia.");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<IActionResult> GetVentaMensualSecretariaElPlataPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
|
|
{
|
|
if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
|
|
|
|
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
|
|
{
|
|
var viewModel = new VentaMensualSecretariaElPlataViewModel
|
|
{
|
|
VentasDiarias = data,
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new VentaMensualSecretariaElPlataDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
string fileName = $"VentaMensualSecretaria_ElPlata_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error PDF VentaMensualSecretariaElPlata.");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<IActionResult> GetVentaMensualSecretariaTirDevoPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
|
|
{
|
|
if (!TienePermiso(PermisoVerListadoDistribucion)) return Forbid();
|
|
|
|
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
|
|
{
|
|
var viewModel = new VentaMensualSecretariaTirDevoViewModel
|
|
{
|
|
VentasDiarias = data,
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new VentaMensualSecretariaTirDevoDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
string fileName = $"VentaMensualSecretaria_TirDevo_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error PDF VentaMensualSecretariaTirDevo.");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<IActionResult> GetReporteDistribucionCanillasPdf([FromQuery] DateTime fecha, [FromQuery] int idEmpresa, [FromQuery] bool soloTotales = false)
|
|
{
|
|
if (!TienePermiso(PermisoVerComprobanteLiquidacionCanilla)) return Forbid();
|
|
|
|
var (
|
|
canillas, canillasAcc, canillasAll, canillasFechaLiq, canillasAccFechaLiq,
|
|
remitos, ctrlDevoluciones, _, error
|
|
) = await _reportesService.ObtenerReporteDistribucionCanillasAsync(fecha, idEmpresa);
|
|
|
|
if (error != null) return BadRequest(new { message = error });
|
|
|
|
// Verificamos si hay datos suficientes para CUALQUIERA de los dos reportes.
|
|
if (!canillas.Any() && !canillasAcc.Any() && !canillasAll.Any())
|
|
{
|
|
return NotFound(new { message = "No hay datos de distribución para generar el PDF." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
|
|
|
|
var viewModel = new DistribucionCanillasViewModel
|
|
{
|
|
Canillas = canillas,
|
|
CanillasAccionistas = canillasAcc,
|
|
CanillasTodos = canillasAll,
|
|
CanillasLiquidadasOtraFecha = canillasFechaLiq,
|
|
CanillasAccionistasLiquidadasOtraFecha = canillasAccFechaLiq,
|
|
ControlDevolucionesDetalle = ctrlDevoluciones,
|
|
RemitoIngresado = remitos.FirstOrDefault()?.Remito ?? 0,
|
|
Empresa = empresa?.Nombre ?? "N/A",
|
|
FechaConsultada = fecha.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
IDocument document;
|
|
string tipoReporte;
|
|
|
|
if (soloTotales)
|
|
{
|
|
document = new DistribucionCanillasTotalesDocument(viewModel);
|
|
tipoReporte = "Totales";
|
|
}
|
|
else
|
|
{
|
|
document = new DistribucionCanillasDocument(viewModel);
|
|
tipoReporte = "Detalle";
|
|
}
|
|
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<IActionResult> GetReporteControlDevolucionesPdf([FromQuery] DateTime fecha, [FromQuery] int idEmpresa)
|
|
{
|
|
if (!TienePermiso(PermisoVerControlDevoluciones)) return Forbid();
|
|
|
|
var (
|
|
_, _, _, _, _, // Datos no utilizados
|
|
remitos, detalles, otrosDias, error
|
|
) = await _reportesService.ObtenerReporteDistribucionCanillasAsync(fecha, idEmpresa);
|
|
|
|
if (error != null) return BadRequest(new { message = error });
|
|
|
|
if ((detalles == null || !detalles.Any()) && (otrosDias == null || !otrosDias.Any()))
|
|
{
|
|
return NotFound(new { message = "No hay datos para generar el PDF para control de devoluciones." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
|
|
|
|
// La creación del ViewModel es ahora mucho más limpia
|
|
var viewModel = new ControlDevolucionesViewModel
|
|
{
|
|
Detalles = detalles ?? Enumerable.Empty<ControlDevolucionesReporteDto>(),
|
|
TotalDevolucionDiasAnteriores = otrosDias?.Sum(d => d.Devueltos) ?? 0,
|
|
NombreEmpresa = empresa?.Nombre ?? "N/A",
|
|
FechaConsultada = fecha.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ControlDevolucionesDocument(viewModel);
|
|
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
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())
|
|
{
|
|
return NotFound(new { message = "No hay datos para generar el reporte de cuenta del distribuidor." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var distribuidor = await _distribuidorRepository.GetByIdAsync(idDistribuidor);
|
|
|
|
var viewModel = new CuentasDistribuidorViewModel
|
|
{
|
|
Movimientos = entradasSalidas,
|
|
Pagos = pagos,
|
|
DebitosCreditos = debitosCreditos,
|
|
SaldoDeCuenta = saldos.FirstOrDefault()?.Monto ?? 0, // <-- Se asigna a SaldoDeCuenta
|
|
NombreDistribuidor = distribuidor.Distribuidor?.Nombre ?? $"Distribuidor ID {idDistribuidor}",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy"),
|
|
};
|
|
|
|
var document = new CuentasDistribuidorDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
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;
|
|
|
|
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
|
|
{
|
|
var publicacion = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
|
|
|
|
string? nombrePlanta = null;
|
|
if (!consolidado && idPlanta.HasValue)
|
|
{
|
|
var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
|
|
nombrePlanta = planta?.Nombre;
|
|
}
|
|
|
|
var viewModel = new TiradasPublicacionesSeccionesViewModel
|
|
{
|
|
Detalles = data,
|
|
NombrePublicacion = publicacion?.Nombre ?? "N/A",
|
|
MesConsultado = fechaDesde.ToString("MMMM 'de' yyyy", new CultureInfo("es-ES")),
|
|
NombrePlanta = nombrePlanta
|
|
};
|
|
|
|
var document = new TiradasPublicacionesSeccionesDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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 al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
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
|
|
{
|
|
string? nombrePlanta = null;
|
|
if (!consolidado && idPlanta.HasValue)
|
|
{
|
|
var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
|
|
nombrePlanta = planta?.Nombre;
|
|
}
|
|
|
|
var viewModel = new ConsumoBobinasSeccionViewModel
|
|
{
|
|
Detalles = data,
|
|
NombrePlanta = nombrePlanta,
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ConsumoBobinasSeccionDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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 al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
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
|
|
{
|
|
var viewModel = new ConsumoBobinasPublicacionViewModel
|
|
{
|
|
Detalles = data,
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ConsumoBobinasPublicacionDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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 al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
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
|
|
{
|
|
string? nombrePlanta = null;
|
|
if (!consolidado && idPlanta.HasValue)
|
|
{
|
|
var planta = await _plantaRepository.GetByIdAsync(idPlanta.Value);
|
|
nombrePlanta = planta?.Nombre;
|
|
}
|
|
|
|
var viewModel = new ComparativaConsumoBobinasViewModel
|
|
{
|
|
Detalles = data,
|
|
NombrePlanta = nombrePlanta,
|
|
MesA = fechaInicioMesA.ToString("MMMM yyyy", new CultureInfo("es-ES")),
|
|
MesB = fechaInicioMesB.ToString("MMMM yyyy", new CultureInfo("es-ES"))
|
|
};
|
|
|
|
var document = new ComparativaConsumoBobinasDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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 al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
// 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
|
|
{
|
|
var publicacionData = await _publicacionRepository.GetByIdSimpleAsync(idPublicacion);
|
|
var distribuidorData = await _distribuidorRepository.GetByIdAsync(idDistribuidor);
|
|
|
|
var viewModel = new ListadoDistribucionDistribuidoresViewModel
|
|
{
|
|
DetalleDiario = simple ?? Enumerable.Empty<ListadoDistribucionDistSimpleDto>(),
|
|
PromediosPorDia = promedios,
|
|
NombrePublicacion = publicacionData?.Nombre ?? "N/A",
|
|
NombreDistribuidor = distribuidorData.Distribuidor?.Nombre ?? "N/A",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ListadoDistribucionDistribuidoresDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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)
|
|
{
|
|
if (!TienePermiso(PermisoVerComprobanteLiquidacionCanilla)) return Forbid();
|
|
|
|
var (detalles, ganancias, error) = await _reportesService.ObtenerDatosTicketLiquidacionAsync(fecha, idCanilla);
|
|
|
|
if (error != null) return BadRequest(new { message = error });
|
|
if (detalles == null || !detalles.Any())
|
|
{
|
|
return NotFound(new { message = "No hay detalles de liquidación para generar el PDF." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var viewModel = new LiquidacionCanillaViewModel
|
|
{
|
|
Detalles = detalles,
|
|
Ganancias = ganancias,
|
|
FechaLiquidacion = fecha.ToString("dd/MM/yyyy"),
|
|
EsAccionista = esAccionista
|
|
};
|
|
|
|
var document = new LiquidacionCanillaDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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)) return Forbid();
|
|
if (fechaDesde > fechaHasta) return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
|
|
|
|
try
|
|
{
|
|
var novedadesDataTask = _novedadCanillaService.ObtenerReporteNovedadesAsync(idEmpresa, fechaDesde, fechaHasta);
|
|
var gananciasDataTask = _novedadCanillaService.ObtenerReporteGananciasAsync(idEmpresa, fechaDesde, fechaHasta);
|
|
|
|
await Task.WhenAll(novedadesDataTask, gananciasDataTask);
|
|
|
|
var novedadesData = await novedadesDataTask;
|
|
var gananciasData = await gananciasDataTask;
|
|
|
|
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);
|
|
|
|
var viewModel = new NovedadesCanillasViewModel
|
|
{
|
|
ResumenCanillas = gananciasData,
|
|
DetallesNovedades = novedadesData ?? Enumerable.Empty<NovedadesCanillasReporteDto>(),
|
|
NombreEmpresa = empresa?.Nombre ?? "N/A",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new NovedadesCanillasDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
|
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
|
|
{
|
|
var viewModel = new ListadoDistCanMensualDiariosViewModel
|
|
{
|
|
Detalles = data,
|
|
TipoDestinatario = esAccionista ? "Accionistas" : "Canillitas",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ListadoDistCanMensualDiariosDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
string tipoDesc = esAccionista ? "Accionistas" : "Canillitas";
|
|
string fileName = $"ListadoDistMensualDiarios_{tipoDesc}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error PDF ListadoDistMensualDiarios");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
|
|
// 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")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
|
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
|
|
{
|
|
var viewModel = new ListadoDistCanMensualViewModel
|
|
{
|
|
Detalles = data,
|
|
TipoDestinatario = esAccionista ? "Accionistas" : "Canillitas",
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy")
|
|
};
|
|
|
|
var document = new ListadoDistCanMensualDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
|
|
string tipoDesc = esAccionista ? "Accionistas" : "Canillitas";
|
|
string fileName = $"ListadoDistMensualPub_{tipoDesc}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error PDF ListadoDistMensualPorPublicacion");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
[HttpGet("suscripciones/facturas-para-publicidad/pdf")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
|
public async Task<IActionResult> GetReporteFacturasPublicidadPdf([FromQuery] int anio, [FromQuery] int mes)
|
|
{
|
|
if (!TienePermiso(PermisoVerReporteFacturasPublicidad)) return Forbid();
|
|
|
|
var (data, error) = await _reportesService.ObtenerFacturasParaReportePublicidad(anio, mes);
|
|
if (error != null) return BadRequest(new { message = error });
|
|
if (data == null || !data.Any())
|
|
{
|
|
return NotFound(new { message = "No hay facturas pagadas y pendientes de facturar para el período seleccionado." });
|
|
}
|
|
|
|
try
|
|
{
|
|
// --- INICIO DE LA LÓGICA DE AGRUPACIÓN ---
|
|
var datosAgrupados = data
|
|
.GroupBy(f => f.IdEmpresa)
|
|
.Select(g => new DatosEmpresaViewModel
|
|
{
|
|
NombreEmpresa = g.First().NombreEmpresa,
|
|
Facturas = g.ToList()
|
|
})
|
|
.OrderBy(e => e.NombreEmpresa);
|
|
|
|
var viewModel = new FacturasPublicidadViewModel
|
|
{
|
|
DatosPorEmpresa = datosAgrupados,
|
|
Periodo = new DateTime(anio, mes, 1).ToString("MMMM yyyy", new CultureInfo("es-ES")),
|
|
FechaGeneracion = DateTime.Now.ToString("dd/MM/yyyy HH:mm")
|
|
};
|
|
// --- FIN DE LA LÓGICA DE AGRUPACIÓN ---
|
|
|
|
var document = new FacturasPublicidadDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
string fileName = $"ReportePublicidad_Suscripciones_{anio}-{mes:D2}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error al generar PDF para Reporte de Facturas a Publicidad.");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
|
|
[HttpGet("suscripciones/distribucion/pdf")]
|
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
|
public async Task<IActionResult> GetReporteDistribucionSuscripcionesPdf([FromQuery] DateTime fechaDesde, [FromQuery] DateTime fechaHasta)
|
|
{
|
|
if (!TienePermiso(PermisoVerReporteDistSuscripciones)) return Forbid();
|
|
|
|
var (altas, bajas, error) = await _reportesService.ObtenerReporteDistribucionSuscripcionesAsync(fechaDesde, fechaHasta);
|
|
if (error != null) return BadRequest(new { message = error });
|
|
if ((altas == null || !altas.Any()) && (bajas == null || !bajas.Any()))
|
|
{
|
|
return NotFound(new { message = "No se encontraron suscripciones activas ni bajas para el período seleccionado." });
|
|
}
|
|
|
|
try
|
|
{
|
|
var viewModel = new DistribucionSuscripcionesViewModel(altas ?? Enumerable.Empty<DistribucionSuscripcionDto>(), bajas ?? Enumerable.Empty<DistribucionSuscripcionDto>())
|
|
{
|
|
FechaDesde = fechaDesde.ToString("dd/MM/yyyy"),
|
|
FechaHasta = fechaHasta.ToString("dd/MM/yyyy"),
|
|
FechaGeneracion = DateTime.Now.ToString("dd/MM/yyyy HH:mm")
|
|
};
|
|
|
|
var document = new DistribucionSuscripcionesDocument(viewModel);
|
|
byte[] pdfBytes = await _pdfGenerator.GeneratePdfAsync(document);
|
|
string fileName = $"ReporteDistribucionSuscripciones_{fechaDesde:yyyyMMdd}_al_{fechaHasta:yyyyMMdd}.pdf";
|
|
return File(pdfBytes, "application/pdf", fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error al generar PDF para Reporte de Distribución de Suscripciones.");
|
|
return StatusCode(500, "Error interno al generar el PDF del reporte.");
|
|
}
|
|
}
|
|
}
|
|
} |