using Dapper; using GestionIntegral.Api.Data.Repositories; using GestionIntegral.Api.Models; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Threading.Tasks; using GestionIntegral.Api.Models.Contables; using System.Text; namespace GestionIntegral.Api.Data.Repositories.Contables { public class SaldoRepository : ISaldoRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public SaldoRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } public async Task> GetAllDistribuidorIdsAsync() { var sql = "SELECT Id_Distribuidor FROM dbo.dist_dtDistribuidores"; try { using (var connection = _connectionFactory.CreateConnection()) { return await connection.QueryAsync(sql); } } catch (Exception ex) { _logger.LogError(ex, "Error al obtener IDs de Distribuidores."); return Enumerable.Empty(); } } public async Task CreateSaldoInicialAsync(string destino, int idDestino, int idEmpresa, IDbTransaction transaction) { var sql = @" INSERT INTO dbo.cue_Saldos (Destino, Id_Destino, Monto, Id_Empresa) VALUES (@Destino, @IdDestino, 0.00, @IdEmpresa);"; try { int rowsAffected = await transaction.Connection!.ExecuteAsync(sql, // Añadir ! new { Destino = destino, IdDestino = idDestino, IdEmpresa = idEmpresa }, transaction: transaction); return rowsAffected == 1; } catch (Exception ex) { _logger.LogError(ex, "Error al insertar saldo inicial para {Destino} ID {IdDestino}, Empresa ID {IdEmpresa}.", destino, idDestino, idEmpresa); throw; } } public async Task DeleteSaldosByEmpresaAsync(int idEmpresa, IDbTransaction transaction) { var sql = "DELETE FROM dbo.cue_Saldos WHERE Id_Empresa = @IdEmpresa"; try { await transaction.Connection!.ExecuteAsync(sql, new { IdEmpresa = idEmpresa }, transaction: transaction); return true; // Asumir éxito si no hay excepción } catch (Exception ex) { _logger.LogError(ex, "Error al eliminar saldos para Empresa ID {IdEmpresa}.", idEmpresa); throw; } } public async Task ModificarSaldoAsync(string destino, int idDestino, int idEmpresa, decimal montoAAgregar, IDbTransaction? transaction = null) { var sql = @"UPDATE dbo.cue_Saldos SET Monto = Monto + @MontoAAgregar, FechaUltimaModificacion = @FechaActualizacion -- << AÑADIR WHERE Destino = @Destino AND Id_Destino = @IdDestino AND Id_Empresa = @IdEmpresa;"; IDbConnection connection = transaction?.Connection ?? _connectionFactory.CreateConnection(); bool ownConnection = transaction == null; try { if (ownConnection && connection.State != ConnectionState.Open) { if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open(); } var parameters = new { MontoAAgregar = montoAAgregar, Destino = destino, IdDestino = idDestino, IdEmpresa = idEmpresa, FechaActualizacion = DateTime.Now // O DateTime.UtcNow si prefieres }; int rowsAffected = await connection.ExecuteAsync(sql, parameters, transaction: transaction); return rowsAffected == 1; } catch (Exception ex) { _logger.LogError(ex, "Error al modificar saldo para {Destino} ID {IdDestino}, Empresa ID {IdEmpresa}.", destino, idDestino, idEmpresa); if (transaction != null) throw; return false; } finally { if (ownConnection && connection.State == ConnectionState.Open) { if (connection is System.Data.Common.DbConnection dbConn) await dbConn.CloseAsync(); else connection.Close(); } if (ownConnection && connection is IDisposable d) d.Dispose(); // Mejorar dispose } } public async Task CheckIfSaldosExistForEmpresaAsync(int idEmpresa) { var sql = "SELECT COUNT(1) FROM dbo.cue_Saldos WHERE Id_Empresa = @IdEmpresa"; try { // Este método es de solo lectura, no necesita transacción externa normalmente using (var connection = _connectionFactory.CreateConnection()) { var count = await connection.ExecuteScalarAsync(sql, new { IdEmpresa = idEmpresa }); return count > 0; // Devuelve true si hay al menos un saldo } } catch (Exception ex) { _logger.LogError(ex, "Error en CheckIfSaldosExistForEmpresaAsync para Empresa ID {IdEmpresa}", idEmpresa); return false; // Asumir que no existen si hay error, para no bloquear la eliminación innecesariamente // O podrías devolver true para ser más conservador si la verificación es crítica. } } public async Task> 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 parameters = new DynamicParameters(); if (!string.IsNullOrWhiteSpace(destinoFilter)) { sqlBuilder.Append(" AND Destino = @Destino"); parameters.Add("Destino", destinoFilter); } if (idDestinoFilter.HasValue) { sqlBuilder.Append(" AND Id_Destino = @IdDestino"); parameters.Add("IdDestino", idDestinoFilter.Value); } if (idEmpresaFilter.HasValue) { sqlBuilder.Append(" AND Id_Empresa = @IdEmpresa"); parameters.Add("IdEmpresa", idEmpresaFilter.Value); } sqlBuilder.Append(" ORDER BY Destino, Id_Empresa, Id_Destino;"); using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync(sqlBuilder.ToString(), parameters); } public async Task GetSaldoAsync(string destino, int idDestino, int idEmpresa, IDbTransaction? transaction = null) { const string sql = "SELECT Id_Saldo AS IdSaldo, Destino, Id_Destino AS IdDestino, Monto, Id_Empresa AS IdEmpresa, FechaUltimaModificacion FROM dbo.cue_Saldos WHERE Destino = @Destino AND Id_Destino = @IdDestino AND Id_Empresa = @IdEmpresa;"; var conn = transaction?.Connection ?? _connectionFactory.CreateConnection(); if (transaction == null && conn.State != ConnectionState.Open) { if (conn is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else conn.Open(); } try { return await conn.QuerySingleOrDefaultAsync(sql, new { Destino = destino, IdDestino = idDestino, IdEmpresa = idEmpresa }, transaction); } finally { if (transaction == null && conn.State == ConnectionState.Open) { if (conn is System.Data.Common.DbConnection dbConn) await dbConn.CloseAsync(); else conn.Close(); } } } public async Task CreateSaldoAjusteHistorialAsync(SaldoAjusteHistorial historialEntry, IDbTransaction transaction) { const string sql = @" INSERT INTO dbo.cue_SaldoAjustesHistorial (Destino, Id_Destino, Id_Empresa, MontoAjuste, SaldoAnterior, SaldoNuevo, Justificacion, FechaAjuste, Id_UsuarioAjuste) VALUES (@Destino, @IdDestino, @IdEmpresa, @MontoAjuste, @SaldoAnterior, @SaldoNuevo, @Justificacion, @FechaAjuste, @IdUsuarioAjuste);"; await transaction.Connection!.ExecuteAsync(sql, historialEntry, transaction); } } }