From 9895cb618186d378f339239dcc6d29b82ea644a0 Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Mon, 13 Jul 2026 16:00:34 +0530 Subject: [PATCH 1/3] FIX_GPA_TPA_ISSUE --- app/Controllers/ClientController.php | 16 ++++++++-------- app/Views/client_policy.php | 8 +++++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index b56714a0..d64146ee 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -2994,20 +2994,20 @@ class ClientController extends AdminController $base_policy = $sanitized_post_data['base_policy'] ?? null; - $insurerValue = (string) $sanitized_post_data['insurer'] ?? null; + $insurerValue = (string) ($sanitized_post_data['insurer'] ?? ''); list($insurerBranchId, $insurerId) = explode('-', $insurerValue); $sanitized_post_data['insurer_branch_id'] = $insurerBranchId; $sanitized_post_data['insurer_id'] = $insurerId; - $tpaValue = (string) $sanitized_post_data['tpa'] ?? null; + $tpaValue = (string) ($sanitized_post_data['tpa'] ?? ''); - if ($tpaValue === null || $tpaValue === '') { + if ($tpaValue === '') { $tpaBranchId = null; $tpaId = null; } else { - list($tpaBranchId, $tpaId) = explode('-', $tpaValue); + list($tpaBranchId, $tpaId) = array_pad(explode('-', $tpaValue, 2), 2, null); } @@ -3197,15 +3197,15 @@ class ClientController extends AdminController $base_policy = $sanitized_post_data['base_policy'] ?? null; - $insurerValue = (string) $sanitized_post_data['insurer']; + $insurerValue = (string) ($sanitized_post_data['insurer'] ?? ''); list($insurerBranchId, $insurerId) = explode('-', $insurerValue); $sanitized_post_data['insurer_branch_id'] = $insurerBranchId ?? null; $sanitized_post_data['insurer_id'] = $insurerId ?? null; - $tpaValue = (string) $sanitized_post_data['tpa'] ?? null; - if (!empty($tpaValue) || $tpaValue !== '') { - list($tpaBranchId, $tpaId) = explode('-', $tpaValue); + $tpaValue = (string) ($sanitized_post_data['tpa'] ?? ''); + if ($tpaValue !== '') { + list($tpaBranchId, $tpaId) = array_pad(explode('-', $tpaValue, 2), 2, null); } else { $tpaBranchId = null; $tpaId = null; diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php index 5b54fbe1..dd898b7a 100755 --- a/app/Views/client_policy.php +++ b/app/Views/client_policy.php @@ -751,6 +751,8 @@ input:checked + .slider_blue::before { $('.loader-mask').fadeIn(); var formData = new FormData($('#policy_form')[0]); + // TPA is optional for GPA and some other policy types; ensure the key is always posted + formData.set('tpa', $('#tpa').val() || ''); ['policy_start_date', 'policy_end_date', 'open_date', 'close_date'].forEach(function(fieldName) { var val = formData.get(fieldName); if (val) { @@ -2056,7 +2058,11 @@ input:checked + .slider_blue::before { if(res.status == true){ $('#insurer').val(res.data.insurer_branch_id + '-' + res.data.insurer_id).change(); - $('#tpa').val(res.data.tpa_branch_id + '-' + res.data.tpa_id).change(); + var baseTpaValue = ''; + if (res.data.tpa_branch_id && res.data.tpa_id) { + baseTpaValue = res.data.tpa_branch_id + '-' + res.data.tpa_id; + } + $('#tpa').val(baseTpaValue).change(); $('#policy_no').val(res.data.policy_no).change(); // $('#open_date').val(rearrangeDateFormat(res.data.open_date)).change(); // $('#close_date').val(rearrangeDateFormat(res.data.close_date)).change(); From 9e241db7a467882e004f96907dd72e6e90a5be46 Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Mon, 13 Jul 2026 17:48:00 +0530 Subject: [PATCH 2/3] FIX_DASHBOARD_OPTIMIZATIONS --- app/Config/Routes.php | 2 + app/Controllers/DashboardController.php | 160 ++++---- app/Controllers/PendingActionsController.php | 375 ++++++++++++++----- app/Models/PolicyTransactionModel.php | 66 ++-- app/Models/TicketMasterModel.php | 45 ++- app/Views/DashBoard.php | 78 +++- app/Views/claims_dash.php | 19 +- app/Views/leads_dash.php | 13 +- 8 files changed, 497 insertions(+), 261 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index db43bc32..d2df5889 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -116,6 +116,8 @@ $routes->group("/user", ["filter" => "authMVC"], function ($routes) { $routes->group("/dashboard", ["filter" => "authMVC"], function ($routes) { $routes->get("view", "DashboardController::dashboard"); + $routes->get("claims-dash", "DashboardController::claimsDashFragment"); + $routes->get("leads-dash", "DashboardController::leadsDashFragment"); $routes->get('get-notification', 'DashboardController::getDashboardNotifications'); $routes->get('acknowledge-notification/(:segment)', 'DashboardController::acknowledgeMessage/$1'); $routes->get('get-pending-action', 'PendingActionsController::getPendingActions'); diff --git a/app/Controllers/DashboardController.php b/app/Controllers/DashboardController.php index 3ff685d7..a7464980 100755 --- a/app/Controllers/DashboardController.php +++ b/app/Controllers/DashboardController.php @@ -191,105 +191,101 @@ class DashboardController extends AdminController public function dashboard() { - $data = []; + $roleId = get_role_id(); + $teams = user_team(); - if (in_array(get_role_id(), [1, 2, 3, 5]) || (in_array(MANAGEMENT_TEAM_ID, user_team()) || in_array(FINANCE_TEAM_ID, user_team()) || in_array(BUSINESS_TEAM_ID, user_team()))) { + $showPending = in_array($roleId, [1, 2, 3, 5]); + $showClaims = ($roleId == STAFF_ROLE_ID && in_array(CLAIMS_TEAM_ID, $teams)) || in_array($roleId, [1, 5]); + $showLeads = ($roleId == STAFF_ROLE_ID && in_array(ENROLLMENT_TEAM_ID, $teams)) || in_array($roleId, [1, 5]); - $db = db_connect(); - $sql = "SELECT - clients.id AS client_id, - clients.client_name, - clients.short_name, - client_branch.id AS client_branch_id, - client_branch.branch_name, - client_branch.branch_code, - - COUNT(employees.id) AS total_employees, - SUM(CASE WHEN employees.emp_status = 'draft' THEN 1 ELSE 0 END) AS draft_count, - SUM(CASE WHEN employees.emp_status IN ('enrolled', 'active') THEN 1 ELSE 0 END) AS enrolled_count, - - SUM(CASE WHEN auth_history.user_id IS NOT NULL THEN 1 ELSE 0 END) AS logged_in_count, - SUM(CASE WHEN auth_history.user_id IS NULL THEN 1 ELSE 0 END) AS not_logged_in_count, - - CASE - WHEN EXISTS ( - SELECT 1 FROM client_policy - WHERE client_policy.client_branch_id = client_branch.id - AND client_policy.is_active = 1 - AND client_policy.open_for_enrollment = 1 - ) THEN 1 - ELSE 0 - END AS open_or_close_enrollment - - FROM clients - LEFT JOIN client_branch ON clients.id = client_branch.client_id - LEFT JOIN employees ON client_branch.id = employees.client_branch_id - LEFT JOIN ( - SELECT user_id, user_type - FROM auth_history - WHERE user_type = 'employee' - GROUP BY user_id - ) AS auth_history ON employees.id = auth_history.user_id - - WHERE employees.relationship = 'Self' - AND employees.emp_status IN ('draft', 'enrolled', 'active') - AND employees.is_active = 1 - AND clients.is_active = 1 - AND client_branch.is_active = 1 - - GROUP BY clients.id, client_branch.id"; - - $query = $db->query($sql); - $results = $query->getResultArray(); - - $pendingActionsController = new PendingActionsController; - $pendingActionsData = $pendingActionsController->getPendingActionsForDashBoard(); - - //BDS dashboard data - // $businessTeamData = $this->policyTransactionModel->getBusinessReportList(); - // $financeTeamData = $this->policyTransactionModel->getFinanceReportList(); - // $businessTeamStatusData = $this->data_construct_for_bds($businessTeamData); - // $financeTeamStatusData = $this->data_construct_for_bds($financeTeamData); - $businessTeamData = []; - $financeTeamData = []; - $businessTeamStatusData = []; - $financeTeamStatusData = []; - - $data['client_branch_emp_list'] = $results; - $session = \Config\Services::session(); - // $session->set('enrollment_data', json_encode($data)); - - $data['pendingActionsData'] = $pendingActionsData; - $data['businessTeamCount'] = count($businessTeamData) ?? 0; - $data['financeTeamCount'] = count($financeTeamData) ?? 0; - $data['businessTeamStatusData'] = $businessTeamStatusData; - $data['financeTeamStatusData'] = $financeTeamStatusData; - $data['policyStatus'] = $this->policyStatus; - $data['colorShades'] = $this->colorShades; + if ($showPending) { + $defaultPane = 'pending'; + } elseif ($showClaims) { + $defaultPane = 'claims'; + } elseif ($showLeads) { + $defaultPane = 'leads'; + } else { + $defaultPane = null; } - if ((get_role_id() == STAFF_ROLE_ID && in_array(CLAIMS_TEAM_ID,user_team())) || in_array(get_role_id(),[1,5])){ + + if ($showPending) { + $pendingActionsController = new PendingActionsController(); + $data['pendingActionsData'] = $pendingActionsController->getPendingActionsForDashBoard(); + $data['businessTeamCount'] = 0; + $data['financeTeamCount'] = 0; + $data['businessTeamStatusData'] = []; + $data['financeTeamStatusData'] = []; + $data['policyStatus'] = $this->policyStatus; + $data['colorShades'] = $this->colorShades; + } + + // Only the default tab loads with the page; other tabs fetch on click. + $data['lazy_load_claims'] = $showClaims && $defaultPane !== 'claims'; + $data['lazy_load_leads'] = $showLeads && $defaultPane !== 'leads'; + + if ($showClaims && !$data['lazy_load_claims']) { $data['claim_data'] = $this->getClaimData(); - $data['colorShades'] = $this->colorShades; - + $data['colorShades'] = $this->colorShades; } - if ((get_role_id() == STAFF_ROLE_ID && in_array(ENROLLMENT_TEAM_ID,user_team())) || in_array(get_role_id(),[1,5])){ + + if ($showLeads && !$data['lazy_load_leads']) { $data['lead_data'] = $this->leadModel->getDashData(); $data['bds_renewal'] = $this->policyTransactionModel->getBDSRenewalData(); - $data['colorShades'] = $this->colorShades; - + $data['colorShades'] = $this->colorShades; } - // dd(get_role_id(),user_team()); - // dd($data); $data['tab_name'] = 'Dashboard'; $data['page_name'] = 'Dashboard'; - echo view('layout/header', $data); + echo view('layout/header', $data); echo view('DashBoard', $data); echo view('layout/footer'); } + /** + * HTML fragment for Claims dashboard tab (loaded on tab click). + */ + public function claimsDashFragment() + { + $roleId = get_role_id(); + $teams = user_team(); + $allowed = ($roleId == STAFF_ROLE_ID && in_array(CLAIMS_TEAM_ID, $teams)) || in_array($roleId, [1, 5]); + if (!$allowed) { + return $this->response->setStatusCode(403)->setBody('Forbidden'); + } + + $data = [ + 'claim_data' => $this->getClaimData(), + 'colorShades' => $this->colorShades, + 'dash_claims_pane_active' => 'active show', + ]; + + return $this->response->setBody(view('claims_dash', $data)); + } + + /** + * HTML fragment for Leads / BDS Renewals dashboard tab (loaded on tab click). + */ + public function leadsDashFragment() + { + $roleId = get_role_id(); + $teams = user_team(); + $allowed = ($roleId == STAFF_ROLE_ID && in_array(ENROLLMENT_TEAM_ID, $teams)) || in_array($roleId, [1, 5]); + if (!$allowed) { + return $this->response->setStatusCode(403)->setBody('Forbidden'); + } + + $data = [ + 'lead_data' => $this->leadModel->getDashData(), + 'bds_renewal' => $this->policyTransactionModel->getBDSRenewalData(), + 'colorShades' => $this->colorShades, + 'dash_leads_pane_active' => 'active show', + ]; + + return $this->response->setBody(view('leads_dash', $data)); + } + public function getClaimData() { diff --git a/app/Controllers/PendingActionsController.php b/app/Controllers/PendingActionsController.php index bb8f2e92..0151f0c2 100755 --- a/app/Controllers/PendingActionsController.php +++ b/app/Controllers/PendingActionsController.php @@ -97,115 +97,292 @@ class PendingActionsController extends AdminController return $data; } - //for only COUNT + /** + * Dashboard counts only — avoids loading full pending-action rowsets. + * Cached briefly so repeated dashboard hits don't re-run heavy aggregations. + */ public function getPendingActionsForDashBoard() { - $tpa = $this->getPendingActionForTPAIDEmpty(); - $uhid = $this->getPendingActionForUHIDEmpty(); - $deletion = $this->getPendingActionForDeletion(); - $inception = $this->getPendingActionForInception(); - $ticketData = $this->getTicketsDataForDashBoard(); - $correction = $this->getPendingActionForCorrection(); - $si_enhancement = $this->getPendingActionForSIEnhancement(); - $PolicyRenewalData = $this->getPolicyRenewalDataForAllClient(); - - $uhid_export_count = []; - $uhid_not_export_count = []; - foreach ($uhid as $value) { - if($value['batch_export_count'] == 1){ - $uhid_export_count[] = $value['batch_export_count']; - }else{ - $uhid_not_export_count[] = $value['batch_export_count']; - } - } - $tpa_export_count = []; - $tpa_not_export_count = []; - foreach ($tpa as $value) { - if($value['batch_export_count'] == 1){ - $tpa_export_count[] = $value['batch_export_count']; - }else{ - $tpa_not_export_count[] = $value['batch_export_count']; - } - } - $deletion_export_count = []; - $deletion_not_export_count = []; - foreach ($deletion as $value) { - if($value['batch_export_count'] == 1){ - $deletion_export_count[] = $value['batch_export_count']; - }else{ - $deletion_not_export_count[] = $value['batch_export_count']; - } - } - $correction_export_count = []; - $correction_not_export_count = []; - foreach ($correction as $value) { - if($value['batch_export_count'] == 1){ - $correction_export_count[] = $value['batch_export_count']; - }else{ - $correction_not_export_count[] = $value['batch_export_count']; - } - } - $si_export_count = []; - $si_not_export_count = []; - foreach ($si_enhancement as $value) { - if($value['batch_export_count'] == 1){ - $si_export_count[] = $value['batch_export_count']; - }else{ - $si_not_export_count[] = $value['batch_export_count']; - } + $cache = \Config\Services::cache(); + $cacheKey = 'dashboard_pending_actions_counts_v2'; + $cached = $cache->get($cacheKey); + if (is_array($cached)) { + return $cached; } - // dd($uhid_export_count, $tpa_export_count ,$deletion_export_count, $correction_export_count, $si_export_count, $ticketData, $inception, $si_enhancement, $correction, $deletion, $tpa, $uhid, $PolicyRenewalData); - - $inception = count($inception); - $correction = count($correction); - $si_enhancement = count($si_enhancement); - $deletion = count($deletion); - $tpa = count($tpa); - $uhid = count($uhid); - $PolicyRenewalData = count($PolicyRenewalData); - $ticketData = count($ticketData); - - $uhid_export_count = count($uhid_export_count); - $tpa_export_count = count($tpa_export_count); - $deletion_export_count = count($deletion_export_count); - $correction_export_count = count($correction_export_count); - $si_export_count = count($si_export_count); - - $uhid_not_export_count = count($uhid_not_export_count); - $tpa_not_export_count = count($tpa_not_export_count); - $deletion_not_export_count = count($deletion_not_export_count); - $correction_not_export_count = count($correction_not_export_count); - $si_not_export_count = count($si_not_export_count); - - - // dd($inception, $si_enhancement, $correction, $deletion, $tpa, $uhid, $PolicyRenewalData); + $uhidCounts = $this->countPendingUhidForDashboard(); + $tpaCounts = $this->countPendingTpaForDashboard(); + $correctionCounts = $this->countPendingCorrectionForDashboard(); + $deletionCounts = $this->countPendingDeletionForDashboard(); + $siCounts = $this->countPendingSiForDashboard(); $data = [ - 'inception' => $inception, - 'correction' => $correction, - 'si_enhancement' => $si_enhancement, - 'deletion' => $deletion, - 'tpa' => $tpa, - 'uhid' => $uhid, - 'PolicyRenewalData' => $PolicyRenewalData, - 'ticketData' => $ticketData, - - 'uhid_export_count' => $uhid_export_count, - 'tpa_export_count' => $tpa_export_count, - 'deletion_export_count' => $deletion_export_count, - 'correction_export_count' => $correction_export_count, - 'si_export_count' => $si_export_count, - - 'uhid_not_export_count' => $uhid_not_export_count, - 'tpa_not_export_count' => $tpa_not_export_count, - 'deletion_not_export_count' => $deletion_not_export_count, - 'correction_not_export_count' => $correction_not_export_count, - 'si_not_export_count' => $si_not_export_count, + 'inception' => $this->countPendingInceptionForDashboard(), + 'correction' => $correctionCounts['total'], + 'si_enhancement' => $siCounts['total'], + 'deletion' => $deletionCounts['total'], + 'tpa' => $tpaCounts['total'], + 'uhid' => $uhidCounts['total'], + 'PolicyRenewalData' => $this->countPolicyRenewalForDashboard(), + 'ticketData' => $this->countTicketsForDashboard(), + 'uhid_export_count' => $uhidCounts['export_count'], + 'tpa_export_count' => $tpaCounts['export_count'], + 'deletion_export_count' => $deletionCounts['export_count'], + 'correction_export_count' => $correctionCounts['export_count'], + 'si_export_count' => $siCounts['export_count'], + 'uhid_not_export_count' => $uhidCounts['not_export_count'], + 'tpa_not_export_count' => $tpaCounts['not_export_count'], + 'deletion_not_export_count' => $deletionCounts['not_export_count'], + 'correction_not_export_count' => $correctionCounts['not_export_count'], + 'si_not_export_count' => $siCounts['not_export_count'], ]; + + $cache->save($cacheKey, $data, 60); + return $data; } + private function countPendingInceptionForDashboard(): int + { + // NOT EXISTS avoids scanning employee_polices for every open policy via LEFT JOIN + HAVING. + $sql = " + SELECT COUNT(*) AS cnt + FROM client_policy cp + INNER JOIN clients ON cp.client_id = clients.id + INNER JOIN client_branch cb ON cb.id = cp.client_branch_id + INNER JOIN policy_type ON cp.policy_type_id = policy_type.id + WHERE cp.is_active = 1 + AND cp.open_for_enrollment = 1 + AND cp.is_addon = 1 + AND cp.policy_status = 1 + AND cp.inception_type = 1 + AND cp.policy_type_id IN (1, 2, 3) + AND NOT EXISTS ( + SELECT 1 + FROM employee_polices ep + WHERE ep.client_policy_id = cp.id + AND ep.is_active = 1 + ) + "; + + return (int) ($this->db->query($sql)->getRowArray()['cnt'] ?? 0); + } + + private function countPendingUhidForDashboard(): array + { + // Aggregate batch_files once, then join — correlated COUNT per policy was acceptable but JOIN scales better. + $sql = " + SELECT + COUNT(*) AS total, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) = 1 THEN 1 ELSE 0 END) AS export_count, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) != 1 THEN 1 ELSE 0 END) AS not_export_count + FROM ( + SELECT ep.client_policy_id + FROM employee_polices ep + INNER JOIN client_policy cp + ON ep.client_policy_id = cp.id + AND cp.is_active = 1 + AND cp.policy_status = 1 + INNER JOIN clients c ON c.id = cp.client_id + INNER JOIN client_branch cb ON cb.id = cp.client_branch_id + INNER JOIN policy_type ON policy_type.id = cp.policy_type_id + WHERE ep.uhid IS NULL + AND ep.status = 'active' + AND ep.is_active = 1 + GROUP BY ep.client_policy_id + ) AS pending + LEFT JOIN ( + SELECT client_policy_id, COUNT(*) AS export_cnt + FROM batch_files + WHERE actions = 'export' + AND event_type = 'inception' + AND insurer_or_tpa = 'insurer' + GROUP BY client_policy_id + ) AS bf ON bf.client_policy_id = pending.client_policy_id + "; + + return $this->normalizeExportCounts($this->db->query($sql)->getRowArray()); + } + + private function countPendingTpaForDashboard(): array + { + $sql = " + SELECT + COUNT(*) AS total, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) = 1 THEN 1 ELSE 0 END) AS export_count, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) != 1 THEN 1 ELSE 0 END) AS not_export_count + FROM ( + SELECT employee_polices.client_policy_id + FROM employee_polices + INNER JOIN client_policy + ON employee_polices.client_policy_id = client_policy.id + AND client_policy.is_active = 1 + AND client_policy.policy_status = 1 + INNER JOIN clients ON clients.id = client_policy.client_id + INNER JOIN client_branch ON client_branch.id = client_policy.client_branch_id + INNER JOIN policy_type ON policy_type.id = client_policy.policy_type_id + WHERE employee_polices.tpa_id IS NULL + AND employee_polices.uhid IS NOT NULL + AND employee_polices.status = 'active' + AND employee_polices.is_active = 1 + GROUP BY employee_polices.client_policy_id + ) AS pending + LEFT JOIN ( + SELECT client_policy_id, COUNT(*) AS export_cnt + FROM batch_files + WHERE actions = 'export' + AND event_type = 'inception' + AND insurer_or_tpa = 'tpa' + GROUP BY client_policy_id + ) AS bf ON bf.client_policy_id = pending.client_policy_id + "; + + return $this->normalizeExportCounts($this->db->query($sql)->getRowArray()); + } + + /** + * Start from pending emp_endorsement rows — NOT from all clients with EXISTS + * (EXISTS over every client was hanging for minutes on staging ~500k policies). + */ + private function countPendingCorrectionForDashboard(): array + { + $sql = " + SELECT + COUNT(*) AS total, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) = 1 THEN 1 ELSE 0 END) AS export_count, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) != 1 THEN 1 ELSE 0 END) AS not_export_count + FROM ( + SELECT e.client_id + FROM emp_endorsement ee + INNER JOIN employees e + ON ee.pk = e.id + AND e.is_active = 1 + AND e.emp_status = 'active' + WHERE ee.actions = 'c' + AND ee.is_active = 1 + AND ee.status = 'pending' + AND ee.endorsement_id IS NULL + GROUP BY e.client_id + ) AS pending + LEFT JOIN ( + SELECT client_id, COUNT(*) AS export_cnt + FROM batch_files + WHERE actions = 'export' + AND event_type = 'correction' + AND insurer_or_tpa = 'tpa' + GROUP BY client_id + ) AS bf ON bf.client_id = pending.client_id + "; + + return $this->normalizeExportCounts($this->db->query($sql)->getRowArray()); + } + + private function countPendingDeletionForDashboard(): array + { + $sql = " + SELECT + COUNT(*) AS total, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) = 1 THEN 1 ELSE 0 END) AS export_count, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) != 1 THEN 1 ELSE 0 END) AS not_export_count + FROM ( + SELECT cp.client_id + FROM emp_endorsement ee + INNER JOIN employee_polices ep + ON ee.pk = ep.id + AND ep.is_active = 1 + AND ep.status = 'active' + INNER JOIN client_policy cp + ON ep.client_policy_id = cp.id + AND cp.is_active = 1 + AND cp.policy_status = 1 + WHERE ee.actions = 'd' + AND ee.is_active = 1 + AND ee.status = 'pending' + AND ee.endorsement_id IS NULL + AND ee.table_name = 'employee_polices' + GROUP BY cp.client_id + ) AS pending + LEFT JOIN ( + SELECT client_id, COUNT(*) AS export_cnt + FROM batch_files + WHERE actions = 'export' + AND event_type = 'deletion' + AND insurer_or_tpa = 'insurer' + GROUP BY client_id + ) AS bf ON bf.client_id = pending.client_id + "; + + return $this->normalizeExportCounts($this->db->query($sql)->getRowArray()); + } + + private function countPendingSiForDashboard(): array + { + $sql = " + SELECT + COUNT(*) AS total, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) = 1 THEN 1 ELSE 0 END) AS export_count, + SUM(CASE WHEN COALESCE(bf.export_cnt, 0) != 1 THEN 1 ELSE 0 END) AS not_export_count + FROM ( + SELECT cp.client_id + FROM emp_endorsement ee + INNER JOIN employee_polices ep + ON ee.pk = ep.id + AND ep.is_active = 1 + AND ep.status = 'active' + INNER JOIN client_policy cp + ON ep.client_policy_id = cp.id + AND cp.is_active = 1 + AND cp.policy_status = 1 + WHERE ee.actions = 'si' + AND ee.is_active = 1 + AND ee.status = 'pending' + AND ee.endorsement_id IS NULL + GROUP BY cp.client_id + ) AS pending + LEFT JOIN ( + SELECT client_id, COUNT(*) AS export_cnt + FROM batch_files + WHERE actions = 'export' + AND event_type = 'si_enhancement' + AND insurer_or_tpa = 'tpa' + GROUP BY client_id + ) AS bf ON bf.client_id = pending.client_id + "; + + return $this->normalizeExportCounts($this->db->query($sql)->getRowArray()); + } + + private function countPolicyRenewalForDashboard(): int + { + return (int) $this->clientPolicyModel + ->join('clients', 'clients.id = client_policy.client_id') + ->join('client_branch', 'client_branch.id = client_policy.client_branch_id') + ->where('client_policy.is_active', 1) + ->where('client_policy.policy_status', 0) + ->where('clients.is_active', 1) + ->where('client_branch.is_active', 1) + ->where('client_policy.policy_end_date < DATE_ADD(CURDATE(), INTERVAL 2 MONTH)', null, false) + ->countAllResults(); + } + + private function countTicketsForDashboard(): int + { + return (int) $this->db->table('hdz_tickets') + ->join('hdz_status', 'hdz_status.id = hdz_tickets.status') + ->where('hdz_status.active', 1) + ->where('hdz_tickets.status !=', 5) + ->countAllResults(); + } + + private function normalizeExportCounts(?array $row): array + { + return [ + 'total' => (int) ($row['total'] ?? 0), + 'export_count' => (int) ($row['export_count'] ?? 0), + 'not_export_count' => (int) ($row['not_export_count'] ?? 0), + ]; + } + diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php index 4f051a66..3f12e119 100644 --- a/app/Models/PolicyTransactionModel.php +++ b/app/Models/PolicyTransactionModel.php @@ -2186,42 +2186,44 @@ // Increase GROUP_CONCAT limit $this->db->query("SET SESSION group_concat_max_len = 1000000;"); - $builder = $this->db->table('policy_transaction pt'); + // NOT EXISTS avoids a self-join that balloons on large policy_transaction tables. + $sql = " + SELECT + SUM(CASE WHEN pt.policy_end_date < CURDATE() THEN 1 ELSE 0 END) AS Expired, + SUM(CASE WHEN pt.policy_end_date BETWEEN CURDATE() AND (CURDATE() + INTERVAL 1 MONTH) THEN 1 ELSE 0 END) AS `Renewal Pending`, + GROUP_CONCAT(CASE WHEN pt.policy_end_date < CURDATE() THEN pt.id ELSE NULL END) AS Expired_ids, + GROUP_CONCAT(CASE WHEN pt.policy_end_date BETWEEN CURDATE() AND (CURDATE() + INTERVAL 1 MONTH) THEN pt.id ELSE NULL END) AS Renewal_Pending_ids + FROM policy_transaction pt + WHERE pt.policy_end_date IS NOT NULL + AND pt.is_active = 1 + AND ( + pt.policy_end_date < CURDATE() + OR pt.policy_end_date BETWEEN CURDATE() AND (CURDATE() + INTERVAL 1 MONTH) + ) + AND NOT EXISTS ( + SELECT 1 + FROM policy_transaction renewed + WHERE renewed.source_client_policy_id = pt.client_policy_id + AND renewed.client_id = pt.client_id + AND renewed.client_branch_id = pt.client_branch_id + ) + "; - $builder->select([ - 'SUM(CASE WHEN pt.policy_end_date < CURDATE() THEN 1 ELSE 0 END) AS Expired', - 'SUM(CASE WHEN pt.policy_end_date BETWEEN CURDATE() AND (CURDATE() + INTERVAL 1 MONTH) THEN 1 ELSE 0 END) AS `Renewal Pending`', - 'GROUP_CONCAT(CASE WHEN pt.policy_end_date < CURDATE() THEN pt.id ELSE NULL END) AS Expired_ids', - 'GROUP_CONCAT(CASE WHEN pt.policy_end_date BETWEEN CURDATE() AND (CURDATE() + INTERVAL 1 MONTH) THEN pt.id ELSE NULL END) AS Renewal_Pending_ids' - ]); - $builder->where("pt.policy_end_date IS NOT NULL", null, false); - $builder->where('pt.is_active', 1); + $result = $this->db->query($sql)->getResultArray(); + $row = $result[0] ?? [ + 'Expired' => 0, + 'Renewal Pending' => 0, + 'Expired_ids' => null, + 'Renewal_Pending_ids' => null, + ]; - // Self join to check if a policy has been renewed - $builder->join('policy_transaction renewed', 'renewed.source_client_policy_id = pt.client_policy_id and renewed.client_id = pt.client_id and renewed.client_branch_id = pt.client_branch_id', 'left'); + $total = (int) ($row['Expired'] ?? 0) + (int) ($row['Renewal Pending'] ?? 0); - // Filter for expired or expiring policies - $builder->where("(pt.policy_end_date < CURDATE() OR pt.policy_end_date BETWEEN CURDATE() AND (CURDATE() + INTERVAL 1 MONTH))", null, false); + $row['Expired_ids'] = $row['Expired_ids'] ?: []; + $row['Renewal Pending_ids'] = $row['Renewal_Pending_ids'] ?: []; + $row['total'] = $total; - $builder->where('renewed.id IS NULL', null, false); - $query = $builder->get(); - $result = $query->getResultArray(); - - $total = 0; - foreach ($result[0] as $key => $value) { - if ($key !== 'Expired_ids' && $key !== 'Renewal_Pending_ids') { - $total += $value; - } - } - - // Ensure ID fields are arrays (not null) - $result[0]['Expired_ids'] = $result[0]['Expired_ids'] ? $result[0]['Expired_ids'] : []; - $result[0]['Renewal Pending_ids'] = $result[0]['Renewal_Pending_ids'] ? $result[0]['Renewal_Pending_ids'] : []; - - // Add total count - $result[0]['total'] = $total; - - return $result[0]; + return $row; } public function reportBDSNew( diff --git a/app/Models/TicketMasterModel.php b/app/Models/TicketMasterModel.php index fe3b4c00..07bdd813 100644 --- a/app/Models/TicketMasterModel.php +++ b/app/Models/TicketMasterModel.php @@ -878,25 +878,37 @@ class TicketMasterModel extends Model public function getDashData($claim_statuses, $limit) { $finalResults = []; + if (empty($claim_statuses)) { + return $finalResults; + } - foreach ($claim_statuses as $typeId => $statuses) { - // Get all active, non-null claim status tickets for this type - $builder = $this->db->table('ticket_master tm') - ->select('tm.id, tm.ticket_type_id, tcs.claim_status, th.last_claim_status_change') - ->join('ticket_claim_status tcs', 'tm.claim_status_id = tcs.id', 'left') - ->join( - '(SELECT ticket_id, MAX(created_at) AS last_claim_status_change + $typeIds = array_map('intval', array_keys($claim_statuses)); + + // One history aggregate + one ticket pull for all types (was 4 full scans). + $builder = $this->db->table('ticket_master tm') + ->select('tm.id, tm.ticket_type_id, tcs.claim_status, th.last_claim_status_change') + ->join('ticket_claim_status tcs', 'tm.claim_status_id = tcs.id', 'left') + ->join( + '(SELECT ticket_id, MAX(created_at) AS last_claim_status_change FROM ticket_history WHERE field_name = \'claim_status_id\' GROUP BY ticket_id) th', - 'tm.id = th.ticket_id', - 'left' - ) - ->where('tm.ticket_type_id', $typeId) - ->where('tm.is_active', 1) - ->where('tm.claim_status_id IS NOT NULL'); + 'tm.id = th.ticket_id', + 'left' + ) + ->whereIn('tm.ticket_type_id', $typeIds) + ->where('tm.is_active', 1) + ->where('tm.claim_status_id IS NOT NULL'); - $results = $builder->get()->getResultArray(); + $allRows = $builder->get()->getResultArray(); + + $rowsByType = []; + foreach ($allRows as $row) { + $rowsByType[$row['ticket_type_id']][] = $row; + } + + foreach ($claim_statuses as $typeId => $statuses) { + $results = $rowsByType[$typeId] ?? []; $summary = [ 'ticket_type_id' => $typeId, @@ -912,7 +924,6 @@ class TicketMasterModel extends Model $threshold = date('Y-m-d H:i:s', strtotime("-{$dateLimit} days")); $ticketIds = []; - // dd($results); foreach ($results as $row) { if ( $row['claim_status'] === $status && @@ -928,17 +939,14 @@ class TicketMasterModel extends Model } $total++; - } } - // Convert ticket IDs array to a comma-separated string $summary[$alias . '_ids'] = implode(',', $ticketIds); } $summary['total'] = $total; - // Add approved but not settled IDs and count $approvedNotSettled = $this->getNotSettledbutApprovedCount($typeId); $summary['approved_not_settled'] = $approvedNotSettled['count']; $summary['approved_not_settled_ids'] = $approvedNotSettled['ticket_ids']; @@ -946,7 +954,6 @@ class TicketMasterModel extends Model $finalResults[$typeId] = $summary; } - // dd($finalResults); return $finalResults; } diff --git a/app/Views/DashBoard.php b/app/Views/DashBoard.php index 561e8098..88e0a6c0 100755 --- a/app/Views/DashBoard.php +++ b/app/Views/DashBoard.php @@ -259,7 +259,7 @@ // $isActive = get_role_id() == STAFF_ROLE_ID && in_array(ENROLLMENT_TEAM_ID,user_team()) ? 'active show' : ''; ?> -->