305 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			305 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using Dapper; | ||
|  | using GestionIntegral.Api.Models.Distribucion; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Data; | ||
|  | using System.Text; // Para StringBuilder | ||
|  | using System.Threading.Tasks; | ||
|  | 
 | ||
|  | namespace GestionIntegral.Api.Data.Repositories.Distribucion | ||
|  | { | ||
|  |     public class ZonaRepository : IZonaRepository | ||
|  |     { | ||
|  |         private readonly DbConnectionFactory _connectionFactory; | ||
|  |         private readonly ILogger<ZonaRepository> _logger; | ||
|  | 
 | ||
|  |         public ZonaRepository(DbConnectionFactory connectionFactory, ILogger<ZonaRepository> logger) | ||
|  |         { | ||
|  |             _connectionFactory = connectionFactory; | ||
|  |             _logger = logger; | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<IEnumerable<Zona>> GetAllAsync(string? nombreFilter, string? descripcionFilter, bool soloActivas = true) | ||
|  |         { | ||
|  |             var sqlBuilder = new StringBuilder("SELECT Id_Zona AS IdZona, Nombre, Descripcion, Estado FROM dbo.dist_dtZonas WHERE 1=1"); | ||
|  |             var parameters = new DynamicParameters(); | ||
|  | 
 | ||
|  |             if (soloActivas) | ||
|  |             { | ||
|  |                 sqlBuilder.Append(" AND Estado = 1"); | ||
|  |             } | ||
|  |             if (!string.IsNullOrWhiteSpace(nombreFilter)) | ||
|  |             { | ||
|  |                 sqlBuilder.Append(" AND Nombre LIKE @NombreFilter"); | ||
|  |                 parameters.Add("NombreFilter", $"%{nombreFilter}%"); | ||
|  |             } | ||
|  |             if (!string.IsNullOrWhiteSpace(descripcionFilter)) | ||
|  |             { | ||
|  |                 sqlBuilder.Append(" AND Descripcion LIKE @DescripcionFilter"); | ||
|  |                 parameters.Add("DescripcionFilter", $"%{descripcionFilter}%"); | ||
|  |             } | ||
|  |             sqlBuilder.Append(" ORDER BY Nombre;"); | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     return await connection.QueryAsync<Zona>(sqlBuilder.ToString(), parameters); | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error al obtener todas las Zonas. Filtros: Nombre={NombreFilter}, Descripcion={DescFilter}", nombreFilter, descripcionFilter); | ||
|  |                 return Enumerable.Empty<Zona>(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<Zona?> GetByIdAsync(int id, bool soloActivas = true) | ||
|  |         { | ||
|  |             var sqlBuilder = new StringBuilder("SELECT Id_Zona AS IdZona, Nombre, Descripcion, Estado FROM dbo.dist_dtZonas WHERE Id_Zona = @Id"); | ||
|  |             if (soloActivas) | ||
|  |             { | ||
|  |                 sqlBuilder.Append(" AND Estado = 1"); | ||
|  |             } | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     return await connection.QuerySingleOrDefaultAsync<Zona>(sqlBuilder.ToString(), new { Id = id }); | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error al obtener Zona por ID: {IdZona}", id); | ||
|  |                 return null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null, bool soloActivas = true) | ||
|  |         { | ||
|  |             var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtZonas WHERE Nombre = @Nombre"); | ||
|  |             var parameters = new DynamicParameters(); | ||
|  |             parameters.Add("Nombre", nombre); | ||
|  | 
 | ||
|  |             if (soloActivas) | ||
|  |             { | ||
|  |                 sqlBuilder.Append(" AND Estado = 1"); | ||
|  |             } | ||
|  |             if (excludeId.HasValue) | ||
|  |             { | ||
|  |                 sqlBuilder.Append(" AND Id_Zona != @ExcludeId"); | ||
|  |                 parameters.Add("ExcludeId", excludeId.Value); | ||
|  |             } | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     var count = await connection.ExecuteScalarAsync<int>(sqlBuilder.ToString(), parameters); | ||
|  |                     return count > 0; | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error en ExistsByNameAsync para Zona con nombre: {Nombre}", nombre); | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<Zona?> CreateAsync(Zona nuevaZona, int idUsuario) | ||
|  |         { | ||
|  |             // Las nuevas zonas siempre se crean con Estado = 1 | ||
|  |             var sqlInsert = @"
 | ||
|  |                 INSERT INTO dbo.dist_dtZonas (Nombre, Descripcion, Estado) | ||
|  |                 OUTPUT INSERTED.Id_Zona AS IdZona, INSERTED.Nombre, INSERTED.Descripcion, INSERTED.Estado | ||
|  |                 VALUES (@Nombre, @Descripcion, 1);";
 | ||
|  | 
 | ||
|  |             var sqlInsertHistorico = @"
 | ||
|  |                 INSERT INTO dbo.dist_dtZonas_H (Id_Zona, Nombre, Descripcion, Estado, Id_Usuario, FechaMod, TipoMod) | ||
|  |                 VALUES (@IdZona, @Nombre, @Descripcion, @Estado, @IdUsuario, @FechaMod, @TipoMod);";
 | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     connection.Open(); | ||
|  |                     using (var transaction = connection.BeginTransaction()) | ||
|  |                     { | ||
|  |                         try | ||
|  |                         { | ||
|  |                             var insertedZona = await connection.QuerySingleAsync<Zona>( | ||
|  |                                 sqlInsert, | ||
|  |                                 new { nuevaZona.Nombre, nuevaZona.Descripcion }, | ||
|  |                                 transaction: transaction | ||
|  |                             ); | ||
|  | 
 | ||
|  |                             await connection.ExecuteAsync(sqlInsertHistorico, new | ||
|  |                             { | ||
|  |                                 IdZona = insertedZona.IdZona, | ||
|  |                                 insertedZona.Nombre, | ||
|  |                                 insertedZona.Descripcion, | ||
|  |                                 Estado = insertedZona.Estado, // Será true (1) | ||
|  |                                 IdUsuario = idUsuario, | ||
|  |                                 FechaMod = DateTime.Now, | ||
|  |                                 TipoMod = "Insertada" | ||
|  |                             }, transaction: transaction); | ||
|  | 
 | ||
|  |                             transaction.Commit(); | ||
|  |                             return insertedZona; | ||
|  |                         } | ||
|  |                         catch (Exception exTrans) | ||
|  |                         { | ||
|  |                             transaction.Rollback(); | ||
|  |                             _logger.LogError(exTrans, "Error en transacción CreateAsync para Zona. Nombre: {Nombre}", nuevaZona.Nombre); | ||
|  |                             return null; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error general en CreateAsync para Zona. Nombre: {Nombre}", nuevaZona.Nombre); | ||
|  |                 return null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<bool> UpdateAsync(Zona zonaAActualizar, int idUsuario) | ||
|  |         { | ||
|  |             var zonaActual = await GetByIdAsync(zonaAActualizar.IdZona, soloActivas: false); // Obtener incluso si está inactiva para el historial | ||
|  |             if (zonaActual == null) return false; | ||
|  | 
 | ||
|  |             // Solo actualizamos si está activa, pero el historial registra el estado que tenía. | ||
|  |             // El servicio decidirá si se puede actualizar una zona inactiva. | ||
|  |             var sqlUpdate = @"
 | ||
|  |                 UPDATE dbo.dist_dtZonas | ||
|  |                 SET Nombre = @Nombre, Descripcion = @Descripcion | ||
|  |                 WHERE Id_Zona = @IdZona;"; //  Podríamos añadir AND Estado = 1 si el servicio lo requiere así estrictamente.
 | ||
|  | 
 | ||
|  |             var sqlInsertHistorico = @"
 | ||
|  |                 INSERT INTO dbo.dist_dtZonas_H (Id_Zona, Nombre, Descripcion, Estado, Id_Usuario, FechaMod, TipoMod) | ||
|  |                 VALUES (@IdZona, @NombreActual, @DescripcionActual, @EstadoActual, @IdUsuario, @FechaMod, @TipoMod);";
 | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     connection.Open(); | ||
|  |                     using (var transaction = connection.BeginTransaction()) | ||
|  |                     { | ||
|  |                         try | ||
|  |                         { | ||
|  |                             // Registrar el estado *antes* de la modificación | ||
|  |                             await connection.ExecuteAsync(sqlInsertHistorico, new | ||
|  |                             { | ||
|  |                                 IdZona = zonaActual.IdZona, | ||
|  |                                 NombreActual = zonaActual.Nombre, | ||
|  |                                 DescripcionActual = zonaActual.Descripcion, | ||
|  |                                 EstadoActual = zonaActual.Estado, | ||
|  |                                 IdUsuario = idUsuario, | ||
|  |                                 FechaMod = DateTime.Now, | ||
|  |                                 TipoMod = "Modificada" | ||
|  |                             }, transaction: transaction); | ||
|  | 
 | ||
|  |                             var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new | ||
|  |                             { | ||
|  |                                 zonaAActualizar.Nombre, | ||
|  |                                 zonaAActualizar.Descripcion, | ||
|  |                                 zonaAActualizar.IdZona | ||
|  |                             }, transaction: transaction); | ||
|  | 
 | ||
|  |                             transaction.Commit(); | ||
|  |                             return rowsAffected == 1; | ||
|  |                         } | ||
|  |                         catch (Exception exTrans) | ||
|  |                         { | ||
|  |                             transaction.Rollback(); | ||
|  |                             _logger.LogError(exTrans, "Error en transacción UpdateAsync para Zona ID: {IdZona}", zonaAActualizar.IdZona); | ||
|  |                             return false; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error general en UpdateAsync para Zona ID: {IdZona}", zonaAActualizar.IdZona); | ||
|  |                 return false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<bool> SoftDeleteAsync(int id, int idUsuario) | ||
|  |         { | ||
|  |             var zonaActual = await GetByIdAsync(id, soloActivas: false); // Obtenerla sin importar su estado para el historial | ||
|  |             if (zonaActual == null) return false; | ||
|  |             if (!zonaActual.Estado) return true; // Ya está "eliminada" (inactiva), considerar éxito | ||
|  | 
 | ||
|  |             var sqlSoftDelete = @"UPDATE dbo.dist_dtZonas SET Estado = 0 WHERE Id_Zona = @IdZona;"; | ||
|  |             var sqlInsertHistorico = @"
 | ||
|  |                 INSERT INTO dbo.dist_dtZonas_H (Id_Zona, Nombre, Descripcion, Estado, Id_Usuario, FechaMod, TipoMod) | ||
|  |                 VALUES (@IdZona, @Nombre, @Descripcion, @EstadoNuevo, @IdUsuario, @FechaMod, @TipoMod);";
 | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     connection.Open(); | ||
|  |                     using (var transaction = connection.BeginTransaction()) | ||
|  |                     { | ||
|  |                         try | ||
|  |                         { | ||
|  |                             // Actualizar la tabla principal | ||
|  |                             var rowsAffected = await connection.ExecuteAsync(sqlSoftDelete, new { IdZona = id }, transaction: transaction); | ||
|  | 
 | ||
|  |                             if (rowsAffected == 1) | ||
|  |                             { | ||
|  |                                 // Registrar en el historial con el nuevo estado (0) | ||
|  |                                 await connection.ExecuteAsync(sqlInsertHistorico, new | ||
|  |                                 { | ||
|  |                                     IdZona = zonaActual.IdZona, | ||
|  |                                     zonaActual.Nombre, | ||
|  |                                     zonaActual.Descripcion, | ||
|  |                                     EstadoNuevo = false, // El estado después del soft delete | ||
|  |                                     IdUsuario = idUsuario, | ||
|  |                                     FechaMod = DateTime.Now, | ||
|  |                                     TipoMod = "Eliminada" // O "Deshabilitada" | ||
|  |                                 }, transaction: transaction); | ||
|  |                             } | ||
|  |                              | ||
|  |                             transaction.Commit(); | ||
|  |                             return rowsAffected == 1; | ||
|  |                         } | ||
|  |                         catch (Exception exTrans) | ||
|  |                         { | ||
|  |                             transaction.Rollback(); | ||
|  |                             _logger.LogError(exTrans, "Error en transacción SoftDeleteAsync para Zona ID: {IdZona}", id); | ||
|  |                             return false; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error general en SoftDeleteAsync para Zona ID: {IdZona}", id); | ||
|  |                 return false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<bool> IsInUseAsync(int id) | ||
|  |         { | ||
|  |             // Verifica en dist_dtDistribuidores y dist_dtCanillas | ||
|  |             var sqlCheckDist = "SELECT COUNT(1) FROM dbo.dist_dtDistribuidores WHERE Id_Zona = @IdZona"; | ||
|  |             var sqlCheckCanillas = "SELECT COUNT(1) FROM dbo.dist_dtCanillas WHERE Id_Zona = @IdZona AND Baja = 0"; // Solo canillas activos | ||
|  |             try | ||
|  |             { | ||
|  |                 using (var connection = _connectionFactory.CreateConnection()) | ||
|  |                 { | ||
|  |                     var countDist = await connection.ExecuteScalarAsync<int>(sqlCheckDist, new { IdZona = id }); | ||
|  |                     if (countDist > 0) return true; | ||
|  | 
 | ||
|  |                     var countCanillas = await connection.ExecuteScalarAsync<int>(sqlCheckCanillas, new { IdZona = id }); | ||
|  |                     return countCanillas > 0; | ||
|  |                 } | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 _logger.LogError(ex, "Error en IsInUseAsync para Zona ID: {IdZona}", id); | ||
|  |                 return true; // Asumir que está en uso si hay error | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |