Compare commits

..

10 Commits

Author SHA1 Message Date
72f55b72d8 Vuelta a Runners de Gitea.
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 14s
2025-06-16 20:08:53 -03:00
21f4facb31 Ajustes de CI/CD.
fix: Run jobs on runner host to resolve network issues

Reseteo de estado por fallas del deply.

Reversión.

Nuevo testeo de CI/CD.

Reversión 2.

Fix

Reversión 3

Test con sh-runner

Reversión antes de cambio de foco.

Sin sh-runner.

No puede resolver gitea. Debe usar el secreto REGISTRY_URL.

Test con Gitea 1.21.11

Reversion 1.24.0

Va

Este

Final?

A ver...

Nuevo

Cambio de Enfoque para CI/CD. Se intenta uso de Drone.

Fix de yml para Drone.

Retry .drone.yml

Fix problema de indentación.

Retry yml

Va

Retry mil

Nuevo test

Fix: Configure docker plugin for insecure registry

Forzar la network.

Retry 0142

Test Webhook

Se agregan debug-network para verificar valores.

Se agregan daemon_dns para poder resolver los dominios de nuget desde los contenedores de despliegue.

Cambio de enfoque. Parametro para MTU (Maximum Transmission Unit) añadidos.

Prueba: Usar el Socket de Docker del Host

Fix indentación. Y Trusted en Drone.

Linter: duplicate step name

Todos los registros de contenedores (Docker Hub, Gitea, etc.) exigen que los nombres de las imágenes de Docker estén en minúsculas. El pipeline está intentando crear una imagen llamada dmolinari/GestionIntegralWeb-backend, pero la parte GestionIntegralWeb contiene mayúsculas.
Esto ocurre porque la variable de Drone ${DRONE_REPO_NAME} toma el nombre directamente de Gitea, que en este caso es GestionIntegralWeb. La sintaxis es: ${VARIABLE,,}.

Se añade la URL del registro al nombre del repo

Cabio de Variable por valor directo.

Retry 1806

Retry 1807

Webhook gitea Enable.

Added: privileged: true

Test con Kaniko

Fix yml

Retest

Cambio de imagen kaniko

Cambio por host
2025-06-16 19:16:24 -03:00
0b8096e734 Removido el .gitignore individual del Frontend. 2025-06-13 14:05:33 -03:00
4e7ba4e5b2 Limpieza completa del índice de Git para aplicar .gitignore 2025-06-13 14:02:45 -03:00
97b0efa3dd Se añade .gitignore global. 2025-06-13 13:48:31 -03:00
cec471b4b1 Fix Selectores de Fechas Reporte Existencia de Papel.
Se agrega Total a Liquidar para la E/S de Canillitas.
2025-06-13 13:23:05 -03:00
b04a3b99bf 1. Funcionalidad Principal: Auditoría General
Se creó una nueva sección de "Auditoría" en la aplicación, diseñada para ser accedida por SuperAdmins.
Se implementó una página AuditoriaGeneralPage.tsx que actúa como un visor centralizado para el historial de cambios de múltiples entidades del sistema.
2. Backend:
Nuevo Controlador (AuditoriaController.cs): Centraliza los endpoints para obtener datos de las tablas de historial (_H).
Servicios y Repositorios Extendidos:
Se añadieron métodos GetHistorialAsync y ObtenerHistorialAsync a las capas de repositorio y servicio para cada una de las siguientes entidades, permitiendo consultar sus tablas _H con filtros:
Usuarios (gral_Usuarios_H)
Pagos de Distribuidores (cue_PagosDistribuidor_H)
Notas de Crédito/Débito (cue_CreditosDebitos_H)
Entradas/Salidas de Distribuidores (dist_EntradasSalidas_H)
Entradas/Salidas de Canillitas (dist_EntradasSalidasCanillas_H)
Novedades de Canillitas (dist_dtNovedadesCanillas_H)
Tipos de Pago (cue_dtTipopago_H)
Canillitas (Maestro) (dist_dtCanillas_H)
Distribuidores (Maestro) (dist_dtDistribuidores_H)
Empresas (Maestro) (dist_dtEmpresas_H)
Zonas (Maestro) (dist_dtZonas_H)
Otros Destinos (Maestro) (dist_dtOtrosDestinos_H)
Publicaciones (Maestro) (dist_dtPublicaciones_H)
Secciones de Publicación (dist_dtPubliSecciones_H)
Precios de Publicación (dist_Precios_H)
Recargos por Zona (dist_RecargoZona_H)
Porcentajes Pago Distribuidores (dist_PorcPago_H)
Porcentajes/Montos Canillita (dist_PorcMonPagoCanilla_H)
Control de Devoluciones (dist_dtCtrlDevoluciones_H)
Tipos de Bobina (bob_dtBobinas_H)
Estados de Bobina (bob_dtEstadosBobinas_H)
Plantas de Impresión (bob_dtPlantas_H)
Stock de Bobinas (bob_StockBobinas_H)
Tiradas (Registro Principal) (bob_RegTiradas_H)
Secciones de Tirada (bob_RegPublicaciones_H)
Cambios de Parada de Canillitas (dist_CambiosParadasCanillas_H)
Ajustes Manuales de Saldo (cue_SaldoAjustesHistorial)
DTOs de Historial: Se crearon DTOs específicos para cada tabla de historial (ej. UsuarioHistorialDto, PagoDistribuidorHistorialDto, etc.) para transferir los datos al frontend, incluyendo el nombre del usuario que realizó la modificación.
Corrección de Lógica de Saldos: Se revisó y corrigió la lógica de afectación de saldos en los servicios PagoDistribuidorService y NotaCreditoDebitoService para asegurar que los débitos y créditos se apliquen correctamente.
3. Frontend:
Nuevo Servicio (auditoriaService.ts): Contiene métodos para llamar a cada uno de los nuevos endpoints de auditoría del backend.
Nueva Página (AuditoriaGeneralPage.tsx):
Permite al SuperAdmin seleccionar el "Tipo de Entidad" a auditar desde un dropdown.
Ofrece filtros comunes (rango de fechas, usuario modificador, tipo de acción) y filtros específicos que aparecen dinámicamente según la entidad seleccionada.
Utiliza un DataGrid de Material-UI para mostrar el historial, con columnas que se adaptan dinámicamente al tipo de entidad consultada.
Nuevos DTOs en TypeScript: Se crearon las interfaces correspondientes a los DTOs de historial del backend.
Gestión de Permisos:
La sección de Auditoría en MainLayout.tsx y su ruta en AppRoutes.tsx están protegidas para ser visibles y accesibles solo por SuperAdmins.
Se añadió un permiso de ejemplo AU_GENERAL_VIEW para ser usado si se decide extender el acceso en el futuro.
Corrección de Errores Menores: Se solucionó el problema del "parpadeo" del selector de fecha en GestionarNovedadesCanillaPage al adoptar un patrón de carga de datos más controlado, similar a otras páginas funcionales.
2025-06-12 19:36:21 -03:00
437b1e8864 Backend:
Diseño de un AuditoriaController con un patrón para añadir endpoints de historial para diferentes entidades.
Implementación de la lógica de servicio y repositorio para obtener datos de las tablas _H para:
Usuarios (gral_Usuarios_H)
Pagos de Distribuidores (cue_PagosDistribuidor_H)
Notas de Crédito/Débito (cue_CreditosDebitos_H)
Entradas/Salidas de Distribuidores (dist_EntradasSalidas_H)
Entradas/Salidas de Canillitas (dist_EntradasSalidasCanillas_H)
Novedades de Canillitas (dist_dtNovedadesCanillas_H)
Ajustes Manuales de Saldo (cue_SaldoAjustesHistorial)
Tipos de Pago (cue_dtTipopago_H)
Canillitas (Maestro) (dist_dtCanillas_H)
Distribuidores (Maestro) (dist_dtDistribuidores_H)
Empresas (Maestro) (dist_dtEmpresas_H)
DTOs específicos para cada tipo de historial, incluyendo NombreUsuarioModifico.
Frontend:
Servicio auditoriaService.ts con métodos para llamar a cada endpoint de historial.
Página AuditoriaGeneralPage.tsx con:
Selector de "Tipo de Entidad a Auditar".
Filtros comunes (Fechas, Usuario Modificador, Tipo de Modificación, ID Entidad).
Un DataGrid que muestra las columnas dinámicamente según el tipo de entidad seleccionada.
Lógica para cargar los datos correspondientes.
DTOs de historial en TypeScript.
Actualizaciones en AppRoutes.tsx y MainLayout.tsx para la nueva sección de Auditoría (restringida a SuperAdmin).
2025-06-09 19:37:07 -03:00
35e24ab7d2 Refinamiento de permisos y ajustes en controles. Añade gestión sobre saldos y visualización. Entre otros.. 2025-06-06 18:33:09 -03:00
8fb94f8cef Comenzando la implementación final de permisos y depuración. Se sigue... 2025-06-03 18:42:56 -03:00
374 changed files with 15399 additions and 13325 deletions

View File

@@ -0,0 +1,61 @@
name: Build and Deploy
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest # Esta etiqueta coincide con la que definimos en el runner
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Login to Gitea Container Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.REGISTRY_URL }} # ej: 192.168.4.128:5000
username: ${{ secrets.GITEA_USER }}
password: ${{ secrets.ACTIONS_PAT }}
- name: Build and Push Backend Image
uses: docker/build-push-action@v4
with:
context: .
file: Backend/GestionIntegral.Api/Dockerfile
push: true
tags: ${{ secrets.REGISTRY_URL }}/${{ gitea.actor }}/${{ toLower(gitea.repository_name) }}-backend:latest,${{ secrets.REGISTRY_URL }}/${{ gitea.actor }}/${{ toLower(gitea.repository_name) }}-backend:${{ gitea.sha_short }}
- name: Build and Push Frontend Image
uses: docker/build-push-action@v4
with:
context: .
file: Frontend/Dockerfile
push: true
tags: ${{ secrets.REGISTRY_URL }}/${{ gitea.actor }}/${{ toLower(gitea.repository_name) }}-frontend:latest,${{ secrets.REGISTRY_URL }}/${{ gitea.actor }}/${{ toLower(gitea.repository_name) }}-frontend:${{ gitea.sha_short }}
- name: Deploy to Production
run: |
echo "Deploying to production server..."
apk add --no-cache openssh-client
mkdir -p ~/.ssh
echo "${{ secrets.PROD_SERVER_SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.PROD_SERVER_HOST }} >> ~/.ssh/known_hosts
ssh ${{ secrets.PROD_SERVER_USER }}@${{ secrets.PROD_SERVER_HOST }} << 'EOF'
echo "--- CONECTADO AL SERVIDOR DE PRODUCCIÓN ---"
cd /opt/gestion-integral
export DB_SA_PASSWORD="${{ secrets.DB_SA_PASSWORD_SECRET }}"
export JWT_KEY="${{ secrets.JWT_KEY_SECRET }}"
docker login ${{ secrets.REGISTRY_URL }} -u ${{ secrets.GITEA_USER }} -p ${{ secrets.ACTIONS_PAT }}
docker compose pull
docker compose up -d
docker image prune -af
echo "--- DESPLIEGUE COMPLETADO ---"
EOF

166
.gitignore vendored Normal file
View File

@@ -0,0 +1,166 @@
# ===================================================================
# Archivo .gitignore para un repositorio con Backend ASP.NET y Frontend React/Vite
# ===================================================================
# Dependencias y paquetes locales
# -------------------------------
node_modules/
dist/
dist-ssr/
*.local
# Archivos de log
# -------------------------------
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Variables de entorno
# -------------------------------
# Nunca subas tus claves de API, contraseñas de BD, etc.
# Crea un archivo .env.example con las variables vacías para guiar a otros desarrolladores.
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Archivos de caché y reportes de herramientas
# ---------------------------------------------
.eslintcache
.stylelintcache
.npm/
.pnpm-store/
coverage/
.nyc_output/
# ===================================================================
# SECCIÓN PARA PROYECTOS ASP.NET CORE (Backend)
# ===================================================================
# Archivos y carpetas generados por Visual Studio y Rider
# -------------------------------------------------------
*.sln.DotSettings.user
*.suo
*.user
*.userosscache
*.sln.docstates
*.vspscc
*.vssscc
.vs/
project.lock.json
project.fragment.lock.json
vs.lock.json
*.csproj.user
*.vcxproj.filters
*.pubxml
*.pubxml.user
# Carpetas de compilación y publicación
# --------------------------------------
[Bb]in/
[Oo]bj/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Dd]ebug/
[Dd]ebug[Pp]ublic/
[Rr]elease[Pp]ublic/
[Tt]est[Rr]esult*/
[Bb]uild[Ss]uccess.txt
[Dd]ebug/
[Rr]elease/
**/[Bb]in
**/[Oo]bj
**/[Dd]ebug
**/[Rr]elease
**/[Ll]ogs
**/[Pp]ackages
*.nupkg
*.snupkg
# Archivos de configuración locales de usuario y secrets
# ------------------------------------------------------
# (appsettings.Development.json a veces se sube, pero si contiene secretos, no debería)
appsettings.Development.json
secrets.json
user-secrets.json
*.secrets.json
# Caché y logs de Resharper y Rider
# ----------------------------------
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
.idea/
# Archivos de Test
# -----------------
TestResults/
*.trx
# Archivos de publicación de base de datos
# -----------------------------------------
*.dacpac
*.dbschema
*.dbmdl
# Otros
# -----
*.log
*.tlog
*.psess
*.vsp
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tmp
*.tmp_proj
*.vsix
*.xaml.cs
# ===================================================================
# SECCIÓN PARA PROYECTOS REACT/VITE (Frontend)
# ===================================================================
# Archivos de caché y logs específicos de Vite/React
# ---------------------------------------------------
.DS_Store
.cache/
.history/
.idea/
.vscode/
# Editor-specific files
# ---------------------
*.swp
*~
*.orig
# Reportes
# --------
junit.xml
# Evitar subir imágenes/assets que deberían estar en el CDN en producción, si aplica.
# Si tus assets están en el repo, ignora esto.
# public/assets/production/
# ===================================================================
# Fin del archivo .gitignore
# ===================================================================

View File

