diff --git a/app/Database/bds_report_performance_indexes.sql b/app/Database/bds_report_performance_indexes.sql new file mode 100644 index 00000000..a3e1291a --- /dev/null +++ b/app/Database/bds_report_performance_indexes.sql @@ -0,0 +1,55 @@ +-- BDS report performance indexes +-- Run manually on the application database (e.g. nhance_live). +-- Safe to re-run: each statement checks information_schema before creating. + +-- policy_transaction: default 90-day filter + active flag +SET @idx := ( + SELECT COUNT(1) FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'policy_transaction' + AND index_name = 'idx_pt_active_created' +); +SET @sql := IF(@idx = 0, + 'CREATE INDEX idx_pt_active_created ON policy_transaction (is_active, created_at)', + 'SELECT ''idx_pt_active_created already exists'' AS info' +); +PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +-- pt_co_share_details: join from policy_transaction +SET @idx := ( + SELECT COUNT(1) FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'pt_co_share_details' + AND index_name = 'idx_pcsd_pt_active' +); +SET @sql := IF(@idx = 0, + 'CREATE INDEX idx_pcsd_pt_active ON pt_co_share_details (pt_id, is_active)', + 'SELECT ''idx_pcsd_pt_active already exists'' AS info' +); +PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +-- co_share_stmt_details: billed/reward aggregate joins +SET @idx := ( + SELECT COUNT(1) FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'co_share_stmt_details' + AND index_name = 'idx_cssd_coshare_stmt_active' +); +SET @sql := IF(@idx = 0, + 'CREATE INDEX idx_cssd_coshare_stmt_active ON co_share_stmt_details (co_share_id, statement_id, is_active)', + 'SELECT ''idx_cssd_coshare_stmt_active already exists'' AS info' +); +PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +-- insurer_statements: month + invoice filters used by aggregates +SET @idx := ( + SELECT COUNT(1) FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'insurer_statements' + AND index_name = 'idx_insq_active_month_invoice' +); +SET @sql := IF(@idx = 0, + 'CREATE INDEX idx_insq_active_month_invoice ON insurer_statements (is_active, month, invoice_status)', + 'SELECT ''idx_insq_active_month_invoice already exists'' AS info' +); +PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php index 3f12e119..38ca5936 100644 --- a/app/Models/PolicyTransactionModel.php +++ b/app/Models/PolicyTransactionModel.php @@ -3425,31 +3425,30 @@ } $main_conditions = ''; - function addCondition(&$main_conditions, &$whereAdded, $condition) - { + $addCondition = static function (&$main_conditions, &$whereAdded, $condition) { if (!$whereAdded) { $main_conditions .= " WHERE $condition "; $whereAdded = true; } else { $main_conditions .= " AND $condition "; } - } + }; // 4. Common filters if ($client_id != 0) { - addCondition($main_conditions, $whereAdded, "client_id = $client_id"); + $addCondition($main_conditions, $whereAdded, "client_id = $client_id"); } if ($insurer_id != 0) { - addCondition($main_conditions, $whereAdded, "insurer_id = $insurer_id"); + $addCondition($main_conditions, $whereAdded, "insurer_id = $insurer_id"); } if ($client_branch_id != 0) { - addCondition($main_conditions, $whereAdded, "client_branch_id = $client_branch_id"); + $addCondition($main_conditions, $whereAdded, "client_branch_id = $client_branch_id"); } if ($insurer_branch_id != 0) { - addCondition($main_conditions, $whereAdded, "insurer_branch_id = $insurer_branch_id"); + $addCondition($main_conditions, $whereAdded, "insurer_branch_id = $insurer_branch_id"); } $sql = " @@ -3592,19 +3591,15 @@ LEFT JOIN pt_co_share_details pcsd ON pt.id = pcsd.pt_id JOIN clients c ON c.id = pt.client_id LEFT JOIN client_branch cb ON pt.client_branch_id = cb.id - LEFT JOIN client_policy cp ON pt.client_policy_id = cp.id - LEFT JOIN user_profiles up ON pt.created_by = up.id LEFT JOIN vehicle v ON pt.vehicle_id = v.id LEFT JOIN policy_type ptype ON pt.policy_type_id = ptype.id LEFT JOIN insurers ins ON pcsd.insurer_id = ins.id LEFT JOIN insurer_branch ib ON pcsd.insurer_branch_id = ib.id LEFT JOIN tpa ON pt.tpa_id = tpa.id - LEFT JOIN tpa_branch tb ON pt.tpa_branch_id = tb.id LEFT JOIN user_profiles su ON pt.sales_generated_by = su.id LEFT JOIN user_profiles se ON pt.serviced_by = se.id LEFT JOIN user_profiles created_user ON pt.created_by = created_user.id LEFT JOIN nhance_branch ON pt.issuer_branch = nhance_branch.id - LEFT JOIN nhance_branch service_branch ON pt.service_person_branch_id = service_branch.id LEFT JOIN user_profiles salse_manager ON pt.salse_person_manager_id = salse_manager.id LEFT JOIN user_profiles service_manager ON pt.service_person_manager_id = service_manager.id @@ -3700,21 +3695,7 @@ 0 AS reward, - COALESCE(( - SELECT SUM( - COALESCE(cs.actual_bp_brokerage_amt,0) + - COALESCE(cs.actual_tp_brokerage_amt,0) + - COALESCE(cs.actual_tep_brokerage_amt,0) - ) - FROM co_share_stmt_details cs - JOIN insurer_statements i ON cs.statement_id = i.id - WHERE cs.co_share_id = pcsd.id - AND i.invoice_status IS NOT NULL - AND i.month = insq.month - AND i.is_active = 1 - AND cs.is_active = 1 - GROUP BY pt.policy_no, i.month, pcsd.insurer_id - ),0) AS billed_amt, + COALESCE(MAX(bds_billed.billed_amt), 0) AS billed_amt, CASE WHEN pcsd.co_share_type IN (0,1) THEN pt.policy_no @@ -3776,27 +3757,40 @@ LEFT JOIN pt_co_share_details pcsd ON pt.id = pcsd.pt_id LEFT JOIN co_share_stmt_details cssd ON pcsd.id = cssd.co_share_id LEFT JOIN insurer_statements insq ON cssd.statement_id = insq.id + INNER JOIN ( + SELECT + cs.co_share_id, + i.month, + SUM( + COALESCE(cs.actual_bp_brokerage_amt, 0) + + COALESCE(cs.actual_tp_brokerage_amt, 0) + + COALESCE(cs.actual_tep_brokerage_amt, 0) + ) AS billed_amt + FROM co_share_stmt_details cs + JOIN insurer_statements i ON cs.statement_id = i.id + WHERE i.invoice_status IS NOT NULL + AND i.is_active = 1 + AND cs.is_active = 1 + GROUP BY cs.co_share_id, i.month + HAVING billed_amt <> 0 + ) bds_billed ON bds_billed.co_share_id = pcsd.id + AND bds_billed.month = insq.month JOIN clients c ON c.id = pt.client_id LEFT JOIN client_branch cb ON pt.client_branch_id = cb.id - LEFT JOIN client_policy cp ON pt.client_policy_id = cp.id - LEFT JOIN user_profiles up ON pt.created_by = up.id LEFT JOIN vehicle v ON pt.vehicle_id = v.id LEFT JOIN policy_type ptype ON pt.policy_type_id = ptype.id LEFT JOIN insurers ins ON pcsd.insurer_id = ins.id LEFT JOIN insurer_branch ib ON pcsd.insurer_branch_id = ib.id LEFT JOIN tpa ON pt.tpa_id = tpa.id - LEFT JOIN tpa_branch tb ON pt.tpa_branch_id = tb.id LEFT JOIN user_profiles su ON pt.sales_generated_by = su.id LEFT JOIN user_profiles se ON pt.serviced_by = se.id LEFT JOIN user_profiles created_user ON pt.created_by = created_user.id LEFT JOIN nhance_branch ON pt.issuer_branch = nhance_branch.id - LEFT JOIN nhance_branch service_branch ON pt.service_person_branch_id = service_branch.id LEFT JOIN user_profiles salse_manager ON pt.salse_person_manager_id = salse_manager.id LEFT JOIN user_profiles service_manager ON pt.service_person_manager_id = service_manager.id LEFT JOIN cd_master ON pt.cd_ac_pk = cd_master.id - WHERE pt.is_active = 1 AND pcsd.is_active = 1 AND cssd.is_active = 1 @@ -3887,16 +3881,7 @@ 0 AS total_irda_amt_2, - COALESCE(( - SELECT SUM(cs.reward) - FROM co_share_stmt_details cs - JOIN insurer_statements i ON cs.statement_id = i.id - WHERE cs.co_share_id = pcsd.id - AND i.month = insq.month - AND i.is_active = 1 - AND cs.is_active = 1 - GROUP BY pt.policy_no, i.month, pcsd.insurer_id - ),0) AS reward, + COALESCE(bds_reward.reward, 0) AS reward, 0 AS billed_amt, @@ -3960,21 +3945,30 @@ LEFT JOIN pt_co_share_details pcsd ON pt.id = pcsd.pt_id LEFT JOIN co_share_stmt_details cssd ON pcsd.id = cssd.co_share_id LEFT JOIN insurer_statements insq ON cssd.statement_id = insq.id + INNER JOIN ( + SELECT + cs.co_share_id, + i.month, + SUM(cs.reward) AS reward + FROM co_share_stmt_details cs + JOIN insurer_statements i ON cs.statement_id = i.id + WHERE i.is_active = 1 + AND cs.is_active = 1 + GROUP BY cs.co_share_id, i.month + HAVING reward <> 0 + ) bds_reward ON bds_reward.co_share_id = pcsd.id + AND bds_reward.month = insq.month JOIN clients c ON c.id = pt.client_id LEFT JOIN client_branch cb ON pt.client_branch_id = cb.id - LEFT JOIN client_policy cp ON pt.client_policy_id = cp.id - LEFT JOIN user_profiles up ON pt.created_by = up.id LEFT JOIN vehicle v ON pt.vehicle_id = v.id LEFT JOIN policy_type ptype ON pt.policy_type_id = ptype.id LEFT JOIN insurers ins ON pcsd.insurer_id = ins.id LEFT JOIN insurer_branch ib ON pcsd.insurer_branch_id = ib.id LEFT JOIN tpa ON pt.tpa_id = tpa.id - LEFT JOIN tpa_branch tb ON pt.tpa_branch_id = tb.id LEFT JOIN user_profiles su ON pt.sales_generated_by = su.id LEFT JOIN user_profiles se ON pt.serviced_by = se.id LEFT JOIN user_profiles created_user ON pt.created_by = created_user.id LEFT JOIN nhance_branch ON pt.issuer_branch = nhance_branch.id - LEFT JOIN nhance_branch service_branch ON pt.service_person_branch_id = service_branch.id LEFT JOIN user_profiles salse_manager ON pt.salse_person_manager_id = salse_manager.id LEFT JOIN user_profiles service_manager ON pt.service_person_manager_id = service_manager.id @@ -4104,17 +4098,19 @@ /** * Cached processed BDS report list for a given filter set. + * Returns ['rows' => array, 'totals' => array]. */ public function getCachedBDSReportList(array $filters): array { - $cacheKey = 'bds_report_v1_' . md5(json_encode($filters)); + $cacheKey = 'bds_report_v2_' . md5(json_encode($filters)); $cache = \Config\Services::cache(); $cached = $cache->get($cacheKey); - if (is_array($cached)) { + if (is_array($cached) && isset($cached['rows']) && isset($cached['totals'])) { return $cached; } + // Legacy cache entries stored raw row arrays — ignore and rebuild. $processed = $this->getBDSReportList( $filters['start_date'] ?? 0, $filters['end_date'] ?? 0, @@ -4130,9 +4126,14 @@ $filters['where'] ?? [] ); - $cache->save($cacheKey, $processed, 300); + $payload = [ + 'rows' => $processed, + 'totals' => $this->calculateBDSReportTotals($processed), + ]; - return $processed; + $cache->save($cacheKey, $payload, 300); + + return $payload; } /** @@ -4140,11 +4141,14 @@ */ public function getBDSReportListDataTable(int $draw, int $start, int $length, string $searchValue, array $filters): array { - $allRows = $this->getCachedBDSReportList($filters); + $cached = $this->getCachedBDSReportList($filters); + $allRows = $cached['rows']; $recordsTotal = count($allRows); + $totals = $cached['totals']; if ($searchValue !== '') { $allRows = $this->filterBDSReportRowsBySearch($allRows, $searchValue); + $totals = $this->calculateBDSReportTotals($allRows); } $recordsFiltered = count($allRows); @@ -4162,7 +4166,7 @@ 'recordsTotal' => $recordsTotal, 'recordsFiltered' => $recordsFiltered, 'data' => $pageRows, - 'totals' => $this->calculateBDSReportTotals($allRows), + 'totals' => $totals, ]; } diff --git a/app/Views/report_bds.php b/app/Views/report_bds.php index fb2c1c90..43f38a2a 100644 --- a/app/Views/report_bds.php +++ b/app/Views/report_bds.php @@ -79,7 +79,7 @@
- Total Policy Count: + Total Policy Count: