Files
SIG-CM/src/SIGCM.API/Controllers/ReportsController.cs
2026-01-06 10:34:06 -03:00

151 lines
5.3 KiB
C#

using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM.Domain.Interfaces;
using SIGCM.Infrastructure.Repositories;
using SIGCM.Infrastructure.Services;
namespace SIGCM.API.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize(Roles = "Cajero,Admin")]
public class ReportsController : ControllerBase
{
private readonly IListingRepository _listingRepo;
private readonly AuditRepository _auditRepo;
public ReportsController(IListingRepository listingRepo, AuditRepository auditRepo)
{
_listingRepo = listingRepo;
_auditRepo = auditRepo;
}
[HttpGet("dashboard")]
[Authorize(Roles = "Admin,GerenteVentas")]
public async Task<IActionResult> GetDashboard([FromQuery] DateTime? from, [FromQuery] DateTime? to)
{
var start = from ?? DateTime.UtcNow.Date;
var end = to ?? DateTime.UtcNow.Date;
var stats = await _listingRepo.GetDashboardStatsAsync(start, end);
return Ok(stats);
}
[HttpGet("sales-by-category")]
[Authorize(Roles = "Admin,GerenteVentas")]
public async Task<IActionResult> GetSalesByCategory([FromQuery] DateTime? from, [FromQuery] DateTime? to)
{
var start = from ?? DateTime.UtcNow.AddMonths(-1);
var end = to ?? DateTime.UtcNow;
var data = await _listingRepo.GetSalesByRootCategoryAsync(start, end);
var totalAmount = data.Sum(x => x.TotalSales);
if (totalAmount > 0)
{
foreach (var item in data)
item.Percentage = Math.Round((item.TotalSales / totalAmount) * 100, 2);
}
return Ok(data);
}
[HttpGet("audit")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetAuditLogs([FromQuery] DateTime? from, [FromQuery] DateTime? to, [FromQuery] int? userId)
{
var start = from ?? DateTime.UtcNow.Date;
var end = to ?? DateTime.UtcNow.AddDays(1).Date.AddSeconds(-1);
var logs = await _auditRepo.GetFilteredLogsAsync(start, end, userId);
return Ok(logs);
}
[HttpGet("cashier")]
[Authorize(Roles = "Cajero,Admin")]
public async Task<IActionResult> GetCashierDashboard([FromQuery] DateTime? from, [FromQuery] DateTime? to)
{
var userIdClaim = User.FindFirst("Id")?.Value;
if (string.IsNullOrEmpty(userIdClaim)) return Unauthorized();
int userId = int.Parse(userIdClaim);
// Si no vienen fechas, usamos hoy por defecto
var start = from ?? DateTime.UtcNow.Date;
var end = to ?? DateTime.UtcNow.Date;
var stats = await _listingRepo.GetCashierStatsAsync(userId, start, end);
return Ok(stats);
}
[HttpGet("export-cierre")]
[Authorize(Roles = "Admin,Cajero")]
public async Task<IActionResult> ExportCierre([FromQuery] DateTime from, [FromQuery] DateTime to, [FromQuery] int? userId) // <--- Agregamos userId opcional
{
var userIdClaim = User.FindFirst("Id")?.Value;
var userRole = User.FindFirst(System.Security.Claims.ClaimTypes.Role)?.Value;
// SEGURIDAD:
// Si es Cajero, ignoramos lo que envíe y forzamos su propio ID.
// Si es Admin, usamos el userId que venga en la URL (si viene).
int? targetUserId = (userRole == "Cajero") ? int.Parse(userIdClaim!) : userId;
// 1. Obtener datos filtrados
var data = await _listingRepo.GetDetailedReportAsync(from, to, targetUserId);
// 2. Título Dinámico: Si hay un filtro de usuario, no es un cierre global.
string title = (targetUserId.HasValue)
? $"REPORTE DE ACTIVIDAD: {data.Items.FirstOrDefault()?.Cashier ?? "Usuario Sin Cargas"}"
: "CIERRE GLOBAL DE JORNADA";
// 3. Generar PDF
var pdfBytes = ReportGenerator.GenerateSalesPdf(data, title);
string fileName = targetUserId.HasValue ? $"Actividad_Caja_{targetUserId}" : "Cierre_Global";
return File(pdfBytes, "application/pdf", $"{fileName}_{from:yyyyMMdd}.pdf");
}
[HttpGet("audit/user/{userId}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetAuditLogsByUser(int userId)
{
var logs = await _auditRepo.GetLogsByUserAsync(userId);
return Ok(logs);
}
[HttpGet("cashier-transactions")]
[Authorize(Roles = "Cajero,Admin")]
public async Task<IActionResult> GetCashierTransactions(
[FromQuery] DateTime? from,
[FromQuery] DateTime? to,
[FromQuery] int? userId)
{
// 1. Obtener datos del usuario logueado
var userIdClaim = User.FindFirst("Id")?.Value;
var userRole = User.FindFirst(System.Security.Claims.ClaimTypes.Role)?.Value;
if (string.IsNullOrEmpty(userIdClaim)) return Unauthorized();
// 2. Lógica de seguridad para el filtro de usuario:
// Si es Admin, puede ver a cualquier cajero (usa el userId que viene por query).
// Si es Cajero, SOLO puede verse a sí mismo (forzamos su propio ID).
int? targetUserId = (userRole == "Admin") ? userId : int.Parse(userIdClaim);
// 3. Manejo de fechas:
// Si no vienen, usamos el rango de hoy.
// Pero el frontend enviará los valores de los selectores.
var startDate = from ?? DateTime.UtcNow.Date;
var endDate = to ?? DateTime.UtcNow.Date;
// Llamamos al repositorio con las fechas REALES enviadas desde el frontend
var transactions = await _listingRepo.GetDetailedReportAsync(startDate, endDate, targetUserId);
return Ok(transactions);
}
[HttpGet("cajeros")]
[Authorize(Roles = "Cajero,Admin")]
public async Task<IActionResult> GetCajeros()
{
var cajeros = await _listingRepo.GetActiveCashiersAsync();
return Ok(cajeros);
}
}