@@ -0,0 +1,715 @@
using GestionIntegral.Api.Services.Usuarios;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Security.Claims; // Para ClaimTypes
using GestionIntegral.Api.Services.Contables; // Para IPagoDistribuidorService, etc.
using GestionIntegral.Api.Services.Distribucion;
using GestionIntegral.Api.Dtos.Auditoria;
using GestionIntegral.Api.Dtos.Zonas;
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Services.Impresion;
using GestionIntegral.Api.Dtos.Impresion;
using GestionIntegral.Api.Dtos.Usuarios;
namespace GestionIntegral.Api.Controllers
{
[Route("api/auditoria")]
[ApiController]
[Authorize]
public class AuditoriaController : ControllerBase
{
private readonly IUsuarioService _usuarioService;
private readonly IPagoDistribuidorService _pagoDistribuidorService;
private readonly INotaCreditoDebitoService _notaCreditoDebitoService;
private readonly IEntradaSalidaDistService _esDistService;
private readonly IDistribuidorService _distribuidorService;
private readonly IEntradaSalidaCanillaService _esCanillaService;
private readonly INovedadCanillaService _novedadCanillaService;
private readonly ICanillaService _canillaService;
private readonly ISaldoService _saldoService;
private readonly ITipoPagoService _tipoPagoService;
private readonly IEmpresaService _empresaService;
private readonly IZonaService _zonaService;
private readonly IOtroDestinoService _otroDestinoService;
private readonly IPublicacionService _publicacionService;
private readonly IPubliSeccionService _publiSeccionService;
private readonly IPrecioService _precioService;
private readonly IRecargoZonaService _recargoZonaService;
private readonly IPorcPagoService _porcPagoService;
private readonly IPorcMonCanillaService _porcMonCanillaService;
private readonly IControlDevolucionesService _controlDevolucionesService;
private readonly ITipoBobinaService _tipoBobinaService;
private readonly IEstadoBobinaService _estadoBobinaService;
private readonly IPlantaService _plantaService;
private readonly IStockBobinaService _stockBobinaService;
private readonly ITiradaService _tiradaService;
private readonly IPerfilService _perfilService;
private readonly IPermisoService _permisoService;
private readonly ICambioParadaService _cambioParadaService;
private readonly ILogger<AuditoriaController> _logger;
// Permiso general para ver cualquier auditoría.
// Podrías tener permisos más granulares por tipo de auditoría si es necesario.
private const string PermisoVerAuditoria = "AU_GENERAL_VIEW"; // Define este permiso
public AuditoriaController(
IUsuarioService usuarioService,
IPagoDistribuidorService pagoDistribuidorService,
INotaCreditoDebitoService notaCreditoDebitoService,
IEntradaSalidaDistService esDistService,
IDistribuidorService distribuidorService,
IEntradaSalidaCanillaService esCanillaService,
INovedadCanillaService novedadCanillaService,
ICanillaService canillaService,
ISaldoService saldoService,
ITipoPagoService tipoPagoService,
IEmpresaService empresaService,
IZonaService zonaService,
IOtroDestinoService otroDestinoService,
IPublicacionService publicacionService,
IPubliSeccionService publiSeccionService,
IPrecioService precioService,
IRecargoZonaService recargoZonaService,
IPorcPagoService porcPagoService,
IPorcMonCanillaService porcMonCanillaService,
IControlDevolucionesService controlDevolucionesService,
ITipoBobinaService tipoBobinaService,
IEstadoBobinaService estadoBobinaService,
IPlantaService plantaService,
IStockBobinaService stockBobinaService,
ITiradaService tiradaService,
IPerfilService perfilService,
IPermisoService permisoService,
ICambioParadaService cambioParadaService,
ILogger<AuditoriaController> logger)
{
_usuarioService = usuarioService;
_pagoDistribuidorService = pagoDistribuidorService;
_notaCreditoDebitoService = notaCreditoDebitoService;
_esDistService = esDistService;
_distribuidorService = distribuidorService;
_esCanillaService = esCanillaService;
_novedadCanillaService = novedadCanillaService;
_canillaService = canillaService;
_saldoService = saldoService;
_tipoPagoService = tipoPagoService;
_empresaService = empresaService;
_zonaService = zonaService;
_otroDestinoService = otroDestinoService;
_publicacionService = publicacionService;
_publiSeccionService = publiSeccionService;
_precioService = precioService;
_recargoZonaService = recargoZonaService;
_porcPagoService = porcPagoService;
_porcMonCanillaService = porcMonCanillaService;
_controlDevolucionesService = controlDevolucionesService;
_tipoBobinaService = tipoBobinaService;
_estadoBobinaService = estadoBobinaService;
_plantaService = plantaService;
_stockBobinaService = stockBobinaService;
_tiradaService = tiradaService;
_perfilService = perfilService;
_cambioParadaService = cambioParadaService;
_permisoService = permisoService;
_logger = logger;
}
private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
private int? GetCurrentUserId() // Podría no ser necesario aquí si solo filtramos por usuario modificador
{
if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId;
return null;
}
[HttpGet("pagos-distribuidores")]
[ProducesResponseType(typeof(IEnumerable<PagoDistribuidorHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPagosDistribuidor(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPagoAfectado) // Parámetro para filtrar por un ID de pago específico
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid(); // O un permiso más específico si lo creas
try
{
var historial = await _pagoDistribuidorService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPagoAfectado);
return Ok(historial ?? Enumerable.Empty<PagoDistribuidorHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de pagos de distribuidores.");
return StatusCode(500, "Error interno al obtener historial de pagos.");
}
}
[HttpGet("notas-credito-debito")]
[ProducesResponseType(typeof(IEnumerable<NotaCreditoDebitoHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialNotasCD(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idNotaAfectada) // ID de la nota original
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _notaCreditoDebitoService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idNotaAfectada);
return Ok(historial ?? Enumerable.Empty<NotaCreditoDebitoHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de notas C/D.");
return StatusCode(500, "Error interno al obtener historial de notas C/D.");
}
}
[HttpGet("entradas-salidas-dist")]
[ProducesResponseType(typeof(IEnumerable<EntradaSalidaDistHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialEntradasSalidasDist(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idParteAfectada) // ID del movimiento original
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _esDistService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idParteAfectada);
return Ok(historial ?? Enumerable.Empty<EntradaSalidaDistHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de E/S Distribuidores.");
return StatusCode(500, "Error interno al obtener historial de E/S Distribuidores.");
}
}
[HttpGet("entradas-salidas-canilla")]
[ProducesResponseType(typeof(IEnumerable<EntradaSalidaCanillaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialEntradasSalidasCanilla(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idParteAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _esCanillaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idParteAfectada);
return Ok(historial ?? Enumerable.Empty<EntradaSalidaCanillaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de E/S Canillitas.");
return StatusCode(500, "Error interno al obtener historial de E/S Canillitas.");
}
}
[HttpGet("novedades-canilla")] // Endpoint consistente con el servicio frontend
[ProducesResponseType(typeof(IEnumerable<NovedadCanillaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialNovedadesCanilla(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idNovedadAfectada) // ID de la novedad original
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _novedadCanillaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idNovedadAfectada);
return Ok(historial ?? Enumerable.Empty<NovedadCanillaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Novedades de Canillitas.");
return StatusCode(500, "Error interno al obtener historial de Novedades de Canillitas.");
}
}
[HttpGet("ajustes-saldo")]
[ProducesResponseType(typeof(IEnumerable<SaldoAjusteHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialAjustesSaldo(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico,
[FromQuery] string? destino, [FromQuery] int? idDestino, [FromQuery] int? idEmpresa)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid(); // O un permiso más específico si lo creas
try
{
var historial = await _saldoService.ObtenerHistorialAjustesAsync(fechaDesde, fechaHasta, idUsuarioModifico, destino, idDestino, idEmpresa);
return Ok(historial ?? Enumerable.Empty<SaldoAjusteHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de ajustes de saldo.");
return StatusCode(500, "Error interno al obtener historial de ajustes de saldo.");
}
}
[HttpGet("tipos-pago")]
[ProducesResponseType(typeof(IEnumerable<TipoPagoHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialTiposPago(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idTipoPagoAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
// Asumiendo que _tipoPagoService está inyectado
var historial = await _tipoPagoService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idTipoPagoAfectado);
return Ok(historial ?? Enumerable.Empty<TipoPagoHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Tipos de Pago.");
return StatusCode(500, "Error interno al obtener historial de Tipos de Pago.");
}
}
[HttpGet("canillitas-maestro")] // Endpoint para el historial del maestro de canillitas
[ProducesResponseType(typeof(IEnumerable<CanillaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialCanillitasMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idCanillaAfectado) // ID del canillita original
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _canillaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idCanillaAfectado);
return Ok(historial ?? Enumerable.Empty<CanillaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Canillitas (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Canillitas (Maestro).");
}
}
[HttpGet("distribuidores-maestro")]
[ProducesResponseType(typeof(IEnumerable<DistribuidorHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialDistribuidoresMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idDistribuidorAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _distribuidorService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idDistribuidorAfectado);
return Ok(historial ?? Enumerable.Empty<DistribuidorHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Distribuidores (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Distribuidores (Maestro).");
}
}
[HttpGet("empresas-maestro")]
[ProducesResponseType(typeof(IEnumerable<EmpresaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialEmpresasMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idEmpresaAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
// Asumiendo que _empresaService está inyectado
var historial = await _empresaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idEmpresaAfectada);
return Ok(historial ?? Enumerable.Empty<EmpresaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Empresas (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Empresas (Maestro).");
}
}
[HttpGet("zonas-maestro")]
[ProducesResponseType(typeof(IEnumerable<ZonaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialZonasMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idZonaAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
// Asumiendo que _zonaService está inyectado
var historial = await _zonaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idZonaAfectada);
return Ok(historial ?? Enumerable.Empty<ZonaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Zonas (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Zonas (Maestro).");
}
}
[HttpGet("otros-destinos-maestro")]
[ProducesResponseType(typeof(IEnumerable<OtroDestinoHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialOtrosDestinosMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idOtroDestinoAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _otroDestinoService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idOtroDestinoAfectado);
return Ok(historial ?? Enumerable.Empty<OtroDestinoHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Otros Destinos (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Otros Destinos (Maestro).");
}
}
[HttpGet("publicaciones-maestro")]
[ProducesResponseType(typeof(IEnumerable<PublicacionHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPublicacionesMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPublicacionAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _publicacionService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPublicacionAfectada);
return Ok(historial ?? Enumerable.Empty<PublicacionHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Publicaciones (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Publicaciones (Maestro).");
}
}
[HttpGet("publi-secciones-maestro")]
[ProducesResponseType(typeof(IEnumerable<PubliSeccionHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPubliSeccionesMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idSeccionAfectada, [FromQuery] int? idPublicacionAfectada) // Nuevos filtros
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _publiSeccionService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idSeccionAfectada, idPublicacionAfectada);
return Ok(historial ?? Enumerable.Empty<PubliSeccionHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Secciones de Publicación.");
return StatusCode(500, "Error interno al obtener historial de Secciones de Publicación.");
}
}
[HttpGet("precios-publicacion-maestro")]
[ProducesResponseType(typeof(IEnumerable<PrecioHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPreciosMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPrecioAfectado, [FromQuery] int? idPublicacionAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _precioService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPrecioAfectado, idPublicacionAfectada);
return Ok(historial ?? Enumerable.Empty<PrecioHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Precios de Publicación.");
return StatusCode(500, "Error interno al obtener historial de Precios de Publicación.");
}
}
[HttpGet("recargos-zona-maestro")]
[ProducesResponseType(typeof(IEnumerable<RecargoZonaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialRecargosZonaMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idRecargoAfectado, [FromQuery] int? idPublicacionAfectada, [FromQuery] int? idZonaAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _recargoZonaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idRecargoAfectado, idPublicacionAfectada, idZonaAfectada);
return Ok(historial ?? Enumerable.Empty<RecargoZonaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Recargos por Zona.");
return StatusCode(500, "Error interno al obtener historial de Recargos por Zona.");
}
}
[HttpGet("porc-pago-dist-maestro")]
[ProducesResponseType(typeof(IEnumerable<PorcPagoHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPorcPagoDistMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPorcentajeAfectado, [FromQuery] int? idPublicacionAfectada, [FromQuery] int? idDistribuidorAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _porcPagoService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPorcentajeAfectado, idPublicacionAfectada, idDistribuidorAfectado);
return Ok(historial ?? Enumerable.Empty<PorcPagoHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Porcentajes de Pago (Dist).");
return StatusCode(500, "Error interno al obtener historial de Porcentajes de Pago (Dist).");
}
}
[HttpGet("porc-mon-canilla-maestro")]
[ProducesResponseType(typeof(IEnumerable<PorcMonCanillaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPorcMonCanillaMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPorcMonAfectado, [FromQuery] int? idPublicacionAfectada, [FromQuery] int? idCanillaAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _porcMonCanillaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPorcMonAfectado, idPublicacionAfectada, idCanillaAfectado);
return Ok(historial ?? Enumerable.Empty<PorcMonCanillaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Porc/Mon Canillita.");
return StatusCode(500, "Error interno al obtener historial de Porc/Mon Canillita.");
}
}
[HttpGet("control-devoluciones-maestro")]
[ProducesResponseType(typeof(IEnumerable<ControlDevolucionesHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialControlDevolucionesMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idControlAfectado, [FromQuery] int? idEmpresaAfectada, [FromQuery] DateTime? fechaAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _controlDevolucionesService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idControlAfectado, idEmpresaAfectada, fechaAfectada);
return Ok(historial ?? Enumerable.Empty<ControlDevolucionesHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Control de Devoluciones.");
return StatusCode(500, "Error interno al obtener historial de Control de Devoluciones.");
}
}
[HttpGet("tipos-bobina-maestro")]
[ProducesResponseType(typeof(IEnumerable<TipoBobinaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialTiposBobinaMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idTipoBobinaAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _tipoBobinaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idTipoBobinaAfectado);
return Ok(historial ?? Enumerable.Empty<TipoBobinaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Tipos de Bobina.");
return StatusCode(500, "Error interno al obtener historial de Tipos de Bobina.");
}
}
[HttpGet("estados-bobina-maestro")]
[ProducesResponseType(typeof(IEnumerable<EstadoBobinaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialEstadosBobinaMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idEstadoBobinaAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _estadoBobinaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idEstadoBobinaAfectado);
return Ok(historial ?? Enumerable.Empty<EstadoBobinaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Estados de Bobina.");
return StatusCode(500, "Error interno al obtener historial de Estados de Bobina.");
}
}
[HttpGet("plantas-impresion-maestro")]
[ProducesResponseType(typeof(IEnumerable<PlantaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPlantasMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPlantaAfectada)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _plantaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPlantaAfectada);
return Ok(historial ?? Enumerable.Empty<PlantaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Plantas de Impresión.");
return StatusCode(500, "Error interno al obtener historial de Plantas de Impresión.");
}
}
[HttpGet("stock-bobinas-maestro")]
[ProducesResponseType(typeof(IEnumerable<StockBobinaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialStockBobinasMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idBobinaAfectada, [FromQuery] int? idTipoBobinaFiltro,
[FromQuery] int? idPlantaFiltro, [FromQuery] int? idEstadoBobinaFiltro)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _stockBobinaService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idBobinaAfectada, idTipoBobinaFiltro, idPlantaFiltro, idEstadoBobinaFiltro);
return Ok(historial ?? Enumerable.Empty<StockBobinaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Stock de Bobinas.");
return StatusCode(500, "Error interno al obtener historial de Stock de Bobinas.");
}
}
[HttpGet("reg-tiradas-maestro")]
[ProducesResponseType(typeof(IEnumerable<RegTiradaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialRegTiradasMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idRegistroAfectado, [FromQuery] int? idPublicacionFiltro,
[FromQuery] int? idPlantaFiltro, [FromQuery] DateTime? fechaTiradaFiltro)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _tiradaService.ObtenerRegTiradasHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idRegistroAfectado, idPublicacionFiltro, idPlantaFiltro, fechaTiradaFiltro);
return Ok(historial ?? Enumerable.Empty<RegTiradaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Registro de Tiradas.");
return StatusCode(500, "Error interno al obtener historial de Registro de Tiradas.");
}
}
[HttpGet("reg-secciones-tirada-maestro")]
[ProducesResponseType(typeof(IEnumerable<RegSeccionTiradaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialRegSeccionesTiradaMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idTiradaAfectada, [FromQuery] int? idPublicacionFiltro,
[FromQuery] int? idSeccionFiltro, [FromQuery] int? idPlantaFiltro, [FromQuery] DateTime? fechaTiradaFiltro)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _tiradaService.ObtenerRegSeccionesTiradaHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idTiradaAfectada, idPublicacionFiltro, idSeccionFiltro, idPlantaFiltro, fechaTiradaFiltro);
return Ok(historial ?? Enumerable.Empty<RegSeccionTiradaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Secciones de Tirada.");
return StatusCode(500, "Error interno al obtener historial de Secciones de Tirada.");
}
}
[HttpGet("perfiles-maestro")]
[ProducesResponseType(typeof(IEnumerable<PerfilHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPerfilesMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPerfilAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _perfilService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPerfilAfectado);
return Ok(historial ?? Enumerable.Empty<PerfilHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Perfiles (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Perfiles (Maestro).");
}
}
[HttpGet("permisos-maestro")]
[ProducesResponseType(typeof(IEnumerable<PermisoHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPermisosMaestro(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPermisoAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _permisoService.ObtenerHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPermisoAfectado);
return Ok(historial ?? Enumerable.Empty<PermisoHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Permisos (Maestro).");
return StatusCode(500, "Error interno al obtener historial de Permisos (Maestro).");
}
}
[HttpGet("permisos-perfiles-historial")]
[ProducesResponseType(typeof(IEnumerable<PermisosPerfilesHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialPermisosPerfiles(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idPerfilAfectado, [FromQuery] int? idPermisoAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _perfilService.ObtenerPermisosAsignadosHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPerfilAfectado, idPermisoAfectado);
return Ok(historial ?? Enumerable.Empty<PermisosPerfilesHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Asignación de Permisos.");
return StatusCode(500, "Error interno al obtener historial de Asignación de Permisos.");
}
}
[HttpGet("cambios-parada-canilla")]
[ProducesResponseType(typeof(IEnumerable<CambioParadaHistorialDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialCambiosParada(
[FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta,
[FromQuery] int? idUsuarioModifico, [FromQuery] string? tipoModificacion,
[FromQuery] int? idCanillaAfectado)
{
if (!TienePermiso(PermisoVerAuditoria)) return Forbid();
try
{
var historial = await _cambioParadaService.ObtenerCambiosParadaHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idCanillaAfectado);
return Ok(historial ?? Enumerable.Empty<CambioParadaHistorialDto>());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error obteniendo historial de Cambios de Parada.");
return StatusCode(500, "Error interno al obtener historial de Cambios de Parada.");
}
}
}
}

View File

@@ -0,0 +1,109 @@
using GestionIntegral.Api.Dtos.Contables;
using GestionIntegral.Api.Services.Contables;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace GestionIntegral.Api.Controllers.Contables
{
[Route("api/saldos")]
[ApiController]
[Authorize] // Requiere autenticación para todos los endpoints
public class SaldosController : ControllerBase
{
private readonly ISaldoService _saldoService;
private readonly ILogger<SaldosController> _logger;
// Define un permiso específico para ver saldos, y otro para ajustarlos (SuperAdmin implícito)
private const string PermisoVerSaldos = "CS001"; // Ejemplo: Cuentas Saldos Ver
private const string PermisoAjustarSaldos = "CS002"; // Ejemplo: Cuentas Saldos Ajustar (o solo SuperAdmin)
public SaldosController(ISaldoService saldoService, ILogger<SaldosController> logger)
{
_saldoService = saldoService;
_logger = logger;
}
private bool TienePermiso(string codAccRequerido)
{
if (User.IsInRole("SuperAdmin")) return true;
return User.HasClaim(c => c.Type == "permission" && c.Value == codAccRequerido);
}
private int? GetCurrentUserId()
{
if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId;
_logger.LogWarning("No se pudo obtener el UserId del token JWT en SaldosController.");
return null;
}
// GET: api/saldos
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<SaldoGestionDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetSaldosGestion(
[FromQuery] string? destino,
[FromQuery] int? idDestino,
[FromQuery] int? idEmpresa)
{
if (!TienePermiso(PermisoVerSaldos)) // Usar el nuevo permiso
{
_logger.LogWarning("Acceso denegado a GetSaldosGestion para Usuario ID {userId}", GetCurrentUserId() ?? 0);
return Forbid();
}
try
{
var saldos = await _saldoService.ObtenerSaldosParaGestionAsync(destino, idDestino, idEmpresa);
return Ok(saldos);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener saldos para gestión.");
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener saldos.");
}
}
// POST: api/saldos/ajustar
[HttpPost("ajustar")]
[ProducesResponseType(typeof(SaldoGestionDto), StatusCodes.Status200OK)] // Devuelve el saldo actualizado
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] // Solo SuperAdmin o con permiso específico
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> AjustarSaldoManualmente([FromBody] AjusteSaldoRequestDto ajusteDto)
{
// Esta operación debería ser MUY restringida. Solo SuperAdmin o un permiso muy específico.
if (!User.IsInRole("SuperAdmin") && !TienePermiso(PermisoAjustarSaldos))
{
_logger.LogWarning("Intento no autorizado de ajustar saldo por Usuario ID {userId}", GetCurrentUserId() ?? 0);
return Forbid("No tiene permisos para realizar ajustes manuales de saldo.");
}
if (!ModelState.IsValid) return BadRequest(ModelState);
var idUsuario = GetCurrentUserId();
if (idUsuario == null) return Unauthorized("No se pudo identificar al usuario.");
try
{
var (exito, error, saldoActualizado) = await _saldoService.RealizarAjusteManualSaldoAsync(ajusteDto, idUsuario.Value);
if (!exito)
{
if (error != null && error.Contains("No se encontró un saldo existente"))
return NotFound(new { message = error });
return BadRequest(new { message = error ?? "Error desconocido al ajustar el saldo." });
}
return Ok(saldoActualizado);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error crítico al ajustar saldo manualmente.");
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar el ajuste de saldo.");
}
}
}
}

View File

@@ -0,0 +1,129 @@
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Services.Distribucion;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace GestionIntegral.Api.Controllers.Distribucion
{
[Route("api/canillas/{idCanilla}/paradas")] // Anidado bajo canillas
[ApiController]
[Authorize]
public class CambiosParadaController : ControllerBase
{
private readonly ICambioParadaService _paradaService;
private readonly ILogger<CambiosParadaController> _logger;
private const string PermisoGestionarParadas = "CG007";
public CambiosParadaController(ICambioParadaService paradaService, ILogger<CambiosParadaController> logger)
{
_paradaService = paradaService;
_logger = logger;
}
private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
private int? GetCurrentUserId()
{
if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId;
_logger.LogWarning("No se pudo obtener el UserId del token JWT en CambiosParadaController.");
return null;
}
// GET: api/canillas/{idCanilla}/paradas
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<CambioParadaDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetParadasPorCanilla(int idCanilla)
{
// Podría usarse CG001 (Ver Canilla) o CG007 para ver el historial de paradas
if (!TienePermiso("CG001") && !TienePermiso(PermisoGestionarParadas)) return Forbid();
var paradas = await _paradaService.ObtenerPorCanillaAsync(idCanilla);
return Ok(paradas);
}
// POST: api/canillas/{idCanilla}/paradas
[HttpPost]
[ProducesResponseType(typeof(CambioParadaDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> CreateParada(int idCanilla, [FromBody] CreateCambioParadaDto createDto)
{
if (!TienePermiso(PermisoGestionarParadas)) return Forbid();
if (!ModelState.IsValid) return BadRequest(ModelState);
var userId = GetCurrentUserId();
if (userId == null) return Unauthorized();
var (paradaDto, error) = await _paradaService.CrearNuevaParadaAsync(idCanilla, createDto, userId.Value);
if (error != null) return BadRequest(new { message = error });
if (paradaDto == null) return StatusCode(StatusCodes.Status500InternalServerError, "Error al crear la parada.");
// La ruta para "GetById" podría estar en otro controlador si decides separar los endpoints de "paradas individuales"
// Por ahora, asumimos que habrá un endpoint para obtener una parada por su ID de registro.
return CreatedAtAction(nameof(GetParadaById), new { idCanilla = idCanilla, idRegistroParada = paradaDto.IdRegistro }, paradaDto);
}
// GET: api/canillas/{idCanilla}/paradas/{idRegistroParada} (o api/paradas/{idRegistroParada})
// Este endpoint es opcional, pero útil si necesitas obtener una parada específica por su ID de registro
[HttpGet("{idRegistroParada:int}", Name = "GetParadaById")]
[ProducesResponseType(typeof(CambioParadaDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetParadaById(int idCanilla, int idRegistroParada) // idCanilla es parte de la ruta base
{
if (!TienePermiso("CG001") && !TienePermiso(PermisoGestionarParadas)) return Forbid();
var parada = await _paradaService.ObtenerPorIdAsync(idRegistroParada);
if (parada == null || parada.IdCanilla != idCanilla) return NotFound(new { message = "Registro de parada no encontrado para este canillita."});
return Ok(parada);
}
// PUT: api/paradas/{idRegistroParada}/cerrar (Ruta ejemplo para cerrar una parada)
// O podrías usar PUT api/canillas/{idCanilla}/paradas/{idRegistroParada} y que el DTO solo tenga VigenciaH
[HttpPut("~/api/paradas/{idRegistroParada}/cerrar")] // Ruta a nivel raíz para paradas si se edita por IdRegistro
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> CerrarVigenciaParada(int idRegistroParada, [FromBody] UpdateCambioParadaDto updateDto)
{
if (!TienePermiso(PermisoGestionarParadas)) return Forbid();
if (!ModelState.IsValid) return BadRequest(ModelState);
var userId = GetCurrentUserId();
if (userId == null) return Unauthorized();
var (exito, error) = await _paradaService.CerrarParadaAsync(idRegistroParada, updateDto, userId.Value);
if (!exito)
{
if (error != null && error.Contains("no encontrado")) return NotFound(new { message = error });
return BadRequest(new { message = error });
}
return NoContent();
}
// DELETE: api/paradas/{idRegistroParada}
[HttpDelete("~/api/paradas/{idRegistroParada}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> DeleteParada(int idRegistroParada)
{
if (!TienePermiso(PermisoGestionarParadas)) return Forbid();
var userId = GetCurrentUserId();
if (userId == null) return Unauthorized();
var (exito, error) = await _paradaService.EliminarParadaAsync(idRegistroParada, userId.Value);
if (!exito)
{
if (error != null && error.Contains("no encontrado")) return NotFound(new { message = error });
return BadRequest(new { message = error });
}
return NoContent();
}
}
}

View File

@@ -47,11 +47,11 @@ namespace GestionIntegral.Api.Controllers.Distribucion
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(IEnumerable<CanillaDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(IEnumerable<CanillaDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetAllCanillas([FromQuery] string? nomApe, [FromQuery] int? legajo, [FromQuery] bool? soloActivos = true) public async Task<IActionResult> GetAllCanillas([FromQuery] string? nomApe, [FromQuery] int? legajo, [FromQuery] bool? esAccionista, [FromQuery] bool? soloActivos = true)
{ {
if (!TienePermiso(PermisoVer)) return Forbid(); if (!TienePermiso(PermisoVer)) return Forbid();
var canillas = await _canillaService.ObtenerTodosAsync(nomApe, legajo, soloActivos); var canillitas = await _canillaService.ObtenerTodosAsync(nomApe, legajo, soloActivos, esAccionista); // <<-- Pasa el parámetro
return Ok(canillas); return Ok(canillitas);
} }
// GET: api/canillas/{id} // GET: api/canillas/{id}

View File

@@ -47,6 +47,15 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return Ok(distribuidores); return Ok(distribuidores);
} }
[HttpGet("dropdown")]
[ProducesResponseType(typeof(IEnumerable<DistribuidorDropdownDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetAllDropdownDistribuidores()
{
var distribuidores = await _distribuidorService.GetAllDropdownAsync();
return Ok(distribuidores);
}
[HttpGet("{id:int}", Name = "GetDistribuidorById")] [HttpGet("{id:int}", Name = "GetDistribuidorById")]
[ProducesResponseType(typeof(DistribuidorDto), StatusCodes.Status200OK)] [ProducesResponseType(typeof(DistribuidorDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
@@ -59,6 +68,17 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return Ok(distribuidor); return Ok(distribuidor);
} }
[HttpGet("{id:int}/lookup", Name = "GetDistribuidorLookupById")]
[ProducesResponseType(typeof(DistribuidorLookupDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> ObtenerLookupPorIdAsync(int id)
{
var distribuidor = await _distribuidorService.ObtenerLookupPorIdAsync(id);
if (distribuidor == null) return NotFound();
return Ok(distribuidor);
}
[HttpPost] [HttpPost]
[ProducesResponseType(typeof(DistribuidorDto), StatusCodes.Status201Created)] [ProducesResponseType(typeof(DistribuidorDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]

View File

@@ -74,6 +74,25 @@ namespace GestionIntegral.Api.Controllers // Ajusta el namespace si es necesario
} }
} }
// GET: api/empresas/dropdown
[HttpGet("dropdown")]
[ProducesResponseType(typeof(IEnumerable<EmpresaDropdownDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetEmpresasDropdown()
{
try
{
var empresas = await _empresaService.ObtenerParaDropdown();
return Ok(empresas);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener todas las Empresas.");
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener las empresas.");
}
}
// GET: api/empresas/{id} // GET: api/empresas/{id}
// Permiso Requerido: DE001 (Ver Empresas) // Permiso Requerido: DE001 (Ver Empresas)
[HttpGet("{id:int}", Name = "GetEmpresaById")] [HttpGet("{id:int}", Name = "GetEmpresaById")]
@@ -101,6 +120,29 @@ namespace GestionIntegral.Api.Controllers // Ajusta el namespace si es necesario
} }
} }
[HttpGet("{id:int}/lookup", Name = "GetEmpresaLookupById")]
[ProducesResponseType(typeof(EmpresaDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> ObtenerLookupPorIdAsync(int id)
{
try
{
var empresa = await _empresaService.ObtenerLookupPorIdAsync(id);
if (empresa == null)
{
return NotFound(new { message = $"Empresa con ID {id} no encontrada." });
}
return Ok(empresa);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener Empresa por ID: {Id}", id);
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener la empresa.");
}
}
// POST: api/empresas // POST: api/empresas
// Permiso Requerido: DE002 (Agregar Empresas) // Permiso Requerido: DE002 (Agregar Empresas)
[HttpPost] [HttpPost]

View File

@@ -0,0 +1,212 @@
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Services.Distribucion;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace GestionIntegral.Api.Controllers.Distribucion
{
[Route("api/novedadescanilla")] // Ruta base más genérica para las novedades
[ApiController]
[Authorize] // Todas las acciones requieren autenticación
public class NovedadesCanillaController : ControllerBase
{
private readonly INovedadCanillaService _novedadService;
private readonly ILogger<NovedadesCanillaController> _logger;
public NovedadesCanillaController(INovedadCanillaService novedadService, ILogger<NovedadesCanillaController> logger)
{
_novedadService = novedadService;
_logger = logger;
}
// --- Helper para verificar permisos ---
private bool TienePermiso(string codAccRequerido)
{
if (User.IsInRole("SuperAdmin")) return true;
return User.HasClaim(c => c.Type == "permission" && c.Value == codAccRequerido);
}
// --- Helper para obtener User ID ---
private int? GetCurrentUserId()
{
var userIdClaim = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub");
if (int.TryParse(userIdClaim, out int userId))
{
return userId;
}
_logger.LogWarning("No se pudo obtener el UserId del token JWT en NovedadesCanillaController.");
return null;
}
// GET: api/novedadescanilla/porcanilla/{idCanilla}
// Obtiene todas las novedades para un canillita específico, opcionalmente filtrado por fecha.
// Permiso: CG001 (Ver Canillas) o CG006 (Gestionar Novedades).
// Si CG006 es "Permite la Carga/Modificación", entonces CG001 podría ser más apropiado solo para ver.
// Vamos a usar CG001 para ver. Si se quiere más granularidad, se puede crear un permiso "Ver Novedades".
[HttpGet("porcanilla/{idCanilla:int}")]
[ProducesResponseType(typeof(IEnumerable<NovedadCanillaDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetNovedadesPorCanilla(int idCanilla, [FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta)
{
if (!TienePermiso("CG001") && !TienePermiso("CG006")) // Necesita al menos uno de los dos
{
_logger.LogWarning("Acceso denegado a GetNovedadesPorCanilla para el usuario {UserId} y canillita {IdCanilla}", GetCurrentUserId() ?? 0, idCanilla);
return Forbid();
}
try
{
var novedades = await _novedadService.ObtenerPorCanillaAsync(idCanilla, fechaDesde, fechaHasta);
return Ok(novedades);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener novedades para Canillita ID: {IdCanilla}", idCanilla);
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener las novedades.");
}
}
// GET: api/novedadescanilla/{idNovedad}
// Obtiene una novedad específica por su ID.
// Permiso: CG001 o CG006
[HttpGet("{idNovedad:int}", Name = "GetNovedadCanillaById")]
[ProducesResponseType(typeof(NovedadCanillaDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetNovedadCanillaById(int idNovedad)
{
if (!TienePermiso("CG001") && !TienePermiso("CG006")) return Forbid();
try
{
var novedad = await _novedadService.ObtenerPorIdAsync(idNovedad);
if (novedad == null)
{
return NotFound(new { message = $"Novedad con ID {idNovedad} no encontrada." });
}
return Ok(novedad);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener NovedadCanilla por ID: {IdNovedad}", idNovedad);
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener la novedad.");
}
}
// POST: api/novedadescanilla
// Crea una nueva novedad. El IdCanilla viene en el DTO.
// Permiso: CG006 (Permite la Carga/Modificación de Novedades)
[HttpPost]
[ProducesResponseType(typeof(NovedadCanillaDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateNovedadCanilla([FromBody] CreateNovedadCanillaDto createDto)
{
if (!TienePermiso("CG006")) return Forbid();
if (!ModelState.IsValid) return BadRequest(ModelState);
var idUsuario = GetCurrentUserId();
if (idUsuario == null) return Unauthorized("No se pudo obtener el ID del usuario del token.");
try
{
var (novedadCreada, error) = await _novedadService.CrearAsync(createDto, idUsuario.Value);
if (error != null) return BadRequest(new { message = error });
if (novedadCreada == null) return StatusCode(StatusCodes.Status500InternalServerError, "Error al crear la novedad.");
// Devuelve la ruta al recurso creado y el recurso mismo
return CreatedAtRoute("GetNovedadCanillaById", new { idNovedad = novedadCreada.IdNovedad }, novedadCreada);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al crear NovedadCanilla para Canilla ID: {IdCanilla} por Usuario ID: {UsuarioId}", createDto.IdCanilla, idUsuario);
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al crear la novedad.");
}
}
// PUT: api/novedadescanilla/{idNovedad}
// Actualiza una novedad existente.
// Permiso: CG006
[HttpPut("{idNovedad:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateNovedadCanilla(int idNovedad, [FromBody] UpdateNovedadCanillaDto updateDto)
{
if (!TienePermiso("CG006")) return Forbid();
if (!ModelState.IsValid) return BadRequest(ModelState);
var idUsuario = GetCurrentUserId();
if (idUsuario == null) return Unauthorized("No se pudo obtener el ID del usuario del token.");
try
{
var (exito, error) = await _novedadService.ActualizarAsync(idNovedad, updateDto, idUsuario.Value);
if (!exito)
{
if (error == "Novedad no encontrada.") return NotFound(new { message = error });
return BadRequest(new { message = error });
}
return NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al actualizar NovedadCanilla ID: {IdNovedad} por Usuario ID: {UsuarioId}", idNovedad, idUsuario);
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al actualizar la novedad.");
}
}
// DELETE: api/novedadescanilla/{idNovedad}
// Elimina una novedad.
// Permiso: CG006 (Asumiendo que el mismo permiso para Carga/Modificación incluye eliminación)
// Si la eliminación es un permiso separado (ej: CG00X), ajústalo.
[HttpDelete("{idNovedad:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> DeleteNovedadCanilla(int idNovedad)
{
if (!TienePermiso("CG006")) return Forbid();
var idUsuario = GetCurrentUserId();
if (idUsuario == null) return Unauthorized("No se pudo obtener el ID del usuario del token.");
try
{
var (exito, error) = await _novedadService.EliminarAsync(idNovedad, idUsuario.Value);
if (!exito)
{
if (error == "Novedad no encontrada.") return NotFound(new { message = error });
return BadRequest(new { message = error }); // Podría ser otro error, como "no se pudo eliminar"
}
return NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al eliminar NovedadCanilla ID: {IdNovedad} por Usuario ID: {UsuarioId}", idNovedad, idUsuario);
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al eliminar la novedad.");
}
}
}
}

View File

@@ -38,6 +38,7 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return null; return null;
} }
// GET: api/publicaciones
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(IEnumerable<PublicacionDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(IEnumerable<PublicacionDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
@@ -48,6 +49,26 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return Ok(publicaciones); return Ok(publicaciones);
} }
// GET: api/publicaciones/dropdown
[HttpGet("dropdown")]
[ProducesResponseType(typeof(IEnumerable<PublicacionDropdownDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
// No se verifica permiso DP001, solo requiere autenticación general ([Authorize] del controlador)
public async Task<IActionResult> GetPublicacionesForDropdown([FromQuery] bool soloHabilitadas = true)
{
try
{
var publicaciones = await _publicacionService.ObtenerParaDropdownAsync(soloHabilitadas);
return Ok(publicaciones);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener publicaciones para dropdown.");
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener publicaciones para selección.");
}
}
// GET: api/publicaciones/{id}
[HttpGet("{id:int}", Name = "GetPublicacionById")] [HttpGet("{id:int}", Name = "GetPublicacionById")]
[ProducesResponseType(typeof(PublicacionDto), StatusCodes.Status200OK)] [ProducesResponseType(typeof(PublicacionDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]
@@ -60,6 +81,7 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return Ok(publicacion); return Ok(publicacion);
} }
// POST: api/publicaciones
[HttpPost] [HttpPost]
[ProducesResponseType(typeof(PublicacionDto), StatusCodes.Status201Created)] [ProducesResponseType(typeof(PublicacionDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
@@ -77,6 +99,7 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return CreatedAtRoute("GetPublicacionById", new { id = dto.IdPublicacion }, dto); return CreatedAtRoute("GetPublicacionById", new { id = dto.IdPublicacion }, dto);
} }
// PUT: api/publicaciones/{id}
[HttpPut("{id:int}")] [HttpPut("{id:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
@@ -98,6 +121,7 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return NoContent(); return NoContent();
} }
// DELETE: api/publicaciones/{id}
[HttpDelete("{id:int}")] [HttpDelete("{id:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
@@ -118,7 +142,7 @@ namespace GestionIntegral.Api.Controllers.Distribucion
return NoContent(); return NoContent();
} }
// Endpoint para obtener las configuraciones de días para una publicación // Endpoint para obtener la configuración de días de publicación para una publicación específica
[HttpGet("{idPublicacion:int}/dias-semana")] [HttpGet("{idPublicacion:int}/dias-semana")]
[ProducesResponseType(typeof(IEnumerable<PublicacionDiaSemanaDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(IEnumerable<PublicacionDiaSemanaDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status403Forbidden)]

View File

@@ -71,6 +71,25 @@ namespace GestionIntegral.Api.Controllers.Impresion
} }
} }
// GET: api/plantas/dropdown
[HttpGet("dropdown")]
[ProducesResponseType(typeof(IEnumerable<PlantaDropdownDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
// NO chequeo TienePermiso("IP001")(requiere autenticación)
public async Task<IActionResult> GetPlantasForDropdown()
{
try
{
var plantas = await _plantaService.ObtenerParaDropdownAsync();
return Ok(plantas);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener plantas para dropdown.");
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener plantas para selección.");
}
}
// GET: api/plantas/{id} // GET: api/plantas/{id}
// Permiso: IP001 (Ver Plantas) // Permiso: IP001 (Ver Plantas)
[HttpGet("{id:int}", Name = "GetPlantaById")] [HttpGet("{id:int}", Name = "GetPlantaById")]

View File

@@ -124,11 +124,15 @@ namespace GestionIntegral.Api.Controllers.Impresion
public async Task<IActionResult> CambiarEstadoBobina(int idBobina, [FromBody] CambiarEstadoBobinaDto cambiarEstadoDto) public async Task<IActionResult> CambiarEstadoBobina(int idBobina, [FromBody] CambiarEstadoBobinaDto cambiarEstadoDto)
{ {
if (!TienePermiso(PermisoCambiarEstado)) return Forbid(); if (!TienePermiso(PermisoCambiarEstado)) return Forbid();
if (!ModelState.IsValid) return BadRequest(ModelState); if (!ModelState.IsValid) return BadRequest(ModelState); // Validaciones de DTO (Required, Range, etc.)
var userId = GetCurrentUserId(); var userId = GetCurrentUserId();
if (userId == null) return Unauthorized(); if (userId == null) return Unauthorized();
// Validación adicional en el controlador para el caso "En Uso" // La validación de que IdPublicacion/IdSeccion son requeridos para estado "En Uso"
// ahora está más robusta en el servicio. Se puede quitar del controlador
// si se prefiere que el servicio sea la única fuente de verdad para esa lógica.
// Si la mantenés acá, es una validación temprana.
/*
if (cambiarEstadoDto.NuevoEstadoId == 2) // Asumiendo 2 = En Uso if (cambiarEstadoDto.NuevoEstadoId == 2) // Asumiendo 2 = En Uso
{ {
if (!cambiarEstadoDto.IdPublicacion.HasValue || cambiarEstadoDto.IdPublicacion.Value <= 0) if (!cambiarEstadoDto.IdPublicacion.HasValue || cambiarEstadoDto.IdPublicacion.Value <= 0)
@@ -136,12 +140,13 @@ namespace GestionIntegral.Api.Controllers.Impresion
if (!cambiarEstadoDto.IdSeccion.HasValue || cambiarEstadoDto.IdSeccion.Value <=0) if (!cambiarEstadoDto.IdSeccion.HasValue || cambiarEstadoDto.IdSeccion.Value <=0)
return BadRequest(new { message = "Se requiere IdSeccion para el estado 'En Uso'."}); return BadRequest(new { message = "Se requiere IdSeccion para el estado 'En Uso'."});
} }
*/
var (exito, error) = await _stockBobinaService.CambiarEstadoBobinaAsync(idBobina, cambiarEstadoDto, userId.Value); var (exito, error) = await _stockBobinaService.CambiarEstadoBobinaAsync(idBobina, cambiarEstadoDto, userId.Value);
if (!exito) if (!exito)
{ {
if (error == "Bobina no encontrada.") return NotFound(new { message = error }); if (error == "Bobina no encontrada.") return NotFound(new { message = error });
// Otros errores específicos del servicio (ej. flujo de estado no permitido) vienen como BadRequest
return BadRequest(new { message = error }); return BadRequest(new { message = error });
} }
return NoContent(); return NoContent();

View File

@@ -11,6 +11,7 @@ using GestionIntegral.Api.Data.Repositories.Impresion;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using GestionIntegral.Api.Data.Repositories.Distribucion; using GestionIntegral.Api.Data.Repositories.Distribucion;
using GestionIntegral.Api.Services.Distribucion;
namespace GestionIntegral.Api.Controllers namespace GestionIntegral.Api.Controllers
{ {
@@ -25,6 +26,7 @@ namespace GestionIntegral.Api.Controllers
private readonly IPublicacionRepository _publicacionRepository; private readonly IPublicacionRepository _publicacionRepository;
private readonly IEmpresaRepository _empresaRepository; private readonly IEmpresaRepository _empresaRepository;
private readonly IDistribuidorRepository _distribuidorRepository; // Para obtener el nombre del distribuidor private readonly IDistribuidorRepository _distribuidorRepository; // Para obtener el nombre del distribuidor
private readonly INovedadCanillaService _novedadCanillaService;
// Permisos // Permisos
@@ -36,22 +38,25 @@ namespace GestionIntegral.Api.Controllers
private const string PermisoVerBalanceCuentas = "RR001"; private const string PermisoVerBalanceCuentas = "RR001";
private const string PermisoVerReporteTiradas = "RR008"; private const string PermisoVerReporteTiradas = "RR008";
private const string PermisoVerReporteConsumoBobinas = "RR007"; private const string PermisoVerReporteConsumoBobinas = "RR007";
private const string PermisoVerReporteNovedadesCanillas = "RR004";
private const string PermisoVerReporteListadoDistMensual = "RR009";
public ReportesController( public ReportesController(
IReportesService reportesService, // <--- CORREGIDO IReportesService reportesService,
INovedadCanillaService novedadCanillaService,
ILogger<ReportesController> logger, ILogger<ReportesController> logger,
IPlantaRepository plantaRepository, IPlantaRepository plantaRepository,
IPublicacionRepository publicacionRepository, IPublicacionRepository publicacionRepository,
IEmpresaRepository empresaRepository, IEmpresaRepository empresaRepository,
IDistribuidorRepository distribuidorRepository) // Añadido IDistribuidorRepository distribuidorRepository)
{ {
_reportesService = reportesService; // <--- CORREGIDO _reportesService = reportesService;
_novedadCanillaService = novedadCanillaService;
_logger = logger; _logger = logger;
_plantaRepository = plantaRepository; _plantaRepository = plantaRepository;
_publicacionRepository = publicacionRepository; _publicacionRepository = publicacionRepository;
_empresaRepository = empresaRepository; _empresaRepository = empresaRepository;
_distribuidorRepository = distribuidorRepository; // Añadido _distribuidorRepository = distribuidorRepository;
} }
private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc); private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
@@ -1457,5 +1462,277 @@ namespace GestionIntegral.Api.Controllers
return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del ticket."); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al generar el PDF del ticket.");
} }
} }
// GET: api/reportes/novedades-canillas
// Obtiene los datos para el reporte de novedades de canillitas
[HttpGet("novedades-canillas")]
[ProducesResponseType(typeof(IEnumerable<NovedadesCanillasReporteDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)] // Si no hay datos
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetReporteNovedadesCanillasData(
[FromQuery] int idEmpresa,
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta)
{
if (!TienePermiso(PermisoVerReporteNovedadesCanillas))
{
_logger.LogWarning("Acceso denegado a GetReporteNovedadesCanillasData. Usuario: {User}", User.Identity?.Name ?? "Desconocido");
return Forbid();
}
if (fechaDesde > fechaHasta)
{
return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
}
try
{
var reporteData = await _novedadCanillaService.ObtenerReporteNovedadesAsync(idEmpresa, fechaDesde, fechaHasta);
if (reporteData == null || !reporteData.Any())
{
// Devolver Ok con array vacío en lugar de NotFound para que el frontend pueda manejarlo como "sin datos"
return Ok(Enumerable.Empty<NovedadesCanillasReporteDto>());
}
return Ok(reporteData);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al generar datos para el reporte de novedades de canillitas. Empresa: {IdEmpresa}, Desde: {FechaDesde}, Hasta: {FechaHasta}", idEmpresa, fechaDesde, fechaHasta);
return StatusCode(StatusCodes.Status500InternalServerError, new { message = "Error interno al generar el reporte de novedades." });
}
}
// GET: api/reportes/novedades-canillas/pdf
// Genera el PDF del reporte de novedades de canillitas
[HttpGet("novedades-canillas/pdf")]
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetReporteNovedadesCanillasPdf(
[FromQuery] int idEmpresa,
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta)
{
if (!TienePermiso(PermisoVerReporteNovedadesCanillas)) // RR004
{
_logger.LogWarning("Acceso denegado a GetReporteNovedadesCanillasPdf. Usuario: {User}", User.Identity?.Name ?? "Desconocido");
return Forbid();
}
if (fechaDesde > fechaHasta)
{
return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
}
try
{
// Obtener datos para AMBOS datasets
var novedadesData = await _novedadCanillaService.ObtenerReporteNovedadesAsync(idEmpresa, fechaDesde, fechaHasta);
var gananciasData = await _novedadCanillaService.ObtenerReporteGananciasAsync(idEmpresa, fechaDesde, fechaHasta); // << OBTENER DATOS DE GANANCIAS
// Verificar si hay datos en *alguno* de los datasets necesarios para el reporte
if ((novedadesData == null || !novedadesData.Any()) && (gananciasData == null || !gananciasData.Any()))
{
return NotFound(new { message = "No hay datos para generar el PDF con los parámetros seleccionados." });
}
var empresa = await _empresaRepository.GetByIdAsync(idEmpresa);
LocalReport report = new LocalReport();
string rdlcPath = Path.Combine("Controllers", "Reportes", "RDLC", "ReporteListadoNovedadesCanillas.rdlc");
if (!System.IO.File.Exists(rdlcPath))
{
_logger.LogError("Archivo RDLC no encontrado en la ruta: {RdlcPath}", rdlcPath);
return StatusCode(StatusCodes.Status500InternalServerError, "Archivo de definición de reporte no encontrado.");
}
using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
report.LoadReportDefinition(fs);
}
// Nombre del DataSet en RDLC para SP_DistCanillasNovedades (detalles)
report.DataSources.Add(new ReportDataSource("DSNovedadesCanillasDetalles", novedadesData ?? new List<NovedadesCanillasReporteDto>()));
// Nombre del DataSet en RDLC para SP_DistCanillasGanancias (ganancias/resumen)
report.DataSources.Add(new ReportDataSource("DSNovedadesCanillas", gananciasData ?? new List<CanillaGananciaReporteDto>()));
var parameters = new List<ReportParameter>
{
new ReportParameter("NomEmp", empresa?.Nombre ?? "N/A"),
new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy"))
};
report.SetParameters(parameters);
byte[] pdfBytes = report.Render("PDF");
string fileName = $"ReporteNovedadesCanillas_Emp{idEmpresa}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf";
return File(pdfBytes, "application/pdf", fileName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al generar PDF para el reporte de novedades de canillitas. Empresa: {IdEmpresa}", idEmpresa);
return StatusCode(StatusCodes.Status500InternalServerError, new { message = $"Error interno al generar el PDF: {ex.Message}" });
}
}
// GET: api/reportes/novedades-canillas-ganancias
[HttpGet("novedades-canillas-ganancias")]
[ProducesResponseType(typeof(IEnumerable<CanillaGananciaReporteDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetReporteGananciasCanillasData(
[FromQuery] int idEmpresa,
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta)
{
if (!TienePermiso(PermisoVerReporteNovedadesCanillas)) return Forbid(); // RR004
if (fechaDesde > fechaHasta)
{
return BadRequest(new { message = "La fecha 'desde' no puede ser posterior a la fecha 'hasta'." });
}
try
{
var gananciasData = await _novedadCanillaService.ObtenerReporteGananciasAsync(idEmpresa, fechaDesde, fechaHasta);
if (gananciasData == null || !gananciasData.Any())
{
return Ok(Enumerable.Empty<CanillaGananciaReporteDto>());
}
return Ok(gananciasData);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener datos de ganancias para el reporte de novedades. Empresa: {IdEmpresa}", idEmpresa);
return StatusCode(StatusCodes.Status500InternalServerError, new { message = "Error interno al obtener datos de ganancias." });
}
}
// GET: api/reportes/listado-distribucion-mensual/diarios
[HttpGet("listado-distribucion-mensual/diarios")]
[ProducesResponseType(typeof(IEnumerable<ListadoDistCanMensualDiariosDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetListadoDistMensualDiarios(
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta,
[FromQuery] bool esAccionista)
{
if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
var (data, error) = await _reportesService.ObtenerReporteMensualDiariosAsync(fechaDesde, fechaHasta, esAccionista);
if (error != null) return BadRequest(new { message = error });
return Ok(data ?? Enumerable.Empty<ListadoDistCanMensualDiariosDto>());
}
[HttpGet("listado-distribucion-mensual/diarios/pdf")]
public async Task<IActionResult> GetListadoDistMensualDiariosPdf(
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta,
[FromQuery] bool esAccionista)
{
if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
var (data, error) = await _reportesService.ObtenerReporteMensualDiariosAsync(fechaDesde, fechaHasta, esAccionista);
if (error != null) return BadRequest(new { message = error });
if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el PDF." });
try
{
LocalReport report = new LocalReport();
string rdlcPath = Path.Combine("Controllers", "Reportes", "RDLC", "ReporteListadoDistribucionCanMensualDiarios.rdlc");
if (!System.IO.File.Exists(rdlcPath))
{
_logger.LogError("Archivo RDLC no encontrado: {Path}", rdlcPath);
return StatusCode(StatusCodes.Status500InternalServerError, $"Archivo de reporte no encontrado: {Path.GetFileName(rdlcPath)}");
}
using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
report.LoadReportDefinition(fs);
}
report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanMensualDiarios", data));
var parameters = new List<ReportParameter>
{
new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")),
new ReportParameter("CanAcc", esAccionista ? "1" : "0") // El RDLC espera un Integer para CanAcc
};
report.SetParameters(parameters);
byte[] pdfBytes = report.Render("PDF");
string tipoDesc = esAccionista ? "Accionistas" : "Canillitas";
return File(pdfBytes, "application/pdf", $"ListadoDistMensualDiarios_{tipoDesc}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
}
catch (Exception ex) { _logger.LogError(ex, "Error PDF ListadoDistMensualDiarios"); return StatusCode(500, "Error interno."); }
}
// GET: api/reportes/listado-distribucion-mensual/publicaciones
[HttpGet("listado-distribucion-mensual/publicaciones")]
[ProducesResponseType(typeof(IEnumerable<ListadoDistCanMensualPubDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetListadoDistMensualPorPublicacion(
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta,
[FromQuery] bool esAccionista)
{
if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
var (data, error) = await _reportesService.ObtenerReporteMensualPorPublicacionAsync(fechaDesde, fechaHasta, esAccionista);
if (error != null) return BadRequest(new { message = error });
return Ok(data ?? Enumerable.Empty<ListadoDistCanMensualPubDto>());
}
[HttpGet("listado-distribucion-mensual/publicaciones/pdf")]
public async Task<IActionResult> GetListadoDistMensualPorPublicacionPdf(
[FromQuery] DateTime fechaDesde,
[FromQuery] DateTime fechaHasta,
[FromQuery] bool esAccionista)
{
if (!TienePermiso(PermisoVerReporteListadoDistMensual)) return Forbid();
if (fechaDesde > fechaHasta) return BadRequest(new { message = "Fecha Desde no puede ser mayor a Fecha Hasta." });
var (data, error) = await _reportesService.ObtenerReporteMensualPorPublicacionAsync(fechaDesde, fechaHasta, esAccionista);
if (error != null) return BadRequest(new { message = error });
if (data == null || !data.Any()) return NotFound(new { message = "No hay datos para generar el PDF." });
try
{
LocalReport report = new LocalReport();
string rdlcPath = Path.Combine("Controllers", "Reportes", "RDLC", "ReporteListadoDistribucionCanMensual.rdlc");
if (!System.IO.File.Exists(rdlcPath))
{
_logger.LogError("Archivo RDLC no encontrado: {Path}", rdlcPath);
return StatusCode(StatusCodes.Status500InternalServerError, $"Archivo de reporte no encontrado: {Path.GetFileName(rdlcPath)}");
}
using (var fs = new FileStream(rdlcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
report.LoadReportDefinition(fs);
}
report.DataSources.Add(new ReportDataSource("DSListadoDistribucionCanMensual", data));
var parameters = new List<ReportParameter>
{
new ReportParameter("FechaDesde", fechaDesde.ToString("dd/MM/yyyy")),
new ReportParameter("FechaHasta", fechaHasta.ToString("dd/MM/yyyy")),
new ReportParameter("CanAcc", esAccionista ? "1" : "0")
};
report.SetParameters(parameters);
byte[] pdfBytes = report.Render("PDF");
string tipoDesc = esAccionista ? "Accionistas" : "Canillitas";
return File(pdfBytes, "application/pdf", $"ListadoDistMensualPub_{tipoDesc}_{fechaDesde:yyyyMMdd}_{fechaHasta:yyyyMMdd}.pdf");
}
catch (Exception ex) { _logger.LogError(ex, "Error PDF ListadoDistMensualPorPublicacion"); return StatusCode(500, "Error interno."); }
}
} }
} }

View File

@@ -16,6 +16,9 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
Task<NotaCreditoDebito?> CreateAsync(NotaCreditoDebito nuevaNota, int idUsuario, IDbTransaction transaction); Task<NotaCreditoDebito?> CreateAsync(NotaCreditoDebito nuevaNota, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(NotaCreditoDebito notaAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(NotaCreditoDebito notaAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int idNota, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idNota, int idUsuario, IDbTransaction transaction);
// No se suele validar unicidad por referencia, ya que podría repetirse. Task<IEnumerable<(NotaCreditoDebitoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idNotaOriginal); // Para filtrar por una nota específica
} }
} }

View File

@@ -17,5 +17,9 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
Task<bool> UpdateAsync(PagoDistribuidor pagoAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(PagoDistribuidor pagoAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int idPago, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idPago, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByReciboAndTipoMovimientoAsync(int recibo, string tipoMovimiento, int? excludeIdPago = null); Task<bool> ExistsByReciboAndTipoMovimientoAsync(int recibo, string tipoMovimiento, int? excludeIdPago = null);
Task<IEnumerable<(PagoDistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPagoOriginal); // Para filtrar por un pago específico
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; // Para IEnumerable using System.Collections.Generic; // Para IEnumerable
using System.Data; using System.Data;
using GestionIntegral.Api.Dtos.Contables; // Para SaldoGestionDto si lo usas aquí
using GestionIntegral.Api.Models.Contables; // Para Saldo, SaldoAjusteHistorial
namespace GestionIntegral.Api.Data.Repositories.Contables namespace GestionIntegral.Api.Data.Repositories.Contables
{ {
@@ -15,5 +17,16 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
// Método para modificar saldo (lo teníamos como privado antes, ahora en el repo) // Método para modificar saldo (lo teníamos como privado antes, ahora en el repo)
Task<bool> ModificarSaldoAsync(string destino, int idDestino, int idEmpresa, decimal montoAAgregar, IDbTransaction? transaction = null); Task<bool> ModificarSaldoAsync(string destino, int idDestino, int idEmpresa, decimal montoAAgregar, IDbTransaction? transaction = null);
Task<bool> CheckIfSaldosExistForEmpresaAsync(int id); Task<bool> CheckIfSaldosExistForEmpresaAsync(int id);
// Para obtener la lista de saldos para la página de gestión
Task<IEnumerable<Saldo>> GetSaldosParaGestionAsync(string? destinoFilter, int? idDestinoFilter, int? idEmpresaFilter);
// Para obtener un saldo específico (ya podría existir uno similar, o crearlo si es necesario)
Task<Saldo?> GetSaldoAsync(string destino, int idDestino, int idEmpresa, IDbTransaction? transaction = null);
// Para registrar el historial de ajuste
Task CreateSaldoAjusteHistorialAsync(SaldoAjusteHistorial historialEntry, IDbTransaction transaction);
Task<IEnumerable<(SaldoAjusteHistorial Historial, string NombreUsuarioModifico)>> GetHistorialAjustesAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico,
string? destino, int? idDestino, int? idEmpresa);
} }
} }

View File

@@ -13,5 +13,9 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
Task<bool> DeleteAsync(int id, int idUsuario); // Devuelve true si fue exitoso Task<bool> DeleteAsync(int id, int idUsuario); // Devuelve true si fue exitoso
Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null); Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null);
Task<bool> IsInUseAsync(int id); Task<bool> IsInUseAsync(int id);
Task<IEnumerable<(TipoPagoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idTipoPagoOriginal);
} }
} }

View File

@@ -86,11 +86,20 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
var inserted = await transaction.Connection!.QuerySingleAsync<NotaCreditoDebito>(sqlInsert, nuevaNota, transaction); 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."); if (inserted == null || inserted.IdNota == 0) throw new DataException("Error al crear la nota o ID no generado.");
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { 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, IdNotaHist = inserted.IdNota,
ObservacionesHist = inserted.Observaciones, IdEmpresaHist = inserted.IdEmpresa, DestinoHist = inserted.Destino,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Creada" 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"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -112,14 +121,24 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
(Id_Nota, Destino, Id_Destino, Referencia, Tipo, Fecha, Monto, Observaciones, Id_Empresa, Id_Usuario, FechaMod, TipoMod) (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);"; VALUES (@IdNotaHist, @DestinoHist, @IdDestinoHist, @ReferenciaHist, @TipoHist, @FechaHist, @MontoHist, @ObservacionesHist, @IdEmpresaHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { 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 IdNotaHist = actual.IdNota,
ObservacionesHist = actual.Observaciones, IdEmpresaHist = actual.IdEmpresa, // Valor ANTERIOR DestinoHist = actual.Destino,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Actualizada" 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"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, new { var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, new
{
notaAActualizar.Monto, notaAActualizar.Monto,
notaAActualizar.Observaciones, notaAActualizar.Observaciones,
notaAActualizar.IdNota notaAActualizar.IdNota
@@ -140,14 +159,67 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
(Id_Nota, Destino, Id_Destino, Referencia, Tipo, Fecha, Monto, Observaciones, Id_Empresa, Id_Usuario, FechaMod, TipoMod) (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);"; VALUES (@IdNotaHist, @DestinoHist, @IdDestinoHist, @ReferenciaHist, @TipoHist, @FechaHist, @MontoHist, @ObservacionesHist, @IdEmpresaHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { 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, IdNotaHist = actual.IdNota,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Eliminada" 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"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdNotaParam = idNota }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdNotaParam = idNota }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
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)>();
}
}
} }
} }

View File

@@ -109,11 +109,20 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
var inserted = await transaction.Connection!.QuerySingleAsync<PagoDistribuidor>(sqlInsert, nuevoPago, transaction); var inserted = await transaction.Connection!.QuerySingleAsync<PagoDistribuidor>(sqlInsert, nuevoPago, transaction);
if (inserted == null || inserted.IdPago == 0) throw new DataException("Error al crear pago o ID no generado."); if (inserted == null || inserted.IdPago == 0) throw new DataException("Error al crear pago o ID no generado.");
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdPagoHist = inserted.IdPago, IdDistribuidorHist = inserted.IdDistribuidor, FechaHist = inserted.Fecha, {
TipoMovimientoHist = inserted.TipoMovimiento, ReciboHist = inserted.Recibo, MontoHist = inserted.Monto, IdPagoHist = inserted.IdPago,
IdTipoPagoHist = inserted.IdTipoPago, DetalleHist = inserted.Detalle, IdEmpresaHist = inserted.IdEmpresa, IdDistribuidorHist = inserted.IdDistribuidor,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Creado" FechaHist = inserted.Fecha,
TipoMovimientoHist = inserted.TipoMovimiento,
ReciboHist = inserted.Recibo,
MontoHist = inserted.Monto,
IdTipoPagoHist = inserted.IdTipoPago,
DetalleHist = inserted.Detalle,
IdEmpresaHist = inserted.IdEmpresa,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Creado"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -137,11 +146,20 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
(Id_Pago, Id_Distribuidor, Fecha, TipoMovimiento, Recibo, Monto, Id_TipoPago, Detalle, Id_Empresa, Id_Usuario, FechaMod, TipoMod) (Id_Pago, Id_Distribuidor, Fecha, TipoMovimiento, Recibo, Monto, Id_TipoPago, Detalle, Id_Empresa, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdPagoHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @ReciboHist, @MontoHist, @IdTipoPagoHist, @DetalleHist, @IdEmpresaHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; VALUES (@IdPagoHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @ReciboHist, @MontoHist, @IdTipoPagoHist, @DetalleHist, @IdEmpresaHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdPagoHist = actual.IdPago, IdDistribuidorHist = actual.IdDistribuidor, FechaHist = actual.Fecha, {
TipoMovimientoHist = actual.TipoMovimiento, ReciboHist = actual.Recibo, MontoHist = actual.Monto, // Valor ANTERIOR IdPagoHist = actual.IdPago,
IdTipoPagoHist = actual.IdTipoPago, DetalleHist = actual.Detalle, IdEmpresaHist = actual.IdEmpresa, // Valores ANTERIORES IdDistribuidorHist = actual.IdDistribuidor,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Actualizado" FechaHist = actual.Fecha,
TipoMovimientoHist = actual.TipoMovimiento,
ReciboHist = actual.Recibo,
MontoHist = actual.Monto, // Valor ANTERIOR
IdTipoPagoHist = actual.IdTipoPago,
DetalleHist = actual.Detalle,
IdEmpresaHist = actual.IdEmpresa, // Valores ANTERIORES
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Actualizado"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, pagoAActualizar, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, pagoAActualizar, transaction);
@@ -161,15 +179,67 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
(Id_Pago, Id_Distribuidor, Fecha, TipoMovimiento, Recibo, Monto, Id_TipoPago, Detalle, Id_Empresa, Id_Usuario, FechaMod, TipoMod) (Id_Pago, Id_Distribuidor, Fecha, TipoMovimiento, Recibo, Monto, Id_TipoPago, Detalle, Id_Empresa, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdPagoHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @ReciboHist, @MontoHist, @IdTipoPagoHist, @DetalleHist, @IdEmpresaHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; VALUES (@IdPagoHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @ReciboHist, @MontoHist, @IdTipoPagoHist, @DetalleHist, @IdEmpresaHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdPagoHist = actual.IdPago, IdDistribuidorHist = actual.IdDistribuidor, FechaHist = actual.Fecha, {
TipoMovimientoHist = actual.TipoMovimiento, ReciboHist = actual.Recibo, MontoHist = actual.Monto, IdPagoHist = actual.IdPago,
IdTipoPagoHist = actual.IdTipoPago, DetalleHist = actual.Detalle, IdEmpresaHist = actual.IdEmpresa, IdDistribuidorHist = actual.IdDistribuidor,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Eliminado" FechaHist = actual.Fecha,
TipoMovimientoHist = actual.TipoMovimiento,
ReciboHist = actual.Recibo,
MontoHist = actual.Monto,
IdTipoPagoHist = actual.IdTipoPago,
DetalleHist = actual.Detalle,
IdEmpresaHist = actual.IdEmpresa,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Eliminado"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdPagoParam = idPago }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdPagoParam = idPago }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(PagoDistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPagoOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Pago, h.Id_Distribuidor, h.Fecha, h.TipoMovimiento, h.Recibo, h.Monto,
h.Id_TipoPago, h.Detalle, h.Id_Empresa,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.cue_PagosDistribuidor_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 (idPagoOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Pago = @IdPagoOriginalParam"); parameters.Add("IdPagoOriginalParam", idPagoOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PagoDistribuidorHistorico, string, (PagoDistribuidorHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Pagos de Distribuidores.");
return Enumerable.Empty<(PagoDistribuidorHistorico, string)>();
}
}
} }
} }

View File

@@ -5,6 +5,8 @@ using Microsoft.Extensions.Logging;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Threading.Tasks; using System.Threading.Tasks;
using GestionIntegral.Api.Models.Contables;
using System.Text;
namespace GestionIntegral.Api.Data.Repositories.Contables namespace GestionIntegral.Api.Data.Repositories.Contables
{ {
@@ -73,44 +75,47 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
public async Task<bool> ModificarSaldoAsync(string destino, int idDestino, int idEmpresa, decimal montoAAgregar, IDbTransaction? transaction = null) public async Task<bool> ModificarSaldoAsync(string destino, int idDestino, int idEmpresa, decimal montoAAgregar, IDbTransaction? transaction = null)
{ {
var sql = @"UPDATE dbo.cue_Saldos var sql = @"UPDATE dbo.cue_Saldos
SET Monto = Monto + @MontoAAgregar SET Monto = Monto + @MontoAAgregar,
FechaUltimaModificacion = @FechaActualizacion -- << AÑADIR
WHERE Destino = @Destino AND Id_Destino = @IdDestino AND Id_Empresa = @IdEmpresa;"; WHERE Destino = @Destino AND Id_Destino = @IdDestino AND Id_Empresa = @IdEmpresa;";
// Usar una variable para la conexión para poder aplicar el '!' si es necesario
IDbConnection connection = transaction?.Connection ?? _connectionFactory.CreateConnection(); IDbConnection connection = transaction?.Connection ?? _connectionFactory.CreateConnection();
bool ownConnection = transaction == null; // Saber si necesitamos cerrar la conexión nosotros bool ownConnection = transaction == null;
try try
{ {
if (ownConnection) await (connection as System.Data.Common.DbConnection)!.OpenAsync(); // Abrir solo si no hay transacción externa if (ownConnection && connection.State != ConnectionState.Open)
{
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
}
var parameters = new { var parameters = new
{
MontoAAgregar = montoAAgregar, MontoAAgregar = montoAAgregar,
Destino = destino, Destino = destino,
IdDestino = idDestino, IdDestino = idDestino,
IdEmpresa = idEmpresa IdEmpresa = idEmpresa,
FechaActualizacion = DateTime.Now // O DateTime.UtcNow si prefieres
}; };
// Aplicar '!' aquí también si viene de la transacción
int rowsAffected = await connection.ExecuteAsync(sql, parameters, transaction: transaction); int rowsAffected = await connection.ExecuteAsync(sql, parameters, transaction: transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error al modificar saldo para {Destino} ID {IdDestino}, Empresa ID {IdEmpresa}.", destino, idDestino, idEmpresa); _logger.LogError(ex, "Error al modificar saldo para {Destino} ID {IdDestino}, Empresa ID {IdEmpresa}.", destino, idDestino, idEmpresa);
if (transaction != null) throw; // Re-lanzar si estamos en una transacción externa if (transaction != null) throw;
return false; // Devolver false si fue una operación aislada que falló return false;
} }
finally finally
{ {
// Cerrar la conexión solo si la abrimos nosotros (no había transacción externa)
if (ownConnection && connection.State == ConnectionState.Open) if (ownConnection && connection.State == ConnectionState.Open)
{ {
await (connection as System.Data.Common.DbConnection)!.CloseAsync(); if (connection is System.Data.Common.DbConnection dbConn) await dbConn.CloseAsync(); else connection.Close();
} }
// Disponer de la conexión si la creamos nosotros if (ownConnection && connection is IDisposable d) d.Dispose(); // Mejorar dispose
if(ownConnection) (connection as IDisposable)?.Dispose();
} }
} }
public async Task<bool> CheckIfSaldosExistForEmpresaAsync(int idEmpresa) public async Task<bool> CheckIfSaldosExistForEmpresaAsync(int idEmpresa)
{ {
var sql = "SELECT COUNT(1) FROM dbo.cue_Saldos WHERE Id_Empresa = @IdEmpresa"; var sql = "SELECT COUNT(1) FROM dbo.cue_Saldos WHERE Id_Empresa = @IdEmpresa";
@@ -130,5 +135,102 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
// O podrías devolver true para ser más conservador si la verificación es crítica. // O podrías devolver true para ser más conservador si la verificación es crítica.
} }
} }
public async Task<IEnumerable<Saldo>> 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<Saldo>(sqlBuilder.ToString(), parameters);
}
public async Task<Saldo?> 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<Saldo>(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);
}
public async Task<IEnumerable<(SaldoAjusteHistorial Historial, string NombreUsuarioModifico)>> GetHistorialAjustesAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico,
string? destino, int? idDestino, int? idEmpresa)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.IdSaldoAjusteHist, h.Destino, h.Id_Destino, h.Id_Empresa,
h.MontoAjuste, h.SaldoAnterior, h.SaldoNuevo, h.Justificacion,
h.FechaAjuste, h.Id_UsuarioAjuste,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.cue_SaldoAjustesHistorial h
JOIN dbo.gral_Usuarios u ON h.Id_UsuarioAjuste = u.Id
WHERE 1=1");
var parameters = new DynamicParameters();
if (fechaDesde.HasValue) { sqlBuilder.Append(" AND h.FechaAjuste >= @FechaDesdeParam"); parameters.Add("FechaDesdeParam", fechaDesde.Value.Date); }
if (fechaHasta.HasValue) { sqlBuilder.Append(" AND h.FechaAjuste <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date.AddDays(1).AddTicks(-1)); }
if (idUsuarioModifico.HasValue) { sqlBuilder.Append(" AND h.Id_UsuarioAjuste = @IdUsuarioModificoParam"); parameters.Add("IdUsuarioModificoParam", idUsuarioModifico.Value); }
if (!string.IsNullOrWhiteSpace(destino)) { sqlBuilder.Append(" AND h.Destino = @DestinoParam"); parameters.Add("DestinoParam", destino); }
if (idDestino.HasValue) { sqlBuilder.Append(" AND h.Id_Destino = @IdDestinoParam"); parameters.Add("IdDestinoParam", idDestino.Value); }
if (idEmpresa.HasValue) { sqlBuilder.Append(" AND h.Id_Empresa = @IdEmpresaParam"); parameters.Add("IdEmpresaParam", idEmpresa.Value); }
sqlBuilder.Append(" ORDER BY h.FechaAjuste DESC;");
try
{
var result = await connection.QueryAsync<SaldoAjusteHistorial, string, (SaldoAjusteHistorial, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Ajustes de Saldo.");
return Enumerable.Empty<(SaldoAjusteHistorial, string)>();
}
}
} }
} }

View File

@@ -2,6 +2,7 @@ using Dapper;
using GestionIntegral.Api.Models.Contables; using GestionIntegral.Api.Models.Contables;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Contables namespace GestionIntegral.Api.Data.Repositories.Contables
@@ -284,5 +285,47 @@ namespace GestionIntegral.Api.Data.Repositories.Contables
return true; // Asumir que está en uso si hay error para prevenir borrado incorrecto return true; // Asumir que está en uso si hay error para prevenir borrado incorrecto
} }
} }
public async Task<IEnumerable<(TipoPagoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idTipoPagoOriginal)
{
using var connection = _connectionFactory.CreateConnection(); // Asumiendo _cf es tu DbConnectionFactory
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_TipoPago, h.Nombre, h.Detalle,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.cue_dtTipopago_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 (idTipoPagoOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_TipoPago = @IdTipoPagoOriginalParam"); parameters.Add("IdTipoPagoOriginalParam", idTipoPagoOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<TipoPagoHistorico, string, (TipoPagoHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Tipos de Pago."); // Asumiendo _log
return Enumerable.Empty<(TipoPagoHistorico, string)>();
}
}
} }
} }

View File

@@ -0,0 +1,193 @@
using Dapper;
using GestionIntegral.Api.Models.Distribucion;
using Microsoft.Extensions.Logging; // Para ILogger
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text; // Para StringBuilder
using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion
{
public class CambioParadaRepository : ICambioParadaRepository
{
private readonly DbConnectionFactory _cf;
private readonly ILogger<CambioParadaRepository> _logger;
public CambioParadaRepository(DbConnectionFactory cf, ILogger<CambioParadaRepository> logger)
{
_cf = cf;
_logger = logger;
}
private async Task LogHistorialAsync(CambioParadaCanilla paradaOriginal, int idUsuario, string tipoMod, IDbConnection connection, IDbTransaction? transaction)
{
var historial = new CambioParadaCanillaHistorial
{
Id_Registro = paradaOriginal.IdRegistro,
Id_Canilla = paradaOriginal.IdCanilla,
Parada = paradaOriginal.Parada,
VigenciaD = paradaOriginal.VigenciaD,
VigenciaH = paradaOriginal.VigenciaH,
Id_Usuario = idUsuario,
FechaMod = DateTime.Now,
TipoMod = tipoMod
};
const string sqlHistorial = @"
INSERT INTO dbo.dist_CambiosParadasCanillas_H
(Id_Registro, Id_Canilla, Parada, VigenciaD, VigenciaH, Id_Usuario, FechaMod, TipoMod)
VALUES
(@Id_Registro, @Id_Canilla, @Parada, @VigenciaD, @VigenciaH, @Id_Usuario, @FechaMod, @TipoMod);";
await connection.ExecuteAsync(sqlHistorial, historial, transaction);
}
public async Task<IEnumerable<CambioParadaCanilla>> GetByCanillaAsync(int idCanilla)
{
using var connection = _cf.CreateConnection();
const string sql = @"
SELECT Id_Registro AS IdRegistro, Id_Canilla AS IdCanilla, Parada, VigenciaD, VigenciaH
FROM dbo.dist_CambiosParadasCanillas
WHERE Id_Canilla = @IdCanilla
ORDER BY VigenciaD DESC, Id_Registro DESC;";
return await connection.QueryAsync<CambioParadaCanilla>(sql, new { IdCanilla = idCanilla });
}
public async Task<CambioParadaCanilla?> GetByIdAsync(int idRegistro)
{
using var connection = _cf.CreateConnection();
const string sql = @"
SELECT Id_Registro AS IdRegistro, Id_Canilla AS IdCanilla, Parada, VigenciaD, VigenciaH
FROM dbo.dist_CambiosParadasCanillas
WHERE Id_Registro = @IdRegistro;";
return await connection.QuerySingleOrDefaultAsync<CambioParadaCanilla>(sql, new { IdRegistro = idRegistro });
}
public async Task<CambioParadaCanilla?> GetCurrentParadaAsync(int idCanilla, IDbTransaction? transaction = null)
{
const string sql = @"
SELECT TOP 1 Id_Registro AS IdRegistro, Id_Canilla AS IdCanilla, Parada, VigenciaD, VigenciaH
FROM dbo.dist_CambiosParadasCanillas
WHERE Id_Canilla = @IdCanilla AND VigenciaH IS NULL
ORDER BY VigenciaD DESC, Id_Registro DESC;"; // Por si hay un error y quedaron varias abiertas
var conn = transaction?.Connection ?? _cf.CreateConnection();
bool manageConnection = transaction == null;
if (manageConnection && conn.State != ConnectionState.Open) { if (conn is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else conn.Open(); }
try
{
return await conn.QuerySingleOrDefaultAsync<CambioParadaCanilla>(sql, new { IdCanilla = idCanilla }, transaction);
}
finally
{
if (manageConnection && conn.State == ConnectionState.Open) { if (conn is System.Data.Common.DbConnection dbConn) await dbConn.CloseAsync(); else conn.Close(); }
}
}
public async Task<CambioParadaCanilla?> CreateAsync(CambioParadaCanilla nuevaParada, int idUsuario, IDbTransaction transaction)
{
const string sqlInsert = @"
INSERT INTO dbo.dist_CambiosParadasCanillas (Id_Canilla, Parada, VigenciaD, VigenciaH)
OUTPUT INSERTED.Id_Registro AS IdRegistro, INSERTED.Id_Canilla AS IdCanilla, INSERTED.Parada, INSERTED.VigenciaD, INSERTED.VigenciaH
VALUES (@IdCanilla, @Parada, @VigenciaD, @VigenciaH);";
// VigenciaH es null al crear una nueva parada activa
var inserted = await transaction.Connection!.QuerySingleAsync<CambioParadaCanilla>(sqlInsert,
new { nuevaParada.IdCanilla, nuevaParada.Parada, nuevaParada.VigenciaD, VigenciaH = (DateTime?)null },
transaction);
if (inserted == null || inserted.IdRegistro == 0) throw new DataException("Error al crear cambio de parada o ID no generado.");
await LogHistorialAsync(inserted, idUsuario, "Creada", transaction.Connection!, transaction);
return inserted;
}
public async Task<bool> UpdateVigenciaHAsync(int idRegistro, DateTime vigenciaH, int idUsuario, IDbTransaction transaction)
{
var paradaOriginal = await GetByIdAsync(idRegistro);
if (paradaOriginal == null) throw new KeyNotFoundException("Registro de parada no encontrado para actualizar VigenciaH.");
var paradaParaHistorial = new CambioParadaCanilla
{
IdRegistro = paradaOriginal.IdRegistro,
IdCanilla = paradaOriginal.IdCanilla,
Parada = paradaOriginal.Parada,
VigenciaD = paradaOriginal.VigenciaD,
VigenciaH = vigenciaH.Date
};
// Loggear el estado que QUEDARÁ en la tabla principal (con la VigenciaH actualizada)
// El TipoMod debería reflejar la acción. "Cerrada".
await LogHistorialAsync(paradaParaHistorial, idUsuario, "Cerrada", transaction.Connection!, transaction);
const string sqlUpdate = @"
UPDATE dbo.dist_CambiosParadasCanillas
SET VigenciaH = @VigenciaH
WHERE Id_Registro = @IdRegistro;";
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate,
new { VigenciaH = vigenciaH.Date, IdRegistro = idRegistro },
transaction);
return rowsAffected == 1;
}
public async Task<bool> DeleteAsync(int idRegistro, int idUsuario, IDbTransaction transaction)
{
var paradaOriginal = await GetByIdAsync(idRegistro);
if (paradaOriginal == null) throw new KeyNotFoundException("Registro de parada no encontrado para eliminar.");
// Loggear ANTES de eliminar
await LogHistorialAsync(paradaOriginal, idUsuario, "Eliminada", transaction.Connection!, transaction);
const string sqlDelete = "DELETE FROM dbo.dist_CambiosParadasCanillas WHERE Id_Registro = @IdRegistro;";
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdRegistro = idRegistro }, transaction);
return rowsAffected == 1;
}
public async Task<IEnumerable<(CambioParadaCanillaHistorial Historial, string NombreUsuarioModifico, string NombreCanilla)>> GetCambiosParadaHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idCanillaOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Registro, h.Id_Canilla, h.Parada, h.VigenciaD, h.VigenciaH,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico,
c.NomApe AS NombreCanilla
FROM dbo.dist_CambiosParadasCanillas_H h
JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id
JOIN dbo.dist_dtCanillas c ON h.Id_Canilla = c.Id_Canilla
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 (idCanillaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Canilla = @IdCanillaOriginalParam"); parameters.Add("IdCanillaOriginalParam", idCanillaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<CambioParadaCanillaHistorial, string, string, (CambioParadaCanillaHistorial, string, string)>(
sqlBuilder.ToString(),
(hist, userMod, canillaNombre) => (hist, userMod, canillaNombre),
parameters,
splitOn: "NombreUsuarioModifico,NombreCanilla"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Cambios de Parada.");
return Enumerable.Empty<(CambioParadaCanillaHistorial, string, string)>();
}
}
}
}

View File

@@ -21,51 +21,56 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
_logger = logger; _logger = logger;
} }
public async Task<IEnumerable<(Canilla Canilla, string NombreZona, string NombreEmpresa)>> GetAllAsync(string? nomApeFilter, int? legajoFilter, bool? soloActivos) public async Task<IEnumerable<(Canilla Canilla, string? NombreZona, string? NombreEmpresa)>> GetAllAsync(
string? nomApeFilter,
int? legajoFilter,
bool? esAccionista,
bool? soloActivos) // <<-- Parámetro aquí
{ {
var sqlBuilder = new StringBuilder(@" using var connection = _connectionFactory.CreateConnection();
SELECT var sqlBuilder = new System.Text.StringBuilder(@"
c.Id_Canilla AS IdCanilla, c.Legajo, c.NomApe, c.Parada, c.Id_Zona AS IdZona, SELECT c.Id_Canilla AS IdCanilla, c.Legajo, c.NomApe, c.Parada, c.Id_Zona AS IdZona,
c.Accionista, c.Obs, c.Empresa, c.Baja, c.FechaBaja, c.Accionista, c.Obs, c.Empresa, c.Baja, c.FechaBaja,
z.Nombre AS NombreZona, z.Nombre AS NombreZona,
ISNULL(e.Nombre, 'N/A (Accionista)') AS NombreEmpresa e.Nombre AS NombreEmpresa
FROM dbo.dist_dtCanillas c FROM dbo.dist_dtCanillas c
INNER JOIN dbo.dist_dtZonas z ON c.Id_Zona = z.Id_Zona LEFT JOIN dbo.dist_dtZonas z ON c.Id_Zona = z.Id_Zona
LEFT JOIN dbo.dist_dtEmpresas e ON c.Empresa = e.Id_Empresa LEFT JOIN dbo.dist_dtEmpresas e ON c.Empresa = e.Id_Empresa
WHERE 1=1"); WHERE 1=1 "); // Cláusula base para añadir AND fácilmente
var parameters = new DynamicParameters(); var parameters = new DynamicParameters();
if (soloActivos.HasValue)
{
sqlBuilder.Append(soloActivos.Value ? " AND c.Baja = 0" : " AND c.Baja = 1");
}
if (!string.IsNullOrWhiteSpace(nomApeFilter)) if (!string.IsNullOrWhiteSpace(nomApeFilter))
{ {
sqlBuilder.Append(" AND c.NomApe LIKE @NomApeParam"); sqlBuilder.Append(" AND c.NomApe LIKE @NomApeFilter ");
parameters.Add("NomApeParam", $"%{nomApeFilter}%"); parameters.Add("NomApeFilter", $"%{nomApeFilter}%");
} }
if (legajoFilter.HasValue) if (legajoFilter.HasValue)
{ {
sqlBuilder.Append(" AND c.Legajo = @LegajoParam"); sqlBuilder.Append(" AND c.Legajo = @LegajoFilter ");
parameters.Add("LegajoParam", legajoFilter.Value); parameters.Add("LegajoFilter", legajoFilter.Value);
} }
if (soloActivos.HasValue)
{
sqlBuilder.Append(" AND c.Baja = @BajaStatus ");
parameters.Add("BajaStatus", !soloActivos.Value); // Si soloActivos es true, Baja debe ser false
}
if (esAccionista.HasValue)
{
sqlBuilder.Append(" AND c.Accionista = @EsAccionista ");
parameters.Add("EsAccionista", esAccionista.Value); // true para accionistas, false para no accionistas (canillitas)
}
sqlBuilder.Append(" ORDER BY c.NomApe;"); sqlBuilder.Append(" ORDER BY c.NomApe;");
try var result = await connection.QueryAsync<Canilla, string, string, (Canilla, string?, string?)>(
{
using var connection = _connectionFactory.CreateConnection();
return await connection.QueryAsync<Canilla, string, string, (Canilla, string, string)>(
sqlBuilder.ToString(), sqlBuilder.ToString(),
(canilla, nombreZona, nombreEmpresa) => (canilla, nombreZona, nombreEmpresa), (can, zona, emp) => (can, zona, emp),
parameters, parameters,
splitOn: "NombreZona,NombreEmpresa" splitOn: "NombreZona,NombreEmpresa"
); );
} return result;
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener todos los Canillas. Filtros: NomApe='{NomApeFilter}', Legajo='{LegajoFilter}', SoloActivos='{SoloActivos}'", nomApeFilter, legajoFilter, soloActivos);
return Enumerable.Empty<(Canilla, string, string)>();
}
} }
public async Task<(Canilla? Canilla, string? NombreZona, string? NombreEmpresa)> GetByIdAsync(int id) public async Task<(Canilla? Canilla, string? NombreZona, string? NombreEmpresa)> GetByIdAsync(int id)
@@ -160,9 +165,19 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
IdCanillaParam = insertedCanilla.IdCanilla, LegajoParam = insertedCanilla.Legajo, NomApeParam = insertedCanilla.NomApe, ParadaParam = insertedCanilla.Parada, IdZonaParam = insertedCanilla.IdZona, IdCanillaParam = insertedCanilla.IdCanilla,
AccionistaParam = insertedCanilla.Accionista, ObsParam = insertedCanilla.Obs, EmpresaParam = insertedCanilla.Empresa, BajaParam = insertedCanilla.Baja, FechaBajaParam = insertedCanilla.FechaBaja, LegajoParam = insertedCanilla.Legajo,
Id_UsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" NomApeParam = insertedCanilla.NomApe,
ParadaParam = insertedCanilla.Parada,
IdZonaParam = insertedCanilla.IdZona,
AccionistaParam = insertedCanilla.Accionista,
ObsParam = insertedCanilla.Obs,
EmpresaParam = insertedCanilla.Empresa,
BajaParam = insertedCanilla.Baja,
FechaBajaParam = insertedCanilla.FechaBaja,
Id_UsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Creado"
}, transaction); }, transaction);
return insertedCanilla; return insertedCanilla;
} }
@@ -190,10 +205,18 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
IdCanillaParam = canillaActual.IdCanilla, IdCanillaParam = canillaActual.IdCanilla,
LegajoParam = canillaActual.Legajo, NomApeParam = canillaActual.NomApe, ParadaParam = canillaActual.Parada, IdZonaParam = canillaActual.IdZona, LegajoParam = canillaActual.Legajo,
AccionistaParam = canillaActual.Accionista, ObsParam = canillaActual.Obs, EmpresaParam = canillaActual.Empresa, NomApeParam = canillaActual.NomApe,
BajaParam = canillaActual.Baja, FechaBajaParam = canillaActual.FechaBaja, ParadaParam = canillaActual.Parada,
Id_UsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Actualizado" IdZonaParam = canillaActual.IdZona,
AccionistaParam = canillaActual.Accionista,
ObsParam = canillaActual.Obs,
EmpresaParam = canillaActual.Empresa,
BajaParam = canillaActual.Baja,
FechaBajaParam = canillaActual.FechaBaja,
Id_UsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Actualizado"
}, transaction); }, transaction);
var rowsAffected = await connection.ExecuteAsync(sqlUpdate, canillaAActualizar, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, canillaAActualizar, transaction);
@@ -218,14 +241,65 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
IdCanillaParam = canillaActual.IdCanilla, LegajoParam = canillaActual.Legajo, NomApeParam = canillaActual.NomApe, ParadaParam = canillaActual.Parada, IdZonaParam = canillaActual.IdZona, IdCanillaParam = canillaActual.IdCanilla,
AccionistaParam = canillaActual.Accionista, ObsParam = canillaActual.Obs, EmpresaParam = canillaActual.Empresa, LegajoParam = canillaActual.Legajo,
BajaNuevaParam = darDeBaja, FechaBajaNuevaParam = (darDeBaja ? fechaBaja : null), NomApeParam = canillaActual.NomApe,
Id_UsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModHistParam = (darDeBaja ? "Baja" : "Alta") ParadaParam = canillaActual.Parada,
IdZonaParam = canillaActual.IdZona,
AccionistaParam = canillaActual.Accionista,
ObsParam = canillaActual.Obs,
EmpresaParam = canillaActual.Empresa,
BajaNuevaParam = darDeBaja,
FechaBajaNuevaParam = (darDeBaja ? fechaBaja : null),
Id_UsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModHistParam = (darDeBaja ? "Baja" : "Alta")
}, transaction); }, transaction);
var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new { BajaParam = darDeBaja, FechaBajaParam = (darDeBaja ? fechaBaja : null), IdCanillaParam = id }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new { BajaParam = darDeBaja, FechaBajaParam = (darDeBaja ? fechaBaja : null), IdCanillaParam = id }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(CanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idCanillaOriginal)
{
using var connection = _connectionFactory.CreateConnection(); // Asumiendo _cf es tu DbConnectionFactory
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Canilla, h.Legajo, h.NomApe, h.Parada, h.Id_Zona, h.Accionista, h.Obs,
h.Empresa, h.Baja, h.FechaBaja,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtCanillas_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 (idCanillaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Canilla = @IdCanillaOriginalParam"); parameters.Add("IdCanillaOriginalParam", idCanillaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<CanillaHistorico, string, (CanillaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Canillitas (Maestro).");
return Enumerable.Empty<(CanillaHistorico, string)>();
}
}
} }
} }

View File

@@ -101,10 +101,18 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
var inserted = await transaction.Connection!.QuerySingleAsync<ControlDevoluciones>(sqlInsert, nuevoControl, transaction); var inserted = await transaction.Connection!.QuerySingleAsync<ControlDevoluciones>(sqlInsert, nuevoControl, transaction);
if (inserted == null || inserted.IdControl == 0) throw new DataException("Error al crear control de devoluciones o ID no generado."); if (inserted == null || inserted.IdControl == 0) throw new DataException("Error al crear control de devoluciones o ID no generado.");
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdControlParam = inserted.IdControl, IdEmpresaParam = inserted.IdEmpresa, FechaParam = inserted.Fecha, {
EntradaParam = inserted.Entrada, SobrantesParam = inserted.Sobrantes, DetalleParam = inserted.Detalle, SinCargoParam = inserted.SinCargo, IdControlParam = inserted.IdControl,
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" IdEmpresaParam = inserted.IdEmpresa,
FechaParam = inserted.Fecha,
EntradaParam = inserted.Entrada,
SobrantesParam = inserted.Sobrantes,
DetalleParam = inserted.Detalle,
SinCargoParam = inserted.SinCargo,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Creado"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -126,10 +134,18 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
(Id_Control, Id_Empresa, Fecha, Entrada, Sobrantes, Detalle, SinCargo, Id_Usuario, FechaMod, TipoMod) (Id_Control, Id_Empresa, Fecha, Entrada, Sobrantes, Detalle, SinCargo, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdControlParam, @IdEmpresaParam, @FechaParam, @EntradaParam, @SobrantesParam, @DetalleParam, @SinCargoParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdControlParam, @IdEmpresaParam, @FechaParam, @EntradaParam, @SobrantesParam, @DetalleParam, @SinCargoParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdControlParam = actual.IdControl, IdEmpresaParam = actual.IdEmpresa, FechaParam = actual.Fecha, // Datos originales {
EntradaParam = actual.Entrada, SobrantesParam = actual.Sobrantes, DetalleParam = actual.Detalle, SinCargoParam = actual.SinCargo, // Valores ANTERIORES IdControlParam = actual.IdControl,
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Actualizado" IdEmpresaParam = actual.IdEmpresa,
FechaParam = actual.Fecha, // Datos originales
EntradaParam = actual.Entrada,
SobrantesParam = actual.Sobrantes,
DetalleParam = actual.Detalle,
SinCargoParam = actual.SinCargo, // Valores ANTERIORES
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Actualizado"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, controlAActualizar, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, controlAActualizar, transaction);
@@ -149,14 +165,66 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
(Id_Control, Id_Empresa, Fecha, Entrada, Sobrantes, Detalle, SinCargo, Id_Usuario, FechaMod, TipoMod) (Id_Control, Id_Empresa, Fecha, Entrada, Sobrantes, Detalle, SinCargo, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdControlParam, @IdEmpresaParam, @FechaParam, @EntradaParam, @SobrantesParam, @DetalleParam, @SinCargoParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdControlParam, @IdEmpresaParam, @FechaParam, @EntradaParam, @SobrantesParam, @DetalleParam, @SinCargoParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdControlParam = actual.IdControl, IdEmpresaParam = actual.IdEmpresa, FechaParam = actual.Fecha, {
EntradaParam = actual.Entrada, SobrantesParam = actual.Sobrantes, DetalleParam = actual.Detalle, SinCargoParam = actual.SinCargo, IdControlParam = actual.IdControl,
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado" IdEmpresaParam = actual.IdEmpresa,
FechaParam = actual.Fecha,
EntradaParam = actual.Entrada,
SobrantesParam = actual.Sobrantes,
DetalleParam = actual.Detalle,
SinCargoParam = actual.SinCargo,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Eliminado"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdControlParam = idControl }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdControlParam = idControl }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(ControlDevolucionesHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idControlOriginal, int? idEmpresaOriginal, DateTime? fechaOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Control, h.Id_Empresa, h.Fecha, h.Entrada, h.Sobrantes, h.Detalle, h.SinCargo,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtCtrlDevoluciones_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 (idControlOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Control = @IdControlOriginalParam"); parameters.Add("IdControlOriginalParam", idControlOriginal.Value); }
if (idEmpresaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Empresa = @IdEmpresaOriginalParam"); parameters.Add("IdEmpresaOriginalParam", idEmpresaOriginal.Value); }
if (fechaOriginal.HasValue) { sqlBuilder.Append(" AND h.Fecha = @FechaOriginalParam"); parameters.Add("FechaOriginalParam", fechaOriginal.Value.Date); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<ControlDevolucionesHistorico, string, (ControlDevolucionesHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Control de Devoluciones.");
return Enumerable.Empty<(ControlDevolucionesHistorico, string)>();
}
}
} }
} }

View File

@@ -1,4 +1,5 @@
using Dapper; using Dapper;
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Models.Distribucion; using GestionIntegral.Api.Models.Distribucion;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; // Añadido para Exception using System; // Añadido para Exception
@@ -62,6 +63,30 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<IEnumerable<DistribuidorDropdownDto?>> GetAllDropdownAsync()
{
var sqlBuilder = new StringBuilder(@"
SELECT
Id_Distribuidor AS IdDistribuidor, Nombre
FROM dbo.dist_dtDistribuidores
WHERE 1=1");
var parameters = new DynamicParameters();
sqlBuilder.Append(" ORDER BY Nombre;");
try
{
using var connection = _connectionFactory.CreateConnection();
return await connection.QueryAsync<DistribuidorDropdownDto>(
sqlBuilder.ToString(),
parameters
);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener todos los Distribuidores.");
return Enumerable.Empty<DistribuidorDropdownDto>();
}
}
public async Task<(Distribuidor? Distribuidor, string? NombreZona)> GetByIdAsync(int id) public async Task<(Distribuidor? Distribuidor, string? NombreZona)> GetByIdAsync(int id)
{ {
const string sql = @" const string sql = @"
@@ -90,6 +115,25 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id)
{
const string sql = @"
SELECT
Id_Distribuidor AS IdDistribuidor, Nombre
FROM dbo.dist_dtDistribuidores
WHERE Id_Distribuidor = @IdParam";
try
{
using var connection = _connectionFactory.CreateConnection();
return await connection.QuerySingleOrDefaultAsync<DistribuidorLookupDto>(sql, new { IdParam = id });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener Distribuidor por ID: {IdDistribuidor}", id);
return null;
}
}
public async Task<Distribuidor?> GetByIdSimpleAsync(int id) public async Task<Distribuidor?> GetByIdSimpleAsync(int id)
{ {
const string sql = @" const string sql = @"
@@ -195,9 +239,21 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
IdDistribuidorParam = inserted.IdDistribuidor, NombreParam = inserted.Nombre, ContactoParam = inserted.Contacto, NroDocParam = inserted.NroDoc, IdZonaParam = inserted.IdZona, IdDistribuidorParam = inserted.IdDistribuidor,
CalleParam = inserted.Calle, NumeroParam = inserted.Numero, PisoParam = inserted.Piso, DeptoParam = inserted.Depto, TelefonoParam = inserted.Telefono, EmailParam = inserted.Email, LocalidadParam = inserted.Localidad, NombreParam = inserted.Nombre,
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" ContactoParam = inserted.Contacto,
NroDocParam = inserted.NroDoc,
IdZonaParam = inserted.IdZona,
CalleParam = inserted.Calle,
NumeroParam = inserted.Numero,
PisoParam = inserted.Piso,
DeptoParam = inserted.Depto,
TelefonoParam = inserted.Telefono,
EmailParam = inserted.Email,
LocalidadParam = inserted.Localidad,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Creado"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -224,9 +280,21 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
IdDistribuidorParam = actual.IdDistribuidor, NombreParam = actual.Nombre, ContactoParam = actual.Contacto, NroDocParam = actual.NroDoc, IdZonaParam = actual.IdZona, IdDistribuidorParam = actual.IdDistribuidor,
CalleParam = actual.Calle, NumeroParam = actual.Numero, PisoParam = actual.Piso, DeptoParam = actual.Depto, TelefonoParam = actual.Telefono, EmailParam = actual.Email, LocalidadParam = actual.Localidad, NombreParam = actual.Nombre,
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Actualizado" ContactoParam = actual.Contacto,
NroDocParam = actual.NroDoc,
IdZonaParam = actual.IdZona,
CalleParam = actual.Calle,
NumeroParam = actual.Numero,
PisoParam = actual.Piso,
DeptoParam = actual.Depto,
TelefonoParam = actual.Telefono,
EmailParam = actual.Email,
LocalidadParam = actual.Localidad,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Actualizado"
}, transaction); }, transaction);
var rowsAffected = await connection.ExecuteAsync(sqlUpdate, distribuidorAActualizar, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, distribuidorAActualizar, transaction);
@@ -251,13 +319,68 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await connection.ExecuteAsync(sqlInsertHistorico, new await connection.ExecuteAsync(sqlInsertHistorico, new
{ {
IdDistribuidorParam = actual.IdDistribuidor, NombreParam = actual.Nombre, ContactoParam = actual.Contacto, NroDocParam = actual.NroDoc, IdZonaParam = actual.IdZona, IdDistribuidorParam = actual.IdDistribuidor,
CalleParam = actual.Calle, NumeroParam = actual.Numero, PisoParam = actual.Piso, DeptoParam = actual.Depto, TelefonoParam = actual.Telefono, EmailParam = actual.Email, LocalidadParam = actual.Localidad, NombreParam = actual.Nombre,
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado" ContactoParam = actual.Contacto,
NroDocParam = actual.NroDoc,
IdZonaParam = actual.IdZona,
CalleParam = actual.Calle,
NumeroParam = actual.Numero,
PisoParam = actual.Piso,
DeptoParam = actual.Depto,
TelefonoParam = actual.Telefono,
EmailParam = actual.Email,
LocalidadParam = actual.Localidad,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Eliminado"
}, transaction); }, transaction);
var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { IdParam = id }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { IdParam = id }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(DistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idDistribuidorOriginal)
{
using var connection = _connectionFactory.CreateConnection(); // Asumiendo _connectionFactory
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Distribuidor, h.Nombre, h.Contacto, h.NroDoc, h.Id_Zona, h.Calle, h.Numero,
h.Piso, h.Depto, h.Telefono, h.Email, h.Localidad,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtDistribuidores_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 (idDistribuidorOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Distribuidor = @IdDistribuidorOriginalParam"); parameters.Add("IdDistribuidorOriginalParam", idDistribuidorOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<DistribuidorHistorico, string, (DistribuidorHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Distribuidores (Maestro)."); // Asumiendo _logger
return Enumerable.Empty<(DistribuidorHistorico, string)>();
}
}
} }
} }

View File

@@ -1,5 +1,6 @@
using Dapper; using Dapper;
using GestionIntegral.Api.Data.Repositories; using GestionIntegral.Api.Data.Repositories;
using GestionIntegral.Api.Dtos.Empresas;
using GestionIntegral.Api.Models.Distribucion; using GestionIntegral.Api.Models.Distribucion;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
@@ -52,6 +53,25 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<IEnumerable<EmpresaDropdownDto>> GetAllDropdownAsync()
{
var sqlBuilder = new StringBuilder("SELECT Id_Empresa AS IdEmpresa, Nombre FROM dbo.dist_dtEmpresas WHERE 1=1");
var parameters = new DynamicParameters();
sqlBuilder.Append(" ORDER BY Nombre;");
try
{
using (var connection = _connectionFactory.CreateConnection())
{
return await connection.QueryAsync<EmpresaDropdownDto>(sqlBuilder.ToString(), parameters);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener todas las Empresas.");
return Enumerable.Empty<EmpresaDropdownDto>();
}
}
public async Task<Empresa?> GetByIdAsync(int id) public async Task<Empresa?> GetByIdAsync(int id)
{ {
var sql = "SELECT Id_Empresa AS IdEmpresa, Nombre, Detalle FROM dbo.dist_dtEmpresas WHERE Id_Empresa = @Id"; var sql = "SELECT Id_Empresa AS IdEmpresa, Nombre, Detalle FROM dbo.dist_dtEmpresas WHERE Id_Empresa = @Id";
@@ -69,6 +89,23 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<Empresa?> ObtenerLookupPorIdAsync(int id)
{
var sql = "SELECT Id_Empresa AS IdEmpresa, Nombre FROM dbo.dist_dtEmpresas WHERE Id_Empresa = @Id";
try
{
using (var connection = _connectionFactory.CreateConnection())
{
return await connection.QuerySingleOrDefaultAsync<Empresa>(sql, new { Id = id });
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener Empresa por ID: {IdEmpresa}", id);
return null;
}
}
public async Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null) public async Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null)
{ {
var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtEmpresas WHERE Nombre = @Nombre"); var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtEmpresas WHERE Nombre = @Nombre");
@@ -144,7 +181,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
// Insertar en historial // Insertar en historial
await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new
{
IdEmpresa = insertedEmpresa.IdEmpresa, IdEmpresa = insertedEmpresa.IdEmpresa,
insertedEmpresa.Nombre, insertedEmpresa.Nombre,
insertedEmpresa.Detalle, insertedEmpresa.Detalle,
@@ -172,7 +210,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
VALUES (@IdEmpresa, @NombreActual, @DetalleActual, @IdUsuario, @FechaMod, @TipoMod);"; VALUES (@IdEmpresa, @NombreActual, @DetalleActual, @IdUsuario, @FechaMod, @TipoMod);";
// Insertar en historial (estado anterior) // Insertar en historial (estado anterior)
await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new
{
IdEmpresa = empresaActual.IdEmpresa, IdEmpresa = empresaActual.IdEmpresa,
NombreActual = empresaActual.Nombre, NombreActual = empresaActual.Nombre,
DetalleActual = empresaActual.Detalle, DetalleActual = empresaActual.Detalle,
@@ -182,7 +221,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
}, transaction: transaction); }, transaction: transaction);
// Actualizar principal // Actualizar principal
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, new { var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, new
{
empresaAActualizar.Nombre, empresaAActualizar.Nombre,
empresaAActualizar.Detalle, empresaAActualizar.Detalle,
empresaAActualizar.IdEmpresa empresaAActualizar.IdEmpresa
@@ -202,7 +242,8 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
VALUES (@IdEmpresa, @Nombre, @Detalle, @IdUsuario, @FechaMod, @TipoMod);"; VALUES (@IdEmpresa, @Nombre, @Detalle, @IdUsuario, @FechaMod, @TipoMod);";
// Insertar en historial (estado antes de borrar) // Insertar en historial (estado antes de borrar)
await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new
{
IdEmpresa = empresaActual.IdEmpresa, IdEmpresa = empresaActual.IdEmpresa,
empresaActual.Nombre, empresaActual.Nombre,
empresaActual.Detalle, empresaActual.Detalle,
@@ -216,5 +257,47 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(EmpresaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idEmpresaOriginal)
{
using var connection = _connectionFactory.CreateConnection(); // Asumiendo _cf
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Empresa, h.Nombre, h.Detalle,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtEmpresas_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 (idEmpresaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Empresa = @IdEmpresaOriginalParam"); parameters.Add("IdEmpresaOriginalParam", idEmpresaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<EmpresaHistorico, string, (EmpresaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Empresas (Maestro)."); // Asumiendo _logger
return Enumerable.Empty<(EmpresaHistorico, string)>();
}
}
} }
} }

View File

@@ -292,5 +292,48 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdParteParam = idParte }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdParteParam = idParte }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(EntradaSalidaCanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idParteOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Parte, h.Id_Publicacion, h.Id_Canilla, h.Fecha,
h.CantSalida, h.CantEntrada, h.Id_Precio, h.Id_Recargo, h.Id_PorcMon, h.Observacion,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_EntradasSalidasCanillas_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 (idParteOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Parte = @IdParteOriginalParam"); parameters.Add("IdParteOriginalParam", idParteOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<EntradaSalidaCanillaHistorico, string, (EntradaSalidaCanillaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Entradas/Salidas Canillitas.");
return Enumerable.Empty<(EntradaSalidaCanillaHistorico, string)>();
}
}
} }
} }

View File

@@ -114,11 +114,22 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
var inserted = await transaction.Connection!.QuerySingleAsync<EntradaSalidaDist>(sqlInsert, nuevaES, transaction); var inserted = await transaction.Connection!.QuerySingleAsync<EntradaSalidaDist>(sqlInsert, nuevaES, transaction);
if (inserted == null || inserted.IdParte == 0) throw new DataException("Error al crear Entrada/Salida o ID no generado."); if (inserted == null || inserted.IdParte == 0) throw new DataException("Error al crear Entrada/Salida o ID no generado.");
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdParteHist = inserted.IdParte, IdPublicacionHist = inserted.IdPublicacion, IdDistribuidorHist = inserted.IdDistribuidor, {
FechaHist = inserted.Fecha, TipoMovimientoHist = inserted.TipoMovimiento, CantidadHist = inserted.Cantidad, RemitoHist = inserted.Remito, ObservacionHist = inserted.Observacion, IdParteHist = inserted.IdParte,
IdPrecioHist = inserted.IdPrecio, IdRecargoHist = inserted.IdRecargo, IdPorcentajeHist = inserted.IdPorcentaje, IdPublicacionHist = inserted.IdPublicacion,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Creada" IdDistribuidorHist = inserted.IdDistribuidor,
FechaHist = inserted.Fecha,
TipoMovimientoHist = inserted.TipoMovimiento,
CantidadHist = inserted.Cantidad,
RemitoHist = inserted.Remito,
ObservacionHist = inserted.Observacion,
IdPrecioHist = inserted.IdPrecio,
IdRecargoHist = inserted.IdRecargo,
IdPorcentajeHist = inserted.IdPorcentaje,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Creada"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -141,11 +152,22 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
(Id_Parte, Id_Publicacion, Id_Distribuidor, Fecha, TipoMovimiento, Cantidad, Remito, Observacion, Id_Precio, Id_Recargo, Id_Porcentaje, Id_Usuario, FechaMod, TipoMod) (Id_Parte, Id_Publicacion, Id_Distribuidor, Fecha, TipoMovimiento, Cantidad, Remito, Observacion, Id_Precio, Id_Recargo, Id_Porcentaje, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdParteHist, @IdPublicacionHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @CantidadHist, @RemitoHist, @ObservacionHist, @IdPrecioHist, @IdRecargoHist, @IdPorcentajeHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; VALUES (@IdParteHist, @IdPublicacionHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @CantidadHist, @RemitoHist, @ObservacionHist, @IdPrecioHist, @IdRecargoHist, @IdPorcentajeHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdParteHist = actual.IdParte, IdPublicacionHist = actual.IdPublicacion, IdDistribuidorHist = actual.IdDistribuidor, {
FechaHist = actual.Fecha, TipoMovimientoHist = actual.TipoMovimiento, CantidadHist = actual.Cantidad, RemitoHist = actual.Remito, ObservacionHist = actual.Observacion, IdParteHist = actual.IdParte,
IdPrecioHist = actual.IdPrecio, IdRecargoHist = actual.IdRecargo, IdPorcentajeHist = actual.IdPorcentaje, // Valores ANTERIORES IdPublicacionHist = actual.IdPublicacion,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Actualizada" IdDistribuidorHist = actual.IdDistribuidor,
FechaHist = actual.Fecha,
TipoMovimientoHist = actual.TipoMovimiento,
CantidadHist = actual.Cantidad,
RemitoHist = actual.Remito,
ObservacionHist = actual.Observacion,
IdPrecioHist = actual.IdPrecio,
IdRecargoHist = actual.IdRecargo,
IdPorcentajeHist = actual.IdPorcentaje, // Valores ANTERIORES
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Actualizada"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, esAActualizar, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, esAActualizar, transaction);
@@ -166,15 +188,69 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
(Id_Parte, Id_Publicacion, Id_Distribuidor, Fecha, TipoMovimiento, Cantidad, Remito, Observacion, Id_Precio, Id_Recargo, Id_Porcentaje, Id_Usuario, FechaMod, TipoMod) (Id_Parte, Id_Publicacion, Id_Distribuidor, Fecha, TipoMovimiento, Cantidad, Remito, Observacion, Id_Precio, Id_Recargo, Id_Porcentaje, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdParteHist, @IdPublicacionHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @CantidadHist, @RemitoHist, @ObservacionHist, @IdPrecioHist, @IdRecargoHist, @IdPorcentajeHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; VALUES (@IdParteHist, @IdPublicacionHist, @IdDistribuidorHist, @FechaHist, @TipoMovimientoHist, @CantidadHist, @RemitoHist, @ObservacionHist, @IdPrecioHist, @IdRecargoHist, @IdPorcentajeHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdParteHist = actual.IdParte, IdPublicacionHist = actual.IdPublicacion, IdDistribuidorHist = actual.IdDistribuidor, {
FechaHist = actual.Fecha, TipoMovimientoHist = actual.TipoMovimiento, CantidadHist = actual.Cantidad, RemitoHist = actual.Remito, ObservacionHist = actual.Observacion, IdParteHist = actual.IdParte,
IdPrecioHist = actual.IdPrecio, IdRecargoHist = actual.IdRecargo, IdPorcentajeHist = actual.IdPorcentaje, IdPublicacionHist = actual.IdPublicacion,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Eliminada" IdDistribuidorHist = actual.IdDistribuidor,
FechaHist = actual.Fecha,
TipoMovimientoHist = actual.TipoMovimiento,
CantidadHist = actual.Cantidad,
RemitoHist = actual.Remito,
ObservacionHist = actual.Observacion,
IdPrecioHist = actual.IdPrecio,
IdRecargoHist = actual.IdRecargo,
IdPorcentajeHist = actual.IdPorcentaje,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Eliminada"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdParteParam = idParte }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdParteParam = idParte }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(EntradaSalidaDistHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idParteOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Parte, h.Id_Publicacion, h.Id_Distribuidor, h.Fecha, h.TipoMovimiento,
h.Cantidad, h.Remito, h.Observacion, h.Id_Precio, h.Id_Recargo, h.Id_Porcentaje,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_EntradasSalidas_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 (idParteOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Parte = @IdParteOriginalParam"); parameters.Add("IdParteOriginalParam", idParteOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<EntradaSalidaDistHistorico, string, (EntradaSalidaDistHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Entradas/Salidas Distribuidores.");
return Enumerable.Empty<(EntradaSalidaDistHistorico, string)>();
}
}
} }
} }

View File

@@ -0,0 +1,22 @@
using GestionIntegral.Api.Models.Distribucion;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion
{
public interface ICambioParadaRepository
{
Task<IEnumerable<CambioParadaCanilla>> GetByCanillaAsync(int idCanilla);
Task<CambioParadaCanilla?> GetByIdAsync(int idRegistro);
Task<CambioParadaCanilla?> GetCurrentParadaAsync(int idCanilla, IDbTransaction? transaction = null);
Task<CambioParadaCanilla?> CreateAsync(CambioParadaCanilla nuevaParada, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateVigenciaHAsync(int idRegistro, DateTime vigenciaH, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int idRegistro, int idUsuario, IDbTransaction transaction);
Task<IEnumerable<(CambioParadaCanillaHistorial Historial, string NombreUsuarioModifico, string NombreCanilla)>> GetCambiosParadaHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idCanillaOriginal);
}
}

View File

@@ -7,13 +7,16 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
{ {
public interface ICanillaRepository public interface ICanillaRepository
{ {
Task<IEnumerable<(Canilla Canilla, string NombreZona, string NombreEmpresa)>> GetAllAsync(string? nomApeFilter, int? legajoFilter, bool? soloActivos); Task<IEnumerable<(Canilla Canilla, string? NombreZona, string? NombreEmpresa)>> GetAllAsync(string? nomApeFilter, int? legajoFilter, bool? soloActivos, bool? esAccionista);
Task<(Canilla? Canilla, string? NombreZona, string? NombreEmpresa)> GetByIdAsync(int id); Task<(Canilla? Canilla, string? NombreZona, string? NombreEmpresa)> GetByIdAsync(int id);
Task<Canilla?> GetByIdSimpleAsync(int id); // Para obtener solo la entidad Canilla Task<Canilla?> GetByIdSimpleAsync(int id); // Para obtener solo la entidad Canilla
Task<Canilla?> CreateAsync(Canilla nuevoCanilla, int idUsuario, IDbTransaction transaction); Task<Canilla?> CreateAsync(Canilla nuevoCanilla, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(Canilla canillaAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(Canilla canillaAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario, IDbTransaction transaction); Task<bool> ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByLegajoAsync(int legajo, int? excludeIdCanilla = null); Task<bool> ExistsByLegajoAsync(int legajo, int? excludeIdCanilla = null);
// IsInUse no es tan directo, ya que las liquidaciones se marcan. Se podría verificar dist_EntradasSalidasCanillas no liquidadas. Task<IEnumerable<(CanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idCanillaOriginal); // Para filtrar por un canillita específico
} }
} }

View File

@@ -14,5 +14,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<ControlDevoluciones?> CreateAsync(ControlDevoluciones nuevoControl, int idUsuario, IDbTransaction transaction); Task<ControlDevoluciones?> CreateAsync(ControlDevoluciones nuevoControl, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(ControlDevoluciones controlAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(ControlDevoluciones controlAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int idControl, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idControl, int idUsuario, IDbTransaction transaction);
Task<IEnumerable<(ControlDevolucionesHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idControlOriginal, int? idEmpresaOriginal, DateTime? fechaOriginal);
} }
} }

View File

@@ -2,6 +2,7 @@ using GestionIntegral.Api.Models.Distribucion;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Data; using System.Data;
using GestionIntegral.Api.Dtos.Distribucion;
namespace GestionIntegral.Api.Data.Repositories.Distribucion namespace GestionIntegral.Api.Data.Repositories.Distribucion
{ {
@@ -16,5 +17,11 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> ExistsByNroDocAsync(string nroDoc, int? excludeIdDistribuidor = null); Task<bool> ExistsByNroDocAsync(string nroDoc, int? excludeIdDistribuidor = null);
Task<bool> ExistsByNameAsync(string nombre, int? excludeIdDistribuidor = null); Task<bool> ExistsByNameAsync(string nombre, int? excludeIdDistribuidor = null);
Task<bool> IsInUseAsync(int id); // Verificar en dist_EntradasSalidas, cue_PagosDistribuidor, dist_PorcPago Task<bool> IsInUseAsync(int id); // Verificar en dist_EntradasSalidas, cue_PagosDistribuidor, dist_PorcPago
Task<IEnumerable<DistribuidorDropdownDto?>> GetAllDropdownAsync();
Task<DistribuidorLookupDto?> ObtenerLookupPorIdAsync(int id);
Task<IEnumerable<(DistribuidorHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idDistribuidorOriginal);
} }
} }

View File

@@ -1,7 +1,8 @@
using GestionIntegral.Api.Models.Distribucion; using GestionIntegral.Api.Models.Distribucion;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Data; // Para IDbTransaction using System.Data;
using GestionIntegral.Api.Dtos.Empresas; // Para IDbTransaction
namespace GestionIntegral.Api.Data.Repositories.Distribucion namespace GestionIntegral.Api.Data.Repositories.Distribucion
{ {
@@ -14,5 +15,11 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); // Necesita transacción Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); // Necesita transacción
Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null); Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null);
Task<bool> IsInUseAsync(int id); Task<bool> IsInUseAsync(int id);
Task<IEnumerable<EmpresaDropdownDto>> GetAllDropdownAsync();
Task<Empresa?> ObtenerLookupPorIdAsync(int id);
Task<IEnumerable<(EmpresaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idEmpresaOriginal);
} }
} }

View File

@@ -19,5 +19,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> DeleteAsync(int idParte, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idParte, int idUsuario, IDbTransaction transaction);
Task<bool> LiquidarAsync(IEnumerable<int> idsPartes, DateTime fechaLiquidacion, int idUsuarioLiquidador, IDbTransaction transaction); Task<bool> LiquidarAsync(IEnumerable<int> idsPartes, DateTime fechaLiquidacion, int idUsuarioLiquidador, IDbTransaction transaction);
Task<bool> ExistsByPublicacionCanillaFechaAsync(int idPublicacion, int idCanilla, DateTime fecha, IDbTransaction? transaction = null, int? excludeIdParte = null); Task<bool> ExistsByPublicacionCanillaFechaAsync(int idPublicacion, int idCanilla, DateTime fecha, IDbTransaction? transaction = null, int? excludeIdParte = null);
Task<IEnumerable<(EntradaSalidaCanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idParteOriginal);
} }
} }

View File

@@ -14,5 +14,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> UpdateAsync(EntradaSalidaDist esAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(EntradaSalidaDist esAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int idParte, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idParte, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByRemitoAndTipoForPublicacionAsync(int remito, string tipoMovimiento, int idPublicacion, int? excludeIdParte = null); Task<bool> ExistsByRemitoAndTipoForPublicacionAsync(int remito, string tipoMovimiento, int idPublicacion, int? excludeIdParte = null);
Task<IEnumerable<(EntradaSalidaDistHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idParteOriginal); // Para filtrar por un movimiento específico
} }
} }

