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 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 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 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 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 GetPending() { var pending = await _repo.GetPendingValidationAsync(); return Ok(pending); } [HttpPost("{id}/validate")] [Authorize(Roles = "Admin")] public async Task 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 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); } }