Files

165 lines
7.9 KiB
C#
Raw Permalink Normal View History

feat: Implementación de Secciones, Recargos, Porc. Pago Dist. y backend E/S Dist. Backend API: - Recargos por Zona (`dist_RecargoZona`): - CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador). - Endpoints anidados bajo `/publicaciones/{idPublicacion}/recargos`. - Lógica de negocio para vigencias (cierre/reapertura de períodos). - Auditoría en `dist_RecargoZona_H`. - Porcentajes de Pago Distribuidores (`dist_PorcPago`): - CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador). - Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajespago`. - Lógica de negocio para vigencias. - Auditoría en `dist_PorcPago_H`. - Porcentajes/Montos Pago Canillitas (`dist_PorcMonPagoCanilla`): - CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador). - Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajesmoncanilla`. - Lógica de negocio para vigencias. - Auditoría en `dist_PorcMonPagoCanilla_H`. - Secciones de Publicación (`dist_dtPubliSecciones`): - CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador). - Endpoints anidados bajo `/publicaciones/{idPublicacion}/secciones`. - Auditoría en `dist_dtPubliSecciones_H`. - Entradas/Salidas Distribuidores (`dist_EntradasSalidas`): - Implementado backend (Modelos, DTOs, Repositorio, Servicio, Controlador). - Lógica para determinar precios/recargos/porcentajes aplicables. - Cálculo de monto y afectación de saldos de distribuidores en `cue_Saldos`. - Auditoría en `dist_EntradasSalidas_H`. - Correcciones de Mapeo Dapper: - Aplicados alias explícitos en repositorios de RecargoZona, PorcPago, PorcMonCanilla, PubliSeccion, Canilla, Distribuidor y Precio para asegurar mapeo correcto de IDs y columnas. Frontend React: - Recargos por Zona: - `recargoZonaService.ts`. - `RecargoZonaFormModal.tsx` para crear/editar períodos de recargos. - `GestionarRecargosPublicacionPage.tsx` para listar y gestionar recargos por publicación. - Porcentajes de Pago Distribuidores: - `porcPagoService.ts`. - `PorcPagoFormModal.tsx`. - `GestionarPorcentajesPagoPage.tsx`. - Porcentajes/Montos Pago Canillitas: - `porcMonCanillaService.ts`. - `PorcMonCanillaFormModal.tsx`. - `GestionarPorcMonCanillaPage.tsx`. - Secciones de Publicación: - `publiSeccionService.ts`. - `PubliSeccionFormModal.tsx`. - `GestionarSeccionesPublicacionPage.tsx`. - Navegación: - Actualizadas rutas y menús para acceder a la gestión de recargos, porcentajes (dist. y canillita) y secciones desde la vista de una publicación. - Layout: - Uso consistente de `Box` con Flexbox en lugar de `Grid` en nuevos modales y páginas para evitar errores de tipo.
2025-05-21 14:58:52 -03:00
using GestionIntegral.Api.Data;
using GestionIntegral.Api.Data.Repositories.Distribucion;
using GestionIntegral.Api.Dtos.Distribucion;
using GestionIntegral.Api.Models.Distribucion;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace GestionIntegral.Api.Services.Distribucion
{
public class SalidaOtroDestinoService : ISalidaOtroDestinoService
{
private readonly ISalidaOtroDestinoRepository _salidaRepository;
private readonly IPublicacionRepository _publicacionRepository;
private readonly IOtroDestinoRepository _otroDestinoRepository;
private readonly DbConnectionFactory _connectionFactory;
private readonly ILogger<SalidaOtroDestinoService> _logger;
public SalidaOtroDestinoService(
ISalidaOtroDestinoRepository salidaRepository,
IPublicacionRepository publicacionRepository,
IOtroDestinoRepository otroDestinoRepository,
DbConnectionFactory connectionFactory,
ILogger<SalidaOtroDestinoService> logger)
{
_salidaRepository = salidaRepository;
_publicacionRepository = publicacionRepository;
_otroDestinoRepository = otroDestinoRepository;
_connectionFactory = connectionFactory;
_logger = logger;
}
private async Task<SalidaOtroDestinoDto> MapToDto(SalidaOtroDestino salida)
{
if (salida == null) return null!; // Debería ser manejado por el llamador
var publicacion = await _publicacionRepository.GetByIdSimpleAsync(salida.IdPublicacion);
var destino = await _otroDestinoRepository.GetByIdAsync(salida.IdDestino);
return new SalidaOtroDestinoDto
{
IdParte = salida.IdParte,
IdPublicacion = salida.IdPublicacion,
NombrePublicacion = publicacion?.Nombre ?? "Publicación Desconocida",
IdDestino = salida.IdDestino,
NombreDestino = destino?.Nombre ?? "Destino Desconocido",
Fecha = salida.Fecha.ToString("yyyy-MM-dd"),
Cantidad = salida.Cantidad,
Observacion = salida.Observacion
};
}
public async Task<IEnumerable<SalidaOtroDestinoDto>> ObtenerTodosAsync(DateTime? fechaDesde, DateTime? fechaHasta, int? idPublicacion, int? idDestino)
{
var salidas = await _salidaRepository.GetAllAsync(fechaDesde, fechaHasta, idPublicacion, idDestino);
var dtos = new List<SalidaOtroDestinoDto>();
foreach (var salida in salidas)
{
dtos.Add(await MapToDto(salida));
}
return dtos;
}
public async Task<SalidaOtroDestinoDto?> ObtenerPorIdAsync(int idParte)
{
var salida = await _salidaRepository.GetByIdAsync(idParte);
return salida == null ? null : await MapToDto(salida);
}
public async Task<(SalidaOtroDestinoDto? Salida, string? Error)> CrearAsync(CreateSalidaOtroDestinoDto createDto, int idUsuario)
{
if (await _publicacionRepository.GetByIdSimpleAsync(createDto.IdPublicacion) == null)
return (null, "La publicación especificada no existe o no está habilitada.");
if (await _otroDestinoRepository.GetByIdAsync(createDto.IdDestino) == null)
return (null, "El destino especificado no existe.");
var nuevaSalida = new SalidaOtroDestino
{
IdPublicacion = createDto.IdPublicacion,
IdDestino = createDto.IdDestino,
Fecha = createDto.Fecha.Date,
Cantidad = createDto.Cantidad,
Observacion = createDto.Observacion
};
using var connection = _connectionFactory.CreateConnection();
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
using var transaction = connection.BeginTransaction();
try
{
var salidaCreada = await _salidaRepository.CreateAsync(nuevaSalida, idUsuario, transaction);
if (salidaCreada == null) throw new DataException("Error al registrar la salida.");
transaction.Commit();
_logger.LogInformation("SalidaOtroDestino ID {Id} creada por Usuario ID {UserId}.", salidaCreada.IdParte, idUsuario);
return (await MapToDto(salidaCreada), null);
}
catch (Exception ex)
{
try { transaction.Rollback(); } catch { }
_logger.LogError(ex, "Error CrearAsync SalidaOtroDestino para Pub ID {IdPub}", createDto.IdPublicacion);
return (null, $"Error interno: {ex.Message}");
}
}
public async Task<(bool Exito, string? Error)> ActualizarAsync(int idParte, UpdateSalidaOtroDestinoDto updateDto, int idUsuario)
{
using var connection = _connectionFactory.CreateConnection();
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
using var transaction = connection.BeginTransaction();
try
{
var salidaExistente = await _salidaRepository.GetByIdAsync(idParte); // Obtener dentro de TX
if (salidaExistente == null) return (false, "Registro de salida no encontrado.");
// Actualizar solo los campos permitidos
salidaExistente.Cantidad = updateDto.Cantidad;
salidaExistente.Observacion = updateDto.Observacion;
var actualizado = await _salidaRepository.UpdateAsync(salidaExistente, idUsuario, transaction);
if (!actualizado) throw new DataException("Error al actualizar la salida.");
transaction.Commit();
_logger.LogInformation("SalidaOtroDestino ID {Id} actualizada por Usuario ID {UserId}.", idParte, idUsuario);
return (true, null);
}
catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Registro no encontrado."); }
catch (Exception ex)
{
try { transaction.Rollback(); } catch { }
_logger.LogError(ex, "Error ActualizarAsync SalidaOtroDestino ID: {Id}", idParte);
return (false, $"Error interno: {ex.Message}");
}
}
public async Task<(bool Exito, string? Error)> EliminarAsync(int idParte, int idUsuario)
{
using var connection = _connectionFactory.CreateConnection();
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
using var transaction = connection.BeginTransaction();
try
{
var salidaExistente = await _salidaRepository.GetByIdAsync(idParte);
if (salidaExistente == null) return (false, "Registro de salida no encontrado.");
var eliminado = await _salidaRepository.DeleteAsync(idParte, idUsuario, transaction);
if (!eliminado) throw new DataException("Error al eliminar la salida.");
transaction.Commit();
_logger.LogInformation("SalidaOtroDestino ID {Id} eliminada por Usuario ID {UserId}.", idParte, idUsuario);
return (true, null);
}
catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Registro no encontrado."); }
catch (Exception ex)
{
try { transaction.Rollback(); } catch { }
_logger.LogError(ex, "Error EliminarAsync SalidaOtroDestino ID: {Id}", idParte);
return (false, $"Error interno: {ex.Message}");
}
}
}
}