Sindbad~EG File Manager

Current Path : /home/copmadinaarea/thecopmadinaarea.org/portal/api/
Upload File :
Current File : /home/copmadinaarea/thecopmadinaarea.org/portal/api/generate-report.php

<?php
require_once '../config/config.php';

header('Content-Type: application/json');

if (!isLoggedIn()) {
    echo json_encode(['success' => false, 'message' => 'Unauthorized']);
    exit();
}

$type = $_GET['type'] ?? '';
$db = Database::getInstance()->getConnection();

// Get access level parameters using safe helper functions
$accessLevel = getUserAccessLevel();
$areaId = getUserAreaId();
$districtId = getUserDistrictId();
$assemblyId = getUserAssemblyId();

$response = ['success' => true, 'title' => '', 'html' => ''];

switch ($type) {
    case 'members':
        $response['title'] = 'Members Report';
        
        try {
            // Check if members table exists
            $db->query("SELECT 1 FROM members LIMIT 1");
            // Build query based on access - with fallback for missing tables
            $query = "SELECT m.*";
            $joins = "";
            $params = [];
            
            // Check if location tables exist
            try {
                $db->query("SELECT 1 FROM areas LIMIT 1");
                $query .= ", a.area_name";
                $joins .= " LEFT JOIN areas a ON m.area_id = a.id";
            } catch (Exception $e) {
                $query .= ", 'N/A' as area_name";
            }
            
            try {
                $db->query("SELECT 1 FROM districts LIMIT 1");
                $query .= ", d.district_name";
                $joins .= " LEFT JOIN districts d ON m.district_id = d.id";
            } catch (Exception $e) {
                $query .= ", 'N/A' as district_name";
            }
            
            try {
                $db->query("SELECT 1 FROM assemblies LIMIT 1");
                $query .= ", asm.assembly_name";
                $joins .= " LEFT JOIN assemblies asm ON m.assembly_id = asm.id";
            } catch (Exception $e) {
                $query .= ", 'N/A' as assembly_name";
            }
            
            $query .= " FROM members m" . $joins . " WHERE 1=1";
            
            // Apply access level filters
            if ($accessLevel === 'assembly' && $assemblyId) {
                $query .= " AND m.assembly_id = :assembly_id";
                $params['assembly_id'] = $assemblyId;
            } elseif ($accessLevel === 'district' && $districtId) {
                $query .= " AND m.district_id = :district_id";
                $params['district_id'] = $districtId;
            } elseif ($accessLevel === 'area' && $areaId) {
                $query .= " AND m.area_id = :area_id";
                $params['area_id'] = $areaId;
            }
            
            $stmt = $db->prepare($query);
            $stmt->execute($params);
            $members = $stmt->fetchAll();
        } catch (Exception $e) {
            // Fallback: simple query without joins
            $query = "SELECT * FROM members WHERE 1=1";
            $params = [];
            
            if ($accessLevel === 'assembly' && $assemblyId) {
                $query .= " AND assembly_id = :assembly_id";
                $params['assembly_id'] = $assemblyId;
            } elseif ($accessLevel === 'district' && $districtId) {
                $query .= " AND district_id = :district_id";
                $params['district_id'] = $districtId;
            } elseif ($accessLevel === 'area' && $areaId) {
                $query .= " AND area_id = :area_id";
                $params['area_id'] = $areaId;
            }
            
            $stmt = $db->prepare($query);
            $stmt->execute($params);
            $members = $stmt->fetchAll();
            
            // Add default location names
            foreach ($members as &$member) {
                $member['area_name'] = $member['area_name'] ?? 'N/A';
                $member['district_name'] = $member['district_name'] ?? 'N/A';
                $member['assembly_name'] = $member['assembly_name'] ?? 'N/A';
            }
        }
        
        $totalMembers = count($members);
        $maleCount = count(array_filter($members, function($m) { return ($m['gender'] ?? '') === 'Male'; }));
        $femaleCount = count(array_filter($members, function($m) { return ($m['gender'] ?? '') === 'Female'; }));
        $communicants = count(array_filter($members, function($m) { return !empty($m['communicant']); }));
        
        $html = '<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">';
        $html .= '<div class="bg-blue-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Total Members</h4><p class="text-2xl font-bold text-blue-600">' . $totalMembers . '</p></div>';
        $html .= '<div class="bg-green-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Male</h4><p class="text-2xl font-bold text-green-600">' . $maleCount . '</p></div>';
        $html .= '<div class="bg-pink-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Female</h4><p class="text-2xl font-bold text-pink-600">' . $femaleCount . '</p></div>';
        $html .= '<div class="bg-yellow-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Communicants</h4><p class="text-2xl font-bold text-yellow-600">' . $communicants . '</p></div>';
        $html .= '</div>';
        
        if ($totalMembers > 0) {
            $html .= '<div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200">';
            $html .= '<thead class="bg-gray-50"><tr>';
            $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Member ID</th>';
            $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th>';
            $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Gender</th>';
            $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Assembly</th>';
            $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Status</th>';
            $html .= '</tr></thead><tbody class="bg-white divide-y divide-gray-200">';
            
            foreach ($members as $member) {
                $html .= '<tr>';
                $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($member['member_id'] ?? $member['id'] ?? 'N/A') . '</td>';
                $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars(($member['first_name'] ?? '') . ' ' . ($member['last_name'] ?? '')) . '</td>';
                $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($member['gender'] ?? 'N/A') . '</td>';
                $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($member['assembly_name'] ?? 'N/A') . '</td>';
                $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . (($member['is_active'] ?? 1) ? '<span class="text-green-600">Active</span>' : '<span class="text-red-600">Inactive</span>') . '</td>';
                $html .= '</tr>';
            }
            
            $html .= '</tbody></table></div>';
        } else {
            $html .= '<div class="text-center py-12">';
            $html .= '<i class="fas fa-users text-6xl text-gray-300 mb-4"></i>';
            $html .= '<h3 class="text-xl font-bold text-gray-600 mb-2">No Members Found</h3>';
            $html .= '<p class="text-gray-500">No members match the current filter criteria or no members have been added to the system yet.</p>';
            $html .= '</div>';
        }
        $response['html'] = $html;
        
        } catch (Exception $e) {
            $response['success'] = false;
            $response['message'] = 'Error generating members report: ' . $e->getMessage();
            $response['html'] = '<div class="bg-red-50 rounded-lg p-4">';
            $response['html'] .= '<h3 class="text-lg font-bold text-red-800 mb-2">Report Generation Error</h3>';
            $response['html'] .= '<p class="text-red-600 mb-4">Unable to generate the members report due to the following error:</p>';
            $response['html'] .= '<div class="bg-red-100 rounded p-3 font-mono text-sm text-red-800">' . htmlspecialchars($e->getMessage()) . '</div>';
            
            if (strpos($e->getMessage(), 'members') !== false && strpos($e->getMessage(), "doesn't exist") !== false) {
                $response['html'] .= '<div class="mt-4 p-3 bg-yellow-50 rounded">';
                $response['html'] .= '<p class="text-yellow-800"><strong>Suggestion:</strong> The members table appears to be missing. Please ensure the database is properly set up with the members table.</p>';
                $response['html'] .= '</div>';
            }
            $response['html'] .= '</div>';
        }
        break;
        
    case 'baptism':
        $response['title'] = 'Baptism Report';
        
        try {
            // Check which baptism columns exist
            $columns = $db->query("SHOW COLUMNS FROM members")->fetchAll();
            $columnNames = array_column($columns, 'Field');
            
            $hasWaterBaptism = in_array('water_baptism', $columnNames);
            $hasWaterBaptismDate = in_array('water_baptism_date', $columnNames);
            $hasBaptized = in_array('baptized', $columnNames);
            $hasBaptismDate = in_array('baptism_date', $columnNames);
            
            // Build query based on available columns
            $query = "SELECT m.*";
            
            if ($hasWaterBaptism) {
                $query .= ", CASE WHEN m.water_baptism = 1 THEN 'Yes' ELSE 'No' END as baptized_status";
                $baptismColumn = 'water_baptism';
            } elseif ($hasBaptized) {
                $query .= ", CASE WHEN m.baptized = 1 THEN 'Yes' ELSE 'No' END as baptized_status";
                $baptismColumn = 'baptized';
            } else {
                $query .= ", 'Unknown' as baptized_status";
                $baptismColumn = null;
            }
            
            if ($hasWaterBaptismDate) {
                $query .= ", m.water_baptism_date as baptism_date";
            } elseif ($hasBaptismDate) {
                $query .= ", m.baptism_date";
            } else {
                $query .= ", NULL as baptism_date";
            }
            
            $query .= " FROM members m WHERE 1=1";
            $params = [];
            
            // Apply access level filters
            if ($accessLevel === 'assembly' && $assemblyId) {
                $query .= " AND m.assembly_id = :assembly_id";
                $params['assembly_id'] = $assemblyId;
            } elseif ($accessLevel === 'district' && $districtId) {
                $query .= " AND m.district_id = :district_id";
                $params['district_id'] = $districtId;
            } elseif ($accessLevel === 'area' && $areaId) {
                $query .= " AND m.area_id = :area_id";
                $params['area_id'] = $areaId;
            }
            
            $stmt = $db->prepare($query);
            $stmt->execute($params);
            $members = $stmt->fetchAll();
            
            // Filter baptized members based on available column
            if ($baptismColumn) {
                $baptized = array_filter($members, fn($m) => $m[$baptismColumn] == 1);
                $notBaptized = array_filter($members, fn($m) => $m[$baptismColumn] != 1);
            } else {
                // No baptism column available
                $baptized = [];
                $notBaptized = $members;
            }
            
            $html = '<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">';
            $html .= '<div class="bg-blue-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Total Members</h4><p class="text-2xl font-bold text-blue-600">' . count($members) . '</p></div>';
            $html .= '<div class="bg-green-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Baptized</h4><p class="text-2xl font-bold text-green-600">' . count($baptized) . '</p></div>';
            $html .= '<div class="bg-red-50 rounded-lg p-4"><h4 class="text-sm text-gray-600">Not Baptized</h4><p class="text-2xl font-bold text-red-600">' . count($notBaptized) . '</p></div>';
            $html .= '</div>';
            
            if (!empty($baptized)) {
                $html .= '<h3 class="text-lg font-bold mb-4">Baptized Members</h3>';
                $html .= '<div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200">';
                $html .= '<thead class="bg-gray-50"><tr>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Name</th>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Gender</th>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Baptism Date</th>';
                $html .= '</tr></thead><tbody class="bg-white divide-y divide-gray-200">';
                
                foreach ($baptized as $member) {
                    $html .= '<tr>';
                    $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($member['first_name'] . ' ' . $member['last_name']) . '</td>';
                    $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($member['gender'] ?? 'N/A') . '</td>';
                    $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($member['baptism_date'] ?? 'N/A') . '</td>';
                    $html .= '</tr>';
                }
                $html .= '</tbody></table></div>';
            } elseif (!$baptismColumn) {
                $html .= '<div class="bg-yellow-50 rounded-lg p-4 mt-4">';
                $html .= '<p class="text-yellow-700"><i class="fas fa-exclamation-triangle mr-2"></i>Baptism tracking columns not found in the database. Please add "water_baptism" and "water_baptism_date" columns to the members table to track baptism records.</p>';
                $html .= '</div>';
            } else {
                $html .= '<div class="text-center py-8">';
                $html .= '<p class="text-gray-500">No baptized members found in the current selection.</p>';
                $html .= '</div>';
            }
            
        } catch (Exception $e) {
            $html = '<div class="bg-red-50 rounded-lg p-4"><p class="text-red-600">Error generating baptism report: ' . htmlspecialchars($e->getMessage()) . '</p></div>';
        }
        
        $response['html'] = $html;
        break;
        
    case 'demographics':
        $response['title'] = 'Demographics Report';
        
        try {
            $query = "SELECT * FROM members WHERE 1=1";
            $params = [];
            
            // Apply access level filters
            if ($accessLevel === 'assembly' && $assemblyId) {
                $query .= " AND assembly_id = :assembly_id";
                $params['assembly_id'] = $assemblyId;
            } elseif ($accessLevel === 'district' && $districtId) {
                $query .= " AND district_id = :district_id";
                $params['district_id'] = $districtId;
            } elseif ($accessLevel === 'area' && $areaId) {
                $query .= " AND area_id = :area_id";
                $params['area_id'] = $areaId;
            }
            
            $stmt = $db->prepare($query);
            $stmt->execute($params);
            $members = $stmt->fetchAll();
            
            // Calculate demographics
            $totalMembers = count($members);
            $maleCount = count(array_filter($members, fn($m) => $m['gender'] === 'Male'));
            $femaleCount = count(array_filter($members, fn($m) => $m['gender'] === 'Female'));
            
            // Age groups
            $children = 0; $youth = 0; $adults = 0; $seniors = 0;
            foreach ($members as $member) {
                if ($member['date_of_birth']) {
                    $age = date_diff(date_create($member['date_of_birth']), date_create('today'))->y;
                    if ($age < 13) $children++;
                    elseif ($age < 25) $youth++;
                    elseif ($age < 60) $adults++;
                    else $seniors++;
                }
            }
            
            $html = '<div class="grid grid-cols-1 md:grid-cols-2 gap-6">';
            
            // Gender Distribution
            $html .= '<div class="bg-white rounded-lg p-6 border">';
            $html .= '<h3 class="text-lg font-bold mb-4">Gender Distribution</h3>';
            $html .= '<div class="space-y-3">';
            $html .= '<div class="flex justify-between items-center"><span>Male</span><span class="font-bold text-blue-600">' . $maleCount . ' (' . ($totalMembers > 0 ? round(($maleCount/$totalMembers)*100, 1) : 0) . '%)</span></div>';
            $html .= '<div class="flex justify-between items-center"><span>Female</span><span class="font-bold text-pink-600">' . $femaleCount . ' (' . ($totalMembers > 0 ? round(($femaleCount/$totalMembers)*100, 1) : 0) . '%)</span></div>';
            $html .= '</div></div>';
            
            // Age Groups
            $html .= '<div class="bg-white rounded-lg p-6 border">';
            $html .= '<h3 class="text-lg font-bold mb-4">Age Distribution</h3>';
            $html .= '<div class="space-y-3">';
            $html .= '<div class="flex justify-between items-center"><span>Children (0-12)</span><span class="font-bold text-green-600">' . $children . '</span></div>';
            $html .= '<div class="flex justify-between items-center"><span>Youth (13-24)</span><span class="font-bold text-yellow-600">' . $youth . '</span></div>';
            $html .= '<div class="flex justify-between items-center"><span>Adults (25-59)</span><span class="font-bold text-blue-600">' . $adults . '</span></div>';
            $html .= '<div class="flex justify-between items-center"><span>Seniors (60+)</span><span class="font-bold text-purple-600">' . $seniors . '</span></div>';
            $html .= '</div></div>';
            
            $html .= '</div>';
            
        } catch (Exception $e) {
            $html = '<div class="bg-red-50 rounded-lg p-4"><p class="text-red-600">Error generating demographics report: ' . htmlspecialchars($e->getMessage()) . '</p></div>';
        }
        
        $response['html'] = $html;
        break;
        
    case 'location':
        $response['title'] = 'Location Report';
        
        try {
            $query = "SELECT area_id, district_id, assembly_id FROM members WHERE 1=1";
            $params = [];
            
            // Apply access level filters
            if ($accessLevel === 'assembly' && $assemblyId) {
                $query .= " AND assembly_id = :assembly_id";
                $params['assembly_id'] = $assemblyId;
            } elseif ($accessLevel === 'district' && $districtId) {
                $query .= " AND district_id = :district_id";
                $params['district_id'] = $districtId;
            } elseif ($accessLevel === 'area' && $areaId) {
                $query .= " AND area_id = :area_id";
                $params['area_id'] = $areaId;
            }
            
            $stmt = $db->prepare($query);
            $stmt->execute($params);
            $members = $stmt->fetchAll();
            
            // Count by location
            $areaStats = [];
            $districtStats = [];
            $assemblyStats = [];
            
            foreach ($members as $member) {
                $areaStats[$member['area_id']] = ($areaStats[$member['area_id']] ?? 0) + 1;
                $districtStats[$member['district_id']] = ($districtStats[$member['district_id']] ?? 0) + 1;
                $assemblyStats[$member['assembly_id']] = ($assemblyStats[$member['assembly_id']] ?? 0) + 1;
            }
            
            $html = '<div class="grid grid-cols-1 md:grid-cols-3 gap-6">';
            
            $html .= '<div class="bg-white rounded-lg p-6 border">';
            $html .= '<h3 class="text-lg font-bold mb-4">By Area</h3>';
            $html .= '<div class="space-y-2">';
            foreach ($areaStats as $areaId => $count) {
                $html .= '<div class="flex justify-between"><span>Area ' . $areaId . '</span><span class="font-bold">' . $count . '</span></div>';
            }
            $html .= '</div></div>';
            
            $html .= '<div class="bg-white rounded-lg p-6 border">';
            $html .= '<h3 class="text-lg font-bold mb-4">By District</h3>';
            $html .= '<div class="space-y-2">';
            foreach ($districtStats as $districtId => $count) {
                $html .= '<div class="flex justify-between"><span>District ' . $districtId . '</span><span class="font-bold">' . $count . '</span></div>';
            }
            $html .= '</div></div>';
            
            $html .= '<div class="bg-white rounded-lg p-6 border">';
            $html .= '<h3 class="text-lg font-bold mb-4">By Assembly</h3>';
            $html .= '<div class="space-y-2">';
            foreach ($assemblyStats as $assemblyId => $count) {
                $html .= '<div class="flex justify-between"><span>Assembly ' . $assemblyId . '</span><span class="font-bold">' . $count . '</span></div>';
            }
            $html .= '</div></div>';
            
            $html .= '</div>';
            
        } catch (Exception $e) {
            $html = '<div class="bg-red-50 rounded-lg p-4"><p class="text-red-600">Error generating location report: ' . htmlspecialchars($e->getMessage()) . '</p></div>';
        }
        
        $response['html'] = $html;
        break;
        
    case 'audit':
        $response['title'] = 'Audit Trail Report';
        
        try {
            // Check if audit_logs table exists
            $db->query("SELECT 1 FROM audit_logs LIMIT 1");
            
            $query = "SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 100";
            $stmt = $db->query($query);
            $logs = $stmt->fetchAll();
            
            $html = '<div class="bg-blue-50 rounded-lg p-4 mb-6">';
            $html .= '<h3 class="text-lg font-bold">Recent System Activity (Last 100 entries)</h3>';
            $html .= '</div>';
            
            if (!empty($logs)) {
                $html .= '<div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200">';
                $html .= '<thead class="bg-gray-50"><tr>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Date/Time</th>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">User</th>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Action</th>';
                $html .= '<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Details</th>';
                $html .= '</tr></thead><tbody class="bg-white divide-y divide-gray-200">';
                
                foreach ($logs as $log) {
                    $html .= '<tr>';
                    $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($log['created_at']) . '</td>';
                    $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($log['user_id'] ?? 'System') . '</td>';
                    $html .= '<td class="px-6 py-4 whitespace-nowrap text-sm">' . htmlspecialchars($log['action'] ?? 'N/A') . '</td>';
                    $html .= '<td class="px-6 py-4 text-sm">' . htmlspecialchars($log['details'] ?? 'N/A') . '</td>';
                    $html .= '</tr>';
                }
                $html .= '</tbody></table></div>';
            } else {
                $html .= '<div class="text-center py-8"><p class="text-gray-500">No audit logs found</p></div>';
            }
            
        } catch (Exception $e) {
            $html = '<div class="bg-yellow-50 rounded-lg p-4">';
            $html .= '<p class="text-yellow-700">Audit logging is not yet configured. This feature tracks system activities and user actions.</p>';
            $html .= '</div>';
        }
        
        $response['html'] = $html;
        break;
        
    case 'custom':
        $response['title'] = 'Custom Report Builder';
        
        $html = '<div class="bg-gradient-to-r from-blue-50 to-purple-50 rounded-lg p-8">';
        $html .= '<div class="text-center">';
        $html .= '<i class="fas fa-tools text-6xl text-gray-400 mb-4"></i>';
        $html .= '<h3 class="text-2xl font-bold text-gray-800 mb-4">Custom Report Builder</h3>';
        $html .= '<p class="text-gray-600 mb-6">Build custom reports with advanced filtering and data selection options.</p>';
        $html .= '<div class="bg-white rounded-lg p-6 max-w-md mx-auto">';
        $html .= '<h4 class="font-bold mb-4">Coming Soon Features:</h4>';
        $html .= '<ul class="text-left space-y-2 text-sm text-gray-600">';
        $html .= '<li>• Drag & drop report builder</li>';
        $html .= '<li>• Custom field selection</li>';
        $html .= '<li>• Advanced filtering options</li>';
        $html .= '<li>• Chart and graph generation</li>';
        $html .= '<li>• Scheduled report delivery</li>';
        $html .= '</ul>';
        $html .= '</div>';
        $html .= '</div>';
        $html .= '</div>';
        
        $response['html'] = $html;
        break;
        
    default:
        $response['success'] = false;
        $response['message'] = 'Invalid report type';
}

echo json_encode($response);

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists