238 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			238 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using GestionIntegral.Api.Dtos.Empresas; // Para los DTOs (EmpresaDto, CreateEmpresaDto, UpdateEmpresaDto) | ||
|  | using Microsoft.Extensions.Logging; // Para ILogger | ||
|  | using System.Collections.Generic; | ||
|  | using System.Linq; | ||
|  | using System.Threading.Tasks; | ||
|  | using System.Data; | ||
|  | using GestionIntegral.Api.Data; | ||
|  | using GestionIntegral.Api.Models.Distribucion; | ||
|  | using GestionIntegral.Api.Data.Repositories.Distribucion; | ||
|  | using GestionIntegral.Api.Data.Repositories.Contables; // Para IDbTransaction, ConnectionState | ||
|  | 
 | ||
|  | namespace GestionIntegral.Api.Services.Distribucion | ||
|  | { | ||
|  |     public class EmpresaService : IEmpresaService | ||
|  |     { | ||
|  |         private readonly IEmpresaRepository _empresaRepository; | ||
|  |         private readonly ISaldoRepository _saldoRepository; | ||
|  |         private readonly DbConnectionFactory _connectionFactory; // Para manejar la transacción | ||
|  |         private readonly ILogger<EmpresaService> _logger; | ||
|  | 
 | ||
|  |         public EmpresaService( | ||
|  |             IEmpresaRepository empresaRepository, | ||
|  |             ISaldoRepository saldoRepository, | ||
|  |             DbConnectionFactory connectionFactory, | ||
|  |             ILogger<EmpresaService> logger) | ||
|  |         { | ||
|  |             _empresaRepository = empresaRepository; | ||
|  |             _saldoRepository = saldoRepository; | ||
|  |             _connectionFactory = connectionFactory; | ||
|  |             _logger = logger; | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<IEnumerable<EmpresaDto>> ObtenerTodasAsync(string? nombreFilter, string? detalleFilter) | ||
|  |         { | ||
|  |             // El repositorio ya devuelve solo las activas si es necesario | ||
|  |             var empresas = await _empresaRepository.GetAllAsync(nombreFilter, detalleFilter); | ||
|  |             // Mapeo Entidad -> DTO | ||
|  |             return empresas.Select(e => new EmpresaDto | ||
|  |             { | ||
|  |                 IdEmpresa = e.IdEmpresa, | ||
|  |                 Nombre = e.Nombre, | ||
|  |                 Detalle = e.Detalle | ||
|  |             }); | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<EmpresaDto?> ObtenerPorIdAsync(int id) | ||
|  |         { | ||
|  |              // El repositorio ya devuelve solo las activas si es necesario | ||
|  |             var empresa = await _empresaRepository.GetByIdAsync(id); | ||
|  |             if (empresa == null) return null; | ||
|  |             // Mapeo Entidad -> DTO | ||
|  |             return new EmpresaDto | ||
|  |             { | ||
|  |                 IdEmpresa = empresa.IdEmpresa, | ||
|  |                 Nombre = empresa.Nombre, | ||
|  |                 Detalle = empresa.Detalle | ||
|  |             }; | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<(EmpresaDto? Empresa, string? Error)> CrearAsync(CreateEmpresaDto createDto, int idUsuario) | ||
|  |         { | ||
|  |             // Validación de negocio: Nombre duplicado | ||
|  |             if (await _empresaRepository.ExistsByNameAsync(createDto.Nombre)) | ||
|  |             { | ||
|  |                 return (null, "El nombre de la empresa ya existe."); | ||
|  |             } | ||
|  | 
 | ||
|  |             var nuevaEmpresa = new Empresa | ||
|  |             { | ||
|  |                 Nombre = createDto.Nombre, | ||
|  |                 Detalle = createDto.Detalle | ||
|  |             }; | ||
|  | 
 | ||
|  |             // --- Transacción --- | ||
|  |             using (var connection = _connectionFactory.CreateConnection()) | ||
|  |             { | ||
|  |                 // Abrir conexión de forma asíncrona | ||
|  |                 if (connection is System.Data.Common.DbConnection dbConnection) | ||
|  |                 { | ||
|  |                     await dbConnection.OpenAsync(); | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     connection.Open(); // Fallback síncrono | ||
|  |                 } | ||
|  | 
 | ||
|  |                 using (var transaction = connection.BeginTransaction()) | ||
|  |                 { | ||
|  |                     try | ||
|  |                     { | ||
|  |                         // 1. Crear Empresa (Repo maneja su historial dentro de esta transacción) | ||
|  |                         var empresaCreada = await _empresaRepository.CreateAsync(nuevaEmpresa, idUsuario, transaction); | ||
|  |                         if (empresaCreada == null) | ||
|  |                         { | ||
|  |                             throw new InvalidOperationException("No se pudo crear la empresa en el repositorio."); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         // 2. Obtener IDs de Distribuidores | ||
|  |                         var distribuidoresIds = await _saldoRepository.GetAllDistribuidorIdsAsync(); // No necesita transacción si solo lee | ||
|  | 
 | ||
|  |                         // 3. Crear Saldos Iniciales (CERO) para cada distribuidor en esta nueva empresa | ||
|  |                         foreach (var idDistribuidor in distribuidoresIds) | ||
|  |                         { | ||
|  |                             bool saldoCreado = await _saldoRepository.CreateSaldoInicialAsync("Distribuidores", idDistribuidor, empresaCreada.IdEmpresa, transaction); | ||
|  |                             if (!saldoCreado) | ||
|  |                             { | ||
|  |                                 throw new InvalidOperationException($"Falló al crear saldo inicial para distribuidor {idDistribuidor} y nueva empresa {empresaCreada.IdEmpresa}."); | ||
|  |                             } | ||
|  |                              _logger.LogInformation("Saldo inicial creado para Distribuidor ID {IdDistribuidor}, Empresa ID {IdEmpresa}", idDistribuidor, empresaCreada.IdEmpresa); | ||
|  |                         } | ||
|  | 
 | ||
|  |                         transaction.Commit(); | ||
|  | 
 | ||
|  |                         var empresaDto = new EmpresaDto | ||
|  |                         { | ||
|  |                             IdEmpresa = empresaCreada.IdEmpresa, | ||
|  |                             Nombre = empresaCreada.Nombre, | ||
|  |                             Detalle = empresaCreada.Detalle | ||
|  |                         }; | ||
|  |                         _logger.LogInformation("Empresa ID {IdEmpresa} creada exitosamente por Usuario ID {IdUsuario}.", empresaCreada.IdEmpresa, idUsuario); | ||
|  |                         return (empresaDto, null); // Éxito | ||
|  |                     } | ||
|  |                     catch (Exception ex) | ||
|  |                     { | ||
|  |                         try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error al intentar hacer rollback en CrearAsync Empresa."); } | ||
|  |                         _logger.LogError(ex, "Error en transacción CrearAsync para Empresa. Nombre: {Nombre}", createDto.Nombre); | ||
|  |                         return (null, "Error interno al procesar la creación de la empresa."); | ||
|  |                     } | ||
|  |                 } // La transacción se dispone aquí (y cierra la conexión si no hubo commit/rollback explícito, aunque ya lo hacemos) | ||
|  |             } // La conexión se cierra/dispone aquí | ||
|  |             // --- Fin Transacción --- | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateEmpresaDto updateDto, int idUsuario) | ||
|  |         { | ||
|  |              var empresaExistente = await _empresaRepository.GetByIdAsync(id); | ||
|  |              if (empresaExistente == null) | ||
|  |              { | ||
|  |                  return (false, "Empresa no encontrada."); | ||
|  |              } | ||
|  | 
 | ||
|  |              if (await _empresaRepository.ExistsByNameAsync(updateDto.Nombre, id)) | ||
|  |              { | ||
|  |                  return (false, "El nombre de la empresa ya existe para otro registro."); | ||
|  |              } | ||
|  | 
 | ||
|  |              empresaExistente.Nombre = updateDto.Nombre; | ||
|  |              empresaExistente.Detalle = updateDto.Detalle; | ||
|  | 
 | ||
|  |             // --- Transacción --- | ||
|  |             using (var connection = _connectionFactory.CreateConnection()) | ||
|  |             { | ||
|  |                  if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } | ||
|  |                  using (var transaction = connection.BeginTransaction()) | ||
|  |                 { | ||
|  |                     try | ||
|  |                     { | ||
|  |                          var actualizado = await _empresaRepository.UpdateAsync(empresaExistente, idUsuario, transaction); | ||
|  |                          if (!actualizado) | ||
|  |                          { | ||
|  |                              throw new InvalidOperationException("La actualización en el repositorio de empresas devolvió false."); | ||
|  |                          } | ||
|  |                          transaction.Commit(); | ||
|  |                          _logger.LogInformation("Empresa ID {IdEmpresa} actualizada exitosamente por Usuario ID {IdUsuario}.", id, idUsuario); | ||
|  |                          return (true, null); // Éxito | ||
|  |                     } | ||
|  |                     catch (Exception ex) | ||
|  |                     { | ||
|  |                         try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error al intentar hacer rollback en ActualizarAsync Empresa."); } | ||
|  |                          _logger.LogError(ex, "Error en transacción ActualizarAsync para Empresa ID: {Id}", id); | ||
|  |                         return (false, "Error interno al actualizar la empresa."); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             // --- Fin Transacción --- | ||
|  |         } | ||
|  | 
 | ||
|  |         public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario) | ||
|  |         { | ||
|  |             // Primero verificamos si existe, incluso inactiva, para evitar errores 404 si no existe | ||
|  |             var empresaExistente = await _empresaRepository.GetByIdAsync(id); | ||
|  |             if (empresaExistente == null) | ||
|  |             { | ||
|  |                 return (false, "Empresa no encontrada."); | ||
|  |             } | ||
|  | 
 | ||
|  |             // Validación: ¿Está en uso? | ||
|  |             if (await _empresaRepository.IsInUseAsync(id)) | ||
|  |             { | ||
|  |                 return (false, "No se puede eliminar. Existen publicaciones relacionadas a la empresa."); | ||
|  |             } | ||
|  | 
 | ||
|  |              // --- Transacción --- | ||
|  |             using (var connection = _connectionFactory.CreateConnection()) | ||
|  |             { | ||
|  |                  if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } | ||
|  |                  using (var transaction = connection.BeginTransaction()) | ||
|  |                 { | ||
|  |                     try | ||
|  |                     { | ||
|  |                         // 1. Eliminar Saldos asociados | ||
|  |                         bool saldosEliminados = await _saldoRepository.DeleteSaldosByEmpresaAsync(id, transaction); | ||
|  |                         // No lanzamos error si saldosEliminados es false, podría no haber tenido saldos. Loggeamos si es necesario. | ||
|  |                          if (!saldosEliminados && await _saldoRepository.CheckIfSaldosExistForEmpresaAsync(id)) // Necesitarías este método en ISaldoRepository | ||
|  |                          { | ||
|  |                              _logger.LogWarning("Se intentó eliminar Empresa ID {IdEmpresa} pero falló la eliminación de saldos asociados.", id); | ||
|  |                              // Decidir si continuar o fallar. Por ahora, continuamos pero loggeamos. | ||
|  |                              // throw new InvalidOperationException("Error al intentar eliminar los saldos asociados a la empresa."); | ||
|  |                          } else if (!saldosEliminados) { | ||
|  |                               _logger.LogInformation("No se encontraron saldos para eliminar de la Empresa ID {IdEmpresa}.", id); | ||
|  |                          } else { | ||
|  |                               _logger.LogInformation("Saldos eliminados para Empresa ID {IdEmpresa}.", id); | ||
|  |                          } | ||
|  | 
 | ||
|  | 
 | ||
|  |                         // 2. Eliminar Empresa (Repo maneja historial) | ||
|  |                          var eliminado = await _empresaRepository.DeleteAsync(id, idUsuario, transaction); | ||
|  |                          if (!eliminado) | ||
|  |                          { | ||
|  |                              throw new InvalidOperationException("La eliminación en el repositorio de empresas devolvió false."); | ||
|  |                          } | ||
|  | 
 | ||
|  |                         transaction.Commit(); | ||
|  |                         _logger.LogInformation("Empresa ID {IdEmpresa} eliminada exitosamente por Usuario ID {IdUsuario}.", id, idUsuario); | ||
|  |                         return (true, null); // Éxito | ||
|  |                     } | ||
|  |                     catch (Exception ex) | ||
|  |                     { | ||
|  |                         try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error al intentar hacer rollback en EliminarAsync Empresa."); } | ||
|  |                          _logger.LogError(ex, "Error en transacción EliminarAsync para Empresa ID: {Id}", id); | ||
|  |                         return (false, "Error interno al eliminar la empresa."); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             // --- Fin Transacción --- | ||
|  |         } | ||
|  |     } | ||
|  | } |