View File

@@ -0,0 +1,27 @@
using GestionIntegral.Api.Dtos.Reportes;
using GestionIntegral.Api.Models.Distribucion;
using System;
using System.Collections.Generic;
using System.Data; // Para IDbTransaction
using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion
{
public interface INovedadCanillaRepository
{
// Para obtener novedades y el nombre del canillita
Task<IEnumerable<(NovedadCanilla Novedad, string NombreCanilla)>> GetByCanillaAsync(int idCanilla, DateTime? fechaDesde, DateTime? fechaHasta);
Task<NovedadCanilla?> GetByIdAsync(int idNovedad);
Task<NovedadCanilla?> CreateAsync(NovedadCanilla novedad, int idUsuario, IDbTransaction? transaction = null);
Task<bool> UpdateAsync(NovedadCanilla novedad, int idUsuario, IDbTransaction? transaction = null);
Task<bool> DeleteAsync(int idNovedad, int idUsuario, IDbTransaction? transaction = null);
// Podrías añadir un método para verificar si existe una novedad para un canillita en una fecha específica si es necesario
Task<bool> ExistsByCanillaAndFechaAsync(int idCanilla, DateTime fecha, int? excludeIdNovedad = null);
Task<IEnumerable<NovedadesCanillasReporteDto>> GetReporteNovedadesAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta);
Task<IEnumerable<CanillaGananciaReporteDto>> GetReporteGananciasAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta);
Task<IEnumerable<(NovedadCanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idNovedadOriginal);
}
}

