| 
									
										
											  
											
												feat: Implementación módulos Empresas, Plantas, Tipos y Estados Bobina
Backend API:
- Implementado CRUD completo para Empresas (DE001-DE004):
  - EmpresaRepository, EmpresaService, EmpresasController.
  - Lógica de creación/eliminación de saldos iniciales en EmpresaService.
  - Transacciones y registro en tablas _H.
  - Verificación de permisos específicos.
- Implementado CRUD completo para Plantas de Impresión (IP001-IP004):
  - PlantaRepository, PlantaService, PlantasController.
  - Transacciones y registro en tablas _H.
  - Verificación de permisos.
- Implementado CRUD completo para Tipos de Bobina (IB006-IB009):
  - TipoBobinaRepository, TipoBobinaService, TiposBobinaController.
  - Transacciones y registro en tablas _H.
  - Verificación de permisos.
- Implementado CRUD completo para Estados de Bobina (IB010-IB013):
  - EstadoBobinaRepository, EstadoBobinaService, EstadosBobinaController.
  - Transacciones y registro en tablas _H.
  - Verificación de permisos.
Frontend React:
- Módulo Empresas:
  - empresaService.ts para interactuar con la API.
  - EmpresaFormModal.tsx para crear/editar empresas.
  - GestionarEmpresasPage.tsx con tabla, filtro, paginación y menú de acciones.
  - Integración con el hook usePermissions para control de acceso.
- Módulo Plantas de Impresión:
  - plantaService.ts.
  - PlantaFormModal.tsx.
  - GestionarPlantasPage.tsx con tabla, filtro, paginación y acciones.
  - Integración con usePermissions.
- Módulo Tipos de Bobina:
  - tipoBobinaService.ts.
  - TipoBobinaFormModal.tsx.
  - GestionarTiposBobinaPage.tsx con tabla, filtro, paginación y acciones.
  - Integración con usePermissions.
- Módulo Estados de Bobina:
  - estadoBobinaService.ts.
  - EstadoBobinaFormModal.tsx.
  - GestionarEstadosBobinaPage.tsx con tabla, filtro, paginación y acciones.
  - Integración con usePermissions.
- Navegación:
  - Añadidas sub-pestañas y rutas para los nuevos módulos dentro de "Distribución" (Empresas) e "Impresión" (Plantas, Tipos Bobina, Estados Bobina).
  - Creado ImpresionIndexPage.tsx para la navegación interna del módulo de Impresión.
Correcciones:
- Corregido el uso de CommitAsync/RollbackAsync a Commit/Rollback síncronos en PlantaService.cs debido a que IDbTransaction no los soporta asíncronamente.
											
										 
											2025-05-09 10:08:53 -03:00
										 |  |  | using GestionIntegral.Api.Data.Repositories.Contables; | 
					
						
							| 
									
										
										
											
												Fase 3:
