Feat: Baja Lógica de Distribuidores (Selectores Dropdown)
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 8m32s

This commit is contained in:
2026-03-23 14:09:26 -03:00
parent 9201d7222b
commit 5212e31a03
17 changed files with 289 additions and 53 deletions

View File

@@ -0,0 +1,27 @@
-- Script para agregar borrado lógico a Distribuidores
-- 1. Agregar columnas a la tabla principal
ALTER TABLE dbo.dist_dtDistribuidores
ADD Baja bit NOT NULL DEFAULT 0;
ALTER TABLE dbo.dist_dtDistribuidores
ADD FechaBaja datetime2(0) NULL;
-- 2. Agregar columnas a la tabla histórica
ALTER TABLE dbo.dist_dtDistribuidores_H
ADD Baja bit NULL;
ALTER TABLE dbo.dist_dtDistribuidores_H
ADD FechaBaja datetime2(0) NULL;
-- 3. ATENCION: Actualizar Stored Procedures de Reportes
-- Los siguientes Stored Procedures deben ser modificados para incluir la condicion "AND Baja = 0"
-- en las consultas a "dist_dtDistribuidores":
-- - SP_BalanceCuentaDistEntradaSalidaPorEmpresa
-- - SP_BalanceCuentDistDebCredEmpresa
-- - SP_BalanceCuentDistPagosEmpresa
-- - SP_BalanceCuentSaldosEmpresas
-- - SP_CantidadEntradaSalida
-- - SP_CantidadEntradaSalidaCPromAgDia
PRINT 'Se agregaron correctamente las columnas Baja y FechaBaja a dist_dtDistribuidores y dist_dtDistribuidores_H';

View File