View File

@@ -14,5 +14,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null); Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null);
Task<bool> IsInUseAsync(int id); // Verificar si se usa en dist_SalidasOtrosDestinos Task<bool> IsInUseAsync(int id); // Verificar si se usa en dist_SalidasOtrosDestinos
Task<IEnumerable<(OtroDestinoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idOtroDestinoOriginal);
} }
} }

View File

@@ -16,5 +16,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> DeleteAsync(int idPorcMon, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idPorcMon, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction);
Task<PorcMonCanilla?> GetPreviousActiveAsync(int idPublicacion, int idCanilla, DateTime vigenciaDNuevo, IDbTransaction transaction); Task<PorcMonCanilla?> GetPreviousActiveAsync(int idPublicacion, int idCanilla, DateTime vigenciaDNuevo, IDbTransaction transaction);
Task<IEnumerable<(PorcMonCanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPorcMonOriginal, int? idPublicacionOriginal, int? idCanillaOriginal);
} }
} }

View File

@@ -16,5 +16,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> DeleteAsync(int idPorcentaje, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idPorcentaje, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction);
Task<PorcPago?> GetPreviousActivePorcPagoAsync(int idPublicacion, int idDistribuidor, DateTime vigenciaDNuevo, IDbTransaction transaction); Task<PorcPago?> GetPreviousActivePorcPagoAsync(int idPublicacion, int idDistribuidor, DateTime vigenciaDNuevo, IDbTransaction transaction);
Task<IEnumerable<(PorcPagoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPorcentajeOriginal, int? idPublicacionOriginal, int? idDistribuidorOriginal);
} }
} }