- Backend API:
Autenticación y autorización básicas con JWT implementadas.
Cambio de contraseña funcional.
Módulo "Tipos de Pago" (CRUD completo) implementado en el backend (Controlador, Servicio, Repositorio) usando Dapper, transacciones y con lógica de historial.
Se incluyen permisos en el token JWT.
- Frontend React:
Estructura base con Vite, TypeScript, MUI.
Contexto de autenticación (AuthContext) que maneja el estado del usuario y el token.
Página de Login.
Modal de Cambio de Contraseña (forzado y opcional).
Hook usePermissions para verificar permisos.
Página GestionarTiposPagoPage con tabla, paginación, filtro, modal para crear/editar, y menú de acciones, respetando permisos.
Layout principal (MainLayout) con navegación por Tabs (funcionalidad básica de navegación).
Estructura de enrutamiento (AppRoutes) que maneja rutas públicas, protegidas y anidadas para módulos.
											
										 
											2025-05-07 13:41:18 -03:00
										 |  |  | using GestionIntegral.Api.Dtos.Contables; | 
					
						
							|  |  |  | using GestionIntegral.Api.Models.Contables; // Para TipoPago | 
					
						
							|  |  |  | using GestionIntegral.Api.Services.Contables; | 
					
						
							|  |  |  | using System.Collections.Generic; | 
					
						
							|  |  |  | using System.Linq; | 
					
						
							|  |  |  | using System.Threading.Tasks; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace GestionIntegral.Api.Services.Contables | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     public class TipoPagoService : ITipoPagoService | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         private readonly ITipoPagoRepository _tipoPagoRepository; | 
					
						
							|  |  |  |         private readonly ILogger<TipoPagoService> _logger; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public TipoPagoService(ITipoPagoRepository tipoPagoRepository, ILogger<TipoPagoService> logger) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             _tipoPagoRepository = tipoPagoRepository; | 
					
						
							|  |  |  |             _logger = logger; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public async Task<IEnumerable<TipoPagoDto>> ObtenerTodosAsync(string? nombreFilter) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             var tiposPago = await _tipoPagoRepository.GetAllAsync(nombreFilter); | 
					
						
							|  |  |  |             // Mapeo de Entidad a DTO | 
					
						
							|  |  |  |             return tiposPago.Select(tp => new TipoPagoDto | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 IdTipoPago = tp.IdTipoPago, | 
					
						
							|  |  |  |                 Nombre = tp.Nombre, | 
					
						
							|  |  |  |                 Detalle = tp.Detalle | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public async Task<TipoPagoDto?> ObtenerPorIdAsync(int id) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             var tipoPago = await _tipoPagoRepository.GetByIdAsync(id); | 
					
						
							|  |  |  |             if (tipoPago == null) return null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Mapeo de Entidad a DTO | 
					
						
							|  |  |  |             return new TipoPagoDto | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 IdTipoPago = tipoPago.IdTipoPago, | 
					
						
							|  |  |  |                 Nombre = tipoPago.Nombre, | 
					
						
							|  |  |  |                 Detalle = tipoPago.Detalle | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public async Task<(TipoPagoDto? TipoPago, string? Error)> CrearAsync(CreateTipoPagoDto createDto, int idUsuario) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Validación: Nombre no puede estar duplicado | 
					
						
							|  |  |  |             if (await _tipoPagoRepository.ExistsByNameAsync(createDto.Nombre)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return (null, "El nombre del tipo de pago ya existe."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var nuevoTipoPago = new TipoPago | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Nombre = createDto.Nombre, | 
					
						
							|  |  |  |                 Detalle = createDto.Detalle | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var tipoPagoCreado = await _tipoPagoRepository.CreateAsync(nuevoTipoPago, idUsuario); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (tipoPagoCreado == null) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 _logger.LogError("Falló la creación del Tipo de Pago en el repositorio para el nombre: {Nombre}", createDto.Nombre); | 
					
						
							|  |  |  |                 return (null, "Error al crear el tipo de pago en la base de datos."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Mapeo de Entidad creada (con ID) a DTO | 
					
						
							|  |  |  |             var tipoPagoDto = new TipoPagoDto | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 IdTipoPago = tipoPagoCreado.IdTipoPago, | 
					
						
							|  |  |  |                 Nombre = tipoPagoCreado.Nombre, | 
					
						
							|  |  |  |                 Detalle = tipoPagoCreado.Detalle | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return (tipoPagoDto, null); // Éxito | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateTipoPagoDto updateDto, int idUsuario) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Verificar si el tipo de pago existe | 
					
						
							|  |  |  |             var tipoPagoExistente = await _tipoPagoRepository.GetByIdAsync(id); | 
					
						
							|  |  |  |             if (tipoPagoExistente == null) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return (false, "Tipo de pago no encontrado."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Validación: Nombre no puede estar duplicado (excluyendo el ID actual) | 
					
						
							|  |  |  |             if (await _tipoPagoRepository.ExistsByNameAsync(updateDto.Nombre, id)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return (false, "El nombre del tipo de pago ya existe para otro registro."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Mapeo de DTO a Entidad para actualizar | 
					
						
							|  |  |  |             tipoPagoExistente.Nombre = updateDto.Nombre; | 
					
						
							|  |  |  |             tipoPagoExistente.Detalle = updateDto.Detalle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var actualizado = await _tipoPagoRepository.UpdateAsync(tipoPagoExistente, idUsuario); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!actualizado) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                  _logger.LogError("Falló la actualización del Tipo de Pago en el repositorio para el ID: {Id}", id); | 
					
						
							|  |  |  |                  return (false, "Error al actualizar el tipo de pago en la base de datos."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return (true, null); // Éxito | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Verificar si el tipo de pago existe | 
					
						
							|  |  |  |             var tipoPagoExistente = await _tipoPagoRepository.GetByIdAsync(id); | 
					
						
							|  |  |  |             if (tipoPagoExistente == null) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return (false, "Tipo de pago no encontrado."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Validación: No se puede eliminar si está en uso | 
					
						
							|  |  |  |             if (await _tipoPagoRepository.IsInUseAsync(id)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return (false, "No se puede eliminar. El tipo de pago está siendo utilizado en pagos registrados."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var eliminado = await _tipoPagoRepository.DeleteAsync(id, idUsuario); | 
					
						
							|  |  |  |             if (!eliminado) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 _logger.LogError("Falló la eliminación del Tipo de Pago en el repositorio para el ID: {Id}", id); | 
					
						
							|  |  |  |                 return (false, "Error al eliminar el tipo de pago de la base de datos."); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return (true, null); // Éxito | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |