Files
GestionIntegralWeb/Frontend/src/routes/AppRoutes.tsx
dmolinari 84187a66df Feat: Implementa flujo completo de facturación y promociones
Este commit introduce la funcionalidad completa para la facturación mensual,
la gestión de promociones y la comunicación con el cliente en el módulo
de suscripciones.

Backend:
- Se añade el servicio de Facturación que calcula automáticamente los importes
  mensuales basándose en las suscripciones activas, días de entrega y precios.
- Se implementa el servicio DebitoAutomaticoService, capaz de generar el
  archivo de texto plano para "Pago Directo Galicia" y de procesar el
  archivo de respuesta para la conciliación de pagos.
- Se desarrolla el ABM completo para Promociones (Servicio, Repositorio,
  Controlador y DTOs), permitiendo la creación de descuentos por porcentaje
  o monto fijo.
- Se implementa la lógica para asignar y desasignar promociones a suscripciones
  específicas.
- Se añade un servicio de envío de email (EmailService) integrado con MailKit
  y un endpoint para notificar facturas a los clientes.
- Se crea la lógica para registrar pagos manuales (efectivo, tarjeta, etc.)
  y actualizar el estado de las facturas.
- Se añaden todos los permisos necesarios a la base de datos para
  segmentar el acceso a las nuevas funcionalidades.

Frontend:
- Se crea la página de Facturación, que permite al usuario seleccionar un
  período, generar la facturación, listar los resultados y generar el archivo
  de débito para el banco.
- Se implementa la funcionalidad para subir y procesar el archivo de
  respuesta del banco, actualizando la UI en consecuencia.
- Se añade la página completa para el ABM de Promociones.
- Se integra un modal en la gestión de suscripciones para asignar y
  desasignar promociones a un cliente.
- Se añade la opción "Enviar Email" en el menú de acciones de las facturas,
  conectada al nuevo endpoint del backend.
- Se completan y corrigen los componentes `PagoManualModal` y `FacturacionPage`
  para incluir la lógica de registro de pagos y solucionar errores de TypeScript.
2025-08-01 12:53:17 -03:00

326 lines
18 KiB
TypeScript