View File

@@ -9,6 +9,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
{ {
Task<IEnumerable<Precio>> GetByPublicacionIdAsync(int idPublicacion); Task<IEnumerable<Precio>> GetByPublicacionIdAsync(int idPublicacion);
Task<Precio?> GetByIdAsync(int idPrecio); Task<Precio?> GetByIdAsync(int idPrecio);
Task<bool> IsInUseAsync(int idPrecio, DateTime vigenciaD, DateTime? vigenciaH);
Task<Precio?> GetActiveByPublicacionAndDateAsync(int idPublicacion, DateTime fecha, IDbTransaction? transaction = null); Task<Precio?> GetActiveByPublicacionAndDateAsync(int idPublicacion, DateTime fecha, IDbTransaction? transaction = null);
Task<Precio?> CreateAsync(Precio nuevoPrecio, int idUsuario, IDbTransaction transaction); Task<Precio?> CreateAsync(Precio nuevoPrecio, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(Precio precioAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(Precio precioAActualizar, int idUsuario, IDbTransaction transaction);
@@ -16,5 +17,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
// MODIFICADO: Añadir idUsuarioAuditoria // MODIFICADO: Añadir idUsuarioAuditoria
Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction);
Task<Precio?> GetPreviousActivePriceAsync(int idPublicacion, DateTime vigenciaDNuevo, IDbTransaction transaction); Task<Precio?> GetPreviousActivePriceAsync(int idPublicacion, DateTime vigenciaDNuevo, IDbTransaction transaction);
Task<IEnumerable<(PrecioHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPrecioOriginal, int? idPublicacionOriginal);
} }
} }

View File

@@ -15,5 +15,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); // Ya existe Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); // Ya existe
Task<bool> ExistsByNameInPublicacionAsync(string nombre, int idPublicacion, int? excludeIdSeccion = null); Task<bool> ExistsByNameInPublicacionAsync(string nombre, int idPublicacion, int? excludeIdSeccion = null);
Task<bool> IsInUseAsync(int idSeccion); // Verificar en bob_RegPublicaciones, bob_StockBobinas Task<bool> IsInUseAsync(int idSeccion); // Verificar en bob_RegPublicaciones, bob_StockBobinas
Task<IEnumerable<(PubliSeccionHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idSeccionOriginal, int? idPublicacionOriginal);
} }
} }

View File

@@ -18,5 +18,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<IEnumerable<PublicacionDiaSemana>> GetConfiguracionDiasAsync(int idPublicacion); Task<IEnumerable<PublicacionDiaSemana>> GetConfiguracionDiasAsync(int idPublicacion);
Task<IEnumerable<int>> GetPublicacionesIdsPorDiaSemanaAsync(byte diaSemana); // Devuelve solo IDs Task<IEnumerable<int>> GetPublicacionesIdsPorDiaSemanaAsync(byte diaSemana); // Devuelve solo IDs
Task UpdateConfiguracionDiasAsync(int idPublicacion, IEnumerable<byte> diasActivos, IDbTransaction transaction); Task UpdateConfiguracionDiasAsync(int idPublicacion, IEnumerable<byte> diasActivos, IDbTransaction transaction);
Task<IEnumerable<(PublicacionHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPublicacionOriginal);
} }
} }

View File

