185 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			185 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using GestionIntegral.Api.Data; // Para DbConnectionFactory | ||
|  | using GestionIntegral.Api.Data.Repositories.Impresion; | ||
|  | using GestionIntegral.Api.Dtos.Impresion; | ||
|  | using GestionIntegral.Api.Models.Impresion; // Para Planta | ||
|  | using Microsoft.Extensions.Logging; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Data; // Para IsolationLevel | ||
|  | using System.Linq; | ||
|  | using System.Threading.Tasks; // Todavía usamos async para operaciones de BD | ||
|  | 
 | ||
|  | namespace GestionIntegral.Api.Services.Impresion | ||
|  | { | ||
|  |     public class PlantaService : IPlantaService | ||
|  |     { | ||
|  |         private readonly IPlantaRepository _plantaRepository; | ||
|  |         private readonly DbConnectionFactory _connectionFactory; // Para manejar transacciones | ||
|  |         private readonly ILogger<PlantaService> _logger; | ||
|  | 
 | ||
|  |         public PlantaService(IPlantaRepository plantaRepository, DbConnectionFactory connectionFactory, ILogger<PlantaService> logger) | ||
|  |         { | ||
|  |             _plantaRepository = plantaRepository; | ||
|  |             _connectionFactory = connectionFactory; | ||
|  |             _logger = logger; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Método para mapear Planta a PlantaDto | ||
|  |         private PlantaDto MapToDto(Planta planta) => new PlantaDto | ||
|  |         { | ||
|  |             IdPlanta = planta.IdPlanta, | ||
|  |             Nombre = planta.Nombre, | ||
|  |             Detalle = planta.Detalle | ||
|  |         }; | ||
|  | 
 | ||
|  |         public async Task<IEnumerable<PlantaDto>> ObtenerTodasAsync(string? nombreFilter, string? detalleFilter) | ||
|  |         { | ||
|  |             // Las operaciones de lectura no suelen necesitar transacción explícita aquí | ||
|  |             var plantas = await _plantaRepository.GetAllAsync(nombreFilter, detalleFilter); | ||
|  |             return plantas.Select(MapToDto); | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<PlantaDto?> ObtenerPorIdAsync(int id) | ||
|  |         { | ||
|  |             var planta = await _plantaRepository.GetByIdAsync(id); | ||
|  |             return planta == null ? null : MapToDto(planta); | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<(PlantaDto? Planta, string? Error)> CrearAsync(CreatePlantaDto createDto, int idUsuario) | ||
|  |         { | ||
|  |             if (await _plantaRepository.ExistsByNameAsync(createDto.Nombre)) | ||
|  |             { | ||
|  |                 return (null, "El nombre de la planta ya existe."); | ||
|  |             } | ||
|  | 
 | ||
|  |             var nuevaPlanta = new Planta | ||
|  |             { | ||
|  |                 Nombre = createDto.Nombre, | ||
|  |                 Detalle = createDto.Detalle | ||
|  |             }; | ||
|  | 
 | ||
|  |             using var connection = _connectionFactory.CreateConnection(); | ||
|  |             // Abrir la conexión asíncronamente si es posible | ||
|  |             if (connection is System.Data.Common.DbConnection dbConnection) | ||
|  |             { | ||
|  |                 await dbConnection.OpenAsync(); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 connection.Open(); // Fallback síncrono | ||
|  |             } | ||
|  | 
 | ||
|  |             // Empezar transacción | ||
|  |             using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 var plantaCreada = await _plantaRepository.CreateAsync(nuevaPlanta, idUsuario, transaction); | ||
|  |                 if (plantaCreada == null) | ||
|  |                 { | ||
|  |                     throw new DataException("La creación en el repositorio devolvió null."); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 transaction.Commit(); // <--- CORREGIDO: Commit síncrono | ||
|  |                 _logger.LogInformation("Planta ID {IdPlanta} creada exitosamente por Usuario ID {IdUsuario}.", plantaCreada.IdPlanta, idUsuario); | ||
|  |                 return (MapToDto(plantaCreada), null); | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 try | ||
|  |                 { | ||
|  |                     transaction.Rollback(); // <--- CORREGIDO: Rollback síncrono | ||
|  |                 } | ||
|  |                 catch (Exception rbEx) | ||
|  |                 { | ||
|  |                     _logger.LogError(rbEx, "Error adicional durante el rollback en CrearAsync Planta."); | ||
|  |                 } | ||
|  |                 _logger.LogError(ex, "Error en transacción CrearAsync para Planta. Nombre: {Nombre}", createDto.Nombre); | ||
|  |                 return (null, $"Error interno al crear la planta: {ex.Message}"); // Devolver mensaje de error | ||
|  |             } | ||
|  |             // La conexión y transacción se disponen automáticamente al salir del 'using' | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdatePlantaDto updateDto, int idUsuario) | ||
|  |         { | ||
|  |             if (await _plantaRepository.ExistsByNameAsync(updateDto.Nombre, id)) | ||
|  |             { | ||
|  |                 return (false, "El nombre de la planta ya existe para otro registro."); | ||
|  |             } | ||
|  | 
 | ||
|  |             var plantaAActualizar = new Planta | ||
|  |             { | ||
|  |                 IdPlanta = id, | ||
|  |                 Nombre = updateDto.Nombre, | ||
|  |                 Detalle = updateDto.Detalle | ||
|  |             }; | ||
|  | 
 | ||
|  |             using var connection = _connectionFactory.CreateConnection(); | ||
|  |              if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } | ||
|  |              using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 var actualizado = await _plantaRepository.UpdateAsync(plantaAActualizar, idUsuario, transaction); | ||
|  |                 if (!actualizado) | ||
|  |                 { | ||
|  |                     // La excepción KeyNotFoundException se manejará en el bloque catch | ||
|  |                     // Aquí asumimos que si devuelve false es porque no afectó filas, lo cual podría ser un error lógico | ||
|  |                     throw new DataException("La operación de actualización no afectó ninguna fila."); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 transaction.Commit(); // <--- CORREGIDO: Commit síncrono | ||
|  |                 _logger.LogInformation("Planta ID {IdPlanta} actualizada exitosamente por Usuario ID {IdUsuario}.", id, idUsuario); | ||
|  |                 return (true, null); | ||
|  |             } | ||
|  |             catch (KeyNotFoundException knfex) // Captura específica si el repo la lanza | ||
|  |             { | ||
|  |                  try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en ActualizarAsync Planta."); } | ||
|  |                  _logger.LogWarning(knfex, "Intento de actualizar Planta ID: {Id} no encontrada.", id); | ||
|  |                  return (false, "Planta no encontrada."); | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                 try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en ActualizarAsync Planta."); } | ||
|  |                  _logger.LogError(ex, "Error en transacción ActualizarAsync para Planta ID: {Id}", id); | ||
|  |                 return (false, $"Error interno al actualizar la planta: {ex.Message}"); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario) | ||
|  |         { | ||
|  |             if (await _plantaRepository.IsInUseAsync(id)) | ||
|  |             { | ||
|  |                 return (false, "No se puede eliminar. La planta está siendo utilizada."); | ||
|  |             } | ||
|  | 
 | ||
|  |             using var connection = _connectionFactory.CreateConnection(); | ||
|  |              if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } | ||
|  |             using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 var eliminado = await _plantaRepository.DeleteAsync(id, idUsuario, transaction); | ||
|  |                  if (!eliminado) | ||
|  |                  { | ||
|  |                     throw new DataException("La operación de eliminación no afectó ninguna fila."); | ||
|  |                  } | ||
|  | 
 | ||
|  |                 transaction.Commit(); // <--- CORREGIDO: Commit síncrono | ||
|  |                 _logger.LogInformation("Planta ID {IdPlanta} eliminada exitosamente por Usuario ID {IdUsuario}.", id, idUsuario); | ||
|  |                 return (true, null); | ||
|  |             } | ||
|  |              catch (KeyNotFoundException knfex) // Captura específica si el repo la lanza | ||
|  |             { | ||
|  |                  try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en EliminarAsync Planta."); } | ||
|  |                  _logger.LogWarning(knfex, "Intento de eliminar Planta ID: {Id} no encontrada.", id); | ||
|  |                  return (false, "Planta no encontrada."); | ||
|  |             } | ||
|  |             catch (Exception ex) | ||
|  |             { | ||
|  |                  try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en EliminarAsync Planta."); } | ||
|  |                  _logger.LogError(ex, "Error en transacción EliminarAsync para Planta ID: {Id}", id); | ||
|  |                 return (false, $"Error interno al eliminar la planta: {ex.Message}"); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |