feat: Implementar página dedicada de gráficos para análisis de pagos de agua
- Crear nueva página /graficos con 4 tipos de gráficos interactivos - Agregar compatibilidad con tema oscuro en selectores - Implementar exportación a PDF profesional con encabezados - Agregar campo 'Monto Real del Recibo' a configuración mensual - Crear migración para nueva columna real_amount en monthly_bills - Mejorar filtros con botones interactivos en lugar de select múltiple - Agregar resumen ejecutivo con estadísticas detalladas - Optimizar espacio visual y responsividad de gráficos - Integrar Chart.js y jsPDF para funcionalidad avanzada - Corregir problemas de carga de datos y filtros dinámicos
This commit is contained in:
208
dashboard.php
208
dashboard.php
@@ -94,7 +94,55 @@ switch ($page) {
|
||||
|
||||
case 'config_actions':
|
||||
header('Content-Type: application/json');
|
||||
Auth::requireAdmin();
|
||||
// Permitir acceso a capturistas para ver gráficos
|
||||
if (!Auth::isCapturist()) {
|
||||
echo json_encode(['success' => false, 'message' => 'Acceso denegado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_GET['action']) && $_GET['action'] == 'get_monthly_data') {
|
||||
$year = $_GET['year'] ?? date('Y');
|
||||
$monthlyBills = MonthlyBill::getYear($year);
|
||||
|
||||
$configured = [];
|
||||
$realAmounts = [];
|
||||
|
||||
$months = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
|
||||
'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
|
||||
|
||||
foreach ($months as $month) {
|
||||
$bill = $monthlyBills[$month] ?? null;
|
||||
$configured[$month] = $bill['total_amount'] ?? 0;
|
||||
$realAmounts[$month] = $bill['real_amount'] ?? 0;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'configured' => $configured,
|
||||
'realAmounts' => $realAmounts
|
||||
]);
|
||||
exit;
|
||||
|
||||
} elseif (isset($_GET['action']) && $_GET['action'] == 'get_payments_data') {
|
||||
$year = $_GET['year'] ?? date('Y');
|
||||
$matrix = Payment::getMatrix($year);
|
||||
$months = $matrix['months'];
|
||||
|
||||
$monthTotals = [];
|
||||
foreach ($months as $month) {
|
||||
$monthTotals[$month] = 0;
|
||||
foreach ($matrix['payments'][$month] ?? [] as $houseId => $paymentData) {
|
||||
$monthTotals[$month] += $paymentData['amount'] ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'payments' => $monthTotals,
|
||||
'months' => $months
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_GET['action']) && $_GET['action'] == 'save_monthly_bill') {
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
@@ -563,11 +611,27 @@ switch ($page) {
|
||||
Auth::requireAdmin();
|
||||
$view = 'users/index';
|
||||
break;
|
||||
case 'importar':
|
||||
Auth::requireAdmin();
|
||||
$concepts = CollectionConcept::all(true);
|
||||
$view = 'import/index';
|
||||
break;
|
||||
case 'graficos':
|
||||
$year = $_GET['year'] ?? date('Y');
|
||||
$matrix = Payment::getMatrix($year);
|
||||
$monthlyBills = MonthlyBill::getYear($year);
|
||||
$months = $matrix['months'];
|
||||
$monthTotals = [];
|
||||
|
||||
foreach ($months as $month) {
|
||||
$monthTotals[$month] = 0;
|
||||
foreach ($matrix['payments'][$month] ?? [] as $houseId => $paymentData) {
|
||||
$monthTotals[$month] += $paymentData['amount'] ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
$view = 'charts/index';
|
||||
break;
|
||||
case 'importar':
|
||||
Auth::requireAdmin();
|
||||
$concepts = CollectionConcept::all(true);
|
||||
$view = 'import/index';
|
||||
break;
|
||||
case 'concept_view_actions': // Nuevo case para acciones AJAX de concept_view
|
||||
if (isset($_GET['action'])) {
|
||||
header('Content-Type: application/json');
|
||||
@@ -634,9 +698,137 @@ switch ($page) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'reportes_actions': // Nuevo case para acciones de exportación de reportes
|
||||
case 'charts_export':
|
||||
// Exportación de gráficos a PDF usando TCPDF (igual que otras exportaciones)
|
||||
date_default_timezone_set('America/Mexico_City');
|
||||
|
||||
// Obtener datos del POST
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$year = $input['year'] ?? date('Y');
|
||||
$chartImages = $input['charts'] ?? [];
|
||||
$chartData = $input['data'] ?? [];
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/vendor/tecnickcom/tcpdf/tcpdf.php';
|
||||
|
||||
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
|
||||
|
||||
$pdf->SetCreator(PDF_CREATOR);
|
||||
$pdf->SetAuthor('Ibiza Condominium');
|
||||
$pdf->SetTitle('Gráficos de Pagos de Agua - IBIZA ' . $year);
|
||||
$pdf->SetSubject('Análisis Gráfico de Pagos');
|
||||
|
||||
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, 'Condominio IBIZA-Cto Sierra Morena 152 - Gráficos de Pagos de Agua ' . $year, 'Generado el ' . date('d/m/Y H:i'));
|
||||
|
||||
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
|
||||
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
|
||||
|
||||
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
|
||||
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
|
||||
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
|
||||
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
|
||||
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
|
||||
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
|
||||
|
||||
if (@file_exists(dirname(__FILE__).'/lang/eng.php')) {
|
||||
require_once(dirname(__FILE__).'/lang/eng.php');
|
||||
$pdf->setLanguageArray($l);
|
||||
}
|
||||
|
||||
$pdf->SetFont('helvetica', '', 12);
|
||||
$pdf->AddPage();
|
||||
|
||||
// Título principal
|
||||
$pdf->SetFont('helvetica', 'B', 18);
|
||||
$pdf->Cell(0, 15, 'Gráficos de Pagos de Agua - IBIZA', 0, 1, 'C');
|
||||
$pdf->SetFont('helvetica', '', 10);
|
||||
$pdf->Cell(0, 8, 'Año: ' . $year . ' - Generado: ' . date('d/m/Y H:i'), 0, 1, 'C');
|
||||
$pdf->Ln(10);
|
||||
|
||||
// Función para agregar gráfico
|
||||
function addChartToPDF($pdf, $imageData, $title, $description = '') {
|
||||
if ($imageData) {
|
||||
$pdf->SetFont('helvetica', 'B', 14);
|
||||
$pdf->Cell(0, 10, $title, 0, 1, 'L');
|
||||
|
||||
if ($description) {
|
||||
$pdf->SetFont('helvetica', 'I', 10);
|
||||
$pdf->Cell(0, 6, $description, 0, 1, 'L');
|
||||
}
|
||||
|
||||
// Agregar imagen del gráfico
|
||||
$pdf->Image('@' . base64_decode(preg_replace('#^data:image/[^;]+;base64,#', '', $imageData)), 15, $pdf->GetY(), 180, 80, 'PNG');
|
||||
$pdf->Ln(90);
|
||||
}
|
||||
}
|
||||
|
||||
// Página 1: Gráficos principales
|
||||
$pdf->SetFont('helvetica', 'B', 16);
|
||||
$pdf->Cell(0, 12, 'Análisis Comparativo de Pagos', 0, 1, 'L');
|
||||
$pdf->Ln(5);
|
||||
|
||||
if (isset($chartImages['comparisonChart'])) {
|
||||
addChartToPDF($pdf, $chartImages['comparisonChart'],
|
||||
'1. Comparación: Pagos Reales vs Monto Configurado',
|
||||
'Este gráfico compara los pagos efectivamente recibidos con los montos que fueron configurados para cada mes.');
|
||||
}
|
||||
|
||||
if (isset($chartImages['trendsChart'])) {
|
||||
addChartToPDF($pdf, $chartImages['trendsChart'],
|
||||
'2. Tendencias de Pagos a lo Largo del Año',
|
||||
'Visualiza la evolución mensual de los ingresos por concepto de agua.');
|
||||
}
|
||||
|
||||
if (isset($chartImages['realAmountChart'])) {
|
||||
addChartToPDF($pdf, $chartImages['realAmountChart'],
|
||||
'3. Comparación: Monto Real del Recibo vs Pagos Efectivos',
|
||||
'Compara el costo real del servicio con lo que efectivamente se cobra y paga.');
|
||||
}
|
||||
|
||||
// Nueva página para resumen ejecutivo
|
||||
$pdf->AddPage();
|
||||
$pdf->SetFont('helvetica', 'B', 16);
|
||||
$pdf->Cell(0, 12, 'Resumen Ejecutivo', 0, 1, 'L');
|
||||
$pdf->Ln(5);
|
||||
|
||||
if (isset($chartImages['summaryChart'])) {
|
||||
addChartToPDF($pdf, $chartImages['summaryChart'],
|
||||
'Distribución General de Cobranza',
|
||||
'Vista panorámica del estado de cobranza con métricas clave.');
|
||||
}
|
||||
|
||||
// Estadísticas textuales
|
||||
$pdf->SetFont('helvetica', 'B', 12);
|
||||
$pdf->Cell(0, 10, 'Métricas de Rendimiento', 0, 1, 'L');
|
||||
$pdf->Ln(5);
|
||||
|
||||
$pdf->SetFont('helvetica', '', 11);
|
||||
$totalPayments = array_sum($chartData['payments'] ?? []);
|
||||
$totalConfigured = array_sum($chartData['configured'] ?? []);
|
||||
$totalReal = array_sum($chartData['realAmounts'] ?? []);
|
||||
|
||||
$pdf->Cell(80, 8, 'Total Pagos Recibidos:', 0, 0, 'L');
|
||||
$pdf->Cell(40, 8, '$ ' . number_format($totalPayments, 2), 0, 1, 'R');
|
||||
|
||||
$pdf->Cell(80, 8, 'Monto Total Configurado:', 0, 0, 'L');
|
||||
$pdf->Cell(40, 8, '$ ' . number_format($totalConfigured, 2), 0, 1, 'R');
|
||||
|
||||
$pdf->Cell(80, 8, 'Monto Real Total:', 0, 0, 'L');
|
||||
$pdf->Cell(40, 8, '$ ' . number_format($totalReal, 2), 0, 1, 'R');
|
||||
|
||||
if ($totalConfigured > 0) {
|
||||
$efficiency = round(($totalPayments / $totalConfigured) * 100, 1);
|
||||
$pdf->Cell(80, 8, 'Eficiencia de Cobranza:', 0, 0, 'L');
|
||||
$pdf->Cell(40, 8, $efficiency . '%', 0, 1, 'R');
|
||||
}
|
||||
|
||||
// Salida del PDF
|
||||
$pdf->Output('Graficos_Pagos_Agua_IBIZA_' . $year . '_' . date('Y-m-d') . '.pdf', 'D');
|
||||
exit;
|
||||
|
||||
case 'reportes_actions': // Nuevo case para acciones de exportación de reportes
|
||||
date_default_timezone_set('America/Mexico_City'); // Asegurar zona horaria
|
||||
|
||||
if (isset($_GET['action'])) {
|
||||
|
||||
Reference in New Issue
Block a user