@@ -10,11 +10,16 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
{ {
Task<IEnumerable<(RecargoZona Recargo, string NombreZona)>> GetByPublicacionIdAsync(int idPublicacion); Task<IEnumerable<(RecargoZona Recargo, string NombreZona)>> GetByPublicacionIdAsync(int idPublicacion);
Task<RecargoZona?> GetByIdAsync(int idRecargo); // Para obtener un recargo específico Task<RecargoZona?> GetByIdAsync(int idRecargo); // Para obtener un recargo específico
Task<bool> IsInUseAsync(int idRecargo, DateTime vigenciaD, DateTime? vigenciaH);
Task<RecargoZona?> GetActiveByPublicacionZonaAndDateAsync(int idPublicacion, int idZona, DateTime fecha, IDbTransaction? transaction = null); Task<RecargoZona?> GetActiveByPublicacionZonaAndDateAsync(int idPublicacion, int idZona, DateTime fecha, IDbTransaction? transaction = null);
Task<RecargoZona?> CreateAsync(RecargoZona nuevoRecargo, int idUsuario, IDbTransaction transaction); Task<RecargoZona?> CreateAsync(RecargoZona nuevoRecargo, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(RecargoZona recargoAActualizar, int idUsuario, IDbTransaction transaction); Task<bool> UpdateAsync(RecargoZona recargoAActualizar, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteAsync(int idRecargo, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int idRecargo, int idUsuario, IDbTransaction transaction);
Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); // Ya existe Task<bool> DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction); // Ya existe
Task<RecargoZona?> GetPreviousActiveRecargoAsync(int idPublicacion, int idZona, DateTime vigenciaDNuevo, IDbTransaction transaction); Task<RecargoZona?> GetPreviousActiveRecargoAsync(int idPublicacion, int idZona, DateTime vigenciaDNuevo, IDbTransaction transaction);
Task<IEnumerable<(RecargoZonaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idRecargoOriginal, int? idPublicacionOriginal, int? idZonaOriginal);
} }
} }

View File

@@ -13,5 +13,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<bool> SoftDeleteAsync(int id, int idUsuario); // Cambiado de DeleteAsync a SoftDeleteAsync Task<bool> SoftDeleteAsync(int id, int idUsuario); // Cambiado de DeleteAsync a SoftDeleteAsync
Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null, bool soloActivas = true); Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null, bool soloActivas = true);
Task<bool> IsInUseAsync(int id); Task<bool> IsInUseAsync(int id);
Task<IEnumerable<(ZonaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idZonaOriginal);
} }
} }

View File

@@ -0,0 +1,278 @@
using Dapper;
using GestionIntegral.Api.Models.Distribucion;
using Microsoft.Extensions.Configuration; // Para IConfiguration
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using Microsoft.Data.SqlClient; // O el proveedor de tu BD
using System.Linq;
using System.Threading.Tasks;
using GestionIntegral.Api.Dtos.Reportes;
using System.Text;
namespace GestionIntegral.Api.Data.Repositories.Distribucion
{
public class NovedadCanillaRepository : INovedadCanillaRepository
{
private readonly DbConnectionFactory _connectionFactory; // Inyecta tu DbConnectionFactory
private readonly ILogger<NovedadCanillaRepository> _logger;
public NovedadCanillaRepository(DbConnectionFactory connectionFactory, ILogger<NovedadCanillaRepository> logger)
{
_connectionFactory = connectionFactory;
_logger = logger;
}
private async Task LogHistorialAsync(NovedadCanilla novedadOriginal, int idUsuario, string tipoMod, IDbConnection connection, IDbTransaction? transaction)
{
var historial = new NovedadCanillaHistorial
{
IdNovedad = novedadOriginal.IdNovedad,
IdCanilla = novedadOriginal.IdCanilla,
Fecha = novedadOriginal.Fecha,
Detalle = novedadOriginal.Detalle,
IdUsuario = idUsuario,
FechaMod = DateTime.Now,
TipoMod = tipoMod
};
var sqlHistorial = @"
INSERT INTO dbo.dist_dtNovedadesCanillas_H
(Id_Novedad, Id_Canilla, Fecha, Detalle, Id_Usuario, FechaMod, TipoMod)
VALUES
(@IdNovedad, @IdCanilla, @Fecha, @Detalle, @IdUsuario, @FechaMod, @TipoMod);";
await connection.ExecuteAsync(sqlHistorial, historial, transaction);
}
public async Task<IEnumerable<(NovedadCanilla Novedad, string NombreCanilla)>> GetByCanillaAsync(int idCanilla, DateTime? fechaDesde, DateTime? fechaHasta)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new System.Text.StringBuilder(@"
SELECT
n.Id_Novedad AS IdNovedad,
n.Id_Canilla AS IdCanilla,
n.Fecha,
n.Detalle,
c.NomApe AS NombreCanilla
FROM dbo.dist_dtNovedadesCanillas n
JOIN dbo.dist_dtCanillas c ON n.Id_Canilla = c.Id_Canilla
WHERE n.Id_Canilla = @IdCanilla");
var parameters = new DynamicParameters();
parameters.Add("IdCanilla", idCanilla);
if (fechaDesde.HasValue)
{
sqlBuilder.Append(" AND n.Fecha >= @FechaDesde");
parameters.Add("FechaDesde", fechaDesde.Value.Date); // Solo fecha, sin hora
}
if (fechaHasta.HasValue)
{
sqlBuilder.Append(" AND n.Fecha <= @FechaHasta");
// Para incluir todo el día de fechaHasta
parameters.Add("FechaHasta", fechaHasta.Value.Date.AddDays(1).AddTicks(-1));
}
sqlBuilder.Append(" ORDER BY n.Fecha DESC, n.Id_Novedad DESC;");
var result = await connection.QueryAsync<NovedadCanilla, string, (NovedadCanilla, string)>(
sqlBuilder.ToString(),
(novedad, nombreCanilla) => (novedad, nombreCanilla),
parameters,
splitOn: "NombreCanilla"
);
return result;
}
public async Task<NovedadCanilla?> GetByIdAsync(int idNovedad)
{
using var connection = _connectionFactory.CreateConnection();
var sql = "SELECT Id_Novedad AS IdNovedad, Id_Canilla AS IdCanilla, Fecha, Detalle FROM dbo.dist_dtNovedadesCanillas WHERE Id_Novedad = @IdNovedad;";
return await connection.QuerySingleOrDefaultAsync<NovedadCanilla>(sql, new { IdNovedad = idNovedad });
}
public async Task<bool> ExistsByCanillaAndFechaAsync(int idCanilla, DateTime fecha, int? excludeIdNovedad = null)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new System.Text.StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtNovedadesCanillas WHERE Id_Canilla = @IdCanilla AND Fecha = @Fecha");
var parameters = new DynamicParameters();
parameters.Add("IdCanilla", idCanilla);
parameters.Add("Fecha", fecha.Date); // Comparar solo la fecha
if (excludeIdNovedad.HasValue)
{
sqlBuilder.Append(" AND Id_Novedad != @ExcludeIdNovedad");
parameters.Add("ExcludeIdNovedad", excludeIdNovedad.Value);
}
var count = await connection.ExecuteScalarAsync<int>(sqlBuilder.ToString(), parameters);
return count > 0;
}
public async Task<NovedadCanilla?> CreateAsync(NovedadCanilla novedad, int idUsuario, IDbTransaction? transaction = null)
{
var sql = @"
INSERT INTO dbo.dist_dtNovedadesCanillas (Id_Canilla, Fecha, Detalle)
VALUES (@IdCanilla, @Fecha, @Detalle);
SELECT CAST(SCOPE_IDENTITY() as int);";
IDbConnection conn = transaction?.Connection ?? _connectionFactory.CreateConnection();
bool manageConnection = transaction == null; // Solo gestionar si no hay transacción externa
try
{
if (manageConnection && conn.State != ConnectionState.Open) await (conn as SqlConnection)!.OpenAsync();
var newId = await conn.QuerySingleAsync<int>(sql, novedad, transaction);
novedad.IdNovedad = newId;
await LogHistorialAsync(novedad, idUsuario, "Insertada", conn, transaction);
return novedad;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al crear NovedadCanilla para Canilla ID: {IdCanilla}", novedad.IdCanilla);
return null;
}
finally
{
if (manageConnection && conn.State == ConnectionState.Open) conn.Close();
}
}
public async Task<bool> UpdateAsync(NovedadCanilla novedad, int idUsuario, IDbTransaction? transaction = null)
{
var novedadOriginal = await GetByIdAsync(novedad.IdNovedad); // Necesitamos el estado original para el log
if (novedadOriginal == null) return false; // No se encontró
var sql = @"
UPDATE dbo.dist_dtNovedadesCanillas SET
Detalle = @Detalle
-- No se permite cambiar IdCanilla ni Fecha de una novedad existente
WHERE Id_Novedad = @IdNovedad;";
IDbConnection conn = transaction?.Connection ?? _connectionFactory.CreateConnection();
bool manageConnection = transaction == null;
try
{
if (manageConnection && conn.State != ConnectionState.Open) await (conn as SqlConnection)!.OpenAsync();
await LogHistorialAsync(novedadOriginal, idUsuario, "Modificada", conn, transaction); // Log con datos ANTES de actualizar
var affectedRows = await conn.ExecuteAsync(sql, novedad, transaction);
return affectedRows > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al actualizar NovedadCanilla ID: {IdNovedad}", novedad.IdNovedad);
return false;
}
finally
{
if (manageConnection && conn.State == ConnectionState.Open) conn.Close();
}
}
public async Task<bool> DeleteAsync(int idNovedad, int idUsuario, IDbTransaction? transaction = null)
{
var novedadOriginal = await GetByIdAsync(idNovedad);
if (novedadOriginal == null) return false;
var sql = "DELETE FROM dbo.dist_dtNovedadesCanillas WHERE Id_Novedad = @IdNovedad;";
IDbConnection conn = transaction?.Connection ?? _connectionFactory.CreateConnection();
bool manageConnection = transaction == null;
try
{
if (manageConnection && conn.State != ConnectionState.Open) await (conn as SqlConnection)!.OpenAsync();
await LogHistorialAsync(novedadOriginal, idUsuario, "Eliminada", conn, transaction);
var affectedRows = await conn.ExecuteAsync(sql, new { IdNovedad = idNovedad }, transaction);
return affectedRows > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al eliminar NovedadCanilla ID: {IdNovedad}", idNovedad);
return false;
}
finally
{
if (manageConnection && conn.State == ConnectionState.Open) conn.Close();
}
}
public async Task<IEnumerable<NovedadesCanillasReporteDto>> GetReporteNovedadesAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
{
using var connection = _connectionFactory.CreateConnection();
var parameters = new
{
idEmpresa,
fechaDesde = fechaDesde.Date, // Enviar solo la fecha
fechaHasta = fechaHasta.Date.AddDays(1).AddTicks(-1) // Para incluir todo el día hasta las 23:59:59.999...
};
// El nombre del SP en el archivo es SP_DistCanillasNovedades
return await connection.QueryAsync<NovedadesCanillasReporteDto>(
"dbo.SP_DistCanillasNovedades", // Asegúrate que el nombre del SP sea exacto
parameters,
commandType: CommandType.StoredProcedure
);
}
public async Task<IEnumerable<CanillaGananciaReporteDto>> GetReporteGananciasAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
{
using var connection = _connectionFactory.CreateConnection();
var parameters = new
{
idEmpresa,
fechaDesde = fechaDesde.Date,
fechaHasta = fechaHasta.Date // El SP SP_DistCanillasGanancias maneja el rango inclusivo directamente
};
return await connection.QueryAsync<CanillaGananciaReporteDto>(
"dbo.SP_DistCanillasGanancias", // Nombre del SP
parameters,
commandType: CommandType.StoredProcedure
);
}
public async Task<IEnumerable<(NovedadCanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idNovedadOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Novedad, h.Id_Canilla, h.Fecha, h.Detalle,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtNovedadesCanillas_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 (idNovedadOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Novedad = @IdNovedadOriginalParam"); parameters.Add("IdNovedadOriginalParam", idNovedadOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<NovedadCanillaHistorico, string, (NovedadCanillaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Novedades de Canillitas.");
return Enumerable.Empty<(NovedadCanillaHistorico, string)>();
}
}
}
}

View File

@@ -185,5 +185,47 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(OtroDestinoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idOtroDestinoOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Destino, h.Nombre, h.Obs,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtOtrosDestinos_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 (idOtroDestinoOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Destino = @IdOtroDestinoOriginalParam"); parameters.Add("IdOtroDestinoOriginalParam", idOtroDestinoOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<OtroDestinoHistorico, string, (OtroDestinoHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Otros Destinos (Maestro).");
return Enumerable.Empty<(OtroDestinoHistorico, string)>();
}
}
} }
} }

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion namespace GestionIntegral.Api.Data.Repositories.Distribucion
@@ -253,5 +254,50 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
throw; throw;
} }
} }
public async Task<IEnumerable<(PorcMonCanillaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPorcMonOriginal, int? idPublicacionOriginal, int? idCanillaOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_PorcMon, h.Id_Publicacion, h.Id_Canilla,
h.VigenciaD, h.VigenciaH, h.PorcMon, h.EsPorcentaje,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_PorcMonPagoCanilla_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 (idPorcMonOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_PorcMon = @IdPorcMonOriginalParam"); parameters.Add("IdPorcMonOriginalParam", idPorcMonOriginal.Value); }
if (idPublicacionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionOriginalParam"); parameters.Add("IdPublicacionOriginalParam", idPublicacionOriginal.Value); }
if (idCanillaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Canilla = @IdCanillaOriginalParam"); parameters.Add("IdCanillaOriginalParam", idCanillaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PorcMonCanillaHistorico, string, (PorcMonCanillaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Porcentajes/Montos Canillita.");
return Enumerable.Empty<(PorcMonCanillaHistorico, string)>();
}
}
} }
} }

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion namespace GestionIntegral.Api.Data.Repositories.Distribucion
@@ -247,5 +248,50 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
throw; throw;
} }
} }
public async Task<IEnumerable<(PorcPagoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPorcentajeOriginal, int? idPublicacionOriginal, int? idDistribuidorOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Porcentaje, h.Id_Publicacion, h.Id_Distribuidor,
h.VigenciaD, h.VigenciaH, h.Porcentaje,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_PorcPago_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 (idPorcentajeOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Porcentaje = @IdPorcentajeOriginalParam"); parameters.Add("IdPorcentajeOriginalParam", idPorcentajeOriginal.Value); }
if (idPublicacionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionOriginalParam"); parameters.Add("IdPublicacionOriginalParam", idPublicacionOriginal.Value); }
if (idDistribuidorOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Distribuidor = @IdDistribuidorOriginalParam"); parameters.Add("IdDistribuidorOriginalParam", idDistribuidorOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PorcPagoHistorico, string, (PorcPagoHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Porcentajes de Pago (Distribuidores).");
return Enumerable.Empty<(PorcPagoHistorico, string)>();
}
}
} }
} }

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion namespace GestionIntegral.Api.Data.Repositories.Distribucion
@@ -138,8 +139,13 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
IdPublicacionHist = inserted.IdPublicacion, IdPublicacionHist = inserted.IdPublicacion,
VigenciaDHist = inserted.VigenciaD, VigenciaDHist = inserted.VigenciaD,
VigenciaHHist = inserted.VigenciaH, VigenciaHHist = inserted.VigenciaH,
LunesHist = inserted.Lunes, MartesHist = inserted.Martes, MiercolesHist = inserted.Miercoles, JuevesHist = inserted.Jueves, LunesHist = inserted.Lunes,
ViernesHist = inserted.Viernes, SabadoHist = inserted.Sabado, DomingoHist = inserted.Domingo, MartesHist = inserted.Martes,
MiercolesHist = inserted.Miercoles,
JuevesHist = inserted.Jueves,
ViernesHist = inserted.Viernes,
SabadoHist = inserted.Sabado,
DomingoHist = inserted.Domingo,
IdUsuarioHist = idUsuario, IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now, FechaModHist = DateTime.Now,
TipoModHist = "Creado" TipoModHist = "Creado"
@@ -171,8 +177,13 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
IdPublicacionHist = actual.IdPublicacion, IdPublicacionHist = actual.IdPublicacion,
VigenciaDHist = actual.VigenciaD, VigenciaDHist = actual.VigenciaD,
VigenciaHHist = actual.VigenciaH, VigenciaHHist = actual.VigenciaH,
LunesHist = actual.Lunes, MartesHist = actual.Martes, MiercolesHist = actual.Miercoles, JuevesHist = actual.Jueves, LunesHist = actual.Lunes,
ViernesHist = actual.Viernes, SabadoHist = actual.Sabado, DomingoHist = actual.Domingo, MartesHist = actual.Martes,
MiercolesHist = actual.Miercoles,
JuevesHist = actual.Jueves,
ViernesHist = actual.Viernes,
SabadoHist = actual.Sabado,
DomingoHist = actual.Domingo,
IdUsuarioHist = idUsuario, IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now, FechaModHist = DateTime.Now,
TipoModHist = "Actualizado" TipoModHist = "Actualizado"
@@ -202,8 +213,13 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
IdPublicacionHist = actual.IdPublicacion, IdPublicacionHist = actual.IdPublicacion,
VigenciaDHist = actual.VigenciaD, VigenciaDHist = actual.VigenciaD,
VigenciaHHist = actual.VigenciaH, VigenciaHHist = actual.VigenciaH,
LunesHist = actual.Lunes, MartesHist = actual.Martes, MiercolesHist = actual.Miercoles, JuevesHist = actual.Jueves, LunesHist = actual.Lunes,
ViernesHist = actual.Viernes, SabadoHist = actual.Sabado, DomingoHist = actual.Domingo, MartesHist = actual.Martes,
MiercolesHist = actual.Miercoles,
JuevesHist = actual.Jueves,
ViernesHist = actual.Viernes,
SabadoHist = actual.Sabado,
DomingoHist = actual.Domingo,
IdUsuarioHist = idUsuario, IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now, FechaModHist = DateTime.Now,
TipoModHist = "Eliminado" TipoModHist = "Eliminado"
@@ -237,8 +253,13 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
IdPublicacionHist = item.IdPublicacion, IdPublicacionHist = item.IdPublicacion,
VigenciaDHist = item.VigenciaD, VigenciaDHist = item.VigenciaD,
VigenciaHHist = item.VigenciaH, VigenciaHHist = item.VigenciaH,
LunesHist = item.Lunes, MartesHist = item.Martes, MiercolesHist = item.Miercoles, JuevesHist = item.Jueves, LunesHist = item.Lunes,
ViernesHist = item.Viernes, SabadoHist = item.Sabado, DomingoHist = item.Domingo, MartesHist = item.Martes,
MiercolesHist = item.Miercoles,
JuevesHist = item.Jueves,
ViernesHist = item.Viernes,
SabadoHist = item.Sabado,
DomingoHist = item.Domingo,
IdUsuarioHist = idUsuarioAuditoria, IdUsuarioHist = idUsuarioAuditoria,
FechaModHist = DateTime.Now, FechaModHist = DateTime.Now,
TipoModHist = "Eliminado (Cascada)" TipoModHist = "Eliminado (Cascada)"
@@ -257,5 +278,82 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
throw; throw;
} }
} }
public async Task<bool> IsInUseAsync(int idPrecio, DateTime vigenciaD, DateTime? vigenciaH)
{
// Verificar si el Id_Precio se usa en movimientos DENTRO del rango de vigencia del precio
// Si VigenciaH es NULL, significa que el precio está activo indefinidamente hacia el futuro.
var sql = @"
SELECT TOP 1 1
FROM (
SELECT Id_Precio, Fecha FROM dbo.dist_EntradasSalidas
UNION ALL
SELECT Id_Precio, Fecha FROM dbo.dist_EntradasSalidasCanillas
) AS Movimientos
WHERE Movimientos.Id_Precio = @IdPrecioParam
AND Movimientos.Fecha >= @VigenciaDParam
AND (@VigenciaHParam IS NULL OR Movimientos.Fecha <= @VigenciaHParam);";
try
{
using var connection = _connectionFactory.CreateConnection();
var parameters = new
{
IdPrecioParam = idPrecio,
VigenciaDParam = vigenciaD.Date,
VigenciaHParam = vigenciaH?.Date
};
var inUse = await connection.ExecuteScalarAsync<int?>(sql, parameters);
return inUse.HasValue && inUse.Value == 1;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error en IsInUseAsync para Precio ID: {IdPrecio}", idPrecio);
return true; // Asumir en uso si hay error, para ser cauteloso
}
}
public async Task<IEnumerable<(PrecioHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPrecioOriginal, int? idPublicacionOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Precio, h.Id_Publicacion, h.VigenciaD, h.VigenciaH,
h.Lunes, h.Martes, h.Miercoles, h.Jueves, h.Viernes, h.Sabado, h.Domingo,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_Precios_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 (idPrecioOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Precio = @IdPrecioOriginalParam"); parameters.Add("IdPrecioOriginalParam", idPrecioOriginal.Value); }
if (idPublicacionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionOriginalParam"); parameters.Add("IdPublicacionOriginalParam", idPublicacionOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PrecioHistorico, string, (PrecioHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Precios de Publicación.");
return Enumerable.Empty<(PrecioHistorico, string)>();
}
}
} }
} }

View File

@@ -235,5 +235,48 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
throw; throw;
} }
} }
public async Task<IEnumerable<(PubliSeccionHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idSeccionOriginal, int? idPublicacionOriginal)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Seccion, h.Id_Publicacion, h.Nombre, h.Estado,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtPubliSecciones_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 (idSeccionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Seccion = @IdSeccionOriginalParam"); parameters.Add("IdSeccionOriginalParam", idSeccionOriginal.Value); }
if (idPublicacionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionOriginalParam"); parameters.Add("IdPublicacionOriginalParam", idPublicacionOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PubliSeccionHistorico, string, (PubliSeccionHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Secciones de Publicación.");
return Enumerable.Empty<(PubliSeccionHistorico, string)>();
}
}
} }
} }

View File

@@ -139,32 +139,33 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<bool> IsInUseAsync(int id) public async Task<bool> IsInUseAsync(int idPublicacion)
{ {
using var connection = _connectionFactory.CreateConnection(); using var connection = _connectionFactory.CreateConnection();
string[] checkQueries = { string[] checkQueries = {
"SELECT TOP 1 1 FROM dbo.dist_EntradasSalidas WHERE Id_Publicacion = @IdParam", "SELECT TOP 1 1 FROM dbo.dist_EntradasSalidas WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.dist_EntradasSalidasCanillas WHERE Id_Publicacion = @IdParam", "SELECT TOP 1 1 FROM dbo.dist_EntradasSalidasCanillas WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.dist_Precios WHERE Id_Publicacion = @IdParam", "SELECT TOP 1 1 FROM dbo.dist_SalidasOtrosDestinos WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.dist_RecargoZona WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.dist_PorcPago WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.dist_PorcMonPagoCanilla WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.dist_dtPubliSecciones WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.bob_RegPublicaciones WHERE Id_Publicacion = @IdParam", "SELECT TOP 1 1 FROM dbo.bob_RegPublicaciones WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.bob_StockBobinas WHERE Id_Publicacion = @IdParam" "SELECT TOP 1 1 FROM dbo.bob_RegTiradas WHERE Id_Publicacion = @IdParam",
"SELECT TOP 1 1 FROM dbo.bob_StockBobinas WHERE Id_Publicacion = @IdParam AND Id_EstadoBobina != 1" // Ejemplo: si una bobina EN USO o DAÑADA está asociada
}; };
try try
{ {
foreach (var query in checkQueries) foreach (var query in checkQueries)
{ {
if (await connection.ExecuteScalarAsync<int?>(query, new { IdParam = id }) == 1) return true; if (await connection.ExecuteScalarAsync<int?>(query, new { IdParam = idPublicacion }) == 1)
{
_logger.LogInformation("Publicacion ID {IdPublicacion} está en uso (Tabla: {Tabla})", idPublicacion, query.Split("FROM")[1].Split("WHERE")[0].Trim());
return true;
}
} }
return false; return false;
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error en IsInUseAsync para Publicacion ID: {IdPublicacion}", id); _logger.LogError(ex, "Error en IsInUseAsync para Publicacion ID: {IdPublicacion}", idPublicacion);
return true; // Asumir en uso si hay error de BD return true; // Asumir en uso si hay error
} }
} }
@@ -325,7 +326,48 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
); );
await Task.WhenAll(insertTasks); await Task.WhenAll(insertTasks);
} }
// No se necesita historial para esta tabla de configuración por ahora. }
public async Task<IEnumerable<(PublicacionHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPublicacionOriginal)
{
using var connection = _connectionFactory.CreateConnection(); // Asumiendo _connectionFactory
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Publicacion, h.Nombre, h.Observacion, h.Id_Empresa, h.Habilitada,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtPublicaciones_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 (idPublicacionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionOriginalParam"); parameters.Add("IdPublicacionOriginalParam", idPublicacionOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PublicacionHistorico, string, (PublicacionHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Publicaciones (Maestro)."); // Asumiendo _logger
return Enumerable.Empty<(PublicacionHistorico, string)>();
}
} }
} }
} }

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; // Necesario para .Any() using System.Linq; // Necesario para .Any()
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace GestionIntegral.Api.Data.Repositories.Distribucion namespace GestionIntegral.Api.Data.Repositories.Distribucion
@@ -48,6 +49,39 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
} }
} }
public async Task<bool> IsInUseAsync(int idRecargo, DateTime vigenciaD, DateTime? vigenciaH)
{
// Similar a Precios, verificar en dist_EntradasSalidas y dist_EntradasSalidasCanillas
// si Id_Recargo se usa en movimientos DENTRO del rango de vigencia del recargo.
var sql = @"
SELECT TOP 1 1
FROM (
SELECT Id_Recargo, Fecha FROM dbo.dist_EntradasSalidas
UNION ALL
SELECT Id_Recargo, Fecha FROM dbo.dist_EntradasSalidasCanillas
) AS Movimientos
WHERE Movimientos.Id_Recargo = @IdRecargoParam
AND Movimientos.Fecha >= @VigenciaDParam
AND (@VigenciaHParam IS NULL OR Movimientos.Fecha <= @VigenciaHParam);";
try
{
using var connection = _connectionFactory.CreateConnection();
var parameters = new
{
IdRecargoParam = idRecargo,
VigenciaDParam = vigenciaD.Date,
VigenciaHParam = vigenciaH?.Date
};
var inUse = await connection.ExecuteScalarAsync<int?>(sql, parameters);
return inUse.HasValue && inUse.Value == 1;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error en IsInUseAsync para Recargo ID: {IdRecargo}", idRecargo);
return true;
}
}
public async Task<RecargoZona?> GetByIdAsync(int idRecargo) public async Task<RecargoZona?> GetByIdAsync(int idRecargo)
{ {
const string sql = @" const string sql = @"
@@ -260,5 +294,49 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
throw; throw;
} }
} }
public async Task<IEnumerable<(RecargoZonaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idRecargoOriginal, int? idPublicacionOriginal, int? idZonaOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Recargo, h.Id_Publicacion, h.Id_Zona, h.VigenciaD, h.VigenciaH, h.Valor,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_RecargoZona_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 (idRecargoOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Recargo = @IdRecargoOriginalParam"); parameters.Add("IdRecargoOriginalParam", idRecargoOriginal.Value); }
if (idPublicacionOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionOriginalParam"); parameters.Add("IdPublicacionOriginalParam", idPublicacionOriginal.Value); }
if (idZonaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Zona = @IdZonaOriginalParam"); parameters.Add("IdZonaOriginalParam", idZonaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<RecargoZonaHistorico, string, (RecargoZonaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Recargos por Zona.");
return Enumerable.Empty<(RecargoZonaHistorico, string)>();
}
}
} }
} }

View File

@@ -301,5 +301,46 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
return true; // Asumir que está en uso si hay error return true; // Asumir que está en uso si hay error
} }
} }
public async Task<IEnumerable<(ZonaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idZonaOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Zona, h.Nombre, h.Descripcion, h.Estado,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.dist_dtZonas_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 (idZonaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Zona = @IdZonaOriginalParam"); parameters.Add("IdZonaOriginalParam", idZonaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<ZonaHistorico, string, (ZonaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Zonas (Maestro).");
return Enumerable.Empty<(ZonaHistorico, string)>();
}
}
} }
} }

View File

@@ -204,5 +204,47 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(EstadoBobinaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idEstadoBobinaOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_EstadoBobina, h.Denominacion, h.Obs,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.bob_dtEstadosBobinas_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 (idEstadoBobinaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_EstadoBobina = @IdEstadoBobinaOriginalParam"); parameters.Add("IdEstadoBobinaOriginalParam", idEstadoBobinaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<EstadoBobinaHistorico, string, (EstadoBobinaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Estados de Bobina.");
return Enumerable.Empty<(EstadoBobinaHistorico, string)>();
}
}
} }
} }

View File

@@ -14,5 +14,9 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByDenominacionAsync(string denominacion, int? excludeId = null); Task<bool> ExistsByDenominacionAsync(string denominacion, int? excludeId = null);
Task<bool> IsInUseAsync(int id); // Verificar si se usa en bob_StockBobinas Task<bool> IsInUseAsync(int id); // Verificar si se usa en bob_StockBobinas
Task<IEnumerable<(EstadoBobinaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idEstadoBobinaOriginal);
} }
} }