@@ -40,19 +40,19 @@ namespace GestionIntegral.Api.Controllers.Distribucion
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(IEnumerable<DistribuidorDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(IEnumerable<DistribuidorDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetAllDistribuidores([FromQuery] string? nombre, [FromQuery] string? nroDoc) public async Task<IActionResult> GetAllDistribuidores([FromQuery] string? nombre, [FromQuery] string? nroDoc, [FromQuery] bool? soloActivos = true)
{ {
if (!TienePermiso(PermisoVer)) return Forbid(); if (!TienePermiso(PermisoVer)) return Forbid();
var distribuidores = await _distribuidorService.ObtenerTodosAsync(nombre, nroDoc); var distribuidores = await _distribuidorService.ObtenerTodosAsync(nombre, nroDoc, soloActivos);
return Ok(distribuidores); return Ok(distribuidores);
} }
[HttpGet("dropdown")] [HttpGet("dropdown")]
[ProducesResponseType(typeof(IEnumerable<DistribuidorDropdownDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(IEnumerable<DistribuidorDropdownDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetAllDropdownDistribuidores() public async Task<IActionResult> GetAllDropdownDistribuidores([FromQuery] bool? soloActivos = true)
{ {
var distribuidores = await _distribuidorService.GetAllDropdownAsync(); var distribuidores = await _distribuidorService.GetAllDropdownAsync(soloActivos);
return Ok(distribuidores); return Ok(distribuidores);
} }
@@ -117,6 +117,27 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return NoContent(); return NoContent();
} }
[HttpPut("{id:int}/toggle-baja")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> ToggleBajaDistribuidor(int id, [FromBody] ToggleBajaDistribuidorDto dto)
{
if (!TienePermiso(PermisoModificar)) return Forbid();
if (!ModelState.IsValid) return BadRequest(ModelState);
var userId = GetCurrentUserId();
if (userId == null) return Unauthorized();
var (exito, error) = await _distribuidorService.ToggleBajaAsync(id, dto.DarDeBaja, dto.FechaBaja, userId.Value);
if (!exito)
{
if (error == "Distribuidor no encontrado.") return NotFound(new { message = error });
return BadRequest(new { message = error });
}
return NoContent();
}
[HttpDelete("{id:int}")] [HttpDelete("{id:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]

View File

@@ -23,7 +23,7 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
public async Task<IEnumerable<int>> GetAllDistribuidorIdsAsync() public async Task<IEnumerable<int>> GetAllDistribuidorIdsAsync()
{ {
var sql = "SELECT Id_Distribuidor FROM dbo.dist_dtDistribuidores"; var sql = "SELECT Id_Distribuidor FROM dbo.dist_dtDistribuidores WHERE Baja = 0";
try try
{ {
using (var connection = _connectionFactory.CreateConnection()) using (var connection = _connectionFactory.CreateConnection())
@@ -138,25 +138,45 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
public async Task<IEnumerable<Saldo>> GetSaldosParaGestionAsync(string? destinoFilter, int? idDestinoFilter, int? idEmpresaFilter) public async Task<IEnumerable<Saldo>> GetSaldosParaGestionAsync(string? destinoFilter, int? idDestinoFilter, int? idEmpresaFilter)
{ {
var sqlBuilder = new StringBuilder("SELECT Id_Saldo AS IdSaldo, Destino, Id_Destino AS IdDestino, Monto, Id_Empresa AS IdEmpresa, FechaUltimaModificacion FROM dbo.cue_Saldos WHERE 1=1"); var sqlBuilder = new StringBuilder(@"
SELECT Id_Saldo AS IdSaldo, Destino, Id_Destino AS IdDestino, Monto, Id_Empresa AS IdEmpresa, FechaUltimaModificacion
FROM dbo.cue_Saldos s
WHERE 1=1");
var parameters = new DynamicParameters(); var parameters = new DynamicParameters();
if (!string.IsNullOrWhiteSpace(destinoFilter)) if (!string.IsNullOrWhiteSpace(destinoFilter))
{ {
sqlBuilder.Append(" AND Destino = @Destino"); sqlBuilder.Append(" AND s.Destino = @Destino");
parameters.Add("Destino", destinoFilter); parameters.Add("Destino", destinoFilter);
// Filtro para excluir distribuidores de baja si el tipo es Distribuidores
// No se aplica a Canillas por requerimiento explícito del usuario
if (destinoFilter == "Distribuidores")
{
sqlBuilder.Append(" AND EXISTS (SELECT 1 FROM dbo.dist_dtDistribuidores d WHERE d.Id_Distribuidor = s.Id_Destino AND d.Baja = 0)");
} }
}
else
{
// Si no hay filtro de destino, aplicamos el filtro de baja solo para Distribuidores
sqlBuilder.Append(@" AND (
(s.Destino = 'Distribuidores' AND EXISTS (SELECT 1 FROM dbo.dist_dtDistribuidores d WHERE d.Id_Distribuidor = s.Id_Destino AND d.Baja = 0))
OR (s.Destino != 'Distribuidores')
)");
}
if (idDestinoFilter.HasValue) if (idDestinoFilter.HasValue)
{ {
sqlBuilder.Append(" AND Id_Destino = @IdDestino"); sqlBuilder.Append(" AND s.Id_Destino = @IdDestino");
parameters.Add("IdDestino", idDestinoFilter.Value); parameters.Add("IdDestino", idDestinoFilter.Value);
} }
if (idEmpresaFilter.HasValue) if (idEmpresaFilter.HasValue)
{ {
sqlBuilder.Append(" AND Id_Empresa = @IdEmpresa"); sqlBuilder.Append(" AND s.Id_Empresa = @IdEmpresa");
parameters.Add("IdEmpresa", idEmpresaFilter.Value); parameters.Add("IdEmpresa", idEmpresaFilter.Value);
} }
sqlBuilder.Append(" ORDER BY Destino, Id_Empresa, Id_Destino;"); sqlBuilder.Append(" ORDER BY s.Destino, s.Id_Empresa, s.Id_Destino;");
using var connection = _connectionFactory.CreateConnection(); using var connection = _connectionFactory.CreateConnection();
return await connection.QueryAsync<Saldo>(sqlBuilder.ToString(), parameters); return await connection.QueryAsync<Saldo>(sqlBuilder.ToString(), parameters);

View File

@@ -22,12 +22,12 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
_logger = logger; _logger = logger;
} }
public async Task<IEnumerable<(Distribuidor Distribuidor, string? NombreZona)>> GetAllAsync(string? nombreFilter, string? nroDocFilter) public async Task<IEnumerable<(Distribuidor Distribuidor, string? NombreZona)>> GetAllAsync(string? nombreFilter, string? nroDocFilter, bool? soloActivos = true)
{ {
var sqlBuilder = new StringBuilder(@" var sqlBuilder = new StringBuilder(@"
SELECT SELECT
d.Id_Distribuidor AS IdDistribuidor, d.Nombre, d.Contacto, d.NroDoc, d.Id_Zona AS IdZona, d.Id_Distribuidor AS IdDistribuidor, d.Nombre, d.Contacto, d.NroDoc, d.Id_Zona AS IdZona,
d.Calle, d.Numero, d.Piso, d.Depto, d.Telefono, d.Email, d.Localidad, d.Calle, d.Numero, d.Piso, d.Depto, d.Telefono, d.Email, d.Localidad, d.Baja, d.FechaBaja,
z.Nombre AS NombreZona z.Nombre AS NombreZona
FROM dbo.dist_dtDistribuidores d FROM dbo.dist_dtDistribuidores d
LEFT JOIN dbo.dist_dtZonas z ON d.Id_Zona = z.Id_Zona LEFT JOIN dbo.dist_dtZonas z ON d.Id_Zona = z.Id_Zona
@@ -44,6 +44,11 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
sqlBuilder.Append(" AND d.NroDoc LIKE @NroDocParam"); sqlBuilder.Append(" AND d.NroDoc LIKE @NroDocParam");
parameters.Add("NroDocParam", $"%{nroDocFilter}%"); parameters.Add("NroDocParam", $"%{nroDocFilter}%");
} }
if (soloActivos.HasValue)
{
sqlBuilder.Append(" AND d.Baja = @BajaStatus ");
parameters.Add("BajaStatus", !soloActivos.Value);
}
sqlBuilder.Append(" ORDER BY d.Nombre;"); sqlBuilder.Append(" ORDER BY d.Nombre;");
try try
@@ -63,7 +68,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<IEnumerable<DistribuidorDropdownDto?>> GetAllDropdownAsync() public async Task<IEnumerable<DistribuidorDropdownDto?>> GetAllDropdownAsync(bool? soloActivos = true)
{ {
var sqlBuilder = new StringBuilder(@" var sqlBuilder = new StringBuilder(@"
SELECT SELECT
@@ -71,6 +76,13 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
FROM dbo.dist_dtDistribuidores FROM dbo.dist_dtDistribuidores
WHERE 1=1"); WHERE 1=1");
var parameters = new DynamicParameters(); var parameters = new DynamicParameters();
if (soloActivos.HasValue)
{
sqlBuilder.Append(" AND Baja = @BajaStatus ");
parameters.Add("BajaStatus", !soloActivos.Value);
}
sqlBuilder.Append(" ORDER BY Nombre;"); sqlBuilder.Append(" ORDER BY Nombre;");
try try
{ {
@@ -92,7 +104,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
const string sql = @" const string sql = @"
SELECT SELECT
d.Id_Distribuidor AS IdDistribuidor, d.Nombre, d.Contacto, d.NroDoc, d.Id_Zona AS IdZona, d.Id_Distribuidor AS IdDistribuidor, d.Nombre, d.Contacto, d.NroDoc, d.Id_Zona AS IdZona,
d.Calle, d.Numero, d.Piso, d.Depto, d.Telefono, d.Email, d.Localidad, d.Calle, d.Numero, d.Piso, d.Depto, d.Telefono, d.Email, d.Localidad, d.Baja, d.FechaBaja,
z.Nombre AS NombreZona z.Nombre AS NombreZona
FROM dbo.dist_dtDistribuidores d FROM dbo.dist_dtDistribuidores d
LEFT JOIN dbo.dist_dtZonas z ON d.Id_Zona = z.Id_Zona LEFT JOIN dbo.dist_dtZonas z ON d.Id_Zona = z.Id_Zona
@@ -139,7 +151,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
const string sql = @" const string sql = @"
SELECT SELECT
Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona, Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona,
Calle, Numero, Piso, Depto, Telefono, Email, Localidad Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja
FROM dbo.dist_dtDistribuidores FROM dbo.dist_dtDistribuidores
WHERE Id_Distribuidor = @IdParam"; WHERE Id_Distribuidor = @IdParam";
try try
@@ -223,10 +235,10 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
public async Task<Distribuidor?> CreateAsync(Distribuidor nuevoDistribuidor, int idUsuario, IDbTransaction transaction) public async Task<Distribuidor?> CreateAsync(Distribuidor nuevoDistribuidor, int idUsuario, IDbTransaction transaction)
{ {
const string sqlInsert = @" const string sqlInsert = @"
INSERT INTO dbo.dist_dtDistribuidores (Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad) INSERT INTO dbo.dist_dtDistribuidores (Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja)
OUTPUT INSERTED.Id_Distribuidor AS IdDistribuidor, INSERTED.Nombre, INSERTED.Contacto, INSERTED.NroDoc, INSERTED.Id_Zona AS IdZona, OUTPUT INSERTED.Id_Distribuidor AS IdDistribuidor, INSERTED.Nombre, INSERTED.Contacto, INSERTED.NroDoc, INSERTED.Id_Zona AS IdZona,
INSERTED.Calle, INSERTED.Numero, INSERTED.Piso, INSERTED.Depto, INSERTED.Telefono, INSERTED.Email, INSERTED.Localidad INSERTED.Calle, INSERTED.Numero, INSERTED.Piso, INSERTED.Depto, INSERTED.Telefono, INSERTED.Email, INSERTED.Localidad, INSERTED.Baja, INSERTED.FechaBaja
VALUES (@Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad);"; VALUES (@Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad, 0, NULL);";
var connection = transaction.Connection!; var connection = transaction.Connection!;
var inserted = await connection.QuerySingleAsync<Distribuidor>(sqlInsert, nuevoDistribuidor, transaction); var inserted = await connection.QuerySingleAsync<Distribuidor>(sqlInsert, nuevoDistribuidor, transaction);
@@ -234,8 +246,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
const string sqlInsertHistorico = @" const string sqlInsertHistorico = @"
INSERT INTO dbo.dist_dtDistribuidores_H INSERT INTO dbo.dist_dtDistribuidores_H
(Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Id_Usuario, FechaMod, TipoMod) (Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @BajaParam, @FechaBajaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
@@ -251,6 +263,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
TelefonoParam = inserted.Telefono, TelefonoParam = inserted.Telefono,
EmailParam = inserted.Email, EmailParam = inserted.Email,
LocalidadParam = inserted.Localidad, LocalidadParam = inserted.Localidad,
BajaParam = inserted.Baja,
FechaBajaParam = inserted.FechaBaja,
IdUsuarioParam = idUsuario, IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now, FechaModParam = DateTime.Now,
TipoModParam = "Creado" TipoModParam = "Creado"
@@ -263,7 +277,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
var connection = transaction.Connection!; var connection = transaction.Connection!;
var actual = await connection.QuerySingleOrDefaultAsync<Distribuidor>( var actual = await connection.QuerySingleOrDefaultAsync<Distribuidor>(
@"SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona, @"SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona,
Calle, Numero, Piso, Depto, Telefono, Email, Localidad Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja
FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdDistribuidorParam", FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdDistribuidorParam",
new { IdDistribuidorParam = distribuidorAActualizar.IdDistribuidor }, transaction); new { IdDistribuidorParam = distribuidorAActualizar.IdDistribuidor }, transaction);
if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado."); if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado.");
@@ -275,8 +289,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
WHERE Id_Distribuidor = @IdDistribuidor;"; WHERE Id_Distribuidor = @IdDistribuidor;";
const string sqlInsertHistorico = @" const string sqlInsertHistorico = @"
INSERT INTO dbo.dist_dtDistribuidores_H INSERT INTO dbo.dist_dtDistribuidores_H
(Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Id_Usuario, FechaMod, TipoMod) (Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @BajaParam, @FechaBajaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
@@ -292,6 +306,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
TelefonoParam = actual.Telefono, TelefonoParam = actual.Telefono,
EmailParam = actual.Email, EmailParam = actual.Email,
LocalidadParam = actual.Localidad, LocalidadParam = actual.Localidad,
BajaParam = actual.Baja,
FechaBajaParam = actual.FechaBaja,
IdUsuarioParam = idUsuario, IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now, FechaModParam = DateTime.Now,
TipoModParam = "Actualizado" TipoModParam = "Actualizado"
@@ -306,7 +322,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
var connection = transaction.Connection!; var connection = transaction.Connection!;
var actual = await connection.QuerySingleOrDefaultAsync<Distribuidor>( var actual = await connection.QuerySingleOrDefaultAsync<Distribuidor>(
@"SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona, @"SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona,
Calle, Numero, Piso, Depto, Telefono, Email, Localidad Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja
FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam", new { IdParam = id }, transaction); FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam", new { IdParam = id }, transaction);
if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado."); if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado.");
@@ -314,8 +330,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
const string sqlDelete = "DELETE FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam"; const string sqlDelete = "DELETE FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam";
const string sqlInsertHistorico = @" const string sqlInsertHistorico = @"
INSERT INTO dbo.dist_dtDistribuidores_H INSERT INTO dbo.dist_dtDistribuidores_H
(Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Id_Usuario, FechaMod, TipoMod) (Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @BajaParam, @FechaBajaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
@@ -331,6 +347,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
TelefonoParam = actual.Telefono, TelefonoParam = actual.Telefono,
EmailParam = actual.Email, EmailParam = actual.Email,
LocalidadParam = actual.Localidad, LocalidadParam = actual.Localidad,
BajaParam = actual.Baja,
FechaBajaParam = actual.FechaBaja,
IdUsuarioParam = idUsuario, IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now, FechaModParam = DateTime.Now,
TipoModParam = "Eliminado" TipoModParam = "Eliminado"
@@ -340,6 +358,47 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<bool> ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario, IDbTransaction transaction)
{
var connection = transaction.Connection!;
var actual = await connection.QuerySingleOrDefaultAsync<Distribuidor>(
@"SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona,
Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja
FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdDistribuidorParam",
new { IdDistribuidorParam = id }, transaction);
if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado para dar de baja/alta.");
const string sqlUpdate = "UPDATE dbo.dist_dtDistribuidores SET Baja = @BajaParam, FechaBaja = @FechaBajaParam WHERE Id_Distribuidor = @IdDistribuidorParam;";
const string sqlInsertHistorico = @"
INSERT INTO dbo.dist_dtDistribuidores_H
(Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @BajaNuevaParam, @FechaBajaNuevaParam, @IdUsuarioParam, @FechaModParam, @TipoModHistParam);";
await connection.ExecuteAsync(sqlInsertHistorico, new
{
IdDistribuidorParam = actual.IdDistribuidor,
NombreParam = actual.Nombre,
ContactoParam = actual.Contacto,
NroDocParam = actual.NroDoc,
IdZonaParam = actual.IdZona,
CalleParam = actual.Calle,
NumeroParam = actual.Numero,
PisoParam = actual.Piso,
DeptoParam = actual.Depto,
TelefonoParam = actual.Telefono,
EmailParam = actual.Email,
LocalidadParam = actual.Localidad,
BajaNuevaParam = darDeBaja,
FechaBajaNuevaParam = (darDeBaja ? fechaBaja : null),
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModHistParam = (darDeBaja ? "Baja" : "Alta")
}, transaction);
var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new { BajaParam = darDeBaja, FechaBajaParam = (darDeBaja ? fechaBaja : null), IdDistribuidorParam = id }, transaction);
return rowsAffected == 1;
}
public async Task<IEnumerable<(DistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync( public async Task<IEnumerable<(DistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion, int? idUsuarioModifico, string? tipoModificacion,

View File

@@ -8,16 +8,17 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
{ {
public interface IDistribuidorRepository public interface IDistribuidorRepository
{ {
Task<IEnumerable<(Distribuidor Distribuidor, string? NombreZona)>> GetAllAsync(string? nombreFilter, string? nroDocFilter); Task<IEnumerable<(Distribuidor Distribuidor, string? NombreZona)>> GetAllAsync(string? nombreFilter, string? nroDocFilter, bool? soloActivos = true);
Task<(Distribuidor? Distribuidor, string? NombreZona)> GetByIdAsync(int id); Task<(Distribuidor? Distribuidor, string? NombreZona)> GetByIdAsync(int id);
Task<Distribuidor?> GetByIdSimpleAsync(int id); // Para uso interno en el servicio Task<Distribuidor?> GetByIdSimpleAsync(int id); // Para uso interno en el servicio
Task<Distribuidor?> CreateAsync(Distribuidor nuevoDistribuidor, int idUsuario, IDbTransaction transaction); Task<Distribuidor?> CreateAsync(Distribuidor nuevoDistribuidor, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(Distribuidor distribuidorAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(Distribuidor distribuidorAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction);
Task<bool> ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByNroDocAsync(string nroDoc, int? excludeIdDistribuidor = null); Task<bool> ExistsByNroDocAsync(string nroDoc, int? excludeIdDistribuidor = null);
Task<bool> ExistsByNameAsync(string nombre, int? excludeIdDistribuidor = null); Task<bool> ExistsByNameAsync(string nombre, int? excludeIdDistribuidor = null);
Task<bool> IsInUseAsync(int id); // Verificar en dist_EntradasSalidas, cue_PagosDistribuidor, dist_PorcPago Task<bool> IsInUseAsync(int id); // Verificar en dist_EntradasSalidas, cue_PagosDistribuidor, dist_PorcPago
Task<IEnumerable<DistribuidorDropdownDto?>> GetAllDropdownAsync(); Task<IEnumerable<DistribuidorDropdownDto?>> GetAllDropdownAsync(bool? soloActivos = true);
Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id); Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id);
Task<IEnumerable<(DistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync( Task<IEnumerable<(DistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaDesde, DateTime? fechaHasta,

View File

@@ -30,7 +30,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
d.Nombre AS NombreDistribuidor d.Nombre AS NombreDistribuidor
FROM dbo.dist_PorcPago pp FROM dbo.dist_PorcPago pp
INNER JOIN dbo.dist_dtDistribuidores d ON pp.Id_Distribuidor = d.Id_Distribuidor INNER JOIN dbo.dist_dtDistribuidores d ON pp.Id_Distribuidor = d.Id_Distribuidor
WHERE pp.Id_Publicacion = @IdPublicacionParam WHERE pp.Id_Publicacion = @IdPublicacionParam AND d.Baja = 0
ORDER BY d.Nombre, pp.VigenciaD DESC"; ORDER BY d.Nombre, pp.VigenciaD DESC";
try try
{ {

View File

@@ -14,5 +14,7 @@ namespace GestionIntegral.Api.Models.Distribucion
public string? Telefono { get; set; } public string? Telefono { get; set; }
public string? Email { get; set; } public string? Email { get; set; }
public string? Localidad { get; set; } public string? Localidad { get; set; }
public bool Baja { get; set; } // Baja (bit, NOT NULL, DEFAULT 0)
public DateTime? FechaBaja { get; set; } // FechaBaja (datetime2(0), NULL)
} }
} }

View File

@@ -16,6 +16,8 @@ namespace GestionIntegral.Api.Models.Distribucion
public string? Telefono { get; set; } public string? Telefono { get; set; }
public string? Email { get; set; } public string? Email { get; set; }
public string? Localidad { get; set; } public string? Localidad { get; set; }
public bool? Baja { get; set; }
public DateTime? FechaBaja { get; set; }
public int Id_Usuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;

View File

@@ -15,5 +15,7 @@ namespace GestionIntegral.Api.Dtos.Distribucion
public string? Telefono { get; set; } public string? Telefono { get; set; }
public string? Email { get; set; } public string? Email { get; set; }
public string? Localidad { get; set; } public string? Localidad { get; set; }
public bool Baja { get; set; }
public DateTime? FechaBaja { get; set; }
} }
} }

View File

@@ -0,0 +1,10 @@
using System;
namespace GestionIntegral.Api.Dtos.Distribucion
{
public class ToggleBajaDistribuidorDto
{
public bool DarDeBaja { get; set; }
public DateTime? FechaBaja { get; set; }
}
}

View File

@@ -187,7 +187,7 @@ builder.Services.AddCors(options =>
policy => policy =>
{ {
policy.WithOrigins( policy.WithOrigins(
"http://localhost:5175", // Para desarrollo local "http://localhost:5173", // Para desarrollo local
"https://gestion.eldiaservicios.com" // Para producción "https://gestion.eldiaservicios.com" // Para producción
) )
.AllowAnyHeader() .AllowAnyHeader()

View File

@@ -22,13 +22,16 @@ namespace GestionIntegral.Api.Services.Anomalia
public async Task<IEnumerable<AlertaGenericaDto>> ObtenerAlertasNoLeidasAsync() public async Task<IEnumerable<AlertaGenericaDto>> ObtenerAlertasNoLeidasAsync()
{ {
// Apunta a la nueva tabla genérica 'Sistema_Alertas' // Apunta a la nueva tabla genérica 'Sistema_Alertas'
var query = "SELECT * FROM Sistema_Alertas WHERE Leida = 0 ORDER BY FechaDeteccion DESC"; //var query = "SELECT * FROM Sistema_Alertas WHERE Leida = 0 ORDER BY FechaDeteccion DESC";
try try
{ {
using (var connection = _dbConnectionFactory.CreateConnection()) using (var connection = _dbConnectionFactory.CreateConnection())
{ {
/*
var alertas = await connection.QueryAsync<AlertaGenericaDto>(query); var alertas = await connection.QueryAsync<AlertaGenericaDto>(query);
return alertas ?? Enumerable.Empty<AlertaGenericaDto>(); return alertas ?? Enumerable.Empty<AlertaGenericaDto>();
*/
return Enumerable.Empty<AlertaGenericaDto>();
} }
} }
catch (System.Exception ex) catch (System.Exception ex)
@@ -40,17 +43,20 @@ namespace GestionIntegral.Api.Services.Anomalia
public async Task<(bool Exito, string? Error)> MarcarComoLeidaAsync(int idAlerta) public async Task<(bool Exito, string? Error)> MarcarComoLeidaAsync(int idAlerta)
{ {
var query = "UPDATE Sistema_Alertas SET Leida = 1 WHERE IdAlerta = @IdAlerta"; //var query = "UPDATE Sistema_Alertas SET Leida = 1 WHERE IdAlerta = @IdAlerta";
try try
{ {
using (var connection = _dbConnectionFactory.CreateConnection()) using (var connection = _dbConnectionFactory.CreateConnection())
{ {
/*
var result = await connection.ExecuteAsync(query, new { IdAlerta = idAlerta }); var result = await connection.ExecuteAsync(query, new { IdAlerta = idAlerta });
if (result > 0) if (result > 0)
{ {
return (true, null); return (true, null);
} }
return (false, "La alerta no fue encontrada o ya estaba marcada."); return (false, "La alerta no fue encontrada o ya estaba marcada.");
*/
return (true, null); // Retornar éxito silencioso por ahora
} }
} }
catch (System.Exception ex) catch (System.Exception ex)
@@ -62,15 +68,18 @@ namespace GestionIntegral.Api.Services.Anomalia
public async Task<(bool Exito, string? Error)> MarcarGrupoComoLeidoAsync(string tipoAlerta, int idEntidad) public async Task<(bool Exito, string? Error)> MarcarGrupoComoLeidoAsync(string tipoAlerta, int idEntidad)
{ {
var query = "UPDATE Sistema_Alertas SET Leida = 1 WHERE TipoAlerta = @TipoAlerta AND IdEntidad = @IdEntidad AND Leida = 0"; //var query = "UPDATE Sistema_Alertas SET Leida = 1 WHERE TipoAlerta = @TipoAlerta AND IdEntidad = @IdEntidad AND Leida = 0";
try try
{ {
using (var connection = _dbConnectionFactory.CreateConnection()) using (var connection = _dbConnectionFactory.CreateConnection())
{ {
/*
var result = await connection.ExecuteAsync(query, new { TipoAlerta = tipoAlerta, IdEntidad = idEntidad }); var result = await connection.ExecuteAsync(query, new { TipoAlerta = tipoAlerta, IdEntidad = idEntidad });
// No es un error si no se actualizan filas (puede que no hubiera ninguna para ese grupo) // No es un error si no se actualizan filas (puede que no hubiera ninguna para ese grupo)
_logger.LogInformation("Marcadas como leídas {Count} alertas para Tipo: {Tipo}, EntidadID: {IdEntidad}", result, tipoAlerta, idEntidad); _logger.LogInformation("Marcadas como leídas {Count} alertas para Tipo: {Tipo}, EntidadID: {IdEntidad}", result, tipoAlerta, idEntidad);
return (true, null); return (true, null);
*/
return (true, null);
} }
} }
catch (System.Exception ex) catch (System.Exception ex)

View File

@@ -56,20 +56,22 @@ namespace GestionIntegral.Api.Services.Distribucion
Depto = data.Distribuidor.Depto, Depto = data.Distribuidor.Depto,
Telefono = data.Distribuidor.Telefono, Telefono = data.Distribuidor.Telefono,
Email = data.Distribuidor.Email, Email = data.Distribuidor.Email,
Localidad = data.Distribuidor.Localidad Localidad = data.Distribuidor.Localidad,
Baja = data.Distribuidor.Baja,
FechaBaja = data.Distribuidor.FechaBaja
}; };
} }
public async Task<IEnumerable<DistribuidorDto>> ObtenerTodosAsync(string? nombreFilter, string? nroDocFilter) public async Task<IEnumerable<DistribuidorDto>> ObtenerTodosAsync(string? nombreFilter, string? nroDocFilter, bool? soloActivos = true)
{ {
var data = await _distribuidorRepository.GetAllAsync(nombreFilter, nroDocFilter); var data = await _distribuidorRepository.GetAllAsync(nombreFilter, nroDocFilter, soloActivos);
// Filtrar nulos y asegurar al compilador que no hay nulos en la lista final // Filtrar nulos y asegurar al compilador que no hay nulos en la lista final
return data.Select(MapToDto).Where(dto => dto != null).Select(dto => dto!); return data.Select(MapToDto).Where(dto => dto != null).Select(dto => dto!);
} }
public async Task<IEnumerable<DistribuidorDropdownDto>> GetAllDropdownAsync() public async Task<IEnumerable<DistribuidorDropdownDto>> GetAllDropdownAsync(bool? soloActivos = true)
{ {
var data = await _distribuidorRepository.GetAllDropdownAsync(); var data = await _distribuidorRepository.GetAllDropdownAsync(soloActivos);
// Asegurar que el resultado no sea nulo y no contiene elementos nulos // Asegurar que el resultado no sea nulo y no contiene elementos nulos
if (data == null) if (data == null)
{ {
@@ -223,6 +225,31 @@ namespace GestionIntegral.Api.Services.Distribucion
} }
} }
public async Task<(bool Exito, string? Error)> ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario)
{
var distribuidorExistente = await _distribuidorRepository.GetByIdSimpleAsync(id);
if (distribuidorExistente == null) return (false, "Distribuidor no encontrado.");
using var connection = _connectionFactory.CreateConnection();
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
using var transaction = connection.BeginTransaction();
try
{
var toggled = await _distribuidorRepository.ToggleBajaAsync(id, darDeBaja, fechaBaja, idUsuario, transaction);
if (!toggled) throw new DataException("Error al cambiar estado de baja.");
transaction.Commit();
_logger.LogInformation("Distribuidor ID {IdDistribuidor} dado de {Estado} por Usuario ID {IdUsuario}.", id, darDeBaja ? "baja" : "alta", idUsuario);
return (true, null);
}
catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Distribuidor no encontrado."); }
catch (Exception ex)
{
try { transaction.Rollback(); } catch { }
_logger.LogError(ex, "Error ToggleBajaAsync Distribuidor ID: {IdDistribuidor}", id);
return (false, $"Error interno: {ex.Message}");
}
}
public async Task<IEnumerable<DistribuidorHistorialDto>> ObtenerHistorialAsync( public async Task<IEnumerable<DistribuidorHistorialDto>> ObtenerHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion, int? idUsuarioModifico, string? tipoModificacion,

View File

@@ -7,12 +7,13 @@ namespace GestionIntegral.Api.Services.Distribucion
{ {
public interface IDistribuidorService public interface IDistribuidorService
{ {
Task<IEnumerable<DistribuidorDto>> ObtenerTodosAsync(string? nombreFilter, string? nroDocFilter); Task<IEnumerable<DistribuidorDto>> ObtenerTodosAsync(string? nombreFilter, string? nroDocFilter, bool? soloActivos = true);
Task<DistribuidorDto?> ObtenerPorIdAsync(int id); Task<DistribuidorDto?> ObtenerPorIdAsync(int id);
Task<(DistribuidorDto? Distribuidor, string? Error)> CrearAsync(CreateDistribuidorDto createDto, int idUsuario); Task<(DistribuidorDto? Distribuidor, string? Error)> CrearAsync(CreateDistribuidorDto createDto, int idUsuario);
Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateDistribuidorDto updateDto, int idUsuario); Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateDistribuidorDto updateDto, int idUsuario);
Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario); Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario);
Task<IEnumerable<DistribuidorDropdownDto>> GetAllDropdownAsync(); Task<(bool Exito, string? Error)> ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario);
Task<IEnumerable<DistribuidorDropdownDto>> GetAllDropdownAsync(bool? soloActivos = true);
Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id); Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id);
Task<IEnumerable<DistribuidorHistorialDto>> ObtenerHistorialAsync( Task<IEnumerable<DistribuidorHistorialDto>> ObtenerHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaDesde, DateTime? fechaHasta,

View File

@@ -12,4 +12,6 @@ export interface DistribuidorDto {
telefono?: string | null; telefono?: string | null;
email?: string | null; email?: string | null;
localidad?: string | null; localidad?: string | null;
baja?: boolean;
fechaBaja?: string | null;
} }

View File

@@ -1,14 +1,16 @@
// src/pages/Distribucion/GestionarDistribuidoresPage.tsx // src/pages/Distribucion/GestionarDistribuidoresPage.tsx
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect, useCallback } from 'react';
import { import {
Box, Typography, TextField, Button, Paper, IconButton, Menu, MenuItem, Box, Typography, TextField, Button, Paper, IconButton, Menu, MenuItem, Switch,
Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination,
CircularProgress, Alert CircularProgress, Alert, Chip, FormControlLabel, ListItemIcon, ListItemText
} from '@mui/material'; } from '@mui/material';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import TrashIcon from '@mui/icons-material/Delete'; import TrashIcon from '@mui/icons-material/Delete';
import MoreVertIcon from '@mui/icons-material/MoreVert'; import MoreVertIcon from '@mui/icons-material/MoreVert';
import ToggleOnIcon from '@mui/icons-material/ToggleOn';
import ToggleOffIcon from '@mui/icons-material/ToggleOff';
import distribuidorService from '../../services/Distribucion/distribuidorService'; import distribuidorService from '../../services/Distribucion/distribuidorService';
import type { DistribuidorDto } from '../../models/dtos/Distribucion/DistribuidorDto'; import type { DistribuidorDto } from '../../models/dtos/Distribucion/DistribuidorDto';
import type { CreateDistribuidorDto } from '../../models/dtos/Distribucion/CreateDistribuidorDto'; import type { CreateDistribuidorDto } from '../../models/dtos/Distribucion/CreateDistribuidorDto';
@@ -24,6 +26,7 @@ const GestionarDistribuidoresPage: React.FC = () => {
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [filtroNombre, setFiltroNombre] = useState(''); const [filtroNombre, setFiltroNombre] = useState('');
const [filtroNroDoc, setFiltroNroDoc] = useState(''); const [filtroNroDoc, setFiltroNroDoc] = useState('');
const [filtroSoloActivos, setFiltroSoloActivos] = useState<boolean | undefined>(true);
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
const [editingDistribuidor, setEditingDistribuidor] = useState<DistribuidorDto | null>(null); const [editingDistribuidor, setEditingDistribuidor] = useState<DistribuidorDto | null>(null);
@@ -49,12 +52,12 @@ const GestionarDistribuidoresPage: React.FC = () => {
} }
setLoading(true); setError(null); setApiErrorMessage(null); setLoading(true); setError(null); setApiErrorMessage(null);
try { try {
const data = await distribuidorService.getAllDistribuidores(filtroNombre, filtroNroDoc); const data = await distribuidorService.getAllDistribuidores(filtroNombre, filtroNroDoc, filtroSoloActivos);
setDistribuidores(data); setDistribuidores(data);
} catch (err) { } catch (err) {
console.error(err); setError('Error al cargar los distribuidores.'); console.error(err); setError('Error al cargar los distribuidores.');
} finally { setLoading(false); } } finally { setLoading(false); }
}, [filtroNombre, filtroNroDoc, puedeVer]); }, [filtroNombre, filtroNroDoc, filtroSoloActivos, puedeVer]);
useEffect(() => { cargarDistribuidores(); }, [cargarDistribuidores]); useEffect(() => { cargarDistribuidores(); }, [cargarDistribuidores]);
@@ -94,6 +97,21 @@ const GestionarDistribuidoresPage: React.FC = () => {
handleMenuClose(); handleMenuClose();
}; };
const handleToggleBaja = async (distribuidor: DistribuidorDto) => {
setApiErrorMessage(null);
const accion = distribuidor.baja ? "reactivar" : "dar de baja";
if (window.confirm(`¿Está seguro de que desea ${accion} a ${distribuidor.nombre}?`)) {
try {
await distribuidorService.toggleBajaDistribuidor(distribuidor.idDistribuidor, { darDeBaja: !distribuidor.baja, fechaBaja: !distribuidor.baja ? new Date().toISOString() : null });
cargarDistribuidores();
} catch (err: any) {
const message = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : `Error al ${accion} el distribuidor.`;
setApiErrorMessage(message);
}
}
handleMenuClose();
};
const handleMenuOpen = (event: React.MouseEvent<HTMLElement>, distribuidor: DistribuidorDto) => { const handleMenuOpen = (event: React.MouseEvent<HTMLElement>, distribuidor: DistribuidorDto) => {
setAnchorEl(event.currentTarget); setSelectedDistribuidorRow(distribuidor); setAnchorEl(event.currentTarget); setSelectedDistribuidorRow(distribuidor);
}; };
@@ -132,7 +150,17 @@ const GestionarDistribuidoresPage: React.FC = () => {
onChange={(e) => setFiltroNroDoc(e.target.value)} onChange={(e) => setFiltroNroDoc(e.target.value)}
sx={{ flexGrow: 1, minWidth: '200px' }} sx={{ flexGrow: 1, minWidth: '200px' }}
/> />
{/* <Button variant="contained" onClick={cargarDistribuidores} size="small">Buscar</Button> */} <FormControlLabel
control={
<Switch
checked={filtroSoloActivos === undefined ? true : filtroSoloActivos}
onChange={(e) => setFiltroSoloActivos(e.target.checked)}
size="small"
/>
}
label="Ver Activos"
sx={{ flexShrink: 0 }}
/>
</Box> </Box>
{puedeCrear && ( {puedeCrear && (
<Button variant="contained" startIcon={<AddIcon />} onClick={() => handleOpenModal()} sx={{ mb: 2 }}>Agregar Distribuidor</Button> <Button variant="contained" startIcon={<AddIcon />} onClick={() => handleOpenModal()} sx={{ mb: 2 }}>Agregar Distribuidor</Button>
@@ -150,6 +178,7 @@ const GestionarDistribuidoresPage: React.FC = () => {
<TableCell>Nombre</TableCell><TableCell>Nro. Doc.</TableCell> <TableCell>Nombre</TableCell><TableCell>Nro. Doc.</TableCell>
<TableCell>Contacto</TableCell><TableCell>Zona</TableCell> <TableCell>Contacto</TableCell><TableCell>Zona</TableCell>
<TableCell>Teléfono</TableCell><TableCell>Localidad</TableCell> <TableCell>Teléfono</TableCell><TableCell>Localidad</TableCell>
<TableCell>Estado</TableCell>
{(puedeModificar || puedeEliminar) && <TableCell align="right">Acciones</TableCell>} {(puedeModificar || puedeEliminar) && <TableCell align="right">Acciones</TableCell>}
</TableRow></TableHead> </TableRow></TableHead>
<TableBody> <TableBody>
@@ -157,10 +186,11 @@ const GestionarDistribuidoresPage: React.FC = () => {
<TableRow><TableCell colSpan={7} align="center">No se encontraron distribuidores.</TableCell></TableRow> <TableRow><TableCell colSpan={7} align="center">No se encontraron distribuidores.</TableCell></TableRow>
) : ( ) : (
displayData.map((d) => ( displayData.map((d) => (
<TableRow key={d.idDistribuidor} hover> <TableRow key={d.idDistribuidor} hover sx={{ backgroundColor: d.baja ? '#ffebee' : 'inherit' }}>
<TableCell>{d.nombre}</TableCell><TableCell>{d.nroDoc}</TableCell> <TableCell>{d.nombre}</TableCell><TableCell>{d.nroDoc}</TableCell>
<TableCell>{d.contacto || '-'}</TableCell><TableCell>{d.nombreZona || '-'}</TableCell> <TableCell>{d.contacto || '-'}</TableCell><TableCell>{d.nombreZona || '-'}</TableCell>
<TableCell>{d.telefono || '-'}</TableCell><TableCell>{d.localidad || '-'}</TableCell> <TableCell>{d.telefono || '-'}</TableCell><TableCell>{d.localidad || '-'}</TableCell>
<TableCell>{d.baja ? <Chip label="Baja" color="error" size="small" /> : <Chip label="Activo" color="success" size="small" />}</TableCell>
{(puedeModificar || puedeEliminar) && ( {(puedeModificar || puedeEliminar) && (
<TableCell align="right"> <TableCell align="right">
<IconButton onClick={(e) => handleMenuOpen(e, d)} disabled={!puedeModificar && !puedeEliminar}><MoreVertIcon /></IconButton> <IconButton onClick={(e) => handleMenuOpen(e, d)} disabled={!puedeModificar && !puedeEliminar}><MoreVertIcon /></IconButton>
@@ -179,8 +209,24 @@ const GestionarDistribuidoresPage: React.FC = () => {
)} )}
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleMenuClose}> <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleMenuClose}>
{puedeModificar && (<MenuItem onClick={() => { handleOpenModal(selectedDistribuidorRow!); handleMenuClose(); }}><EditIcon fontSize="small" sx={{ mr: 1 }} />Modificar</MenuItem>)} {puedeModificar && selectedDistribuidorRow && (
{puedeEliminar && (<MenuItem onClick={() => handleDelete(selectedDistribuidorRow!.idDistribuidor)}><TrashIcon fontSize="small" sx={{ mr: 1 }} />Eliminar</MenuItem>)} <MenuItem onClick={() => { handleOpenModal(selectedDistribuidorRow); handleMenuClose(); }}>
<ListItemIcon><EditIcon fontSize="small" /></ListItemIcon>
<ListItemText>Modificar</ListItemText>
</MenuItem>
)}
{puedeEliminar && selectedDistribuidorRow && (
<MenuItem onClick={() => handleToggleBaja(selectedDistribuidorRow)}>
<ListItemIcon>{selectedDistribuidorRow.baja ? <ToggleOnIcon fontSize="small" /> : <ToggleOffIcon fontSize="small" />}</ListItemIcon>
<ListItemText>{selectedDistribuidorRow.baja ? 'Reactivar' : 'Dar de Baja'}</ListItemText>
</MenuItem>
)}
{puedeEliminar && selectedDistribuidorRow && (
<MenuItem onClick={() => handleDelete(selectedDistribuidorRow.idDistribuidor)}>
<ListItemIcon><TrashIcon fontSize="small" /></ListItemIcon>
<ListItemText>Eliminar (Físico)</ListItemText>
</MenuItem>
)}
{(!puedeModificar && !puedeEliminar) && <MenuItem disabled>Sin acciones</MenuItem>} {(!puedeModificar && !puedeEliminar) && <MenuItem disabled>Sin acciones</MenuItem>}
</Menu> </Menu>

View File

@@ -5,8 +5,10 @@ import type { UpdateDistribuidorDto } from '../../models/dtos/Distribucion/Updat
import type { DistribuidorDropdownDto } from '../../models/dtos/Distribucion/DistribuidorDropdownDto'; import type { DistribuidorDropdownDto } from '../../models/dtos/Distribucion/DistribuidorDropdownDto';
import type { DistribuidorLookupDto } from '../../models/dtos/Distribucion/DistribuidorLookupDto'; import type { DistribuidorLookupDto } from '../../models/dtos/Distribucion/DistribuidorLookupDto';
const getAllDistribuidores = async (nombreFilter?: string, nroDocFilter?: string): Promise<DistribuidorDto[]> => { const getAllDistribuidores = async (nombreFilter?: string, nroDocFilter?: string, soloActivos: boolean = true): Promise<DistribuidorDto[]> => {
const params: Record<string, string> = {}; const params: Record<string, string | boolean> = {
soloActivos: soloActivos
};
if (nombreFilter) params.nombre = nombreFilter; if (nombreFilter) params.nombre = nombreFilter;
if (nroDocFilter) params.nroDoc = nroDocFilter; if (nroDocFilter) params.nroDoc = nroDocFilter;
@@ -37,11 +39,15 @@ const deleteDistribuidor = async (id: number): Promise<void> => {
await apiClient.delete(`/distribuidores/${id}`); await apiClient.delete(`/distribuidores/${id}`);
}; };
const getAllDistribuidoresDropdown = async (): Promise<DistribuidorDropdownDto[]> => { const getAllDistribuidoresDropdown = async (soloActivos: boolean = true): Promise<DistribuidorDropdownDto[]> => {
const response = await apiClient.get<DistribuidorDropdownDto[]>('/distribuidores/dropdown'); const response = await apiClient.get<DistribuidorDropdownDto[]>('/distribuidores/dropdown', { params: { soloActivos } });
return response.data; return response.data;
}; };
const toggleBajaDistribuidor = async (id: number, data: { darDeBaja: boolean, fechaBaja: string | null }): Promise<void> => {
await apiClient.put(`/distribuidores/${id}/toggle-baja`, data);
};
const distribuidorService = { const distribuidorService = {
getAllDistribuidores, getAllDistribuidores,
getDistribuidorById, getDistribuidorById,
@@ -50,6 +56,7 @@ const distribuidorService = {
deleteDistribuidor, deleteDistribuidor,
getAllDistribuidoresDropdown, getAllDistribuidoresDropdown,
getDistribuidorLookupById, getDistribuidorLookupById,
toggleBajaDistribuidor,
}; };
export default distribuidorService; export default distribuidorService;