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

171 lines
5.7 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM.Application.DTOs;
using SIGCM.Infrastructure.Repositories;
using SIGCM.Domain.Entities; // <-- Faltaba para AuditLog
using System.Security.Claims;
using SIGCM.Infrastructure.Services; // <-- Recomendado para claridad en User.FindFirst
namespace SIGCM.API.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class CashSessionsController : ControllerBase
{
private readonly CashSessionRepository _repo;
private readonly AuditRepository _auditRepo; // <-- AGREGADO: Declaración del campo
// ACTUALIZADO: Inyección de ambos repositorios en el constructor
public CashSessionsController(CashSessionRepository repo, AuditRepository auditRepo)
{
_repo = repo;
_auditRepo = auditRepo;
}
[HttpGet("status")]
public async Task<IActionResult> GetStatus()
{
var userIdClaim = User.FindFirst("Id")?.Value;
if (string.IsNullOrEmpty(userIdClaim) || !int.TryParse(userIdClaim, out int userId))
return Unauthorized();
var session = await _repo.GetActiveSessionAsync(userId);
return Ok(new { isOpen = session != null, session });
}
[HttpPost("open")]
public async Task<IActionResult> Open([FromBody] CashOpeningDto dto)
{
var userIdClaim = User.FindFirst("Id")?.Value;
if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();
var existing = await _repo.GetActiveSessionAsync(userId);
if (existing != null) return BadRequest("Ya tienes una caja abierta");
var id = await _repo.OpenSessionAsync(userId, dto.OpeningBalance);
// Opcional: Auditar la apertura
await _auditRepo.AddLogAsync(new AuditLog
{
UserId = userId,
Action = "CASH_SESSION_OPENED",
EntityId = id,
EntityType = "CashSession",
Details = $"Caja abierta con fondo: ${dto.OpeningBalance}",
CreatedAt = DateTime.UtcNow
});
return Ok(new { id });
}
[HttpPost("close")]
public async Task<IActionResult> Close(CashClosingDto dto)
{
var userIdClaim = User.FindFirst("Id")?.Value;
if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();
var session = await _repo.GetActiveSessionAsync(userId);
if (session == null) return BadRequest("No hay una sesión activa para cerrar");
var system = await _repo.GetSystemTotalsAsync(userId, session.OpeningDate, DateTime.UtcNow);
session.DeclaredCash = dto.DeclaredCash;
session.DeclaredCards = dto.DeclaredDebit + dto.DeclaredCredit;
session.DeclaredTransfers = dto.DeclaredTransfer;
session.SystemExpectedCash = (decimal)(system.Cash ?? 0m);
session.SystemExpectedCards = (decimal)(system.Cards ?? 0m);
session.SystemExpectedTransfers = (decimal)(system.Transfers ?? 0m);
decimal totalExpected = session.SystemExpectedCash.Value + session.OpeningBalance +
session.SystemExpectedCards.Value + session.SystemExpectedTransfers.Value;
decimal totalDeclared = dto.DeclaredCash + dto.DeclaredDebit + dto.DeclaredCredit + dto.DeclaredTransfer;
session.TotalDifference = totalDeclared - totalExpected;
await _repo.CloseSessionAsync(session);
// Auditar el cierre
await _auditRepo.AddLogAsync(new AuditLog
{
UserId = userId,
Action = "CASH_SESSION_CLOSED",
EntityId = session.Id,
EntityType = "CashSession",
Details = $"Caja cerrada por el usuario. Diferencia detectada: ${session.TotalDifference}",
CreatedAt = DateTime.UtcNow
});
return Ok(new
{
message = "Caja cerrada. Pendiente de validación por supervisor.",
difference = session.TotalDifference,
sessionId = session.Id
});
}
[HttpGet("summary")]
public async Task<IActionResult> GetSummary()
{
var userIdClaim = User.FindFirst("Id")?.Value;
if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();
var session = await _repo.GetActiveSessionAsync(userId);
if (session == null) return BadRequest("No hay sesión activa");
var system = await _repo.GetSystemTotalsAsync(userId, session.OpeningDate, DateTime.UtcNow);
return Ok(new
{
openingBalance = session.OpeningBalance,
cashSales = (decimal)(system.Cash ?? 0m),
cardSales = (decimal)(system.Cards ?? 0m),
transferSales = (decimal)(system.Transfers ?? 0m),
totalExpected = session.OpeningBalance + (decimal)(system.Cash ?? 0m) + (decimal)(system.Cards ?? 0m) + (decimal)(system.Transfers ?? 0m)
});
}
[HttpGet("pending")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetPending()
{
var pending = await _repo.GetPendingValidationAsync();
return Ok(pending);
}
[HttpPost("{id}/validate")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Validate(int id, [FromBody] string notes)
{
var adminIdClaim = User.FindFirst("Id")?.Value;
if (!int.TryParse(adminIdClaim, out int adminId)) return Unauthorized();
await _repo.ValidateSessionAsync(id, adminId, notes);
await _auditRepo.AddLogAsync(new AuditLog
{
UserId = adminId,
Action = "CASH_SESSION_VALIDATED",
EntityId = id,
EntityType = "CashSession",
Details = $"Caja #{id} validada y liquidada. Notas: {notes}",
CreatedAt = DateTime.UtcNow
});
return Ok(new { message = "Sesión liquidada correctamente" });
}
[HttpGet("{id}/pdf")]
public async Task<IActionResult> DownloadPdf(int id)
{
var session = await _repo.GetSessionDetailAsync(id);
if (session == null) return NotFound();
var pdfBytes = ReportGenerator.GenerateCashSessionPdf(session);
string fileName = $"Acta_Cierre_{id}_{DateTime.Now:yyyyMMdd}.pdf";
return File(pdfBytes, "application/pdf", fileName);
}
}