View File

@@ -14,5 +14,9 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); // Borrado físico con historial Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); // Borrado físico con historial
Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null); Task<bool> ExistsByNameAsync(string nombre, int? excludeId = null);
Task<bool> IsInUseAsync(int id); // Verificar si se usa en bob_StockBobinas o bob_RegPublicaciones Task<bool> IsInUseAsync(int id); // Verificar si se usa en bob_StockBobinas o bob_RegPublicaciones
Task<IEnumerable<(PlantaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPlantaOriginal);
} }
} }

View File

@@ -14,7 +14,15 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
Task<bool> DeleteAsync(int idRegistro, int idUsuario, IDbTransaction transaction); // Si se borra el registro principal Task<bool> DeleteAsync(int idRegistro, int idUsuario, IDbTransaction transaction); // Si se borra el registro principal
Task<bool> DeleteByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, int idUsuario, IDbTransaction transaction); Task<bool> DeleteByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, int idUsuario, IDbTransaction transaction);
Task<RegTirada?> GetByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, IDbTransaction? transaction = null); Task<RegTirada?> GetByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, IDbTransaction? transaction = null);
Task<IEnumerable<(RegTiradaHistorico Historial, string NombreUsuarioModifico, string NombrePublicacion, string NombrePlanta)>> GetRegTiradasHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idRegistroOriginal, int? idPublicacionFiltro, int? idPlantaFiltro, DateTime? fechaTiradaFiltro);
Task<IEnumerable<(RegPublicacionSeccionHistorico Historial, string NombreUsuarioModifico, string NombrePublicacion, string NombreSeccion, string NombrePlanta)>> GetRegSeccionesTiradaHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idTiradaOriginal, // ID del registro en bob_RegPublicaciones
int? idPublicacionFiltro, int? idSeccionFiltro, int? idPlantaFiltro, DateTime? fechaTiradaFiltro);
} }
public interface IRegPublicacionSeccionRepository // Para bob_RegPublicaciones public interface IRegPublicacionSeccionRepository // Para bob_RegPublicaciones

View File

@@ -22,5 +22,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
Task<StockBobina?> CreateAsync(StockBobina nuevaBobina, int idUsuario, IDbTransaction transaction); Task<StockBobina?> CreateAsync(StockBobina nuevaBobina, int idUsuario, IDbTransaction transaction);
Task<bool> UpdateAsync(StockBobina bobinaAActualizar, int idUsuario, IDbTransaction transaction, string tipoMod = "Actualizada"); // tipoMod para historial Task<bool> UpdateAsync(StockBobina bobinaAActualizar, int idUsuario, IDbTransaction transaction, string tipoMod = "Actualizada"); // tipoMod para historial
Task<bool> DeleteAsync(int idBobina, int idUsuario, IDbTransaction transaction); // Solo si está en estado "Disponible" Task<bool> DeleteAsync(int idBobina, int idUsuario, IDbTransaction transaction); // Solo si está en estado "Disponible"
Task<IEnumerable<(StockBobinaHistorico Historial, string NombreUsuarioModifico, string? NombreTipoBobina, string? NombrePlanta, string? NombreEstadoBobina, string? NombrePublicacion, string? NombreSeccion)>> GetHistorialDetalladoAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idBobinaOriginal, int? idTipoBobinaFiltro, int? idPlantaFiltro, int? idEstadoBobinaFiltro);
} }
} }

View File

@@ -14,5 +14,9 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction); Task<bool> DeleteAsync(int id, int idUsuario, IDbTransaction transaction);
Task<bool> ExistsByDenominacionAsync(string denominacion, int? excludeId = null); Task<bool> ExistsByDenominacionAsync(string denominacion, int? excludeId = null);
Task<bool> IsInUseAsync(int id); // Verificar si se usa en bob_StockBobinas Task<bool> IsInUseAsync(int id); // Verificar si se usa en bob_StockBobinas
Task<IEnumerable<(TipoBobinaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idTipoBobinaOriginal);
} }
} }

View File

@@ -225,5 +225,47 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(PlantaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPlantaOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Planta, h.Nombre, h.Detalle,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.bob_dtPlantas_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 (idPlantaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Planta = @IdPlantaOriginalParam"); parameters.Add("IdPlantaOriginalParam", idPlantaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PlantaHistorico, string, (PlantaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Plantas de Impresión.");
return Enumerable.Empty<(PlantaHistorico, string)>();
}
}
} }
} }

View File

@@ -69,9 +69,16 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdRegistroParam = inserted.IdRegistro, EjemplaresParam = inserted.Ejemplares, IdPublicacionParam = inserted.IdPublicacion, FechaParam = inserted.Fecha, IdPlantaParam = inserted.IdPlanta, {
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" IdRegistroParam = inserted.IdRegistro,
EjemplaresParam = inserted.Ejemplares,
IdPublicacionParam = inserted.IdPublicacion,
FechaParam = inserted.Fecha,
IdPlantaParam = inserted.IdPlanta,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Creado"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -84,9 +91,16 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
const string sqlDelete = "DELETE FROM dbo.bob_RegTiradas WHERE Id_Registro = @IdRegistroParam"; const string sqlDelete = "DELETE FROM dbo.bob_RegTiradas WHERE Id_Registro = @IdRegistroParam";
const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdRegistroParam = actual.IdRegistro, EjemplaresParam = actual.Ejemplares, IdPublicacionParam = actual.IdPublicacion, FechaParam = actual.Fecha, IdPlantaParam = actual.IdPlanta, {
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado" IdRegistroParam = actual.IdRegistro,
EjemplaresParam = actual.Ejemplares,
IdPublicacionParam = actual.IdPublicacion,
FechaParam = actual.Fecha,
IdPlantaParam = actual.IdPlanta,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Eliminado"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdRegistroParam = idRegistro }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdRegistroParam = idRegistro }, transaction);
@@ -100,9 +114,16 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
{ {
const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdRegistroParam = actual.IdRegistro, EjemplaresParam = actual.Ejemplares, IdPublicacionParam = actual.IdPublicacion, FechaParam = actual.Fecha, IdPlantaParam = actual.IdPlanta, {
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado (Por Fecha/Pub/Planta)" IdRegistroParam = actual.IdRegistro,
EjemplaresParam = actual.Ejemplares,
IdPublicacionParam = actual.IdPublicacion,
FechaParam = actual.Fecha,
IdPlantaParam = actual.IdPlanta,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Eliminado (Por Fecha/Pub/Planta)"
}, transaction); }, transaction);
} }
@@ -111,6 +132,108 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
new { FechaParam = fecha.Date, IdPublicacionParam = idPublicacion, IdPlantaParam = idPlanta }, transaction); new { FechaParam = fecha.Date, IdPublicacionParam = idPublicacion, IdPlantaParam = idPlanta }, transaction);
return rowsAffected > 0; // Devuelve true si se borró al menos una fila return rowsAffected > 0; // Devuelve true si se borró al menos una fila
} }
public async Task<IEnumerable<(RegTiradaHistorico Historial, string NombreUsuarioModifico, string NombrePublicacion, string NombrePlanta)>> GetRegTiradasHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idRegistroOriginal, int? idPublicacionFiltro, int? idPlantaFiltro, DateTime? fechaTiradaFiltro)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Registro, h.Ejemplares, h.Id_Publicacion, h.Fecha, h.Id_Planta,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico,
pub.Nombre AS NombrePublicacion,
p.Nombre AS NombrePlanta
FROM dbo.bob_RegTiradas_H h
JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id
JOIN dbo.dist_dtPublicaciones pub ON h.Id_Publicacion = pub.Id_Publicacion
JOIN dbo.bob_dtPlantas p ON h.Id_Planta = p.Id_Planta
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 (idRegistroOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Registro = @IdRegistroOriginalParam"); parameters.Add("IdRegistroOriginalParam", idRegistroOriginal.Value); }
if (idPublicacionFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionFiltroParam"); parameters.Add("IdPublicacionFiltroParam", idPublicacionFiltro.Value); }
if (idPlantaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Planta = @IdPlantaFiltroParam"); parameters.Add("IdPlantaFiltroParam", idPlantaFiltro.Value); }
if (fechaTiradaFiltro.HasValue) { sqlBuilder.Append(" AND h.Fecha = @FechaTiradaFiltroParam"); parameters.Add("FechaTiradaFiltroParam", fechaTiradaFiltro.Value.Date); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<RegTiradaHistorico, string, string, string, (RegTiradaHistorico, string, string, string)>(
sqlBuilder.ToString(),
(hist, userMod, pubNombre, plantaNombre) => (hist, userMod, pubNombre, plantaNombre),
parameters,
splitOn: "NombreUsuarioModifico,NombrePublicacion,NombrePlanta"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Registro de Tiradas.");
return Enumerable.Empty<(RegTiradaHistorico, string, string, string)>();
}
}
public async Task<IEnumerable<(RegPublicacionSeccionHistorico Historial, string NombreUsuarioModifico, string NombrePublicacion, string NombreSeccion, string NombrePlanta)>> GetRegSeccionesTiradaHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idTiradaOriginal, int? idPublicacionFiltro, int? idSeccionFiltro, int? idPlantaFiltro, DateTime? fechaTiradaFiltro)
{
using var connection = _cf.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Tirada, h.Id_Publicacion, h.Id_Seccion, h.CantPag, h.Fecha, h.Id_Planta,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico,
pub.Nombre AS NombrePublicacion,
sec.Nombre AS NombreSeccion,
p.Nombre AS NombrePlanta
FROM dbo.bob_RegPublicaciones_H h
JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id
JOIN dbo.dist_dtPublicaciones pub ON h.Id_Publicacion = pub.Id_Publicacion
JOIN dbo.dist_dtPubliSecciones sec ON h.Id_Seccion = sec.Id_Seccion
AND h.Id_Publicacion = sec.Id_Publicacion -- Crucial para el JOIN correcto de sección
JOIN dbo.bob_dtPlantas p ON h.Id_Planta = p.Id_Planta
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 (idTiradaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Tirada = @IdTiradaOriginalParam"); parameters.Add("IdTiradaOriginalParam", idTiradaOriginal.Value); }
if (idPublicacionFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionFiltroParam"); parameters.Add("IdPublicacionFiltroParam", idPublicacionFiltro.Value); }
if (idSeccionFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Seccion = @IdSeccionFiltroParam"); parameters.Add("IdSeccionFiltroParam", idSeccionFiltro.Value); }
if (idPlantaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Planta = @IdPlantaFiltroParam"); parameters.Add("IdPlantaFiltroParam", idPlantaFiltro.Value); }
if (fechaTiradaFiltro.HasValue) { sqlBuilder.Append(" AND h.Fecha = @FechaTiradaFiltroParam"); parameters.Add("FechaTiradaFiltroParam", fechaTiradaFiltro.Value.Date); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<RegPublicacionSeccionHistorico, string, string, string, string, (RegPublicacionSeccionHistorico, string, string, string, string)>(
sqlBuilder.ToString(),
(hist, userMod, pubNombre, secNombre, plantaNombre) => (hist, userMod, pubNombre, secNombre, plantaNombre),
parameters,
splitOn: "NombreUsuarioModifico,NombrePublicacion,NombreSeccion,NombrePlanta"
);
return result;
}
catch (Exception ex)
{
_log.LogError(ex, "Error al obtener historial de Secciones de Tirada.");
return Enumerable.Empty<(RegPublicacionSeccionHistorico, string, string, string, string)>();
}
}
} }
public class RegPublicacionSeccionRepository : IRegPublicacionSeccionRepository public class RegPublicacionSeccionRepository : IRegPublicacionSeccionRepository
@@ -138,9 +261,17 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
const string sqlHistorico = @"INSERT INTO dbo.bob_RegPublicaciones_H (Id_Tirada, Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) const string sqlHistorico = @"INSERT INTO dbo.bob_RegPublicaciones_H (Id_Tirada, Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdTiradaParam, @IdPublicacionParam, @IdSeccionParam, @CantPagParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdTiradaParam, @IdPublicacionParam, @IdSeccionParam, @CantPagParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdTiradaParam = inserted.IdTirada, IdPublicacionParam = inserted.IdPublicacion, IdSeccionParam = inserted.IdSeccion, CantPagParam = inserted.CantPag, FechaParam = inserted.Fecha, IdPlantaParam = inserted.IdPlanta, {
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" IdTiradaParam = inserted.IdTirada,
IdPublicacionParam = inserted.IdPublicacion,
IdSeccionParam = inserted.IdSeccion,
CantPagParam = inserted.CantPag,
FechaParam = inserted.Fecha,
IdPlantaParam = inserted.IdPlanta,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Creado"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -153,9 +284,17 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
{ {
const string sqlHistorico = @"INSERT INTO dbo.bob_RegPublicaciones_H (Id_Tirada, Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) const string sqlHistorico = @"INSERT INTO dbo.bob_RegPublicaciones_H (Id_Tirada, Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdTiradaParam, @IdPublicacionParam, @IdSeccionParam, @CantPagParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; VALUES (@IdTiradaParam, @IdPublicacionParam, @IdSeccionParam, @CantPagParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);";
await transaction.Connection!.ExecuteAsync(sqlHistorico, new { await transaction.Connection!.ExecuteAsync(sqlHistorico, new
IdTiradaParam = actual.IdTirada, IdPublicacionParam = actual.IdPublicacion, IdSeccionParam = actual.IdSeccion, CantPagParam = actual.CantPag, FechaParam = actual.Fecha, IdPlantaParam = actual.IdPlanta, {
IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado (Por Fecha/Pub/Planta)" IdTiradaParam = actual.IdTirada,
IdPublicacionParam = actual.IdPublicacion,
IdSeccionParam = actual.IdSeccion,
CantPagParam = actual.CantPag,
FechaParam = actual.Fecha,
IdPlantaParam = actual.IdPlanta,
IdUsuarioParam = idUsuario,
FechaModParam = DateTime.Now,
TipoModParam = "Eliminado (Por Fecha/Pub/Planta)"
}, transaction); }, transaction);
} }

View File

@@ -147,10 +147,21 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new
{ {
IdBobinaHist = inserted.IdBobina, IdTipoBobinaHist = inserted.IdTipoBobina, NroBobinaHist = inserted.NroBobina, PesoHist = inserted.Peso, IdBobinaHist = inserted.IdBobina,
IdPlantaHist = inserted.IdPlanta, IdEstadoBobinaHist = inserted.IdEstadoBobina, RemitoHist = inserted.Remito, FechaRemitoHist = inserted.FechaRemito, IdTipoBobinaHist = inserted.IdTipoBobina,
FechaEstadoHist = inserted.FechaEstado, IdPublicacionHist = inserted.IdPublicacion, IdSeccionHist = inserted.IdSeccion, ObsHist = inserted.Obs, NroBobinaHist = inserted.NroBobina,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Ingreso" PesoHist = inserted.Peso,
IdPlantaHist = inserted.IdPlanta,
IdEstadoBobinaHist = inserted.IdEstadoBobina,
RemitoHist = inserted.Remito,
FechaRemitoHist = inserted.FechaRemito,
FechaEstadoHist = inserted.FechaEstado,
IdPublicacionHist = inserted.IdPublicacion,
IdSeccionHist = inserted.IdSeccion,
ObsHist = inserted.Obs,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Ingreso"
}, transaction); }, transaction);
return inserted; return inserted;
} }
@@ -180,10 +191,21 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new
{ {
IdBobinaHist = actual.IdBobina, IdTipoBobinaHist = actual.IdTipoBobina, NroBobinaHist = actual.NroBobina, PesoHist = actual.Peso, IdBobinaHist = actual.IdBobina,
IdPlantaHist = actual.IdPlanta, IdEstadoBobinaHist = actual.IdEstadoBobina, RemitoHist = actual.Remito, FechaRemitoHist = actual.FechaRemito, IdTipoBobinaHist = actual.IdTipoBobina,
FechaEstadoHist = actual.FechaEstado, IdPublicacionHist = actual.IdPublicacion, IdSeccionHist = actual.IdSeccion, ObsHist = actual.Obs, NroBobinaHist = actual.NroBobina,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = tipoMod // "Actualizada" o "Estado Cambiado" PesoHist = actual.Peso,
IdPlantaHist = actual.IdPlanta,
IdEstadoBobinaHist = actual.IdEstadoBobina,
RemitoHist = actual.Remito,
FechaRemitoHist = actual.FechaRemito,
FechaEstadoHist = actual.FechaEstado,
IdPublicacionHist = actual.IdPublicacion,
IdSeccionHist = actual.IdSeccion,
ObsHist = actual.Obs,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = tipoMod // "Actualizada" o "Estado Cambiado"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, bobinaAActualizar, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, bobinaAActualizar, transaction);
@@ -192,23 +214,24 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
public async Task<bool> DeleteAsync(int idBobina, int idUsuario, IDbTransaction transaction) public async Task<bool> DeleteAsync(int idBobina, int idUsuario, IDbTransaction transaction)
{ {
// Normalmente, una bobina en stock no se "elimina" físicamente si ya tuvo movimientos. var connection = transaction.Connection!; // Asegurar que la conexión no es null
// Este método sería para borrar un ingreso erróneo que aún esté "Disponible". var actual = await connection.QuerySingleOrDefaultAsync<StockBobina>(
var actual = await transaction.Connection!.QuerySingleOrDefaultAsync<StockBobina>(
@"SELECT Id_Bobina AS IdBobina, Id_TipoBobina AS IdTipoBobina, NroBobina, Peso, @"SELECT Id_Bobina AS IdBobina, Id_TipoBobina AS IdTipoBobina, NroBobina, Peso,
Id_Planta AS IdPlanta, Id_EstadoBobina AS IdEstadoBobina, Remito, FechaRemito, Id_Planta AS IdPlanta, Id_EstadoBobina AS IdEstadoBobina, Remito, FechaRemito,
FechaEstado, Id_Publicacion AS IdPublicacion, Id_Seccion AS IdSeccion, Obs FechaEstado, Id_Publicacion AS IdPublicacion, Id_Seccion AS IdSeccion, Obs
FROM dbo.bob_StockBobinas WHERE Id_Bobina = @IdBobinaParam", FROM dbo.bob_StockBobinas WHERE Id_Bobina = @IdBobinaParam",
new { IdBobinaParam = idBobina }, transaction); new { IdBobinaParam = idBobina }, transaction);
if (actual == null) throw new KeyNotFoundException("Bobina no encontrada para eliminar."); if (actual == null) throw new KeyNotFoundException("Bobina no encontrada para eliminar.");
// VALIDACIÓN IMPORTANTE: Solo permitir borrar si está en estado "Disponible" (o el que se defina) // --- INICIO DE CAMBIO EN VALIDACIÓN ---
if (actual.IdEstadoBobina != 1) // Asumiendo 1 = Disponible // Permitir eliminar si está Disponible (1) o Dañada (3)
if (actual.IdEstadoBobina != 1 && actual.IdEstadoBobina != 3)
{ {
_logger.LogWarning("Intento de eliminar bobina {IdBobina} que no está en estado 'Disponible'. Estado actual: {EstadoActual}", idBobina, actual.IdEstadoBobina); _logger.LogWarning("Intento de eliminar bobina {IdBobina} que no está en estado 'Disponible' o 'Dañada'. Estado actual: {EstadoActual}", idBobina, actual.IdEstadoBobina);
// No lanzar excepción para que la transacción no falle si es una validación de negocio return false; // Devolver false si no cumple la condición para ser eliminada
return false;
} }
// --- FIN DE CAMBIO EN VALIDACIÓN ---
const string sqlDelete = "DELETE FROM dbo.bob_StockBobinas WHERE Id_Bobina = @IdBobinaParam"; const string sqlDelete = "DELETE FROM dbo.bob_StockBobinas WHERE Id_Bobina = @IdBobinaParam";
const string sqlInsertHistorico = @" const string sqlInsertHistorico = @"
@@ -216,17 +239,84 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion
(Id_Bobina, Id_TipoBobina, NroBobina, Peso, Id_Planta, Id_EstadoBobina, Remito, FechaRemito, FechaEstado, Id_Publicacion, Id_Seccion, Obs, Id_Usuario, FechaMod, TipoMod) (Id_Bobina, Id_TipoBobina, NroBobina, Peso, Id_Planta, Id_EstadoBobina, Remito, FechaRemito, FechaEstado, Id_Publicacion, Id_Seccion, Obs, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdBobinaHist, @IdTipoBobinaHist, @NroBobinaHist, @PesoHist, @IdPlantaHist, @IdEstadoBobinaHist, @RemitoHist, @FechaRemitoHist, @FechaEstadoHist, @IdPublicacionHist, @IdSeccionHist, @ObsHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; VALUES (@IdBobinaHist, @IdTipoBobinaHist, @NroBobinaHist, @PesoHist, @IdPlantaHist, @IdEstadoBobinaHist, @RemitoHist, @FechaRemitoHist, @FechaEstadoHist, @IdPublicacionHist, @IdSeccionHist, @ObsHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
await connection.ExecuteAsync(sqlInsertHistorico, new
await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new
{ {
IdBobinaHist = actual.IdBobina, IdTipoBobinaHist = actual.IdTipoBobina, NroBobinaHist = actual.NroBobina, PesoHist = actual.Peso, IdBobinaHist = actual.IdBobina,
IdPlantaHist = actual.IdPlanta, IdEstadoBobinaHist = actual.IdEstadoBobina, RemitoHist = actual.Remito, FechaRemitoHist = actual.FechaRemito, IdTipoBobinaHist = actual.IdTipoBobina,
FechaEstadoHist = actual.FechaEstado, IdPublicacionHist = actual.IdPublicacion, IdSeccionHist = actual.IdSeccion, ObsHist = actual.Obs, NroBobinaHist = actual.NroBobina,
IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Eliminada" PesoHist = actual.Peso,
IdPlantaHist = actual.IdPlanta,
IdEstadoBobinaHist = actual.IdEstadoBobina,
RemitoHist = actual.Remito,
FechaRemitoHist = actual.FechaRemito,
FechaEstadoHist = actual.FechaEstado,
IdPublicacionHist = actual.IdPublicacion,
IdSeccionHist = actual.IdSeccion,
ObsHist = actual.Obs,
IdUsuarioHist = idUsuario,
FechaModHist = DateTime.Now,
TipoModHist = "Eliminada"
}, transaction); }, transaction);
var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdBobinaParam = idBobina }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { IdBobinaParam = idBobina }, transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(StockBobinaHistorico Historial, string NombreUsuarioModifico, string? NombreTipoBobina, string? NombrePlanta, string? NombreEstadoBobina, string? NombrePublicacion, string? NombreSeccion)>> GetHistorialDetalladoAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idBobinaOriginal, int? idTipoBobinaFiltro, int? idPlantaFiltro, int? idEstadoBobinaFiltro)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_Bobina, h.Id_TipoBobina, h.NroBobina, h.Peso, h.Id_Planta, h.Id_EstadoBobina,
h.Remito, h.FechaRemito, h.FechaEstado, h.Id_Publicacion, h.Id_Seccion, h.Obs,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico,
tb.Denominacion AS NombreTipoBobina,
p.Nombre AS NombrePlanta,
eb.Denominacion AS NombreEstadoBobina,
pub.Nombre AS NombrePublicacion,
sec.Nombre AS NombreSeccion
FROM dbo.bob_StockBobinas_H h
JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id
LEFT JOIN dbo.bob_dtBobinas tb ON h.Id_TipoBobina = tb.Id_TipoBobina
LEFT JOIN dbo.bob_dtPlantas p ON h.Id_Planta = p.Id_Planta
LEFT JOIN dbo.bob_dtEstadosBobinas eb ON h.Id_EstadoBobina = eb.Id_EstadoBobina
LEFT JOIN dbo.dist_dtPublicaciones pub ON h.Id_Publicacion = pub.Id_Publicacion
LEFT JOIN dbo.dist_dtPubliSecciones sec ON h.Id_Seccion = sec.Id_Seccion
AND h.Id_Publicacion = sec.Id_Publicacion -- Asegurar que la sección pertenezca a la publicación
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 (idBobinaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Bobina = @IdBobinaOriginalParam"); parameters.Add("IdBobinaOriginalParam", idBobinaOriginal.Value); }
if (idTipoBobinaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_TipoBobina = @IdTipoBobinaFiltroParam"); parameters.Add("IdTipoBobinaFiltroParam", idTipoBobinaFiltro.Value); }
if (idPlantaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Planta = @IdPlantaFiltroParam"); parameters.Add("IdPlantaFiltroParam", idPlantaFiltro.Value); }
if (idEstadoBobinaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_EstadoBobina = @IdEstadoBobinaFiltroParam"); parameters.Add("IdEstadoBobinaFiltroParam", idEstadoBobinaFiltro.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<StockBobinaHistorico, string, string, string, string, string, string, (StockBobinaHistorico, string, string?, string?, string?, string?, string?)>(
sqlBuilder.ToString(),
(hist, userMod, tipoBob, planta, estadoBob, pub, secc) => (hist, userMod, tipoBob, planta, estadoBob, pub, secc),
parameters,
splitOn: "NombreUsuarioModifico,NombreTipoBobina,NombrePlanta,NombreEstadoBobina,NombrePublicacion,NombreSeccion"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial detallado de Stock de Bobinas.");
return Enumerable.Empty<(StockBobinaHistorico, string, string?, string?, string?, string?, string?)>();
}
}
} }
} }

View File

@@ -101,8 +101,6 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
} }
} }
// --- Métodos de Escritura (USAN TRANSACCIÓN) ---
public async Task<TipoBobina?> CreateAsync(TipoBobina nuevoTipoBobina, int idUsuario, IDbTransaction transaction) public async Task<TipoBobina?> CreateAsync(TipoBobina nuevoTipoBobina, int idUsuario, IDbTransaction transaction)
{ {
const string sqlInsert = @" const string sqlInsert = @"
@@ -199,5 +197,47 @@ namespace GestionIntegral.Api.Data.Repositories.Impresion
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(TipoBobinaHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idTipoBobinaOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.Id_TipoBobina, h.Denominacion,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.bob_dtBobinas_H h -- Nombre de tabla de historial correcto
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 (idTipoBobinaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_TipoBobina = @IdTipoBobinaOriginalParam"); parameters.Add("IdTipoBobinaOriginalParam", idTipoBobinaOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<TipoBobinaHistorico, string, (TipoBobinaHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Tipos de Bobina.");
return Enumerable.Empty<(TipoBobinaHistorico, string)>();
}
}
} }
} }

View File

@@ -43,5 +43,7 @@ namespace GestionIntegral.Api.Data.Repositories.Reportes
Task<(IEnumerable<ListadoDistribucionDistSimpleDto> Simple, IEnumerable<ListadoDistribucionDistPromedioDiaDto> Promedios, string? Error)> ObtenerListadoDistribucionDistribuidoresAsync(int idDistribuidor, int idPublicacion, DateTime fechaDesde, DateTime fechaHasta); Task<(IEnumerable<ListadoDistribucionDistSimpleDto> Simple, IEnumerable<ListadoDistribucionDistPromedioDiaDto> Promedios, string? Error)> ObtenerListadoDistribucionDistribuidoresAsync(int idDistribuidor, int idPublicacion, DateTime fechaDesde, DateTime fechaHasta);
Task<IEnumerable<LiquidacionCanillaDetalleDto>> GetLiquidacionCanillaDetalleAsync(DateTime fecha, int idCanilla); Task<IEnumerable<LiquidacionCanillaDetalleDto>> GetLiquidacionCanillaDetalleAsync(DateTime fecha, int idCanilla);
Task<IEnumerable<LiquidacionCanillaGananciaDto>> GetLiquidacionCanillaGananciasAsync(DateTime fecha, int idCanilla); Task<IEnumerable<LiquidacionCanillaGananciaDto>> GetLiquidacionCanillaGananciasAsync(DateTime fecha, int idCanilla);
Task<IEnumerable<ListadoDistCanMensualDiariosDto>> GetReporteMensualDiariosAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista);
Task<IEnumerable<ListadoDistCanMensualPubDto>> GetReporteMensualPorPublicacionAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista);
} }
} }

View File

