2025-05-23 15:47:39 -03:00
using GestionIntegral.Api.Dtos.Distribucion ;
using GestionIntegral.Api.Services.Distribucion ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.Extensions.Logging ;
using System ;
using System.Collections.Generic ;
using System.Security.Claims ;
using System.Threading.Tasks ;
namespace GestionIntegral.Api.Controllers.Distribucion
{
[Route("api/entradassalidascanilla")] // Ruta base
[ApiController]
[Authorize]
public class EntradasSalidasCanillaController : ControllerBase
{
private readonly IEntradaSalidaCanillaService _esCanillaService ;
private readonly ILogger < EntradasSalidasCanillaController > _logger ;
// Permisos para E/S Canillitas (MC001 a MC005)
private const string PermisoVerMovimientos = "MC001" ;
private const string PermisoCrearMovimiento = "MC002" ;
private const string PermisoModificarMovimiento = "MC003" ;
private const string PermisoEliminarMovimiento = "MC004" ; // (si no está liquidado)
private const string PermisoLiquidar = "MC005" ; // Asumo que ver comprobante implica poder liquidar.
public EntradasSalidasCanillaController ( IEntradaSalidaCanillaService esCanillaService , ILogger < EntradasSalidasCanillaController > logger )
{
_esCanillaService = esCanillaService ;
_logger = logger ;
}
private bool TienePermiso ( string codAcc ) = > User . IsInRole ( "SuperAdmin" ) | | User . HasClaim ( c = > c . Type = = "permission" & & c . Value = = codAcc ) ;
private int? GetCurrentUserId ( )
{
if ( int . TryParse ( User . FindFirstValue ( ClaimTypes . NameIdentifier ) ? ? User . FindFirstValue ( "sub" ) , out int userId ) ) return userId ;
_logger . LogWarning ( "No se pudo obtener el UserId del token JWT en EntradasSalidasCanillaController." ) ;
return null ;
}
// GET: api/entradassalidascanilla
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<EntradaSalidaCanillaDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task < IActionResult > GetAll (
[FromQuery] DateTime ? fechaDesde , [ FromQuery ] DateTime ? fechaHasta ,
[FromQuery] int? idPublicacion , [ FromQuery ] int? idCanilla ,
[FromQuery] bool? liquidados , [ FromQuery ] bool? incluirNoLiquidados = true ) // incluirNoLiquidados por defecto true para ver todo
{
if ( ! TienePermiso ( PermisoVerMovimientos ) ) return Forbid ( ) ;
try
{
var movimientos = await _esCanillaService . ObtenerTodosAsync ( fechaDesde , fechaHasta , idPublicacion , idCanilla , liquidados , incluirNoLiquidados ) ;
return Ok ( movimientos ) ;
}
catch ( Exception ex )
{
_logger . LogError ( ex , "Error al obtener listado de E/S Canillitas." ) ;
return StatusCode ( StatusCodes . Status500InternalServerError , "Error interno." ) ;
}
}
// GET: api/entradassalidascanilla/{idParte}
[HttpGet("{idParte:int}", Name = "GetEntradaSalidaCanillaById")]
[ProducesResponseType(typeof(EntradaSalidaCanillaDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task < IActionResult > GetById ( int idParte )
{
if ( ! TienePermiso ( PermisoVerMovimientos ) ) return Forbid ( ) ;
var movimiento = await _esCanillaService . ObtenerPorIdAsync ( idParte ) ;
if ( movimiento = = null ) return NotFound ( new { message = $"Movimiento con ID {idParte} no encontrado." } ) ;
return Ok ( movimiento ) ;
}
// PUT: api/entradassalidascanilla/{idParte}
[HttpPut("{idParte:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task < IActionResult > UpdateMovimiento ( int idParte , [ FromBody ] UpdateEntradaSalidaCanillaDto updateDto )
{
if ( ! TienePermiso ( PermisoModificarMovimiento ) ) return Forbid ( ) ;
2025-06-03 13:45:20 -03:00
// Esta línea es la que dispara la validación del modelo 'updateDto'
if ( ! ModelState . IsValid ) return BadRequest ( ModelState ) ;
2025-05-23 15:47:39 -03:00
var userId = GetCurrentUserId ( ) ;
if ( userId = = null ) return Unauthorized ( ) ;
var ( exito , error ) = await _esCanillaService . ActualizarMovimientoAsync ( idParte , updateDto , userId . Value ) ;
if ( ! exito )
{
if ( error = = "Movimiento no encontrado." | | error = = "No se puede modificar un movimiento ya liquidado." )
2025-06-03 13:45:20 -03:00
return NotFound ( new { message = error } ) ;
2025-05-23 15:47:39 -03:00
return BadRequest ( new { message = error } ) ;
}
return NoContent ( ) ;
}
// DELETE: api/entradassalidascanilla/{idParte}
[HttpDelete("{idParte:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task < IActionResult > DeleteMovimiento ( int idParte )
{
// Permiso base MC004
// El servicio ahora usa User (ClaimsPrincipal) para verificar MC006 si es necesario
string permisoBaseRequerido = "MC004" ; // Asumiendo que esta constante existe o la defines
if ( ! TienePermiso ( permisoBaseRequerido ) )
{
_logger . LogWarning ( "Acceso denegado a DeleteMovimiento (IDParte: {IdParte}) para Usuario ID {UserId}. Permiso {Permiso} requerido." , idParte , GetCurrentUserId ( ) ? ? 0 , permisoBaseRequerido ) ;
return Forbid ( ) ;
}
var userId = GetCurrentUserId ( ) ;
if ( userId = = null ) return Unauthorized ( "No se pudo obtener el ID del usuario del token." ) ;
var ( exito , error ) = await _esCanillaService . EliminarMovimientoAsync ( idParte , userId . Value , User ) ; // Pasar ClaimsPrincipal (User)
if ( ! exito )
{
if ( error = = "Movimiento no encontrado." ) return NotFound ( new { message = error } ) ;
// Otros errores como "no tiene permiso para eliminar liquidados" o errores internos.
// El servicio podría devolver un código de estado más específico o el controlador interpretarlo.
// Por ahora, un BadRequest es genérico para fallos de lógica de negocio o permisos no cumplidos en el servicio.
if ( error ! = null & & error . Contains ( "No tiene permiso" ) )
{
_logger . LogWarning ( "Intento fallido de eliminar movimiento ID {IdParte} por Usuario ID {UserId}. Razón: {Error}" , idParte , userId , error ) ;
return StatusCode ( StatusCodes . Status403Forbidden , new { message = error } ) ;
}
return BadRequest ( new { message = error ? ? "Error desconocido al eliminar." } ) ;
}
return NoContent ( ) ;
}
// POST: api/entradassalidascanilla/liquidar
[HttpPost("liquidar")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task < IActionResult > LiquidarMovimientos ( [ FromBody ] LiquidarMovimientosCanillaRequestDto liquidarDto )
{
if ( ! TienePermiso ( PermisoLiquidar ) ) return Forbid ( ) ;
if ( ! ModelState . IsValid ) return BadRequest ( ModelState ) ;
var userId = GetCurrentUserId ( ) ;
if ( userId = = null ) return Unauthorized ( ) ;
var ( exito , error ) = await _esCanillaService . LiquidarMovimientosAsync ( liquidarDto , userId . Value ) ;
if ( ! exito )
{
return BadRequest ( new { message = error } ) ;
}
return NoContent ( ) ;
}
[HttpPost("bulk")] // Nueva ruta o ajustar la existente y diferenciar por DTO
[ProducesResponseType(typeof(IEnumerable<EntradaSalidaCanillaDto>), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task < IActionResult > CreateBulkMovimientos ( [ FromBody ] CreateBulkEntradaSalidaCanillaDto createBulkDto )
{
// Mantener PermisoCrearMovimiento = "MC002"
if ( ! TienePermiso ( PermisoCrearMovimiento ) ) return Forbid ( ) ;
if ( ! ModelState . IsValid ) return BadRequest ( ModelState ) ;
var userId = GetCurrentUserId ( ) ;
if ( userId = = null ) return Unauthorized ( ) ;
var ( dtos , error ) = await _esCanillaService . CrearMovimientosEnLoteAsync ( createBulkDto , userId . Value ) ;
if ( error ! = null ) return BadRequest ( new { message = error } ) ;
if ( dtos = = null | | ! dtos . Any ( ) ) return StatusCode ( StatusCodes . Status500InternalServerError , "No se pudo registrar ningún movimiento o hubo un error." ) ;
// Podrías devolver solo un 201 Created si la lista de DTOs es muy grande
// o si no necesitas los detalles de cada uno inmediatamente.
// O devolver la lista como se hace aquí.
return StatusCode ( StatusCodes . Status201Created , dtos ) ;
}
}
}