Files
GestionIntegralWeb/Frontend/src/pages/Reportes/SeleccionaReporteDistribucionSuscripciones.tsx
dmolinari 21c5c1d7d9 Feat: Implementa Reporte de Distribución de Suscripciones y Refactoriza Gestión de Ajustes
Se introduce una nueva funcionalidad de reporte crucial para la logística y se realiza una refactorización mayor del sistema de ajustes para garantizar la correcta imputación contable.

###  Nuevas Características

- **Nuevo Reporte de Distribución de Suscripciones (RR011):**
    - Se añade un nuevo reporte en PDF que genera un listado de todas las suscripciones activas en un rango de fechas.
    - El reporte está diseñado para el equipo de reparto, incluyendo datos clave como nombre del suscriptor, dirección, teléfono, días de entrega y observaciones.
    - Se implementa el endpoint, la lógica de servicio, la consulta a la base de datos y el template de QuestPDF en el backend.
    - Se crea la página correspondiente en el frontend (React) con su selector de fechas y se añade la ruta y el enlace en el menú de reportes.

### 🔄 Refactorización Mayor

- **Asociación de Ajustes a Empresas:**
    - Se refactoriza por completo la entidad `Ajuste` para incluir una referencia obligatoria a una `IdEmpresa`.
    - **Motivo:** Corregir un error crítico en la lógica de negocio donde los ajustes de un suscriptor se aplicaban a la primera factura generada, sin importar a qué empresa correspondía el ajuste.
    - Se provee un script de migración SQL para actualizar el esquema de la base de datos (`susc_Ajustes`).
    - Se actualizan todos los DTOs, repositorios y servicios (backend) para manejar la nueva relación.
    - Se modifica el `FacturacionService` para que ahora aplique los ajustes pendientes correspondientes a cada empresa dentro de su bucle de facturación.
    - Se actualiza el formulario de creación/edición de ajustes en el frontend (React) para incluir un selector de empresa obligatorio.

### ️ Optimizaciones de Rendimiento

- **Solución de N+1 Queries:**
    - Se optimiza el método `ObtenerTodos` en `SuscriptorService` para obtener todas las formas de pago en una única consulta en lugar de una por cada suscriptor.
    - Se optimiza el método `ObtenerAjustesPorSuscriptor` en `AjusteService` para obtener todos los nombres de usuarios y empresas en dos consultas masivas, en lugar de N consultas individuales.
    - Se añade el método `GetByIdsAsync` al `IUsuarioRepository` y su implementación para soportar esta optimización.

### 🐛 Corrección de Errores

- Se corrigen múltiples errores en el script de migración de base de datos (uso de `GO` dentro de transacciones, error de "columna inválida").
- Se soluciona un error de SQL (`INSERT` statement) en `AjusteRepository` que impedía la creación de nuevos ajustes.
- Se corrige un bug en el `AjusteService` que causaba que el nombre de la empresa apareciera como "N/A" en la UI debido a un mapeo incompleto en el método optimizado.
- Se corrige la lógica de generación de emails en `FacturacionService` para mostrar correctamente el nombre de la empresa en cada sección del resumen de cuenta.
2025-08-09 17:39:21 -03:00

63 lines
2.2 KiB
TypeScript

import React, { useState } from 'react';
import { Box, Typography, Button, CircularProgress, Alert, TextField } from '@mui/material';
interface SeleccionaReporteProps {
onGenerarReporte: (params: { fechaDesde: string, fechaHasta: string }) => Promise<void>;
isLoading?: boolean;
apiErrorMessage?: string | null;
}
const SeleccionaReporteDistribucionSuscripciones: React.FC<SeleccionaReporteProps> = ({
onGenerarReporte,
isLoading,
apiErrorMessage
}) => {
const [fechaDesde, setFechaDesde] = useState(new Date().toISOString().split('T')[0]);
const [fechaHasta, setFechaHasta] = useState(new Date().toISOString().split('T')[0]);
const handleGenerar = () => {
onGenerarReporte({ fechaDesde, fechaHasta });
};
return (
<Box sx={{ p: 2, border: '1px solid #ccc', borderRadius: '4px', minWidth: 400 }}>
<Typography variant="h6" gutterBottom>
Reporte de Distribución de Suscripciones
</Typography>
<Typography variant="body2" color="text.secondary" sx={{mb: 2}}>
Seleccione un rango de fechas para generar el listado de suscriptores activos y sus detalles de entrega.
</Typography>
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center', mb: 2 }}>
<TextField
label="Fecha Desde"
type="date"
fullWidth
value={fechaDesde}
onChange={(e) => setFechaDesde(e.target.value)}
InputLabelProps={{ shrink: true }}
disabled={isLoading}
/>
<TextField
label="Fecha Hasta"
type="date"
fullWidth
value={fechaHasta}
onChange={(e) => setFechaHasta(e.target.value)}
InputLabelProps={{ shrink: true }}
disabled={isLoading}
/>
</Box>
{apiErrorMessage && <Alert severity="error" sx={{ mt: 2 }}>{apiErrorMessage}</Alert>}
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end', gap: 1 }}>
<Button onClick={handleGenerar} variant="contained" disabled={isLoading}>
{isLoading ? <CircularProgress size={24} /> : 'Generar Reporte'}
</Button>
</Box>
</Box>
);
};
export default SeleccionaReporteDistribucionSuscripciones;