Este commit introduce una refactorización significativa en el módulo de
suscripciones para alinear el sistema con reglas de negocio clave:
facturación consolidada por empresa, cobro a mes adelantado con
imputación de ajustes diferida, y una interfaz de usuario más clara.
Backend:
- **Facturación por Empresa:** Se modifica `FacturacionService` para
agrupar las suscripciones por cliente y empresa, generando una
factura consolidada para cada combinación. Esto asegura la correcta
separación fiscal.
- **Imputación de Ajustes:** Se ajusta la lógica para que la facturación
de un período (ej. Septiembre) aplique únicamente los ajustes
pendientes cuya fecha corresponde al período anterior (Agosto).
- **Cierre Secuencial:** Se implementa una validación en
`GenerarFacturacionMensual` que impide generar la facturación de un
período si el anterior no ha sido cerrado, garantizando el orden
cronológico.
- **Emails Consolidados:** El proceso de notificación automática al
generar el cierre ahora envía un único email consolidado por
suscriptor, detallando los cargos de todas sus facturas/empresas.
- **Envío de PDF Individual:** Se refactoriza el endpoint de envío manual
para que opere sobre una `idFactura` individual y adjunte el PDF
correspondiente si existe.
- **Repositorios Mejorados:** Se optimizan y añaden métodos en
`FacturaRepository` y `AjusteRepository` para soportar los nuevos
requisitos de filtrado y consulta de datos consolidados.
Frontend:
- **Separación de Vistas:** La página de "Facturación" se divide en dos:
- `ProcesosPage`: Para acciones masivas (generar cierre, archivo de
débito, procesar respuesta).
- `ConsultaFacturasPage`: Una nueva página dedicada a buscar,
filtrar y gestionar facturas individuales con una interfaz de doble
acordeón (Suscriptor -> Empresa).
- **Filtros Avanzados:** La página `ConsultaFacturasPage` ahora incluye
filtros por nombre de suscriptor, estado de pago y estado de
facturación.
- **Filtros de Fecha por Defecto:** La página de "Cuenta Corriente"
ahora filtra por el mes actual por defecto para mejorar el rendimiento
y la usabilidad.
- **Validación de Fechas:** Se añade lógica en los filtros de fecha para
impedir la selección de rangos inválidos.
- **Validación de Monto de Pago:** El modal de pago manual ahora impide
registrar un monto superior al saldo pendiente de la factura.
1723 lines
86 KiB
C#
1723 lines
86 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";
|
|
|
|
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.");
|
|
}
|
|
}
|
|
}
|
|
} |