From a1789654d85837f40dffcfaf5b3779d3dd442e18 Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Thu, 9 Jul 2026 17:37:45 +0530 Subject: [PATCH] FEAT_BDS_OPTIMIZATIONS --- app/Config/Routes.php | 6 + .../PolicyTransactionController.php | 618 ++++++++++++++---- app/Models/PolicyTransactionModel.php | 490 ++++++++++++-- .../policy_transaction_endorsement_list.php | 210 +++--- .../policy_transaction_inception_list.php | 247 ++++--- app/Views/report_bds.php | 375 ++++------- 6 files changed, 1346 insertions(+), 600 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index e18e3df7..9989ee54 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -501,6 +501,8 @@ $routes->group("policy_tranction", ["filter" => "authMVC"], function ($routes) { $routes->group("inception", ["filter" => "authMVC"], function ($routes) { $routes->match(['get', 'post'], 'list', 'PolicyTransactionController::viewInception'); + $routes->post('list/datatable', 'PolicyTransactionController::inceptionListDataTable'); + $routes->post('list/clear-cache', 'PolicyTransactionController::clearInceptionListCache'); $routes->post("create", "PolicyTransactionController::createInceptionPolicy"); $routes->get("list/(:any)", "PolicyTransactionController::getInceptionDataForEdit/$1"); $routes->get("remove/(:any)", "PolicyTransactionController::removeCDMaster/$1"); @@ -511,6 +513,8 @@ $routes->group("policy_tranction", ["filter" => "authMVC"], function ($routes) { $routes->group("endorsement", ["filter" => "authMVC"], function ($routes) { $routes->get("list", "PolicyTransactionController::viewEndorsement"); + $routes->post("list/datatable", "PolicyTransactionController::endorsementListDataTable"); + $routes->post("list/clear-cache", "PolicyTransactionController::clearEndorsementListCache"); $routes->post("create", "PolicyTransactionController::createEndorsementPolicy"); $routes->get("list/(:any)", "PolicyTransactionController::getEndorsementDataForEdit/$1"); $routes->get("remove/(:any)", "PolicyTransactionController::removeCDMaster/$1"); @@ -520,6 +524,8 @@ $routes->group("policy_tranction", ["filter" => "authMVC"], function ($routes) { $routes->group("report", ["filter" => "authMVC"], function ($routes) { $routes->match(['get', 'post'],"list", "PolicyTransactionController::reportBDS"); + $routes->post("list/datatable", "PolicyTransactionController::reportBDSDataTable"); + $routes->post("list/clear-cache", "PolicyTransactionController::clearReportBDSCache"); $routes->match(['get', 'post'],"list_new", "PolicyTransactionController::reportBDSNew"); $routes->get("report-varience-list", "PolicyTransactionController::reportVarience"); $routes->get("report-business-list", "PolicyTransactionController::reportBusinessList"); diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index f793af2a..818c3d1f 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -602,59 +602,9 @@ class PolicyTransactionController extends BaseController 'policy_end_date' => 'Policy End Date', ]; - // Filter data - $start_date = $this->request->getGet('start_date'); - $end_date = $this->request->getGet('end_date'); - $client_id = $this->request->getGet('client_id'); - $insurer_id = $this->request->getGet('insurer_id'); - $policy_type_id = $this->request->getGet('policy_type_id'); - $date_type = $this->request->getGet('date_type'); - $issuer = $this->request->getGet('issuer'); - $status = $this->request->getGet('status'); - - // Handle null or empty values - $start_date = empty($start_date) ? 0 : $start_date; - $end_date = empty($end_date) ? 0 : $end_date; - $client_id = empty($client_id) ? 0 : $client_id; - $insurer_id = empty($insurer_id) ? 0 : $insurer_id; - $policy_type_id = empty($policy_type_id) ? 0 : $policy_type_id; - $date_type = empty($date_type) ? 0 : $date_type; - $issuer = empty($issuer) ? 0 : $issuer; - $status = empty($status) ? 0 : $status; // Corrected from `$issuer` - - if(empty($bds_edit_pt_id) && empty($view)){ - if ($this->request->is('get')) { - - // Fetch inception data list - $data['inception_data_list'] = $this->policyTransactionModel->getInceptionTranctionListData( - $start_date, - $end_date, - $client_id, - $insurer_id, - $policy_type_id, - $date_type, - $issuer, - $status - ); - } else { - - $ids = $this->request->getPost('ids'); - $ids = array_filter(explode(',', $ids)); - $data['inception_data_list'] = $this->policyTransactionModel->getInceptionTranctionListData( - $start_date = 0, - $end_date = 0, - $client_id = 0, - $insurer_id = 0, - $policy_type_id = 0, - $date_type = 0, - $issuer = 0, - $status = 0, - $ids - ); - } - }else{ - $data['inception_data_list'] = []; - } + // List rows are loaded via server-side DataTables AJAX. + $data['inception_data_list'] = []; + $data['inception_filters'] = $this->buildInceptionFiltersFromRequest(); @@ -746,6 +696,136 @@ class PolicyTransactionController extends BaseController $this->loadLayout('policy_transaction_inception_list', $data); } + public function inceptionListDataTable() + { + if (!$this->request->isAJAX()) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Invalid request.', + ]); + } + + $draw = (int) ($this->request->getPost('draw') ?? 0); + $start = max(0, (int) ($this->request->getPost('start') ?? 0)); + $length = (int) ($this->request->getPost('length') ?? 10); + $search = trim((string) ($this->request->getPost('search')['value'] ?? '')); + + $filters = $this->buildInceptionFiltersFromRequest(); + $result = $this->policyTransactionModel->getInceptionTranctionListDataTable( + $draw, + $start, + $length, + $search, + $filters + ); + + $rows = []; + foreach ($result['data'] as $index => $row) { + $rows[] = $this->formatInceptionRowForDataTable($row, $start + $index + 1); + } + + return $this->response->setJSON([ + 'draw' => $result['draw'], + 'recordsTotal' => $result['recordsTotal'], + 'recordsFiltered' => $result['recordsFiltered'], + 'data' => $rows, + 'cache_expires_in_ms' => $result['cache_expires_in_ms'] ?? 300000, + ]); + } + + public function clearInceptionListCache() + { + if (!$this->request->isAJAX()) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Invalid request.', + ]); + } + + session()->set('inception_list_cache_version', time()); + + return $this->response->setJSON([ + 'status' => true, + 'message' => 'Inception list cache cleared.', + ]); + } + + protected function buildInceptionFiltersFromRequest(): array + { + $normalize = static function ($value) { + return (!isset($value) || $value === '' || $value === null) ? 0 : $value; + }; + + $ids = []; + if ($this->request->is('post')) { + $postIds = $this->request->getPost('ids') ?? ''; + $ids = array_filter(explode(',', (string) $postIds)); + } + + return [ + 'start_date' => $normalize($this->request->getGet('start_date') ?? $this->request->getPost('start_date')), + 'end_date' => $normalize($this->request->getGet('end_date') ?? $this->request->getPost('end_date')), + 'client_id' => $normalize($this->request->getGet('client_id') ?? $this->request->getPost('client_id')), + 'insurer_id' => $normalize($this->request->getGet('insurer_id') ?? $this->request->getPost('insurer_id')), + 'policy_type_id' => $normalize($this->request->getGet('policy_type_id') ?? $this->request->getPost('policy_type_id')), + 'date_type' => $normalize($this->request->getGet('date_type') ?? $this->request->getPost('date_type')), + 'issuer' => $normalize($this->request->getGet('issuer') ?? $this->request->getPost('issuer')), + 'status' => $normalize($this->request->getGet('status') ?? $this->request->getPost('status')), + 'ids' => $ids, + 'cache_version' => (int) (session()->get('inception_list_cache_version') ?? 1), + ]; + } + + protected function formatInceptionRowForDataTable(array $row, int $serialNo): array + { + $issuerMap = [1 => 'JIBS', 2 => 'Nhance']; + $issuingTypeMap = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over']; + $clientTypeMap = [1 => 'Group', 2 => 'Individual']; + $policyStatusMap = [ + 'under_process' => 'Under Process', + 'client_pending' => 'Client Pending', + 'insurer_pending' => 'Insurer Pending', + 'co_insurer_pending' => 'Co-Insurer Pending', + 'tpa_pending' => 'TPA Pending', + 'validated' => 'Validated', + 'cancelled' => 'Cancelled', + 'instalment_pending' => 'Instalment Pending', + 'completed' => 'Completed', + 'lost' => 'Lost', + ]; + + $clientBranch = ((int) ($row['client_type'] ?? 0) === 2) + ? (($row['client_name'] ?? 'N/A') . ' - ' . (!empty($row['pan']) ? $row['pan'] : 'N/A')) + : (($row['client_short_name'] ?? 'N/A') . ' - ' . ($row['client_branch_name'] ?? 'N/A')); + + $editAction = 'Edit'; + $deleteAction = ''; + if ((int) get_role_id() === 5) { + $deleteAction = 'Delete'; + } + + $actionHtml = ''; + + return [ + 0 => $serialNo, + 1 => $issuerMap[$row['issuer'] ?? 2] ?? 'Nhance', + 2 => $issuingTypeMap[$row['issue_type'] ?? 0] ?? 'N/A', + 3 => $clientTypeMap[$row['client_type'] ?? 0] ?? 'N/A', + 4 => $clientBranch, + 5 => $row['insurer_short_name'] ?: 'N/A', + 6 => $row['policy_type'] ?: 'N/A', + 7 => $row['policy_no'] ?: 'N/A', + 8 => empty($row['policy_issue_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_issue_date'])), + 9 => empty($row['policy_start_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_start_date'])), + 10 => empty($row['policy_end_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_end_date'])), + 11 => $row['emp_count'] ?: '0', + 12 => $row['dependent_count'] ?: '0', + 13 => $policyStatusMap[$row['status'] ?? ''] ?? 'N/A', + 14 => $row['user_name'] ?: 'N/A', + 15 => $actionHtml, + ]; + } + public function viewInception2() { $bds_edit_pt_id = $this->request->getGet('pt_id') ?? null; @@ -921,6 +1001,8 @@ class PolicyTransactionController extends BaseController // policy Transaction Create function start public function createInceptionPolicy() { + session()->set('inception_list_cache_version', time()); + $post_data = $this->request->getPost(); $rules = [ @@ -2391,31 +2473,8 @@ class PolicyTransactionController extends BaseController 'policy_end_date' => 'Policy End Date', ]; - //filter datas - $start_date = $this->request->getGet('start_date'); - $end_date = $this->request->getGet('end_date'); - $client_id = $this->request->getGet('client_id'); - $insurer_id = $this->request->getGet('insurer_id'); - $policy_type_id = $this->request->getGet('policy_type_id'); - $date_type = $this->request->getGet('date_type'); - $issuer = $this->request->getGet('issuer'); - $status = $this->request->getGet('status'); - - $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date; - $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date; - - $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id; - $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id; - $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id; - $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type; - $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer; - $status = (!isset($status) || $status === '' || $status === null) ? 0 : $status; - - if($bds_edit_pt_id == null){ - $data['endorsement_data_list'] = $this->policyTransactionModel->getEndorsementTranctionListData($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer, $status); - }else{ - $data['endorsement_data_list'] = []; - } + $data['endorsement_data_list'] = []; + $data['endorsement_filters'] = $this->buildEndorsementFiltersFromRequest(); $data['client'] = $this->clientModel->where('is_active', 1)->findAll(); $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll(); @@ -2434,6 +2493,134 @@ class PolicyTransactionController extends BaseController $this->loadLayout('policy_transaction_endorsement_list', $data); } + public function endorsementListDataTable() + { + if (!$this->request->isAJAX()) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Invalid request.', + ]); + } + + $draw = (int) ($this->request->getPost('draw') ?? 0); + $start = max(0, (int) ($this->request->getPost('start') ?? 0)); + $length = (int) ($this->request->getPost('length') ?? 10); + $search = trim((string) ($this->request->getPost('search')['value'] ?? '')); + + $filters = $this->buildEndorsementFiltersFromRequest(); + $result = $this->policyTransactionModel->getEndorsementTranctionListDataTable( + $draw, + $start, + $length, + $search, + $filters + ); + + $rows = []; + foreach ($result['data'] as $index => $row) { + $rows[] = $this->formatEndorsementRowForDataTable($row, $start + $index + 1); + } + + return $this->response->setJSON([ + 'draw' => $result['draw'], + 'recordsTotal' => $result['recordsTotal'], + 'recordsFiltered' => $result['recordsFiltered'], + 'data' => $rows, + 'cache_expires_in_ms' => $result['cache_expires_in_ms'] ?? 300000, + ]); + } + + public function clearEndorsementListCache() + { + if (!$this->request->isAJAX()) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Invalid request.', + ]); + } + + session()->set('endorsement_list_cache_version', time()); + + return $this->response->setJSON([ + 'status' => true, + 'message' => 'Endorsement list cache cleared.', + ]); + } + + protected function buildEndorsementFiltersFromRequest(): array + { + $normalize = static function ($value) { + return (!isset($value) || $value === '' || $value === null) ? 0 : $value; + }; + + return [ + 'start_date' => $normalize($this->request->getGet('start_date') ?? $this->request->getPost('start_date')), + 'end_date' => $normalize($this->request->getGet('end_date') ?? $this->request->getPost('end_date')), + 'client_id' => $normalize($this->request->getGet('client_id') ?? $this->request->getPost('client_id')), + 'insurer_id' => $normalize($this->request->getGet('insurer_id') ?? $this->request->getPost('insurer_id')), + 'policy_type_id' => $normalize($this->request->getGet('policy_type_id') ?? $this->request->getPost('policy_type_id')), + 'date_type' => $normalize($this->request->getGet('date_type') ?? $this->request->getPost('date_type')), + 'issuer' => $normalize($this->request->getGet('issuer') ?? $this->request->getPost('issuer')), + 'status' => $normalize($this->request->getGet('status') ?? $this->request->getPost('status')), + 'cache_version' => (int) (session()->get('endorsement_list_cache_version') ?? 1), + ]; + } + + protected function formatEndorsementRowForDataTable(array $row, int $serialNo): array + { + $issuerMap = [1 => 'JIBS', 2 => 'Nhance']; + $policyStatusMap = [ + 'under_process' => 'Under Process', + 'client_pending' => 'Client Pending', + 'insurer_pending' => 'Insurer Pending', + 'co_insurer_pending' => 'Co-Insurer Pending', + 'tpa_pending' => 'TPA Pending', + 'validated' => 'Validated', + 'cancelled' => 'Cancelled', + 'instalment_pending' => 'Instalment Pending', + 'completed' => 'Completed', + ]; + $actionTypeMap = [ + 'addition' => 'Addition', + 'deletion' => 'Deletion', + 'addition_deletion' => 'Addition & Deletion', + 'si_enhancement' => 'SI Enhancement', + 'combo_a_d_si' => 'Combo A, D & SI', + 'correction' => 'Correction', + 'baby_addition' => 'Baby Addition', + 'policy_instalment' => 'Policy Instalment', + 'addition_inception' => 'Addition-Inception', + 'bds_correction' => 'BDS Correction', + 'policy_correction' => 'Policy Correction', + 'policy_cancellation' => 'Policy Cancellation', + ]; + + $editAction = 'Edit'; + $deleteAction = ''; + if ((int) get_role_id() === 5) { + $deleteAction = 'Delete'; + } + + $actionHtml = ''; + + return [ + 0 => $serialNo, + 1 => $issuerMap[$row['issuer'] ?? 0] ?? 'N/A', + 2 => $row['client_short_name'] ?: 'N/A', + 3 => $row['client_branch_name'] ?: 'N/A', + 4 => $row['insurer_short_name'] ?: 'N/A', + 5 => $row['policy_type'] ?: 'N/A', + 6 => $actionTypeMap[$row['action_type'] ?? ''] ?? 'N/A', + 7 => $row['endorsement_no'] ?: 'N/A', + 8 => empty($row['data_received_date']) ? 'N/A' : date('d/m/Y', strtotime($row['data_received_date'])), + 9 => $row['emp_count'] ?: '0', + 10 => $row['dependent_count'] ?: '0', + 11 => empty($row['policy_issue_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_issue_date'])), + 12 => $policyStatusMap[$row['status'] ?? ''] ?? 'N/A', + 13 => $actionHtml, + ]; + } + public function viewEndorsement2() { // echo '
';
@@ -2530,6 +2717,8 @@ class PolicyTransactionController extends BaseController
 
     public function createEndorsementPolicy()
     {
+        session()->set('endorsement_list_cache_version', time());
+
         // $id = $this->request->getPost('id');
         $rules = [
                 // ==========================================
@@ -3793,65 +3982,230 @@ class PolicyTransactionController extends BaseController
         $data['users'] = $this->userModel->where('is_active', 1)->findAll();
         $data['policy_count'] = $this->policyTransactionModel->where('is_active', 1)->countAllResults();
 
-
-        //filter datas
-        $start_date = $this->request->getGet('start_date');
-        $end_date = $this->request->getGet('end_date');
-        $client_id = $this->request->getGet('client_id');
-        $insurer_id = $this->request->getGet('insurer_id');
-        $policy_type_id = $this->request->getGet('policy_type_id');
-        $date_type = $this->request->getGet('date_type');
-        $issuer = $this->request->getGet('issuer');
-        $client_branch_id = $this->request->getGet('client_branch_id');
-        $insurer_branch_id = $this->request->getGet('insurer_branch_id');
-        $client_policy_id = $this->request->getGet('client_policy_id');
-        $user_id = $this->request->getGet('user_id');
-
-        if ($date_type == 'statement_month') {
-            $start_date = (string)date('Y-m-01', strtotime($start_date));
-            $end_date = (string)date('Y-m-31', strtotime($end_date));
-        }
-
-        // dd($start_date, $end_date, $date_type);
-
-        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date;
-        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date;
-
-        $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id;
-        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
-        $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id;
-        $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type;
-        $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer;
-        $client_branch_id = (!isset($client_branch_id) || $client_branch_id === '' || $client_branch_id === null) ? 0 : $client_branch_id;
-        $insurer_branch_id = (!isset($insurer_branch_id) || $insurer_branch_id === '' || $insurer_branch_id === null) ? 0 : $insurer_branch_id;
-        $client_policy_id = (!isset($client_policy_id) || $client_policy_id === '' || $client_policy_id === null) ? 0 : $client_policy_id;
-        $user_id = (!isset($user_id) || $user_id === '' || $user_id === null) ? 0 : $user_id;
-        if ($this->request->is('post')) {
-            $request_post_data   = $this->request->getPost();
-            $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data);
-            $isFromDashboard = $sanitized_post_data["is_dashboard"];
-
-            if (isset($isFromDashboard) && !empty($isFromDashboard) && $isFromDashboard == 1) {
-                $ids = $sanitized_post_data['ids'];
-
-                $ids = array_filter(explode(',', $ids));
-
-                if (!empty($ids)) {
-                    $idsStr = implode(',', array_map('intval', $ids)); // sanitize IDs to be integers
-                    $where = "policy_transaction.id IN ($idsStr)";
-                } else {
-                    $where = []; // No valid IDs, return empty result
-                }
-            }
-            // dd($ids);
-        }
-        //Actual data for the list
-        $data['report_list'] = $this->policyTransactionModel->getBDSReportList($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer, $client_branch_id, $insurer_branch_id, $client_policy_id, $user_id, isset($where) ? $where : '');
+        // List data loaded via server-side DataTables AJAX
+        $data['report_list'] = [];
+        $data['bds_filters'] = $this->buildBDSReportFiltersFromRequest();
         // dd($data);
 
         $this->loadLayout('report_bds_filter', $data);
     }
 
+    /**
+     * Server-side DataTables endpoint for BDS report list.
+     */
+    public function reportBDSDataTable()
+    {
+        if (!$this->request->isAJAX()) {
+            return $this->response->setStatusCode(400)->setJSON([
+                'status'  => false,
+                'message' => 'Invalid request.',
+            ]);
+        }
+
+        $draw   = (int) ($this->request->getPost('draw') ?? 0);
+        $start  = max(0, (int) ($this->request->getPost('start') ?? 0));
+        $length = (int) ($this->request->getPost('length') ?? 10);
+        $search = trim((string) ($this->request->getPost('search')['value'] ?? ''));
+
+        $filters = $this->buildBDSReportFiltersFromRequest();
+
+        $result = $this->policyTransactionModel->getBDSReportListDataTable(
+            $draw,
+            $start,
+            $length,
+            $search,
+            $filters
+        );
+
+        $serialStart = $start + 1;
+        $data        = [];
+
+        foreach ($result['data'] as $index => $row) {
+            $data[] = $this->formatBdsReportRowForDataTable($row, $serialStart + $index);
+        }
+
+        return $this->response->setJSON([
+            'draw'            => $result['draw'],
+            'recordsTotal'    => $result['recordsTotal'],
+            'recordsFiltered' => $result['recordsFiltered'],
+            'data'            => $data,
+            'totals'          => $result['totals'],
+        ]);
+    }
+
+    public function clearReportBDSCache()
+    {
+        if (!$this->request->isAJAX()) {
+            return $this->response->setStatusCode(400)->setJSON([
+                'status'  => false,
+                'message' => 'Invalid request.',
+            ]);
+        }
+
+        session()->set('bds_report_cache_version', time());
+
+        return $this->response->setJSON([
+            'status'  => true,
+            'message' => 'BDS report cache cleared.',
+        ]);
+    }
+
+    /**
+     * Normalize BDS report filter params from the current request.
+     */
+    protected function buildBDSReportFiltersFromRequest(): array
+    {
+        $start_date        = $this->request->getGet('start_date') ?? $this->request->getPost('start_date');
+        $end_date          = $this->request->getGet('end_date') ?? $this->request->getPost('end_date');
+        $client_id         = $this->request->getGet('client_id') ?? $this->request->getPost('client_id');
+        $insurer_id        = $this->request->getGet('insurer_id') ?? $this->request->getPost('insurer_id');
+        $policy_type_id    = $this->request->getGet('policy_type_id') ?? $this->request->getPost('policy_type_id');
+        $date_type         = $this->request->getGet('date_type') ?? $this->request->getPost('date_type');
+        $issuer            = $this->request->getGet('issuer') ?? $this->request->getPost('issuer');
+        $client_branch_id  = $this->request->getGet('client_branch_id') ?? $this->request->getPost('client_branch_id');
+        $insurer_branch_id = $this->request->getGet('insurer_branch_id') ?? $this->request->getPost('insurer_branch_id');
+        $client_policy_id  = $this->request->getGet('client_policy_id') ?? $this->request->getPost('client_policy_id');
+        $user_id           = $this->request->getGet('user_id') ?? $this->request->getPost('user_id');
+
+        if ($date_type == 'statement_month' && $start_date && $end_date) {
+            $start_date = (string) date('Y-m-01', strtotime($start_date));
+            $end_date   = (string) date('Y-m-31', strtotime($end_date));
+        }
+
+        $normalize = static function ($value) {
+            return (!isset($value) || $value === '' || $value === null) ? 0 : $value;
+        };
+
+        $where = '';
+        if ($this->request->is('post')) {
+            $request_post_data   = $this->request->getPost();
+            $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data);
+            $isFromDashboard     = $sanitized_post_data['is_dashboard'] ?? null;
+
+            if (isset($isFromDashboard) && !empty($isFromDashboard) && (int) $isFromDashboard === 1) {
+                $ids = array_filter(explode(',', $sanitized_post_data['ids'] ?? ''));
+
+                if (!empty($ids)) {
+                    $idsStr = implode(',', array_map('intval', $ids));
+                    $where  = "policy_transaction.id IN ($idsStr)";
+                } else {
+                    $where = [];
+                }
+            }
+        }
+
+        return [
+            'start_date'        => $normalize($start_date),
+            'end_date'          => $normalize($end_date),
+            'client_id'         => $normalize($client_id),
+            'insurer_id'        => $normalize($insurer_id),
+            'policy_type_id'    => $normalize($policy_type_id),
+            'date_type'         => $normalize($date_type),
+            'issuer'            => $normalize($issuer),
+            'client_branch_id'  => $normalize($client_branch_id),
+            'insurer_branch_id' => $normalize($insurer_branch_id),
+            'client_policy_id'  => $normalize($client_policy_id),
+            'user_id'           => $normalize($user_id),
+            'where'             => $where,
+            'cache_version'     => (int) (session()->get('bds_report_cache_version') ?? 1),
+        ];
+    }
+
+    /**
+     * Format a single BDS report row for DataTables output.
+     */
+    protected function formatBdsReportRowForDataTable(array $row, int $serialNo): array
+    {
+        $hasIrda      = ((float) ($row['total_irda_amt'] ?? 0)) != 0.0;
+        $actionType  = strtolower((string) ($row['action_type'] ?? ''));
+        $editBaseUrl = $actionType === 'policy'
+            ? base_url('policy_tranction/inception/list')
+            : base_url('policy_tranction/endorsement/list');
+        $editLink    = $editBaseUrl . '?pt_id=' . ($row['id'] ?? '');
+        $totalIrdaAmt = $row['total_irda_amt'] ?? '0.00';
+        $unbilled     = isset($row['unbilled_amount']) ? number_format((float) $row['unbilled_amount'], 2, '.', '') : '0.00';
+
+        $fmtDate = static function ($value) {
+            return empty($value) ? 'N/A' : change_date_format($value, 'Y-m-d', 'd/m/Y');
+        };
+
+        $fmtNum = static function ($value, int $decimals = 2) {
+            return number_format((float) ($value ?? 0), $decimals, '.', '');
+        };
+
+        $na = static function ($value) {
+            return ($value !== null && $value !== '') ? $value : 'N/A';
+        };
+
+        $cells = [
+            $serialNo . '   ',
+            $na($row['user_name'] ?? null),
+            $na($row['policy_issue_month'] ?? null),
+            $na($row['revenue_type'] ?? null),
+            $na($row['client_type'] ?? null),
+            $na($row['client_name'] ?? null),
+            $na($row['action_type'] ?? null),
+            $na($row['policy_type'] ?? null),
+            $na($row['bap'] ?? null),
+            $na($row['vehicle_no'] ?? null),
+            $na($row['policy_no'] ?? null),
+            $na($row['endorsement_no'] ?? null),
+            $na($row['insurer_branch_name'] ?? null),
+            $fmtDate($row['endorse_eff_date'] ?? null),
+            $fmtDate($row['policy_start_date'] ?? null),
+            $fmtDate($row['policy_end_date'] ?? null),
+            $na($row['ref'] ?? null),
+            $na($row['remarks'] ?? null),
+            $hasIrda ? ($row['bp_amt'] ?: '0.00') : '0.00',
+            $hasIrda ? ($row['tp_or_ter'] ?: '0.00') : '0.00',
+            $hasIrda ? ($row['premium_wo_gst'] ?: '0.00') : '0.00',
+            $hasIrda ? ($row['total_premium'] ?: '0.00') : '0.00',
+            ($hasIrda ? ($row['agreed_bp_per'] ?: '0.00') : '0.00') . '%',
+            ($hasIrda ? ($row['agreed_tp_or_ter_per'] ?: '0.00') : '0.00') . '%',
+            isset($row['reward']) ? $row['reward'] : '0.00',
+            '' . $totalIrdaAmt . '',
+            '' . (empty($row['billed_amt']) ? '0.00' : $row['billed_amt']) . '',
+            '' . $unbilled . '',
+            $na($row['salse_person_name'] ?? null),
+            $na($row['service_person_name'] ?? null),
+            $na($row['nhance_branch'] ?? null),
+            $na($row['installment'] ?? null),
+            $fmtDate($row['data_received_date'] ?? null),
+            $fmtDate($row['renewal_date'] ?? null),
+            $row['co_share'] ?? 'No',
+            $row['bro_payable_by'] ?? 'No',
+            $na($row['salse_manager_name'] ?? null),
+            $na($row['service_manager_name'] ?? null),
+            $na($row['service_branch'] ?? null),
+            $fmtDate($row['rollover_date'] ?? null),
+            $na($row['policy_holder_name'] ?? null),
+            $row['same_as_proposer'] ?? 'No',
+            $na($row['follower_policy_no'] ?? null),
+            $fmtNum($row['co_share_per'] ?? 0),
+            $fmtNum($row['non_comm_per_amt'] ?? 0),
+            $fmtNum($row['bp_igst'] ?? 0),
+            $fmtNum($row['bp_sgst'] ?? 0),
+            $fmtNum($row['bp_cgst'] ?? 0),
+            $fmtNum($row['stamp_duty'] ?? 0),
+            $fmtNum($row['standerd_bp_per'] ?? 0),
+            $fmtNum($row['standerd_tp_per'] ?? 0),
+            $fmtNum($row['actual_bp_amt'] ?? 0),
+            $fmtNum($row['actual_tp_amt'] ?? 0),
+            $fmtNum($row['actual_bp_per'] ?? 0),
+            $fmtNum($row['actual_tp_per'] ?? 0),
+            $fmtNum($row['actual_tep_brokerage_amt'] ?? 0),
+            $fmtNum($row['actual_tp_brokerage_amt'] ?? 0),
+            $na($row['cd_ac_no'] ?? null),
+        ];
+
+        $rowData = ['DT_RowAttr' => ['data-id' => $row['pt_id'] ?? '']];
+        foreach ($cells as $index => $cell) {
+            $rowData[$index] = $cell;
+        }
+
+        return $rowData;
+    }
+
     public function reportVarience()
     {
         $data['tab_name'] = 'Variance Report';
diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php
index 2e520918..4f051a66 100644
--- a/app/Models/PolicyTransactionModel.php
+++ b/app/Models/PolicyTransactionModel.php
@@ -1136,6 +1136,136 @@
             return $data;
         }
 
+        public function getCachedInceptionTranctionListData(array $filters): array
+        {
+            $cacheKey = 'inception_list_v1_' . md5(json_encode($filters));
+            $cache    = \Config\Services::cache();
+            $cached   = $cache->get($cacheKey);
+
+            if (is_array($cached) && isset($cached['rows'], $cached['expires_at'])) {
+                return $cached;
+            }
+
+            $ttl = 300;
+            $rows = $this->getInceptionTranctionListData(
+                $filters['start_date'] ?? 0,
+                $filters['end_date'] ?? 0,
+                $filters['client_id'] ?? 0,
+                $filters['insurer_id'] ?? 0,
+                $filters['policy_type_id'] ?? 0,
+                $filters['date_type'] ?? 0,
+                $filters['issuer'] ?? 0,
+                $filters['status'] ?? 0,
+                $filters['ids'] ?? null
+            );
+
+            $payload = [
+                'rows'       => $rows,
+                'expires_at' => time() + $ttl,
+            ];
+            $cache->save($cacheKey, $payload, $ttl);
+
+            return $payload;
+        }
+
+        public function filterInceptionTranctionRowsBySearch(array $rows, string $searchValue): array
+        {
+            $needle = mb_strtolower(trim($searchValue));
+            if ($needle === '') {
+                return $rows;
+            }
+
+            $issuerMap = [1 => 'jibs', 2 => 'nhance'];
+            $issueTypeMap = [1 => 'fresh', 2 => 'renewal', 3 => 'roll over'];
+            $clientTypeMap = [1 => 'group', 2 => 'individual'];
+            $statusMap = [
+                'under_process' => 'under process',
+                'client_pending' => 'client pending',
+                'insurer_pending' => 'insurer pending',
+                'co_insurer_pending' => 'co-insurer pending',
+                'tpa_pending' => 'tpa pending',
+                'validated' => 'validated',
+                'cancelled' => 'cancelled',
+                'instalment_pending' => 'instalment pending',
+                'completed' => 'completed',
+                'lost' => 'lost',
+            ];
+
+            $fields = [
+                'client_name',
+                'client_short_name',
+                'client_branch_name',
+                'insurer_short_name',
+                'policy_type',
+                'policy_no',
+                'user_name',
+                'status',
+                'pan',
+            ];
+
+            return array_values(array_filter($rows, static function (array $row) use ($needle, $fields, $issuerMap, $issueTypeMap, $clientTypeMap, $statusMap) {
+                foreach ($fields as $field) {
+                    $value = $row[$field] ?? '';
+                    if ($value !== '' && mb_strpos(mb_strtolower((string) $value), $needle) !== false) {
+                        return true;
+                    }
+                }
+
+                // Search by rendered labels shown in list columns.
+                $issuerText = $issuerMap[(int) ($row['issuer'] ?? 0)] ?? '';
+                if ($issuerText !== '' && mb_strpos($issuerText, $needle) !== false) {
+                    return true;
+                }
+
+                $issueTypeText = $issueTypeMap[(int) ($row['issue_type'] ?? 0)] ?? '';
+                if ($issueTypeText !== '' && mb_strpos($issueTypeText, $needle) !== false) {
+                    return true;
+                }
+
+                $clientTypeText = $clientTypeMap[(int) ($row['client_type'] ?? 0)] ?? '';
+                if ($clientTypeText !== '' && mb_strpos($clientTypeText, $needle) !== false) {
+                    return true;
+                }
+
+                $statusCode = (string) ($row['status'] ?? '');
+                $statusText = $statusMap[$statusCode] ?? '';
+                if ($statusText !== '' && mb_strpos($statusText, $needle) !== false) {
+                    return true;
+                }
+
+                return false;
+            }));
+        }
+
+        public function getInceptionTranctionListDataTable(int $draw, int $start, int $length, string $searchValue, array $filters): array
+        {
+            $cached       = $this->getCachedInceptionTranctionListData($filters);
+            $allRows      = $cached['rows'] ?? [];
+            $recordsTotal = count($allRows);
+
+            if ($searchValue !== '') {
+                $allRows = $this->filterInceptionTranctionRowsBySearch($allRows, $searchValue);
+            }
+
+            $recordsFiltered = count($allRows);
+
+            if ($length < 0) {
+                $length = $recordsFiltered;
+            }
+
+            $pageRows = $length > 0
+                ? array_slice(array_values($allRows), $start, $length)
+                : array_values($allRows);
+
+            return [
+                'draw'            => $draw,
+                'recordsTotal'    => $recordsTotal,
+                'recordsFiltered' => $recordsFiltered,
+                'data'            => $pageRows,
+                'cache_expires_in_ms' => max(0, (($cached['expires_at'] ?? time()) - time()) * 1000),
+            ];
+        }
+
 
         public function getEndorsementTranctionListData($start_date = 0, $end_date = 0, $client_id = 0, $insurer_id = 0, $policy_type_id = 0, $date_type = 0, $issuer = 0, $status = 0)
         {
@@ -1248,6 +1378,136 @@
             return $builder->get()->getResultArray();
         }
 
+        public function getCachedEndorsementTranctionListData(array $filters): array
+        {
+            $cacheKey = 'endorsement_list_v1_' . md5(json_encode($filters));
+            $cache    = \Config\Services::cache();
+            $cached   = $cache->get($cacheKey);
+
+            if (is_array($cached) && isset($cached['rows'], $cached['expires_at'])) {
+                return $cached;
+            }
+
+            $ttl = 300;
+            $rows = $this->getEndorsementTranctionListData(
+                $filters['start_date'] ?? 0,
+                $filters['end_date'] ?? 0,
+                $filters['client_id'] ?? 0,
+                $filters['insurer_id'] ?? 0,
+                $filters['policy_type_id'] ?? 0,
+                $filters['date_type'] ?? 0,
+                $filters['issuer'] ?? 0,
+                $filters['status'] ?? 0
+            );
+
+            $payload = [
+                'rows'       => $rows,
+                'expires_at' => time() + $ttl,
+            ];
+            $cache->save($cacheKey, $payload, $ttl);
+
+            return $payload;
+        }
+
+        public function filterEndorsementTranctionRowsBySearch(array $rows, string $searchValue): array
+        {
+            $needle = mb_strtolower(trim($searchValue));
+            if ($needle === '') {
+                return $rows;
+            }
+
+            $issuerMap = [1 => 'jibs', 2 => 'nhance'];
+            $statusMap = [
+                'under_process' => 'under process',
+                'client_pending' => 'client pending',
+                'insurer_pending' => 'insurer pending',
+                'co_insurer_pending' => 'co-insurer pending',
+                'tpa_pending' => 'tpa pending',
+                'validated' => 'validated',
+                'cancelled' => 'cancelled',
+                'instalment_pending' => 'instalment pending',
+                'completed' => 'completed',
+            ];
+            $actionTypeMap = [
+                'addition' => 'addition',
+                'deletion' => 'deletion',
+                'addition_deletion' => 'addition & deletion',
+                'si_enhancement' => 'si enhancement',
+                'combo_a_d_si' => 'combo a, d & si',
+                'correction' => 'correction',
+                'baby_addition' => 'baby addition',
+                'policy_instalment' => 'policy instalment',
+                'addition_inception' => 'addition-inception',
+                'bds_correction' => 'bds correction',
+                'policy_correction' => 'policy correction',
+                'policy_cancellation' => 'policy cancellation',
+            ];
+
+            $fields = [
+                'client_short_name',
+                'client_branch_name',
+                'insurer_short_name',
+                'policy_type',
+                'endorsement_no',
+                'policy_no',
+            ];
+
+            return array_values(array_filter($rows, static function (array $row) use ($needle, $fields, $issuerMap, $statusMap, $actionTypeMap) {
+                foreach ($fields as $field) {
+                    $value = $row[$field] ?? '';
+                    if ($value !== '' && mb_strpos(mb_strtolower((string) $value), $needle) !== false) {
+                        return true;
+                    }
+                }
+
+                $issuerText = $issuerMap[(int) ($row['issuer'] ?? 0)] ?? '';
+                if ($issuerText !== '' && mb_strpos($issuerText, $needle) !== false) {
+                    return true;
+                }
+
+                $statusText = $statusMap[(string) ($row['status'] ?? '')] ?? '';
+                if ($statusText !== '' && mb_strpos($statusText, $needle) !== false) {
+                    return true;
+                }
+
+                $actionTypeText = $actionTypeMap[(string) ($row['action_type'] ?? '')] ?? '';
+                if ($actionTypeText !== '' && mb_strpos($actionTypeText, $needle) !== false) {
+                    return true;
+                }
+
+                return false;
+            }));
+        }
+
+        public function getEndorsementTranctionListDataTable(int $draw, int $start, int $length, string $searchValue, array $filters): array
+        {
+            $cached       = $this->getCachedEndorsementTranctionListData($filters);
+            $allRows      = $cached['rows'] ?? [];
+            $recordsTotal = count($allRows);
+
+            if ($searchValue !== '') {
+                $allRows = $this->filterEndorsementTranctionRowsBySearch($allRows, $searchValue);
+            }
+
+            $recordsFiltered = count($allRows);
+
+            if ($length < 0) {
+                $length = $recordsFiltered;
+            }
+
+            $pageRows = $length > 0
+                ? array_slice(array_values($allRows), $start, $length)
+                : array_values($allRows);
+
+            return [
+                'draw'            => $draw,
+                'recordsTotal'    => $recordsTotal,
+                'recordsFiltered' => $recordsFiltered,
+                'data'            => $pageRows,
+                'cache_expires_in_ms' => max(0, (($cached['expires_at'] ?? time()) - time()) * 1000),
+            ];
+        }
+
         public function getVarienceReportLIst($start_date = 0, $end_date = 0, $client_id = 0, $insurer_id = 0, $policy_type_id = 0, $date_type = 0, $issuer = 0, $client_branch_id = 0, $insurer_branch_id = 0, $client_policy_id = 0)
         {
             $builder = $this->db->table('policy_transaction')
@@ -3099,11 +3359,15 @@
                 }
             }
 
-            // 2. Dynamic $where array
+            // 2. Dynamic $where (string SQL fragment or column => value map)
             if (!empty($where)) {
-                foreach ($where as $column => $value) {
-                    $value = addslashes($value);
-                    $conditions .= " AND `$column` = '$value' ";
+                if (is_string($where)) {
+                    $conditions .= ' AND ' . $where . ' ';
+                } else {
+                    foreach ($where as $column => $value) {
+                        $value = addslashes($value);
+                        $conditions .= " AND `$column` = '$value' ";
+                    }
                 }
             }
 
@@ -3739,119 +4003,245 @@
             $query = $this->db->query($sql);
             $result = $query->getResultArray();
 
+            return $this->processBDSReportResults($result);
+        }
 
-            // $countofalldata = count($result);
-            // Kint::dump($result);
-            // dd($this->db->getLastQuery()->getQuery());
-
+        /**
+         * Post-process raw BDS report rows (dedup, rewards, unbilled amounts).
+         */
+        public function processBDSReportResults(array $result): array
+        {
             $keys     = [];
             $filtered = [];
 
             foreach ($result as $row) {
-
-                // Normalize endorsement number
                 $endorsement_number = !empty($row['endorsement_no']) ? $row['endorsement_no'] : '-';
 
                 $reward     = (float) ($row['reward'] ?? 0);
                 $billed_amt = (float) ($row['billed_amt'] ?? 0);
 
-                if($reward == 0.00 && $billed_amt == 0.00 && $row['statement_uploaded'] === 'statement uploaded'){
+                if ($reward == 0.00 && $billed_amt == 0.00 && $row['statement_uploaded'] === 'statement uploaded') {
                     continue;
                 }
 
-               if ($reward > 0 && ($row['billed_amt'] ?? 0) == 0.00) { 
-                    $row['total_irda_amt'] = '0.00'; 
-                    $row['billed_amt'] = $reward; 
-                    $rewardFlag = 'R'; // Reward row 
-                } else { 
-                    $rewardFlag = 'N'; // Normal row 
+                if ($reward > 0 && ($row['billed_amt'] ?? 0) == 0.00) {
+                    $row['total_irda_amt'] = '0.00';
+                    $row['billed_amt']     = $reward;
+                    $rewardFlag            = 'R';
+                } else {
+                    $rewardFlag = 'N';
                 }
 
-                // ✅ Stable key (NO reward flag)
                 $key = implode('|', [
                     $row['statement_year_month'],
                     $row['insurer_name'],
                     $row['policy_no'],
                     $endorsement_number,
-                    $rewardFlag
+                    $rewardFlag,
                 ]);
 
-                // Prefer "statement uploaded"
                 if ($row['statement_uploaded'] === 'statement uploaded') {
                     $filtered[$key] = $row;
-                    $keys[$key] = true;
-                }
-                // Keep no-statement only if uploaded not present
-                elseif (!isset($keys[$key])) {
+                    $keys[$key]     = true;
+                } elseif (!isset($keys[$key])) {
                     $filtered[$key] = $row;
                 }
             }
 
-            // Reindex final output
             $result = array_values($filtered);
 
-            // dd($result);
-
-            // --------------------------------------------------------------------------------------------------------
-
             $totalBilled  = [];
             $totalIrdaMap = [];
 
             foreach ($result as $row) {
-                $key = $row['pt_id'].'-'.$row['insurer_id'];
+                $key = $row['pt_id'] . '-' . $row['insurer_id'];
 
-                // Sum billed amount
                 $totalBilled[$key] = ($totalBilled[$key] ?? 0) + (float) ($row['billed_amt'] ?? 0);
 
-                // Store total_irda_amt once
                 if (!isset($totalIrdaMap[$key])) {
                     $totalIrdaMap[$key] = (float) $row['total_irda_amt'];
                 }
 
-                if(($row['reward'] ?? 0) > 0){
-                     $totalIrdaMap[$key] = ($totalIrdaMap[$key] ?? 0) + (float) $row['reward'];
+                if (($row['reward'] ?? 0) > 0) {
+                    $totalIrdaMap[$key] = ($totalIrdaMap[$key] ?? 0) + (float) $row['reward'];
                 }
             }
 
-            // dd($totalBilled, $totalIrdaMap);
-
             $ptSeen = [];
             $final  = [];
 
             foreach ($result as $row) {
-                $ptId = $row['pt_id'].'-'.$row['insurer_id'];
+                $ptId = $row['pt_id'] . '-' . $row['insurer_id'];
                 if (!isset($ptSeen[$ptId])) {
-
-                    $totalIrdaVal = $totalIrdaMap[$ptId] ?? 0;
+                    $totalIrdaVal   = $totalIrdaMap[$ptId] ?? 0;
                     $totalBilledVal = $totalBilled[$ptId] ?? 0;
-                    $addMinus = false;
+                    $addMinus       = false;
 
-                    if($totalIrdaVal < 0){
-                        $totalIrdaVal = abs($totalIrdaVal);
+                    if ($totalIrdaVal < 0) {
+                        $totalIrdaVal   = abs($totalIrdaVal);
                         $totalBilledVal = abs($totalBilledVal);
-                        $addMinus = true;
+                        $addMinus       = true;
                     }
 
-                    // First entry → set unbilled amount
-                    $row['unbilled_amount'] = round((float) ($totalIrdaVal - $totalBilledVal),2 );
+                    $row['unbilled_amount'] = round((float) ($totalIrdaVal - $totalBilledVal), 2);
 
-                    if($addMinus){
+                    if ($addMinus) {
                         $row['unbilled_amount'] = ($row['unbilled_amount'] * -1);
                     }
 
                     $ptSeen[$ptId] = true;
                 } else {
-                    // Other entries → zero
                     $row['unbilled_amount'] = '0.00';
                 }
 
                 $final[] = $row;
             }
 
-            $result = $final;
+            return $final;
+        }
 
-            // dd($result); die;
-            return $result;
+        /**
+         * Cached processed BDS report list for a given filter set.
+         */
+        public function getCachedBDSReportList(array $filters): array
+        {
+            $cacheKey = 'bds_report_v1_' . md5(json_encode($filters));
+            $cache    = \Config\Services::cache();
+            $cached   = $cache->get($cacheKey);
+
+            if (is_array($cached)) {
+                return $cached;
+            }
+
+            $processed = $this->getBDSReportList(
+                $filters['start_date'] ?? 0,
+                $filters['end_date'] ?? 0,
+                $filters['client_id'] ?? 0,
+                $filters['insurer_id'] ?? 0,
+                $filters['policy_type_id'] ?? 0,
+                $filters['date_type'] ?? 0,
+                $filters['issuer'] ?? 0,
+                $filters['client_branch_id'] ?? 0,
+                $filters['insurer_branch_id'] ?? 0,
+                $filters['client_policy_id'] ?? 0,
+                $filters['user_id'] ?? 0,
+                $filters['where'] ?? []
+            );
+
+            $cache->save($cacheKey, $processed, 300);
+
+            return $processed;
+        }
+
+        /**
+         * Server-side DataTables payload for BDS report.
+         */
+        public function getBDSReportListDataTable(int $draw, int $start, int $length, string $searchValue, array $filters): array
+        {
+            $allRows      = $this->getCachedBDSReportList($filters);
+            $recordsTotal = count($allRows);
+
+            if ($searchValue !== '') {
+                $allRows = $this->filterBDSReportRowsBySearch($allRows, $searchValue);
+            }
+
+            $recordsFiltered = count($allRows);
+
+            if ($length < 0) {
+                $length = $recordsFiltered;
+            }
+
+            $pageRows = $length > 0
+                ? array_slice(array_values($allRows), $start, $length)
+                : array_values($allRows);
+
+            return [
+                'draw'            => $draw,
+                'recordsTotal'    => $recordsTotal,
+                'recordsFiltered' => $recordsFiltered,
+                'data'            => $pageRows,
+                'totals'          => $this->calculateBDSReportTotals($allRows),
+            ];
+        }
+
+        /**
+         * Global search across BDS report row fields.
+         */
+        public function filterBDSReportRowsBySearch(array $rows, string $searchValue): array
+        {
+            $needle = mb_strtolower(trim($searchValue));
+            if ($needle === '') {
+                return $rows;
+            }
+
+            // Match DataTables "common search" behavior against primary visible columns.
+            $searchFields = [
+                'user_name',
+                'policy_issue_month',
+                'client_name',
+                'action_type',
+                'policy_type',
+                'policy_no',
+                'endorsement_no',
+                'insurer_branch_name',
+            ];
+
+            return array_values(array_filter($rows, static function (array $row) use ($needle, $searchFields) {
+                foreach ($searchFields as $field) {
+                    $value = $row[$field] ?? '';
+                    if ($value !== '' && mb_strpos(mb_strtolower((string) $value), $needle) !== false) {
+                        return true;
+                    }
+                }
+
+                $numericFields = [
+                    'bp_amt', 'tp_or_ter', 'premium_wo_gst', 'total_premium', 'agreed_bp_per',
+                    'agreed_tp_or_ter_per', 'reward', 'total_irda_amt', 'billed_amt', 'unbilled_amount',
+                ];
+                foreach ($numericFields as $field) {
+                    $value = $row[$field] ?? '';
+                    if ($value !== '' && $value !== null && mb_strpos((string) $value, $needle) !== false) {
+                        return true;
+                    }
+                }
+
+                return false;
+            }));
+        }
+
+        /**
+         * Summary totals for BDS report badges (matches client-side footerCallback logic).
+         */
+        public function calculateBDSReportTotals(array $rows): array
+        {
+            $totalPremium = 0.0;
+            $totalRewards = 0.0;
+            $totalIrda    = 0.0;
+            $totalBilled  = 0.0;
+            $totalUnbilled = 0.0;
+
+            foreach ($rows as $row) {
+                $hasIrda = ((float) ($row['total_irda_amt'] ?? 0)) != 0.0;
+
+                $totalPremium += $hasIrda ? (float) ($row['premium_wo_gst'] ?? 0) : 0.0;
+                $totalRewards += (float) ($row['reward'] ?? 0);
+                $totalIrda    += (float) ($row['total_irda_amt'] ?? 0);
+                $totalBilled  += (float) ($row['billed_amt'] ?? 0);
+                $totalUnbilled += (float) ($row['unbilled_amount'] ?? 0);
+            }
+
+            $totalIrdaAmt = $totalBilled - $totalRewards;
+            $totalRevenue = $totalIrdaAmt + $totalRewards;
+
+            return [
+                'total_premium'  => number_format($totalPremium, 2, '.', ''),
+                'total_rewards'  => number_format($totalRewards, 2, '.', ''),
+                'total_irda'     => number_format($totalIrdaAmt, 2, '.', ''),
+                'total_revenue'  => number_format($totalRevenue, 2, '.', ''),
+                'total_billed'   => number_format($totalBilled, 2, '.', ''),
+                'total_unbilled' => number_format($totalUnbilled, 2, '.', ''),
+                'policy_count'   => count($rows),
+            ];
         }
 
 
diff --git a/app/Views/policy_transaction_endorsement_list.php b/app/Views/policy_transaction_endorsement_list.php
index 0f2555fa..5dc37652 100644
--- a/app/Views/policy_transaction_endorsement_list.php
+++ b/app/Views/policy_transaction_endorsement_list.php
@@ -293,40 +293,7 @@
                             Action 
                         
                     
-                    
-                         $row) { ?>
-                            
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                
-                                    
-                                
-                            
-                        
-                    
+                    
                 
             
         
@@ -388,32 +355,122 @@
 
     })
 
+    var endorsementTableFilters = ;
+    var endorsementListDataTableUrl = '';
+    var endorsementClearCacheUrl = '';
+    var endorsementAutoReloadTimer = null;
+
+    function scheduleEndorsementAutoReload(ms) {
+        if (endorsementAutoReloadTimer) {
+            clearTimeout(endorsementAutoReloadTimer);
+        }
+        if (ms > 0) {
+            endorsementAutoReloadTimer = setTimeout(function() {
+                window.location.reload();
+            }, ms);
+        }
+    }
+
+    function exportServerSideFilteredEndorsementData(e, dt, button, config, buttonType) {
+        var self = this;
+        var oldStart = dt.page.info().start;
+
+        dt.one('preXhr', function (x, s, data) {
+            data.start = 0;
+            data.length = -1;
+        });
+
+        dt.one('draw', function () {
+            $.fn.dataTable.ext.buttons[buttonType].action.call(self, e, dt, button, config);
+
+            dt.one('preXhr', function (x, s, data) {
+                data.start = oldStart;
+                data.length = dt.page.len();
+            });
+
+            setTimeout(function () {
+                dt.ajax.reload(null, false);
+            }, 0);
+        });
+
+        dt.ajax.reload();
+    }
+
+    function clearEndorsementCacheAndReloadTable(dt) {
+        $.ajax({
+            url: endorsementClearCacheUrl,
+            type: 'POST',
+            success: function(response) {
+                if (response && response.status) {
+                    endorsementTableFilters.cache_version = new Date().getTime();
+                    dt.ajax.reload(null, true);
+                    toastr.success(response.message || 'Cache cleared and list reloaded.', 'Success');
+                } else {
+                    toastr.warning((response && response.message) ? response.message : 'Unable to clear cache.', 'Warning');
+                }
+            },
+            error: function() {
+                toastr.error('Failed to clear cache.', 'Error');
+            }
+        });
+    }
+
     //DataTable document ready
     $(document).ready(function() {
         var ticketsTable = $('#tickets-table');
 
         if (ticketsTable.length) {
-            var table = ticketsTable.DataTable({
-                scrollX: true,
-                dom: "<'row'<'col-sm-7'f><'col-sm-5 text-right'B>>" + // Filter left, buttons right
-                "<'row'<'col-sm-12'tr>>" +
-                "<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>",
-            lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]],
-            buttons: [      
+            nhanceListDataTableBeforeInit();
+            var table = ticketsTable.DataTable(nhanceMergeListDataTableOptions({
+                autoWidth: false,
+                processing: true,
+                serverSide: true,
+                deferRender: true,
+                searchDelay: 400,
+                columns: (function() {
+                    var cols = [];
+                    for (var i = 0; i < 14; i++) {
+                        cols.push({ data: String(i), orderable: false });
+                    }
+                    return cols;
+                })(),
+                ajax: {
+                    url: endorsementListDataTableUrl,
+                    type: 'POST',
+                    data: function(d) {
+                        return $.extend({}, d, endorsementTableFilters);
+                    },
+                    dataSrc: function(json) {
+                        scheduleEndorsementAutoReload(json.cache_expires_in_ms || 300000);
+                        return json.data;
+                    }
+                },
+                dom: "<'row'<'col-sm-7'f><'col-sm-5 text-right'B>>" +
+                    "<'row'<'col-sm-12'tr>>" +
+                    "<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>",
+                lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]],
+                buttons: [      
+                    {
+                        text: '  Reload ',
+                        className: 'btn app-btn-secondary mr-2',
+                        action: function(e, dt) {
+                            clearEndorsementCacheAndReloadTable(dt);
+                        }
+                    },
                     {
                         text: ' Filter ',
                         className: 'btn app-btn-primary mr-2',
-                        action: function (e, dt, node, config) {
+                        action: function () {
                             openEndorsementFilterNav();
                         }
                     },      
-                   {
+                    {
                         text: '  Add ',
                         className: 'btn app-btn-primary  mr-2',
-                        action: function (e, dt, node, config) {
+                        action: function () {
                             hide_list_show_add();
                             addHTMLInput(null, 'policy_docs_div');
-                            $('#policy_docs').show()
+                            $('#policy_docs').show();
                         },
                         attr: { id: 'btnAdd' }
                     },
@@ -422,14 +479,30 @@
                         text: ' Export ',
                         className: 'btn app-btn-secondary ',
                         buttons: [
-                                    {
-                                        extend: 'csv',
-                                        text: '  CSV ',
-                                        title: 'Policy-Tranction-Endorsement-List',
-                                        exportOptions: {
-                                            columns: ':not(:last-child)'
-                                        },
-                                    }
+                            {
+                                extend: 'csv',
+                                text: '  CSV ',
+                                title: 'Policy-Tranction-Endorsement-List',
+                                action: function (e, dt, button, config) {
+                                    exportServerSideFilteredEndorsementData.call(this, e, dt, button, config, 'csvHtml5');
+                                },
+                                exportOptions: {
+                                    modifier: { search: 'applied', page: 'all' },
+                                    columns: ':not(:last-child)'
+                                },
+                            },
+                            {
+                                extend: 'excel',
+                                text: '  EXCEL ',
+                                title: 'Policy-Tranction-Endorsement-List',
+                                action: function (e, dt, button, config) {
+                                    exportServerSideFilteredEndorsementData.call(this, e, dt, button, config, 'excelHtml5');
+                                },
+                                exportOptions: {
+                                    modifier: { search: 'applied', page: 'all' },
+                                    columns: ':not(:last-child)'
+                                },
+                            }
                         ]
                     }
                 ],
@@ -444,33 +517,14 @@
                     `,
                     searchPlaceholder: "Search",
                     emptyTable: '
No Data found
', - paginate: { - previous: '◄', - next: '►' - } + paginate: { previous: '◄', next: '►' } }, - paging: true, // Enable pagination - pageLength: 10, // Set default number of rows per page (optional) + paging: true, + pageLength: 10, ordering: false, - }); - - function applyBottomRowDropup() { - if (!table) return; - - const currentRows = table.rows({ page: 'current' }).nodes().toArray(); - $('#tickets-table tbody tr').removeClass('nh-force-dropup'); - $('#tickets-table tbody tr td.table-action-cell .btn-group.dropdown').removeClass('dropup'); - - const targetCount = Math.min(2, currentRows.length); - for (let i = 0; i < targetCount; i++) { - const row = currentRows[currentRows.length - 1 - i]; - if (!row) continue; - $(row).addClass('nh-force-dropup'); - $(row).find('td.table-action-cell .btn-group.dropdown').addClass('dropup'); - } - } - applyBottomRowDropup(); - ticketsTable.on('draw.dt', applyBottomRowDropup); + })); + nhanceListDataTableAfterInit(); + nhanceListDataTableBindAdjust(table); } else { console.error("Table not found."); } diff --git a/app/Views/policy_transaction_inception_list.php b/app/Views/policy_transaction_inception_list.php index 9a48f2d2..a86effe9 100644 --- a/app/Views/policy_transaction_inception_list.php +++ b/app/Views/policy_transaction_inception_list.php @@ -321,43 +321,7 @@ table.dataTable tbody td { - - $row){ ?> - - - - - - - - - - - - - - - - - - - - - - + @@ -673,6 +637,66 @@ function getAddPage(){ } } +var inceptionTableFilters = ; +var inceptionListDataTableUrl = ''; +var inceptionClearCacheUrl = ''; +var inceptionAutoReloadTimer = null; + +function scheduleInceptionAutoReload(ms) { + if (inceptionAutoReloadTimer) { + clearTimeout(inceptionAutoReloadTimer); + } + if (ms > 0) { + inceptionAutoReloadTimer = setTimeout(function() { + window.location.reload(); + }, ms); + } +} + +function exportServerSideFilteredInceptionData(e, dt, button, config, buttonType) { + var self = this; + var oldStart = dt.page.info().start; + + dt.one('preXhr', function (x, s, data) { + data.start = 0; + data.length = -1; + }); + + dt.one('draw', function () { + $.fn.dataTable.ext.buttons[buttonType].action.call(self, e, dt, button, config); + + dt.one('preXhr', function (x, s, data) { + data.start = oldStart; + data.length = dt.page.len(); + }); + + setTimeout(function () { + dt.ajax.reload(null, false); + }, 0); + }); + + dt.ajax.reload(); +} + +function clearInceptionCacheAndReloadTable(dt) { + $.ajax({ + url: inceptionClearCacheUrl, + type: 'POST', + success: function(response) { + if (response && response.status) { + inceptionTableFilters.cache_version = new Date().getTime(); + dt.ajax.reload(null, true); + toastr.success(response.message || 'Cache cleared and list reloaded.', 'Success'); + } else { + toastr.warning((response && response.message) ? response.message : 'Unable to clear cache.', 'Warning'); + } + }, + error: function() { + toastr.error('Failed to clear cache.', 'Error'); + } + }); +} + // Datatable document ready $(document).ready(function() { @@ -692,64 +716,109 @@ $(document).ready(function() { var ticketsTable = $('#tickets-table'); if (ticketsTable.length) { - ticketsTable.DataTable({ - scrollX: true, - // dom: "<'row'<'col-12'f><'col-sm-11 text-right'B>>" + // Filter left, buttons right - // dom: "<'row'<'col-12 d-flex justify-content-between'<'datatable-search dataTables_filter'f><'datatable-buttons dt-buttons'B>>>" + - // "<'row'<'col-sm-12'tr>>" + - // "<'row'<'col-sm-5'i><'col-sm-7'p>>", // Pagination at the bottom, without page length selector - dom: "<'row'<'col-sm-7'f><'col-sm-5 text-right'B>>" + // Filter left, buttons right + nhanceListDataTableBeforeInit(); + var inceptionTable = ticketsTable.DataTable(nhanceMergeListDataTableOptions({ + autoWidth: false, + processing: true, + serverSide: true, + deferRender: true, + searchDelay: 400, + columns: (function() { + var cols = []; + for (var i = 0; i < 16; i++) { + cols.push({ data: String(i), orderable: false }); + } + return cols; + })(), + ajax: { + url: inceptionListDataTableUrl, + type: 'POST', + data: function(d) { + return $.extend({}, d, inceptionTableFilters); + }, + dataSrc: function(json) { + scheduleInceptionAutoReload(json.cache_expires_in_ms || 300000); + return json.data; + } + }, + dom: "<'row'<'col-sm-7'f><'col-sm-5 text-right'B>>" + "<'row'<'col-sm-12'tr>>" + "<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>", lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]], - buttons: [ - { - text: ' Filter ', - className: 'btn app-btn-primary mr-2', - action: function(e, dt, node, config) { - openPolicyFilterNav(); - } - }, - { - text: ' Add ', - className: 'btn app-btn-primary mr-2', - action: function (e, dt, node, config) { - openPolicyNoAddModal(); - } - }, - { - extend: 'collection', - text: ' Export ', - className: 'btn app-btn-secondary ', - buttons: [ - { - extend: 'csv', - text: ' CSV ', - className: 'app-btn-primary ', - title: 'Policy-Tranction-Inception-List', - exportOptions: { - columns: ':not(:last-child)' - }, - } - ] + buttons: [ + { + text: ' Reload ', + className: 'btn app-btn-secondary mr-2', + action: function(e, dt) { + clearInceptionCacheAndReloadTable(dt); } - ], + }, + { + text: ' Filter ', + className: 'btn app-btn-primary mr-2', + action: function() { + openPolicyFilterNav(); + } + }, + { + text: ' Add ', + className: 'btn app-btn-primary mr-2', + action: function () { + openPolicyNoAddModal(); + } + }, + { + extend: 'collection', + text: ' Export ', + className: 'btn app-btn-secondary ', + buttons: [ + { + extend: 'csv', + text: ' CSV ', + className: 'app-btn-primary ', + title: 'Policy-Tranction-Inception-List', + action: function (e, dt, button, config) { + exportServerSideFilteredInceptionData.call(this, e, dt, button, config, 'csvHtml5'); + }, + exportOptions: { + modifier: { search: 'applied', page: 'all' }, + columns: ':not(:last-child)' + } + }, + { + extend: 'excel', + text: ' EXCEL ', + className: 'app-btn-primary ', + title: 'Policy-Tranction-Inception-List', + action: function (e, dt, button, config) { + exportServerSideFilteredInceptionData.call(this, e, dt, button, config, 'excelHtml5'); + }, + exportOptions: { + modifier: { search: 'applied', page: 'all' }, + columns: ':not(:last-child)' + } + } + ] + } + ], language: { - search: ` -
- _INPUT_ - - -
`, - searchPlaceholder: "Search", - emptyTable: '
No Data found
' + search: ` +
+ _INPUT_ + + +
`, + searchPlaceholder: "Search", + emptyTable: '
No Data found
' }, - paging: true, // Enable pagination - pageLength: 10, // Set default number of rows per page (optional) - // ordering: false, - }); + paging: true, + pageLength: 10, + ordering: false, + })); + nhanceListDataTableAfterInit(); + nhanceListDataTableBindAdjust(inceptionTable); } else { console.error("Table not found."); } diff --git a/app/Views/report_bds.php b/app/Views/report_bds.php index 80246a6d..fb2c1c90 100644 --- a/app/Views/report_bds.php +++ b/app/Views/report_bds.php @@ -165,130 +165,6 @@ - - $row){ ?> - -   " class="mdi mdi-pencil" > - - - - - - - - - - - - - - - - - - - - - - - - - - % - % - - - i am print 0.00. - // REF : Velmurugan but he told handle in query - // Date : 6/11/25 12:50 - $irda_amt = isset($row['total_irda_amt']) && $row['total_irda_amt'] !== '' ? (float)$row['total_irda_amt'] : 0; - $exp_amt = isset($row['exp_amt']) && $row['exp_amt'] !== '' ? (float)$row['exp_amt'] : 0; - // $max_amount = max($irda_amt, $exp_amt); - // $total_irda_amt = number_format($max_amount, 2, '.', ''); - // $total_irda_amt = empty($row['total_irda_amt']) ? $row['exp_amt'] : $row['total_irda_amt']; - $total_irda_amt = $row['total_irda_amt'] ?? '0.00'; - ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -332,6 +208,68 @@