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.
			
			
This commit is contained in:
		| @@ -0,0 +1,165 @@ | ||||
| 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}"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user