// src/routes/AppRoutes.tsx
import React, { type JSX } from 'react';
import { BrowserRouter, Routes, Route, Navigate, Outlet } from 'react-router-dom';
import LoginPage from '../pages/LoginPage';
import HomePage from '../pages/HomePage';
import { useAuth } from '../contexts/AuthContext';
import MainLayout from '../layouts/MainLayout';
import { Typography } from '@mui/material';
import SectionProtectedRoute from './SectionProtectedRoute';
// Distribución
import DistribucionIndexPage from '../pages/Distribucion/DistribucionIndexPage';
import GestionarCanillitasPage from '../pages/Distribucion/GestionarCanillitasPage';
import GestionarDistribuidoresPage from '../pages/Distribucion/GestionarDistribuidoresPage';
import GestionarPublicacionesPage from '../pages/Distribucion/GestionarPublicacionesPage';
import GestionarSeccionesPublicacionPage from '../pages/Distribucion/GestionarSeccionesPublicacionPage';
import GestionarPreciosPublicacionPage from '../pages/Distribucion/GestionarPreciosPublicacionPage';
import GestionarRecargosPublicacionPage from '../pages/Distribucion/GestionarRecargosPublicacionPage';
import GestionarPorcentajesPagoPage from '../pages/Distribucion/GestionarPorcentajesPagoPage';
import GestionarPorcMonCanillaPage from '../pages/Distribucion/GestionarPorcMonCanillaPage';
import GestionarOtrosDestinosPage from '../pages/Distribucion/GestionarOtrosDestinosPage';
import GestionarZonasPage from '../pages/Distribucion/GestionarZonasPage';
import GestionarEmpresasPage from '../pages/Distribucion/GestionarEmpresasPage';
import GestionarSalidasOtrosDestinosPage from '../pages/Distribucion/GestionarSalidasOtrosDestinosPage';
import GestionarEntradasSalidasDistPage from '../pages/Distribucion/GestionarEntradasSalidasDistPage';
import GestionarEntradasSalidasCanillaPage from '../pages/Distribucion/GestionarEntradasSalidasCanillaPage';
import GestionarControlDevolucionesPage from '../pages/Distribucion/GestionarControlDevolucionesPage';
import GestionarParadasCanillaPage from '../pages/Distribucion/GestionarParadasCanillaPage';
// Impresión
import ImpresionIndexPage from '../pages/Impresion/ImpresionIndexPage';
import GestionarPlantasPage from '../pages/Impresion/GestionarPlantasPage';
import GestionarTiposBobinaPage from '../pages/Impresion/GestionarTiposBobinaPage';
import GestionarEstadosBobinaPage from '../pages/Impresion/GestionarEstadosBobinaPage';
import GestionarStockBobinasPage from '../pages/Impresion/GestionarStockBobinasPage';
import GestionarTiradasPage from '../pages/Impresion/GestionarTiradasPage';
// Contables
import ContablesIndexPage from '../pages/Contables/ContablesIndexPage';
import GestionarTiposPagoPage from '../pages/Contables/GestionarTiposPagoPage';
import GestionarPagosDistribuidorPage from '../pages/Contables/GestionarPagosDistribuidorPage';
import GestionarNotasCDPage from '../pages/Contables/GestionarNotasCDPage';
import GestionarSaldosPage from '../pages/Contables/GestionarSaldosPage';
// Usuarios
import UsuariosIndexPage from '../pages/Usuarios/UsuariosIndexPage'; // Crear este componente
import GestionarPerfilesPage from '../pages/Usuarios/GestionarPerfilesPage';
import GestionarPermisosPage from '../pages/Usuarios/GestionarPermisosPage';
import AsignarPermisosAPerfilPage from '../pages/Usuarios/AsignarPermisosAPerfilPage';
import GestionarUsuariosPage from '../pages/Usuarios/GestionarUsuariosPage';
// Radios
import RadiosIndexPage from '../pages/Radios/RadiosIndexPage';
import GestionarRitmosPage from '../pages/Radios/GestionarRitmosPage';
import GestionarCancionesPage from '../pages/Radios/GestionarCancionesPage';
import GenerarListasRadioPage from '../pages/Radios/GenerarListasRadioPage';
// Reportes
import ReportesIndexPage from '../pages/Reportes/ReportesIndexPage';
import ReporteExistenciaPapelPage from '../pages/Reportes/ReporteExistenciaPapelPage';
import ReporteMovimientoBobinasPage from '../pages/Reportes/ReporteMovimientoBobinasPage';
import ReporteMovimientoBobinasEstadoPage from '../pages/Reportes/ReporteMovimientoBobinasEstadoPage';
import ReporteListadoDistribucionGeneralPage from '../pages/Reportes/ReporteListadoDistribucionGeneralPage';
import ReporteListadoDistribucionCanillasPage from '../pages/Reportes/ReporteListadoDistribucionCanillasPage';
import ReporteListadoDistribucionCanillasImportePage from '../pages/Reportes/ReporteListadoDistribucionCanillasImportePage';
import ReporteVentaMensualSecretariaPage from '../pages/Reportes/ReporteVentaMensualSecretariaPage';
import ReporteDetalleDistribucionCanillasPage from '../pages/Reportes/ReporteDetalleDistribucionCanillasPage';
import ReporteTiradasPublicacionesSeccionesPage from '../pages/Reportes/ReporteTiradasPublicacionesSeccionesPage';
import ReporteConsumoBobinasSeccionPage from '../pages/Reportes/ReporteConsumoBobinasSeccionPage';
import ReporteConsumoBobinasPublicacionPage from '../pages/Reportes/ReporteConsumoBobinasPublicacionPage';
import ReporteComparativaConsumoBobinasPage from '../pages/Reportes/ReporteComparativaConsumoBobinasPage';
import ReporteCuentasDistribuidoresPage from '../pages/Reportes/ReporteCuentasDistribuidoresPage';
import ReporteListadoDistribucionPage from '../pages/Reportes/ReporteListadoDistribucionPage';
import ReporteControlDevolucionesPage from '../pages/Reportes/ReporteControlDevolucionesPage';
import GestionarNovedadesCanillaPage from '../pages/Distribucion/GestionarNovedadesCanillaPage';
import ReporteNovedadesCanillasPage from '../pages/Reportes/ReporteNovedadesCanillasPage';
import ReporteListadoDistMensualPage from '../pages/Reportes/ReporteListadoDistMensualPage';
// Suscripciones
import SuscripcionesIndexPage from '../pages/Suscripciones/SuscripcionesIndexPage';
import GestionarSuscriptoresPage from '../pages/Suscripciones/GestionarSuscriptoresPage';
import GestionarSuscripcionesSuscriptorPage from '../pages/Suscripciones/GestionarSuscripcionesSuscriptorPage';
import FacturacionPage from '../pages/Suscripciones/FacturacionPage';
import GestionarPromocionesPage from '../pages/Suscripciones/GestionarPromocionesPage';
// Anonalías
import AlertasPage from '../pages/Anomalia/AlertasPage';
// Auditorias
import GestionarAuditoriaUsuariosPage from '../pages/Usuarios/Auditoria/GestionarAuditoriaUsuariosPage';
import AuditoriaGeneralPage from '../pages/Auditoria/AuditoriaGeneralPage';
// --- ProtectedRoute y PublicRoute SIN CAMBIOS ---
const ProtectedRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const { isAuthenticated, isLoading } = useAuth();
// console.log("ProtectedRoute Check:", { path: window.location.pathname, isAuthenticated, isLoading });
if (isLoading) return null;
if (!isAuthenticated) {
// console.log("ProtectedRoute: Not authenticated, redirecting to /login");
return <Navigate to="/login" replace />;
}
// console.log("ProtectedRoute: Authenticated, rendering children");
return children;
};
const PublicRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const { isAuthenticated, isLoading } = useAuth();
// console.log("PublicRoute Check:", { path: window.location.pathname, isAuthenticated, isLoading });
if (isLoading) return null;
if (isAuthenticated) {
// console.log("PublicRoute: Authenticated, redirecting to /");
return <Navigate to="/" replace />;
}
// console.log("PublicRoute: Not authenticated, rendering children");
return children;
};
// --- Fin Protected/Public ---
const MainLayoutWrapper: React.FC = () => (
<MainLayout>
<Outlet />
</MainLayout>
);
const AppRoutes = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<PublicRoute><LoginPage /></PublicRoute>} />
{/* Rutas Protegidas que usan el MainLayout */}
<Route
path="/" // La ruta padre para todas las secciones protegidas
element={
<ProtectedRoute>
<MainLayoutWrapper />
</ProtectedRoute>
}
>
{/* Rutas hijas que se renderizarán en el Outlet de MainLayoutWrapper */}
<Route index element={<HomePage />} /> {/* Para la ruta exacta "/" */}
{/* Módulo de Anomalías */}
<Route
path="anomalias"
element={
<SectionProtectedRoute requiredPermission="AL001" sectionName="Anomalías">
<Outlet />
</SectionProtectedRoute>
}
>
<Route index element={<Navigate to="alertas" replace />} />
<Route path="alertas" element={<AlertasPage />} />
</Route>
{/* Módulo de Distribución (anidado) */}
<Route
path="distribucion"
element={
<SectionProtectedRoute requiredPermission="SS001" sectionName="Distribución">
<DistribucionIndexPage />
</SectionProtectedRoute>
}
>
<Route index element={<Navigate to="es-canillas" replace />} />
<Route path="es-canillas" element={<GestionarEntradasSalidasCanillaPage />} />
<Route path="control-devoluciones" element={<GestionarControlDevolucionesPage />} />
<Route path="es-distribuidores" element={<GestionarEntradasSalidasDistPage />} />
<Route path="salidas-otros-destinos" element={<GestionarSalidasOtrosDestinosPage />} />
<Route path="canillas" element={<GestionarCanillitasPage />} />
<Route path="canillas/:idCanilla/novedades" element={<GestionarNovedadesCanillaPage />} />
<Route path="canillas/:idCanilla/paradas" element={<GestionarParadasCanillaPage />} />
<Route path="distribuidores" element={<GestionarDistribuidoresPage />} />
<Route path="otros-destinos" element={<GestionarOtrosDestinosPage />} />
<Route path="zonas" element={<GestionarZonasPage />} />
<Route path="empresas" element={<GestionarEmpresasPage />} />
{/* Rutas para Publicaciones y sus detalles */}
<Route path="publicaciones" element={<Outlet />}> {/* Contenedor para sub-rutas de publicaciones */}
<Route index element={<GestionarPublicacionesPage />} /> {/* Lista de publicaciones */}
<Route path=":idPublicacion/precios" element={<GestionarPreciosPublicacionPage />} />
<Route path=":idPublicacion/recargos" element={<GestionarRecargosPublicacionPage />} />
<Route path=":idPublicacion/porcentajes-pago-dist" element={<GestionarPorcentajesPagoPage />} />
<Route path=":idPublicacion/porcentajes-mon-canilla" element={<GestionarPorcMonCanillaPage />} />
<Route path=":idPublicacion/secciones" element={<GestionarSeccionesPublicacionPage />} />
</Route>
</Route>
{/* --- Módulo de Suscripciones --- */}
<Route
path="/suscripciones"
element={
<SectionProtectedRoute requiredPermission="SS007" sectionName="Suscripciones">
<SuscripcionesIndexPage />
</SectionProtectedRoute>
}
>
<Route index element={<Navigate to="suscriptores" replace />} />
<Route path="suscriptores" element={
<SectionProtectedRoute requiredPermission="SU001" sectionName="Suscriptores">
<GestionarSuscriptoresPage />
</SectionProtectedRoute>
} />
<Route path="suscriptor/:idSuscriptor" element={
<SectionProtectedRoute requiredPermission="SU001" sectionName="Suscripciones del Cliente">
<GestionarSuscripcionesSuscriptorPage />
</SectionProtectedRoute>
} />
<Route path="facturacion" element={
<SectionProtectedRoute requiredPermission="SU006" sectionName="Facturación de Suscripciones">
<FacturacionPage />
</SectionProtectedRoute>
} />
<Route path="promociones" element={
<SectionProtectedRoute requiredPermission="SU010" sectionName="Promociones">
<GestionarPromocionesPage />
</SectionProtectedRoute>
} />
</Route>
{/* Módulo Contable (anidado) */}
<Route
path="contables"
element={
<SectionProtectedRoute requiredPermission="SS002" sectionName="Contables">
<ContablesIndexPage />
</SectionProtectedRoute>
}
>
<Route index element={<Navigate to="tipos-pago" replace />} />
<Route path="tipos-pago" element={<GestionarTiposPagoPage />} />
<Route path="pagos-distribuidores" element={<GestionarPagosDistribuidorPage />} />
<Route path="notas-cd" element={<GestionarNotasCDPage />} />
<Route path="gestion-saldos" element={<GestionarSaldosPage />} />
</Route>
{/* Módulo de Impresión (anidado) */}
<Route path="impresion"
element={
<SectionProtectedRoute requiredPermission="SS003" sectionName="Impresión">
<ImpresionIndexPage />
</SectionProtectedRoute>}
>
<Route index element={<Navigate to="plantas" replace />} />
<Route path="plantas" element={<GestionarPlantasPage />} />
<Route path="tipos-bobina" element={<GestionarTiposBobinaPage />} />
<Route path="estados-bobina" element={<GestionarEstadosBobinaPage />} />
<Route path="stock-bobinas" element={<GestionarStockBobinasPage />} />
<Route path="tiradas" element={<GestionarTiradasPage />} />
</Route>
{/* Módulo de Reportes */}
<Route path="reportes"
element={
<SectionProtectedRoute requiredPermission="SS004" sectionName="Reportes">
<ReportesIndexPage />
</SectionProtectedRoute>}
>
<Route index element={<Typography sx={{ p: 2 }}>Seleccione un reporte del menú lateral.</Typography>} /> {/* Placeholder */}
<Route path="existencia-papel" element={<ReporteExistenciaPapelPage />} />
<Route path="movimiento-bobinas" element={<ReporteMovimientoBobinasPage />} />
<Route path="movimiento-bobinas-estado" element={<ReporteMovimientoBobinasEstadoPage />} />
<Route path="listado-distribucion-general" element={<ReporteListadoDistribucionGeneralPage />} />
<Route path="listado-distribucion-canillas" element={<ReporteListadoDistribucionCanillasPage />} />
<Route path="listado-distribucion-canillas-importe" element={<ReporteListadoDistribucionCanillasImportePage />} />
<Route path="venta-mensual-secretaria" element={<ReporteVentaMensualSecretariaPage />} />
<Route path="detalle-distribucion-canillas" element={<ReporteDetalleDistribucionCanillasPage />} />
<Route path="tiradas-publicaciones-secciones" element={<ReporteTiradasPublicacionesSeccionesPage />} />
<Route path="consumo-bobinas-seccion" element={<ReporteConsumoBobinasSeccionPage />} />
<Route path="consumo-bobinas-publicacion" element={<ReporteConsumoBobinasPublicacionPage />} />
<Route path="comparativa-consumo-bobinas" element={<ReporteComparativaConsumoBobinasPage />} />
<Route path="cuentas-distribuidores" element={<ReporteCuentasDistribuidoresPage />} />
<Route path="listado-distribucion-distribuidores" element={<ReporteListadoDistribucionPage />} />
<Route path="control-devoluciones" element={<ReporteControlDevolucionesPage />} />
<Route path="novedades-canillas" element={<ReporteNovedadesCanillasPage />} />
<Route path="listado-distribucion-mensual" element={<ReporteListadoDistMensualPage />} />
</Route>
{/* Módulo de Radios (anidado) */}
<Route path="radios"
element={
<SectionProtectedRoute requiredPermission="SS005" sectionName="Radios">
<RadiosIndexPage />
</SectionProtectedRoute>}
>
<Route index element={<Navigate to="ritmos" replace />} />
<Route path="ritmos" element={<GestionarRitmosPage />} />
<Route path="canciones" element={<GestionarCancionesPage />} />
<Route path="generar-listas" element={<GenerarListasRadioPage />} />
</Route>
{/* Módulo de Usuarios (anidado) */}
<Route path="usuarios"
element={
<SectionProtectedRoute requiredPermission="SS006" sectionName="Usuarios">
<UsuariosIndexPage />
</SectionProtectedRoute>}
>
<Route index element={<Navigate to="perfiles" replace />} /> {/* Redirigir a la primera subpestaña */}
<Route path="perfiles" element={<GestionarPerfilesPage />} />
<Route path="permisos" element={<GestionarPermisosPage />} />
<Route path="perfiles/:idPerfil/permisos" element={<AsignarPermisosAPerfilPage />} />
<Route path="gestion-usuarios" element={<GestionarUsuariosPage />} />
<Route path="auditoria-usuarios" element={<GestionarAuditoriaUsuariosPage />} />
</Route>
{/* Módulo de Auditoías (anidado) */}
<Route path="auditoria"
element={
<SectionProtectedRoute onlySuperAdmin={true} sectionName="Auditoría">
<Outlet />
</SectionProtectedRoute>
}
>
<Route index element={<Navigate to="general" replace />} />
<Route path="general" element={<AuditoriaGeneralPage />} />
</Route>
{/* Ruta catch-all DENTRO del layout protegido */}
<Route path="*" element={<Navigate to="/" replace />} />
</Route> {/* Cierre de la ruta padre "/" */}
</Routes>
</BrowserRouter>
);
};
export default AppRoutes;