217 lines
11 KiB
C#
217 lines
11 KiB
C#
// src/Services/Distribucion/DistribuidorService.cs
|
|
using GestionIntegral.Api.Data;
|
|
using GestionIntegral.Api.Data.Repositories.Contables;
|
|
using GestionIntegral.Api.Data.Repositories.Distribucion;
|
|
using GestionIntegral.Api.Dtos.Distribucion;
|
|
using GestionIntegral.Api.Models.Distribucion;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace GestionIntegral.Api.Services.Distribucion
|
|
{
|
|
public class DistribuidorService : IDistribuidorService
|
|
{
|
|
private readonly IDistribuidorRepository _distribuidorRepository;
|
|
private readonly ISaldoRepository _saldoRepository;
|
|
private readonly IEmpresaRepository _empresaRepository;
|
|
private readonly IZonaRepository _zonaRepository;
|
|
private readonly DbConnectionFactory _connectionFactory;
|
|
private readonly ILogger<DistribuidorService> _logger;
|
|
|
|
public DistribuidorService(
|
|
IDistribuidorRepository distribuidorRepository,
|
|
ISaldoRepository saldoRepository,
|
|
IEmpresaRepository empresaRepository,
|
|
IZonaRepository zonaRepository,
|
|
DbConnectionFactory connectionFactory,
|
|
ILogger<DistribuidorService> logger)
|
|
{
|
|
_distribuidorRepository = distribuidorRepository;
|
|
_saldoRepository = saldoRepository;
|
|
_empresaRepository = empresaRepository;
|
|
_zonaRepository = zonaRepository;
|
|
_connectionFactory = connectionFactory;
|
|
_logger = logger;
|
|
}
|
|
|
|
private DistribuidorDto? MapToDto((Distribuidor? Distribuidor, string? NombreZona) data)
|
|
{
|
|
if (data.Distribuidor == null) return null;
|
|
|
|
return new DistribuidorDto
|
|
{
|
|
IdDistribuidor = data.Distribuidor.IdDistribuidor,
|
|
Nombre = data.Distribuidor.Nombre,
|
|
Contacto = data.Distribuidor.Contacto,
|
|
NroDoc = data.Distribuidor.NroDoc,
|
|
IdZona = data.Distribuidor.IdZona,
|
|
NombreZona = data.NombreZona, // Ya es anulable en el DTO y en la tupla
|
|
Calle = data.Distribuidor.Calle,
|
|
Numero = data.Distribuidor.Numero,
|
|
Piso = data.Distribuidor.Piso,
|
|
Depto = data.Distribuidor.Depto,
|
|
Telefono = data.Distribuidor.Telefono,
|
|
Email = data.Distribuidor.Email,
|
|
Localidad = data.Distribuidor.Localidad
|
|
};
|
|
}
|
|
|
|
public async Task<IEnumerable<DistribuidorDto>> ObtenerTodosAsync(string? nombreFilter, string? nroDocFilter)
|
|
{
|
|
var data = await _distribuidorRepository.GetAllAsync(nombreFilter, nroDocFilter);
|
|
// 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!);
|
|
}
|
|
|
|
public async Task<IEnumerable<DistribuidorDropdownDto>> GetAllDropdownAsync()
|
|
{
|
|
var data = await _distribuidorRepository.GetAllDropdownAsync();
|
|
// Asegurar que el resultado no sea nulo y no contiene elementos nulos
|
|
if (data == null)
|
|
{
|
|
return new List<DistribuidorDropdownDto>
|
|
{
|
|
new DistribuidorDropdownDto { IdDistribuidor = 0, Nombre = "No hay distribuidores disponibles" }
|
|
};
|
|
}
|
|
return data.Where(x => x != null)!;
|
|
}
|
|
|
|
public async Task<DistribuidorDto?> ObtenerPorIdAsync(int id)
|
|
{
|
|
var data = await _distribuidorRepository.GetByIdAsync(id);
|
|
// MapToDto ahora devuelve DistribuidorDto?
|
|
return MapToDto(data);
|
|
}
|
|
|
|
public async Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id)
|
|
{
|
|
var data = await _distribuidorRepository.ObtenerLookupPorIdAsync(id);
|
|
return data;
|
|
}
|
|
|
|
public async Task<(DistribuidorDto? Distribuidor, string? Error)> CrearAsync(CreateDistribuidorDto createDto, int idUsuario)
|
|
{
|
|
if (await _distribuidorRepository.ExistsByNroDocAsync(createDto.NroDoc))
|
|
return (null, "El número de documento ya existe para otro distribuidor.");
|
|
if (await _distribuidorRepository.ExistsByNameAsync(createDto.Nombre))
|
|
return (null, "El nombre del distribuidor ya existe.");
|
|
if (createDto.IdZona.HasValue && await _zonaRepository.GetByIdAsync(createDto.IdZona.Value) == null)
|
|
return (null, "La zona seleccionada no es válida o no está activa.");
|
|
|
|
var nuevoDistribuidor = new Distribuidor
|
|
{
|
|
Nombre = createDto.Nombre, Contacto = createDto.Contacto, NroDoc = createDto.NroDoc, IdZona = createDto.IdZona,
|
|
Calle = createDto.Calle, Numero = createDto.Numero, Piso = createDto.Piso, Depto = createDto.Depto,
|
|
Telefono = createDto.Telefono, Email = createDto.Email, Localidad = createDto.Localidad
|
|
};
|
|
|
|
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 distribuidorCreado = await _distribuidorRepository.CreateAsync(nuevoDistribuidor, idUsuario, transaction);
|
|
if (distribuidorCreado == null) throw new DataException("Error al crear el distribuidor.");
|
|
|
|
var empresas = await _empresaRepository.GetAllAsync(null, null);
|
|
foreach (var empresa in empresas)
|
|
{
|
|
bool saldoCreado = await _saldoRepository.CreateSaldoInicialAsync("Distribuidores", distribuidorCreado.IdDistribuidor, empresa.IdEmpresa, transaction);
|
|
if (!saldoCreado)
|
|
{
|
|
throw new DataException($"Falló al crear saldo inicial para el distribuidor {distribuidorCreado.IdDistribuidor} en la empresa {empresa.IdEmpresa}.");
|
|
}
|
|
}
|
|
|
|
transaction.Commit();
|
|
var dataCompleta = await _distribuidorRepository.GetByIdAsync(distribuidorCreado.IdDistribuidor);
|
|
_logger.LogInformation("Distribuidor ID {IdDistribuidor} creado por Usuario ID {IdUsuario}.", distribuidorCreado.IdDistribuidor, idUsuario);
|
|
// MapToDto ahora devuelve DistribuidorDto?
|
|
return (MapToDto(dataCompleta), null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
try { transaction.Rollback(); } catch {}
|
|
_logger.LogError(ex, "Error CrearAsync Distribuidor: {Nombre}", createDto.Nombre);
|
|
return (null, $"Error interno al crear el distribuidor: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateDistribuidorDto updateDto, int idUsuario)
|
|
{
|
|
var distribuidorExistente = await _distribuidorRepository.GetByIdSimpleAsync(id);
|
|
if (distribuidorExistente == null) return (false, "Distribuidor no encontrado.");
|
|
|
|
if (await _distribuidorRepository.ExistsByNroDocAsync(updateDto.NroDoc, id))
|
|
return (false, "El número de documento ya existe para otro distribuidor.");
|
|
// CORREGIDO: La tupla de retorno para la validación de nombre debe ser (bool, string?)
|
|
if (await _distribuidorRepository.ExistsByNameAsync(updateDto.Nombre, id))
|
|
return (false, "El nombre del distribuidor ya existe."); // Antes (null, ...)
|
|
if (updateDto.IdZona.HasValue && await _zonaRepository.GetByIdAsync(updateDto.IdZona.Value) == null)
|
|
return (false, "La zona seleccionada no es válida o no está activa.");
|
|
|
|
distribuidorExistente.Nombre = updateDto.Nombre; distribuidorExistente.Contacto = updateDto.Contacto;
|
|
distribuidorExistente.NroDoc = updateDto.NroDoc; distribuidorExistente.IdZona = updateDto.IdZona;
|
|
distribuidorExistente.Calle = updateDto.Calle; distribuidorExistente.Numero = updateDto.Numero;
|
|
distribuidorExistente.Piso = updateDto.Piso; distribuidorExistente.Depto = updateDto.Depto;
|
|
distribuidorExistente.Telefono = updateDto.Telefono; distribuidorExistente.Email = updateDto.Email;
|
|
distribuidorExistente.Localidad = updateDto.Localidad;
|
|
|
|
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 actualizado = await _distribuidorRepository.UpdateAsync(distribuidorExistente, idUsuario, transaction);
|
|
if (!actualizado) throw new DataException("Error al actualizar.");
|
|
transaction.Commit();
|
|
_logger.LogInformation("Distribuidor ID {IdDistribuidor} actualizado por Usuario ID {IdUsuario}.", id, 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 ActualizarAsync Distribuidor ID: {IdDistribuidor}", id);
|
|
return (false, $"Error interno: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario)
|
|
{
|
|
var distribuidorExistente = await _distribuidorRepository.GetByIdSimpleAsync(id);
|
|
if (distribuidorExistente == null) return (false, "Distribuidor no encontrado.");
|
|
|
|
if (await _distribuidorRepository.IsInUseAsync(id))
|
|
return (false, "No se puede eliminar. El distribuidor tiene movimientos o configuraciones asociadas.");
|
|
|
|
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
|
|
{
|
|
// Lógica para eliminar saldos asociados (si se implementa)
|
|
// var saldosEliminados = await _saldoRepository.DeleteSaldosByDestinoAsync("Distribuidores", id, transaction);
|
|
// if (!saldosEliminados) throw new DataException("Error al eliminar saldos del distribuidor.");
|
|
|
|
var eliminado = await _distribuidorRepository.DeleteAsync(id, idUsuario, transaction);
|
|
if (!eliminado) throw new DataException("Error al eliminar.");
|
|
transaction.Commit();
|
|
_logger.LogInformation("Distribuidor ID {IdDistribuidor} eliminado por Usuario ID {IdUsuario}.", id, 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 EliminarAsync Distribuidor ID: {IdDistribuidor}", id);
|
|
return (false, $"Error interno: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
} |