2025-05-23 15:47:39 -03:00
using Dapper ;
using GestionIntegral.Api.Models.Contables ;
using Microsoft.Extensions.Logging ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
namespace GestionIntegral.Api.Data.Repositories.Contables
{
public class NotaCreditoDebitoRepository : INotaCreditoDebitoRepository
{
private readonly DbConnectionFactory _cf ;
private readonly ILogger < NotaCreditoDebitoRepository > _log ;
public NotaCreditoDebitoRepository ( DbConnectionFactory cf , ILogger < NotaCreditoDebitoRepository > log )
{
_cf = cf ;
_log = log ;
}
private string SelectQueryBase ( ) = > @ "
SELECT
Id_Nota AS IdNota , Destino , Id_Destino AS IdDestino , Referencia , Tipo , Fecha ,
Monto , Observaciones , Id_Empresa AS IdEmpresa
FROM dbo . cue_CreditosDebitos ";
public async Task < IEnumerable < NotaCreditoDebito > > GetAllAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
string? destino , int? idDestino , int? idEmpresa , string? tipoNota )
{
var sqlBuilder = new StringBuilder ( SelectQueryBase ( ) ) ;
sqlBuilder . Append ( " WHERE 1=1" ) ;
var parameters = new DynamicParameters ( ) ;
if ( fechaDesde . HasValue ) { sqlBuilder . Append ( " AND Fecha >= @FechaDesdeParam" ) ; parameters . Add ( "FechaDesdeParam" , fechaDesde . Value . Date ) ; }
if ( fechaHasta . HasValue ) { sqlBuilder . Append ( " AND Fecha <= @FechaHastaParam" ) ; parameters . Add ( "FechaHastaParam" , fechaHasta . Value . Date ) ; }
if ( ! string . IsNullOrWhiteSpace ( destino ) ) { sqlBuilder . Append ( " AND Destino = @DestinoParam" ) ; parameters . Add ( "DestinoParam" , destino ) ; }
if ( idDestino . HasValue ) { sqlBuilder . Append ( " AND Id_Destino = @IdDestinoParam" ) ; parameters . Add ( "IdDestinoParam" , idDestino . Value ) ; }
if ( idEmpresa . HasValue ) { sqlBuilder . Append ( " AND Id_Empresa = @IdEmpresaParam" ) ; parameters . Add ( "IdEmpresaParam" , idEmpresa . Value ) ; }
if ( ! string . IsNullOrWhiteSpace ( tipoNota ) ) { sqlBuilder . Append ( " AND Tipo = @TipoParam" ) ; parameters . Add ( "TipoParam" , tipoNota ) ; }
2025-06-09 19:37:07 -03:00
2025-05-23 15:47:39 -03:00
sqlBuilder . Append ( " ORDER BY Fecha DESC, Id_Nota DESC;" ) ;
try
{
using var connection = _cf . CreateConnection ( ) ;
return await connection . QueryAsync < NotaCreditoDebito > ( sqlBuilder . ToString ( ) , parameters ) ;
}
catch ( Exception ex )
{
_log . LogError ( ex , "Error al obtener todas las Notas de Crédito/Débito." ) ;
return Enumerable . Empty < NotaCreditoDebito > ( ) ;
}
}
public async Task < NotaCreditoDebito ? > GetByIdAsync ( int idNota )
{
var sql = SelectQueryBase ( ) + " WHERE Id_Nota = @IdNotaParam" ;
try
{
using var connection = _cf . CreateConnection ( ) ;
return await connection . QuerySingleOrDefaultAsync < NotaCreditoDebito > ( sql , new { IdNotaParam = idNota } ) ;
}
catch ( Exception ex )
{
_log . LogError ( ex , "Error al obtener Nota C/D por ID: {IdNota}" , idNota ) ;
return null ;
}
}
public async Task < NotaCreditoDebito ? > CreateAsync ( NotaCreditoDebito nuevaNota , int idUsuario , IDbTransaction transaction )
{
const string sqlInsert = @ "
INSERT INTO dbo . cue_CreditosDebitos ( Destino , Id_Destino , Referencia , Tipo , Fecha , Monto , Observaciones , Id_Empresa )
OUTPUT INSERTED . Id_Nota AS IdNota , INSERTED . Destino , INSERTED . Id_Destino AS IdDestino , INSERTED . Referencia ,
INSERTED . Tipo , INSERTED . Fecha , INSERTED . Monto , INSERTED . Observaciones , INSERTED . Id_Empresa AS IdEmpresa
VALUES ( @Destino , @IdDestino , @Referencia , @Tipo , @Fecha , @Monto , @Observaciones , @IdEmpresa ) ; ";
const string sqlHistorico = @ "
INSERT INTO dbo . cue_CreditosDebitos_H
( Id_Nota , Destino , Id_Destino , Referencia , Tipo , Fecha , Monto , Observaciones , Id_Empresa , Id_Usuario , FechaMod , TipoMod )
VALUES ( @IdNotaHist , @DestinoHist , @IdDestinoHist , @ReferenciaHist , @TipoHist , @FechaHist , @MontoHist , @ObservacionesHist , @IdEmpresaHist , @IdUsuarioHist , @FechaModHist , @TipoModHist ) ; ";
var inserted = await transaction . Connection ! . QuerySingleAsync < NotaCreditoDebito > ( sqlInsert , nuevaNota , transaction ) ;
if ( inserted = = null | | inserted . IdNota = = 0 ) throw new DataException ( "Error al crear la nota o ID no generado." ) ;
2025-06-09 19:37:07 -03:00
await transaction . Connection ! . ExecuteAsync ( sqlHistorico , new
{
IdNotaHist = inserted . IdNota ,
DestinoHist = inserted . Destino ,
IdDestinoHist = inserted . IdDestino ,
ReferenciaHist = inserted . Referencia ,
TipoHist = inserted . Tipo ,
FechaHist = inserted . Fecha ,
MontoHist = inserted . Monto ,
ObservacionesHist = inserted . Observaciones ,
IdEmpresaHist = inserted . IdEmpresa ,
IdUsuarioHist = idUsuario ,
FechaModHist = DateTime . Now ,
TipoModHist = "Creada"
2025-05-23 15:47:39 -03:00
} , transaction ) ;
return inserted ;
}
public async Task < bool > UpdateAsync ( NotaCreditoDebito notaAActualizar , int idUsuario , IDbTransaction transaction )
{
var actual = await transaction . Connection ! . QuerySingleOrDefaultAsync < NotaCreditoDebito > (
SelectQueryBase ( ) + " WHERE Id_Nota = @IdNotaParam" ,
new { IdNotaParam = notaAActualizar . IdNota } , transaction ) ;
if ( actual = = null ) throw new KeyNotFoundException ( "Nota de Crédito/Débito no encontrada." ) ;
// Solo se permite actualizar Monto y Observaciones
const string sqlUpdate = @ "
UPDATE dbo . cue_CreditosDebitos SET
Monto = @Monto , Observaciones = @Observaciones
WHERE Id_Nota = @IdNota ; ";
2025-06-09 19:37:07 -03:00
const string sqlHistorico = @ "
2025-05-23 15:47:39 -03:00
INSERT INTO dbo . cue_CreditosDebitos_H
( Id_Nota , Destino , Id_Destino , Referencia , Tipo , Fecha , Monto , Observaciones , Id_Empresa , Id_Usuario , FechaMod , TipoMod )
VALUES ( @IdNotaHist , @DestinoHist , @IdDestinoHist , @ReferenciaHist , @TipoHist , @FechaHist , @MontoHist , @ObservacionesHist , @IdEmpresaHist , @IdUsuarioHist , @FechaModHist , @TipoModHist ) ; ";
2025-06-09 19:37:07 -03:00
await transaction . Connection ! . ExecuteAsync ( sqlHistorico , new
{
IdNotaHist = actual . IdNota ,
DestinoHist = actual . Destino ,
IdDestinoHist = actual . IdDestino ,
ReferenciaHist = actual . Referencia ,
TipoHist = actual . Tipo ,
FechaHist = actual . Fecha ,
MontoHist = actual . Monto , // Valor ANTERIOR
ObservacionesHist = actual . Observaciones ,
IdEmpresaHist = actual . IdEmpresa , // Valor ANTERIOR
IdUsuarioHist = idUsuario ,
FechaModHist = DateTime . Now ,
TipoModHist = "Actualizada"
2025-05-23 15:47:39 -03:00
} , transaction ) ;
2025-06-09 19:37:07 -03:00
var rowsAffected = await transaction . Connection ! . ExecuteAsync ( sqlUpdate , new
{
2025-05-23 15:47:39 -03:00
notaAActualizar . Monto ,
notaAActualizar . Observaciones ,
notaAActualizar . IdNota
2025-06-09 19:37:07 -03:00
} , transaction ) ;
2025-05-23 15:47:39 -03:00
return rowsAffected = = 1 ;
}
public async Task < bool > DeleteAsync ( int idNota , int idUsuario , IDbTransaction transaction )
{
var actual = await transaction . Connection ! . QuerySingleOrDefaultAsync < NotaCreditoDebito > (
SelectQueryBase ( ) + " WHERE Id_Nota = @IdNotaParam" ,
new { IdNotaParam = idNota } , transaction ) ;
if ( actual = = null ) throw new KeyNotFoundException ( "Nota de Crédito/Débito no encontrada para eliminar." ) ;
const string sqlDelete = "DELETE FROM dbo.cue_CreditosDebitos WHERE Id_Nota = @IdNotaParam" ;
const string sqlHistorico = @ "
INSERT INTO dbo . cue_CreditosDebitos_H
( Id_Nota , Destino , Id_Destino , Referencia , Tipo , Fecha , Monto , Observaciones , Id_Empresa , Id_Usuario , FechaMod , TipoMod )
VALUES ( @IdNotaHist , @DestinoHist , @IdDestinoHist , @ReferenciaHist , @TipoHist , @FechaHist , @MontoHist , @ObservacionesHist , @IdEmpresaHist , @IdUsuarioHist , @FechaModHist , @TipoModHist ) ; ";
2025-06-09 19:37:07 -03:00
await transaction . Connection ! . ExecuteAsync ( sqlHistorico , new
{
IdNotaHist = actual . IdNota ,
DestinoHist = actual . Destino ,
IdDestinoHist = actual . IdDestino ,
ReferenciaHist = actual . Referencia ,
TipoHist = actual . Tipo ,
FechaHist = actual . Fecha ,
MontoHist = actual . Monto ,
ObservacionesHist = actual . Observaciones ,
IdEmpresaHist = actual . IdEmpresa ,
IdUsuarioHist = idUsuario ,
FechaModHist = DateTime . Now ,
TipoModHist = "Eliminada"
2025-05-23 15:47:39 -03:00
} , transaction ) ;
var rowsAffected = await transaction . Connection ! . ExecuteAsync ( sqlDelete , new { IdNotaParam = idNota } , transaction ) ;
return rowsAffected = = 1 ;
}
2025-06-09 19:37:07 -03:00
public async Task < IEnumerable < ( NotaCreditoDebitoHistorico Historial , string NombreUsuarioModifico ) > > GetHistorialAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idUsuarioModifico , string? tipoModificacion ,
int? idNotaOriginal )
{
using var connection = _cf . CreateConnection ( ) ;
var sqlBuilder = new StringBuilder ( @ "
SELECT
h . Id_Nota , h . Destino , h . Id_Destino , h . Referencia , h . Tipo , h . Fecha , h . Monto ,
h . Observaciones , h . Id_Empresa ,
h . Id_Usuario , h . FechaMod , h . TipoMod ,
u . Nombre + ' ' + u . Apellido AS NombreUsuarioModifico
FROM dbo . cue_CreditosDebitos_H h
JOIN dbo . gral_Usuarios u ON h . Id_Usuario = u . Id
WHERE 1 = 1 ");
var parameters = new DynamicParameters ( ) ;
if ( fechaDesde . HasValue ) { sqlBuilder . Append ( " AND h.FechaMod >= @FechaDesdeParam" ) ; parameters . Add ( "FechaDesdeParam" , fechaDesde . Value . Date ) ; }
if ( fechaHasta . HasValue ) { sqlBuilder . Append ( " AND h.FechaMod <= @FechaHastaParam" ) ; parameters . Add ( "FechaHastaParam" , fechaHasta . Value . Date . AddDays ( 1 ) . AddTicks ( - 1 ) ) ; }
if ( idUsuarioModifico . HasValue ) { sqlBuilder . Append ( " AND h.Id_Usuario = @IdUsuarioModificoParam" ) ; parameters . Add ( "IdUsuarioModificoParam" , idUsuarioModifico . Value ) ; }
if ( ! string . IsNullOrWhiteSpace ( tipoModificacion ) ) { sqlBuilder . Append ( " AND h.TipoMod = @TipoModParam" ) ; parameters . Add ( "TipoModParam" , tipoModificacion ) ; }
if ( idNotaOriginal . HasValue ) { sqlBuilder . Append ( " AND h.Id_Nota = @IdNotaOriginalParam" ) ; parameters . Add ( "IdNotaOriginalParam" , idNotaOriginal . Value ) ; }
sqlBuilder . Append ( " ORDER BY h.FechaMod DESC;" ) ;
try
{
var result = await connection . QueryAsync < NotaCreditoDebitoHistorico , string , ( NotaCreditoDebitoHistorico , string ) > (
sqlBuilder . ToString ( ) ,
( hist , userName ) = > ( hist , userName ) ,
parameters ,
splitOn : "NombreUsuarioModifico"
) ;
return result ;
}
catch ( Exception ex )
{
_log . LogError ( ex , "Error al obtener historial de Notas C/D." ) ;
return Enumerable . Empty < ( NotaCreditoDebitoHistorico , string ) > ( ) ;
}
}
2025-05-23 15:47:39 -03:00
}
}