@@ -515,5 +515,37 @@ namespace GestionIntegral.Api.Data.Repositories.Reportes
return Enumerable.Empty<LiquidacionCanillaGananciaDto>(); return Enumerable.Empty<LiquidacionCanillaGananciaDto>();
} }
} }
public async Task<IEnumerable<ListadoDistCanMensualDiariosDto>> GetReporteMensualDiariosAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
{
using var connection = _dbConnectionFactory.CreateConnection();
var parameters = new
{
fechaDesde = fechaDesde.Date,
fechaHasta = fechaHasta.Date, // El SP parece manejar el rango incluyendo el último día
accionista = esAccionista
};
return await connection.QueryAsync<ListadoDistCanMensualDiariosDto>(
"dbo.SP_DistCanillasAccConImporteEntreFechasDiarios",
parameters,
commandType: CommandType.StoredProcedure
);
}
public async Task<IEnumerable<ListadoDistCanMensualPubDto>> GetReporteMensualPorPublicacionAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
{
using var connection = _dbConnectionFactory.CreateConnection();
var parameters = new
{
fechaDesde = fechaDesde.Date,
fechaHasta = fechaHasta.Date,
accionista = esAccionista
};
return await connection.QueryAsync<ListadoDistCanMensualPubDto>(
"dbo.SP_DistCanillasAccConImporteEntreFechas",
parameters,
commandType: CommandType.StoredProcedure
);
}
} }
} }

View File

@@ -16,5 +16,14 @@ namespace GestionIntegral.Api.Data.Repositories.Usuarios
Task<bool> IsInUseAsync(int id); Task<bool> IsInUseAsync(int id);
Task<IEnumerable<int>> GetPermisoIdsByPerfilIdAsync(int idPerfil); Task<IEnumerable<int>> GetPermisoIdsByPerfilIdAsync(int idPerfil);
Task UpdatePermisosByPerfilIdAsync(int idPerfil, IEnumerable<int> nuevosPermisosIds, IDbTransaction transaction); Task UpdatePermisosByPerfilIdAsync(int idPerfil, IEnumerable<int> nuevosPermisosIds, IDbTransaction transaction);
Task LogPermisoAsignacionHistorialAsync(int idPerfil, int idPermiso, int idUsuario, string tipoMod, IDbTransaction transaction);
Task<IEnumerable<(PerfilHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPerfilOriginal);
Task<IEnumerable<(PermisosPerfilesHistorico Historial, string NombreUsuarioModifico, string NombrePerfil, string DescPermiso, string CodAccPermiso)>> GetPermisosAsignadosHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPerfilAfectado, int? idPermisoAfectado);
} }
} }

View File

@@ -15,5 +15,9 @@ namespace GestionIntegral.Api.Data.Repositories.Usuarios
Task<bool> ExistsByCodAccAsync(string codAcc, int? excludeId = null); Task<bool> ExistsByCodAccAsync(string codAcc, int? excludeId = null);
Task<bool> IsInUseAsync(int id); Task<bool> IsInUseAsync(int id);
Task<IEnumerable<Permiso>> GetPermisosByIdsAsync(IEnumerable<int> ids); Task<IEnumerable<Permiso>> GetPermisosByIdsAsync(IEnumerable<int> ids);
Task<IEnumerable<(PermisoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPermisoOriginal);
} }
} }

View File

@@ -240,11 +240,112 @@ namespace GestionIntegral.Api.Data.Repositories.Usuarios
var permisosParaInsertar = nuevosPermisosIds.Select(idPermiso => new { IdPerfil = idPerfil, IdPermiso = idPermiso }); var permisosParaInsertar = nuevosPermisosIds.Select(idPermiso => new { IdPerfil = idPerfil, IdPermiso = idPermiso });
await connection.ExecuteAsync(sqlInsert, permisosParaInsertar, transaction: transaction); await connection.ExecuteAsync(sqlInsert, permisosParaInsertar, transaction: transaction);
} }
// No hay tabla _H para gral_PermisosPerfiles directamente en este diseño. }
// La auditoría de qué usuario cambió los permisos de un perfil se podría registrar
// en una tabla de log de acciones más general si fuera necesario, o deducir public async Task LogPermisoAsignacionHistorialAsync(int idPerfil, int idPermiso, int idUsuario, string tipoMod, IDbTransaction transaction)
// indirectamente si la interfaz de usuario solo permite a SuperAdmin hacer esto. {
const string sql = @"
INSERT INTO dbo.gral_PermisosPerfiles_H (idPerfil, idPermiso, Id_Usuario, FechaMod, TipoMod)
VALUES (@IdPerfil, @IdPermiso, @IdUsuario, @FechaMod, @TipoMod);";
await transaction.Connection!.ExecuteAsync(sql, new
{
IdPerfil = idPerfil,
IdPermiso = idPermiso,
IdUsuario = idUsuario,
FechaMod = DateTime.Now,
TipoMod = tipoMod
}, transaction: transaction);
}
public async Task<IEnumerable<(PerfilHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPerfilOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.idPerfil, h.perfil, h.descPerfil, -- Campos de gral_Perfiles_H
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.gral_Perfiles_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 (idPerfilOriginal.HasValue) { sqlBuilder.Append(" AND h.idPerfil = @IdPerfilOriginalParam"); parameters.Add("IdPerfilOriginalParam", idPerfilOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PerfilHistorico, string, (PerfilHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Perfiles.");
return Enumerable.Empty<(PerfilHistorico, string)>();
} }
} }
public async Task<IEnumerable<(PermisosPerfilesHistorico Historial, string NombreUsuarioModifico, string NombrePerfil, string DescPermiso, string CodAccPermiso)>> GetPermisosAsignadosHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPerfilAfectado, int? idPermisoAfectado)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.IdHist, h.idPerfil, h.idPermiso,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico,
pf.perfil AS NombrePerfil,
p.descPermiso AS DescPermiso,
p.codAcc AS CodAccPermiso
FROM dbo.gral_PermisosPerfiles_H h
JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id
JOIN dbo.gral_Perfiles pf ON h.idPerfil = pf.id
JOIN dbo.gral_Permisos p ON h.idPermiso = p.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 (idPerfilAfectado.HasValue) { sqlBuilder.Append(" AND h.idPerfil = @IdPerfilAfectadoParam"); parameters.Add("IdPerfilAfectadoParam", idPerfilAfectado.Value); }
if (idPermisoAfectado.HasValue) { sqlBuilder.Append(" AND h.idPermiso = @IdPermisoAfectadoParam"); parameters.Add("IdPermisoAfectadoParam", idPermisoAfectado.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PermisosPerfilesHistorico, string, string, string, string, (PermisosPerfilesHistorico, string, string, string, string)>(
sqlBuilder.ToString(),
(hist, userMod, perf, desc, cod) => (hist, userMod, perf, desc, cod),
parameters,
splitOn: "NombreUsuarioModifico,NombrePerfil,DescPermiso,CodAccPermiso"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Asignación de Permisos.");
return Enumerable.Empty<(PermisosPerfilesHistorico, string, string, string, string)>();
}
}
}
} }

View File

@@ -227,5 +227,47 @@ namespace GestionIntegral.Api.Data.Repositories.Usuarios
var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction: transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction: transaction);
return rowsAffected == 1; return rowsAffected == 1;
} }
public async Task<IEnumerable<(PermisoHistorico Historial, string NombreUsuarioModifico)>> GetHistorialAsync(
DateTime? fechaDesde, DateTime? fechaHasta,
int? idUsuarioModifico, string? tipoModificacion,
int? idPermisoOriginal)
{
using var connection = _connectionFactory.CreateConnection();
var sqlBuilder = new StringBuilder(@"
SELECT
h.IdHist, h.idPermiso, h.modulo, h.descPermiso, h.codAcc,
h.Id_Usuario, h.FechaMod, h.TipoMod,
u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico
FROM dbo.gral_Permisos_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 (idPermisoOriginal.HasValue) { sqlBuilder.Append(" AND h.idPermiso = @IdPermisoOriginalParam"); parameters.Add("IdPermisoOriginalParam", idPermisoOriginal.Value); }
sqlBuilder.Append(" ORDER BY h.FechaMod DESC;");
try
{
var result = await connection.QueryAsync<PermisoHistorico, string, (PermisoHistorico, string)>(
sqlBuilder.ToString(),
(hist, userName) => (hist, userName),
parameters,
splitOn: "NombreUsuarioModifico"
);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al obtener historial de Permisos (Maestro).");
return Enumerable.Empty<(PermisoHistorico, string)>();
}
}
} }
} }

View File

@@ -0,0 +1,37 @@
# --- Etapa 1: Build ---
# Usamos el SDK de .NET 9 (o el que corresponda) para compilar.
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
# Copiamos los archivos de proyecto (.sln y .csproj) y restauramos las dependencias.
# Esto es una optimización de caché de Docker.
COPY GestionIntegralWeb.sln .
COPY Backend/GestionIntegral.Api/GestionIntegral.Api.csproj Backend/GestionIntegral.Api/
# Restauramos los paquetes NuGet.
RUN dotnet restore "GestionIntegralWeb.sln"
# Copiamos todo el resto del código fuente.
COPY . .
# Nos movemos al directorio del proyecto y lo construimos en modo Release.
WORKDIR "/src/Backend/GestionIntegral.Api"
RUN dotnet build "GestionIntegral.Api.csproj" -c Release -o /app/build
# --- Etapa 2: Publish ---
# Publicamos la aplicación, lo que genera los artefactos listos para producción.
FROM build AS publish
RUN dotnet publish "GestionIntegral.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false
# --- Etapa 3: Final ---
# Usamos la imagen de runtime de ASP.NET, que es mucho más ligera que el SDK.
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /app
COPY --from=publish /app/publish .
# El puerto en el que la API escuchará DENTRO del contenedor.
# Usaremos 8080 para evitar conflictos si en el futuro corres algo en el puerto 80.
EXPOSE 8080
# El comando para iniciar la API cuando el contenedor arranque.
ENTRYPOINT ["dotnet", "GestionIntegral.Api.dll"]

View File

@@ -0,0 +1,9 @@
public class Saldo
{
public int IdSaldo { get; set; }
public string Destino { get; set; } = string.Empty;
public int IdDestino { get; set; }
public decimal Monto { get; set; }
public int IdEmpresa { get; set; }
public DateTime FechaUltimaModificacion { get; set; }
}

View File

@@ -0,0 +1,19 @@
using System;
namespace GestionIntegral.Api.Models.Contables
{
public class SaldoAjusteHistorial
{
public int IdSaldoAjusteHist { get; set; } // PK, Identity
public string Destino { get; set; } = string.Empty;
public int IdDestino { get; set; }
public int IdEmpresa { get; set; }
public decimal MontoAjuste { get; set; } // El monto que se sumó/restó
public decimal SaldoAnterior { get; set; }
public decimal SaldoNuevo { get; set; }
public string Justificacion { get; set; } = string.Empty;
public DateTime FechaAjuste { get; set; }
public int IdUsuarioAjuste { get; set; }
// Podrías añadir NombreUsuarioAjuste si quieres desnormalizar o hacer un JOIN al consultar
}
}

View File

@@ -1,12 +1,14 @@
using System;
namespace GestionIntegral.Api.Models.Contables namespace GestionIntegral.Api.Models.Contables
{ {
public class TipoPagoHistorico public class TipoPagoHistorico
{ {
public int IdTipoPago { get; set; } // Este NO es IDENTITY public int Id_TipoPago { get; set; } // ID del TipoPago original
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
public string? Detalle { get; set; } public string? Detalle { get; set; }
public int IdUsuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; // "Insertada", "Modificada", "Eliminada" public string TipoMod { get; set; } = string.Empty;
} }
} }

View File

@@ -0,0 +1,13 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion
{
public class CambioParadaCanilla
{
public int IdRegistro { get; set; } // Id_Registro (PK, Identity)
public int IdCanilla { get; set; } // Id_Canilla (FK)
public string Parada { get; set; } = string.Empty; // Parada (nueva dirección)
public DateTime VigenciaD { get; set; } // VigenciaD (fecha desde que aplica la nueva parada)
public DateTime? VigenciaH { get; set; } // VigenciaH (fecha hasta que aplicó esta parada, NULL si es la actual)
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion
{
public class CambioParadaCanillaHistorial
{
public int Id_Registro { get; set; } // FK al registro original
public int Id_Canilla { get; set; }
public string Parada { get; set; } = string.Empty;
public DateTime VigenciaD { get; set; }
public DateTime? VigenciaH { get; set; } // Nullable
public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -1,19 +1,19 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class CanillaHistorico public class CanillaHistorico // Corresponde a dist_dtCanillas_H
{ {
public int IdCanilla { get; set; } public int Id_Canilla { get; set; }
public int? Legajo { get; set; } public int? Legajo { get; set; }
public string NomApe { get; set; } = string.Empty; public string NomApe { get; set; } = string.Empty;
public string? Parada { get; set; } public string? Parada { get; set; }
public int IdZona { get; set; } public int Id_Zona { get; set; }
public bool Accionista { get; set; } public bool Accionista { get; set; }
public string? Obs { get; set; } public string? Obs { get; set; }
public int Empresa { get; set; } public int Empresa { get; set; }
public bool Baja { get; set; } public bool Baja { get; set; }
public DateTime? FechaBaja { get; set; } public DateTime? FechaBaja { get; set; }
// Campos de Auditoría
public int Id_Usuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;

View File

@@ -1,10 +1,10 @@
using System; using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class ControlDevolucionesHistorico // Corresponde a dist_dtCtrlDevoluciones_H public class ControlDevolucionesHistorico // Corresponde a dist_dtCtrlDevoluciones_H
{ {
// No hay PK explícita en _H public int Id_Control { get; set; } // ID del ControlDevoluciones original
public int Id_Control { get; set; } // Coincide con columna en _H
public int Id_Empresa { get; set; } public int Id_Empresa { get; set; }
public DateTime Fecha { get; set; } public DateTime Fecha { get; set; }
public int Entrada { get; set; } public int Entrada { get; set; }

View File

@@ -1,12 +1,14 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class DistribuidorHistorico public class DistribuidorHistorico // Corresponde a dist_dtDistribuidores_H
{ {
public int IdDistribuidor { get; set; } // FK public int Id_Distribuidor { get; set; }
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
public string? Contacto { get; set; } public string? Contacto { get; set; }
public string NroDoc { get; set; } = string.Empty; public string NroDoc { get; set; } = string.Empty;
public int? IdZona { get; set; } public int? Id_Zona { get; set; }
public string? Calle { get; set; } public string? Calle { get; set; }
public string? Numero { get; set; } public string? Numero { get; set; }
public string? Piso { get; set; } public string? Piso { get; set; }
@@ -14,8 +16,6 @@ namespace GestionIntegral.Api.Models.Distribucion
public string? Telefono { get; set; } public string? Telefono { get; set; }
public string? Email { get; set; } public string? Email { get; set; }
public string? Localidad { get; set; } public string? Localidad { get; set; }
// Campos de Auditoría
public int Id_Usuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;

View File

@@ -1,11 +1,13 @@
namespace GestionIntegral.Api.Models.Empresas using System;
namespace GestionIntegral.Api.Models.Distribucion
{ {
public class EmpresaHistorico public class EmpresaHistorico // Corresponde a dist_dtEmpresas_H
{ {
public int IdEmpresa { get; set; } public int Id_Empresa { get; set; } // ID de la Empresa original
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
public string? Detalle { get; set; } public string? Detalle { get; set; }
public int IdUsuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;
} }

View File

@@ -0,0 +1,23 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion // Asegúrate que este namespace sea el correcto
{
public class EntradaSalidaCanillaHistorico
{
public int Id_Parte { get; set; }
public int Id_Publicacion { get; set; }
public int Id_Canilla { get; set; }
public DateTime Fecha { get; set; }
public int CantSalida { get; set; }
public int CantEntrada { get; set; }
public int Id_Precio { get; set; }
public int Id_Recargo { get; set; }
public int Id_PorcMon { get; set; }
public string? Observacion { get; set; }
public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
// El campo Liquidado, FechaLiquidado, UserLiq no están en dist_EntradasSalidasCanillas_H según tu script.
// Si los necesitas auditar, deberías añadirlos a la tabla _H y al modelo.
}
}

View File

@@ -0,0 +1,10 @@
namespace GestionIntegral.Api.Models.Distribucion
{
public class NovedadCanilla
{
public int IdNovedad { get; set; }
public int IdCanilla { get; set; }
public DateTime Fecha { get; set; }
public string? Detalle { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
namespace GestionIntegral.Api.Models.Distribucion
{
public class NovedadCanillaHistorial
{
// No tiene un ID propio, es una tabla de historial puro
public int IdNovedad { get; set; } // FK a la novedad original
public int IdCanilla { get; set; }
public DateTime Fecha { get; set; }
public string? Detalle { get; set; }
public int IdUsuario { get; set; } // Quién hizo el cambio
public DateTime FechaMod { get; set; } // Cuándo se hizo el cambio
public required string TipoMod { get; set; } // "Insertada", "Modificada", "Eliminada"
}
}

View File

@@ -0,0 +1,20 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion // Asegúrate que el namespace sea el correcto
{
public class NovedadCanillaHistorico // Corresponde a la tabla dist_dtNovedadesCanillas_H
{
// Columnas de la tabla dist_dtNovedadesCanillas_H
// No hay una PK propia en la tabla _H, se referencia por Id_Novedad de la tabla principal
public int Id_Novedad { get; set; }
public int Id_Canilla { get; set; }
public DateTime Fecha { get; set; } // Fecha original de la novedad
public string? Detalle { get; set; }
// Columnas de auditoría estándar
public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -1,19 +1,14 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class OtroDestinoHistorico public class OtroDestinoHistorico // Corresponde a dist_dtOtrosDestinos_H
{ {
// Columna: Id_Destino (int, FK) public int Id_Destino { get; set; } // ID del OtroDestino original
public int IdDestino { get; set; }
// Columna: Nombre (varchar(100), NOT NULL)
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
// Columna: Obs (varchar(250), NULL)
public string? Obs { get; set; } public string? Obs { get; set; }
public int Id_Usuario { get; set; }
// Columnas de Auditoría
public int IdUsuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; // "Insertada", "Modificada", "Eliminada" public string TipoMod { get; set; } = string.Empty;
} }
} }

View File

@@ -2,9 +2,9 @@ using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class PorcMonCanillaHistorico public class PorcMonCanillaHistorico // Corresponde a dist_PorcMonPagoCanilla_H
{ {
public int Id_PorcMon { get; set; } // Coincide con la columna public int Id_PorcMon { get; set; } // ID del PorcMon original
public int Id_Publicacion { get; set; } public int Id_Publicacion { get; set; }
public int Id_Canilla { get; set; } public int Id_Canilla { get; set; }
public DateTime VigenciaD { get; set; } public DateTime VigenciaD { get; set; }

View File

@@ -1,15 +1,16 @@
using System; using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class PorcPagoHistorico public class PorcPagoHistorico // Corresponde a dist_PorcPago_H
{ {
public int IdPorcentaje { get; set; } // Id_Porcentaje public int Id_Porcentaje { get; set; } // ID del PorcPago original
public int IdPublicacion { get; set; } public int Id_Publicacion { get; set; }
public int IdDistribuidor { get; set; } public int Id_Distribuidor { get; set; }
public DateTime VigenciaD { get; set; } public DateTime VigenciaD { get; set; } // smalldatetime en BD, DateTime en C# está bien
public DateTime? VigenciaH { get; set; } public DateTime? VigenciaH { get; set; }
public decimal Porcentaje { get; set; } public decimal Porcentaje { get; set; }
public int IdUsuario { get; set; } // Coincide con Id_Usuario en la tabla _H public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;
} }

View File

@@ -1,9 +1,11 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class PrecioHistorico public class PrecioHistorico // Corresponde a dist_Precios_H
{ {
public int IdPrecio { get; set; } // FK a dist_Precios.Id_Precio public int Id_Precio { get; set; } // ID del Precio original
public int IdPublicacion { get; set; } public int Id_Publicacion { get; set; }
public DateTime VigenciaD { get; set; } public DateTime VigenciaD { get; set; }
public DateTime? VigenciaH { get; set; } public DateTime? VigenciaH { get; set; }
public decimal? Lunes { get; set; } public decimal? Lunes { get; set; }
@@ -13,8 +15,6 @@ namespace GestionIntegral.Api.Models.Distribucion
public decimal? Viernes { get; set; } public decimal? Viernes { get; set; }
public decimal? Sabado { get; set; } public decimal? Sabado { get; set; }
public decimal? Domingo { get; set; } public decimal? Domingo { get; set; }
// Campos de Auditoría
public int Id_Usuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;

View File

@@ -2,10 +2,10 @@ using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class PubliSeccionHistorico public class PubliSeccionHistorico // Corresponde a dist_dtPubliSecciones_H
{ {
public int Id_Seccion { get; set; } // Coincide con la columna public int Id_Seccion { get; set; } // ID de la Sección original
public int Id_Publicacion { get; set; } public int Id_Publicacion { get; set; } // A qué publicación pertenecía en ese momento
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
public bool Estado { get; set; } public bool Estado { get; set; }
public int Id_Usuario { get; set; } public int Id_Usuario { get; set; }

View File

@@ -1,15 +1,15 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class PublicacionHistorico public class PublicacionHistorico // Corresponde a dist_dtPublicaciones_H
{ {
// No hay PK autoincremental explícita en el script de _H public int Id_Publicacion { get; set; } // ID de la Publicacion original
public int IdPublicacion { get; set; }
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
public string? Observacion { get; set; } public string? Observacion { get; set; }
public int IdEmpresa { get; set; } public int Id_Empresa { get; set; }
public bool? Habilitada { get; set; } // Coincide con la tabla _H // public bool CtrlDevoluciones { get; set; } // Parece que no está en _H
public bool? Habilitada { get; set; } // Es nullable en _H
// Campos de Auditoría
public int Id_Usuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;

View File

@@ -1,14 +1,16 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class RecargoZonaHistorico public class RecargoZonaHistorico // Corresponde a dist_RecargoZona_H
{ {
public int IdRecargo { get; set; } public int Id_Recargo { get; set; } // ID del Recargo original
public int IdPublicacion { get; set; } public int Id_Publicacion { get; set; }
public int IdZona { get; set; } public int Id_Zona { get; set; }
public DateTime VigenciaD { get; set; } public DateTime VigenciaD { get; set; }
public DateTime? VigenciaH { get; set; } public DateTime? VigenciaH { get; set; }
public decimal Valor { get; set; } public decimal Valor { get; set; }
public int IdUsuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;
} }

View File

@@ -1,12 +1,14 @@
using System;
namespace GestionIntegral.Api.Models.Distribucion namespace GestionIntegral.Api.Models.Distribucion
{ {
public class ZonaHistorico public class ZonaHistorico
{ {
public int IdZona { get; set; } // NO es IDENTITY public int Id_Zona { get; set; }
public string Nombre { get; set; } = string.Empty; public string Nombre { get; set; } = string.Empty;
public string? Descripcion { get; set; } public string? Descripcion { get; set; }
public bool Estado { get; set; } // Importante para registrar el estado al momento del cambio public bool Estado { get; set; } // El estado de la zona en ese momento del historial
public int IdUsuario { get; set; } public int Id_Usuario { get; set; }
public DateTime FechaMod { get; set; } public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty; public string TipoMod { get; set; } = string.Empty;
} }

View File

@@ -0,0 +1,19 @@
using System;
namespace GestionIntegral.Api.Dtos.Distribucion // O Auditoria
{
public class CambioParadaHistorialDto
{
public int Id_Registro { get; set; }
public int Id_Canilla { get; set; }
public string NombreCanilla { get; set; } = string.Empty; // Para mostrar
public string Parada { get; set; } = string.Empty; // Dirección de la parada en ese momento
public DateTime VigenciaD { get; set; }
public DateTime? VigenciaH { get; set; }
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class CanillaHistorialDto
{
public int Id_Canilla { get; set; }
public int? Legajo { get; set; }
public string NomApe { get; set; } = string.Empty;
public string? Parada { get; set; }
public int Id_Zona { get; set; }
// public string NombreZona { get; set; } // Opcional, si lo quieres traer con JOIN
public bool Accionista { get; set; }
public string? Obs { get; set; }
public int Empresa { get; set; } // Id de la empresa
// public string NombreEmpresa { get; set; } // Opcional
public bool Baja { get; set; }
public DateTime? FechaBaja { get; set; }
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class ControlDevolucionesHistorialDto
{
public int Id_Control { get; set; }
public int Id_Empresa { get; set; }
// public string NombreEmpresa { get; set; } // Opcional
public DateTime Fecha { get; set; } // Fecha original del control
public int Entrada { get; set; }
public int Sobrantes { get; set; }
public string? Detalle { get; set; }
public int SinCargo { get; set; }
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,26 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class DistribuidorHistorialDto
{
public int Id_Distribuidor { get; set; }
public string Nombre { get; set; } = string.Empty;
public string? Contacto { get; set; }
public string NroDoc { get; set; } = string.Empty;
public int? Id_Zona { get; set; }
// public string NombreZona { get; set; } // Opcional
public string? Calle { get; set; }
public string? Numero { get; set; }
public string? Piso { get; set; }
public string? Depto { get; set; }
public string? Telefono { get; set; }
public string? Email { get; set; }
public string? Localidad { get; set; }
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class EmpresaHistorialDto
{
public int Id_Empresa { get; set; }
public string Nombre { get; set; } = string.Empty;
public string? Detalle { get; set; }
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,31 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class EntradaSalidaCanillaHistorialDto
{
// Campos de la tabla _H (dist_EntradasSalidasCanillas_H)
public int Id_Parte { get; set; } // ID del movimiento original
public int Id_Publicacion { get; set; }
// public string NombrePublicacion { get; set; } // Opcional
public int Id_Canilla { get; set; }
// public string NombreCanilla { get; set; } // Opcional
public DateTime Fecha { get; set; } // Fecha original del movimiento
public int CantSalida { get; set; }
public int CantEntrada { get; set; }
public int Id_Precio { get; set; }
public int Id_Recargo { get; set; }
public int Id_PorcMon { get; set; } // ID de la config de Porcentaje/Monto
public string? Observacion { get; set; }
// Nota: Los campos Liquidado, FechaLiquidado, UserLiq del historial
// podrían o no ser relevantes para mostrar en esta auditoría de *cambios de datos*.
// Si un cambio fue "Liquidado = true", el TipoMod sería "Liquidada" o similar.
// Podrías incluirlos si quieres ver el estado de liquidación en el momento del cambio.
// Campos de auditoría
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,28 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class EntradaSalidaDistHistorialDto
{
// Campos de la tabla _H (dist_EntradasSalidas_H)
public int Id_Parte { get; set; } // ID del movimiento original
public int Id_Publicacion { get; set; }
// public string NombrePublicacion { get; set; } // Opcional
public int Id_Distribuidor { get; set; }
// public string NombreDistribuidor { get; set; } // Opcional
public DateTime Fecha { get; set; } // Fecha original del movimiento
public string TipoMovimiento { get; set; } = string.Empty;
public int Cantidad { get; set; }
public int Remito { get; set; }
public string? Observacion { get; set; }
public int Id_Precio { get; set; }
public int Id_Recargo { get; set; }
public int Id_Porcentaje { get; set; }
// Campos de auditoría
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class EstadoBobinaHistorialDto
{
public int Id_EstadoBobina { get; set; }
public string Denominacion { get; set; } = string.Empty;
public string? Obs { get; set; }
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

View File

@@ -0,0 +1,26 @@
using System;
namespace GestionIntegral.Api.Dtos.Auditoria
{
public class NotaCreditoDebitoHistorialDto
{
// Campos de la tabla _H (cue_CreditosDebitos_H)
public int Id_Nota { get; set; } // ID de la nota original
public string Destino { get; set; } = string.Empty;
public int Id_Destino { get; set; }
// public string NombreDestinatario { get; set; } // Opcional, si lo quieres traer con JOIN
public string? Referencia { get; set; }
public string Tipo { get; set; } = string.Empty; // "Debito" o "Credito"
public DateTime Fecha { get; set; } // Fecha original de la nota
public decimal Monto { get; set; }
public string? Observaciones { get; set; }
public int Id_Empresa { get; set; }
// public string NombreEmpresa { get; set; } // Opcional
// Campos de auditoría
public int Id_Usuario { get; set; }
public string NombreUsuarioModifico { get; set; } = string.Empty;
public DateTime FechaMod { get; set; }
public string TipoMod { get; set; } = string.Empty;
}
}

Some files were not shown because too many files have changed in this diff Show More