diff --git a/app/Config/Routes.php b/app/Config/Routes.php index e816ef8b..2d215227 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -239,6 +239,9 @@ $routes->group("/employee", ["filter" => "authMVC"], function ($routes) { $routes->get("search", "EmployeeController::search"); $routes->get("upload", "EmployeeController::employeesUplodWithEvents"); $routes->post("upload", "EmployeeController::employeesUplodWithEvents"); + $routes->post("upload/file-list/datatable", "EmployeeController::fileListDataTable"); + $routes->post("upload/batch-list/datatable", "EmployeeController::batchListDataTable"); + $routes->post("upload/hr-file-list/datatable", "EmployeeController::hrFileListDataTable"); $routes->get("excel_error/(:any)", "EmployeeController::getExcelFileErrors/$1"); $routes->get("endorsement-list", "EmployeeController::endorsementList"); $routes->match(['get','post'],'enrollment-list','EmployeeController::enrollmentClientList'); diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 89d99b13..3834ae06 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -19,6 +19,7 @@ use App\Models\PolicesModel; use App\Models\FileModel; use App\Models\BatchListModel; use App\Models\BatchFileModel; +use App\Models\HrFileUploadModel; use App\Models\EmpEndorsementModel; use App\Models\ClientPolicyModel; use App\Models\TPAModel; @@ -70,6 +71,7 @@ class EmployeeController extends AdminController protected $fileModel; protected $batchListModel; protected $batchFileModel; + protected $hrFileUploadModel; protected $empEndorsementModel; protected $clientPolicyModel; protected $TPAModel; @@ -96,6 +98,7 @@ class EmployeeController extends AdminController $this->fileModel = new FileModel(); $this->batchListModel = new BatchListModel(); $this->batchFileModel = new BatchFileModel(); + $this->hrFileUploadModel = new HrFileUploadModel(); $this->empEndorsementModel = new EmpEndorsementModel(); $this->clientPolicyModel = new ClientPolicyModel(); $this->TPAModel = new TPAModel(); @@ -416,9 +419,6 @@ class EmployeeController extends AdminController } } - $get_data = $this->request->getGet(); - // dd($get_data); - $data['tab_name'] = 'View Inception'; $data['page_name'] = 'View Inception'; @@ -432,201 +432,10 @@ class EmployeeController extends AdminController $data['import_or_export'] = ['import' => 'Upload', 'export' => 'Download']; $data['insurer_or_tpa'] = ['insurer' => 'Insurer', 'tpa' => 'TPA']; - // $data['fileList'] = $this->fileModel - // ->select(['files.*', 'up.emp_code', 'up.first_name', 'pm.name as policy_name', 'c.short_name', 'cp.id as client_policy_id']) - // ->join('user_profiles up', 'files.created_by = up.id') - // ->join('client_policy cp', 'files.policy_id = cp.id', 'left') - // ->join('policies pm', 'cp.policy_id = pm.id', 'left') - // ->join('clients c', 'files.client_id = c.id and files.client_id = cp.client_id', 'left') - // ->where('files.created_by', get_session_userid())->orderBy('files.created_at', 'desc')->findAll(); - // dd($this->fileModel->getLastQuery()); - $role_id = get_role_id(); - $user_id = get_session_userid(); + // List rows are loaded via server-side DataTables AJAX (10 per page). + $data['fileList'] = []; + $data['batch_list'] = []; - $query = $this->fileModel - ->select([ - 'files.id', - 'files.file_name', - 'files.created_by', - 'files.created_at', - 'files.is_active', - 'files.status', - 'files.client_id', - 'files.policy_id', - 'files.client_branch_id', - 'files.action', - 'files.uploaded_by', - 'up.emp_code', - // 'up.first_name', - 'c.short_name', - 'cb.branch_name', - 'cp.id as client_policy_id', - '"0" as employee_count', - '"0" as total', - 'policy_type.policy_type', - 'cp.policy_no', - "CASE - WHEN files.hr_id IS NOT NULL THEN - CONCAT( - ( - SELECT lc.name - FROM level_contacts lc - WHERE lc.id = files.hr_id - LIMIT 1 - ), - ' (HR)' - ) - ELSE up.first_name - END AS first_name - " - ]) - ->join('user_profiles up', 'files.created_by = up.id', 'left') - ->join('client_policy cp', 'files.policy_id = cp.id', 'left') - ->join('client_branch cb', 'files.client_branch_id = cb.id', 'left') - ->join('policy_type', 'policy_type.id = cp.policy_type_id') - ->join('clients c', 'files.client_id = c.id and files.client_id = cp.client_id', 'left') - ->join("client_rm cr", "cr.client_id = c.id and cr.is_active = 1", 'left') - ->where('files.is_active', 1); - - if (!empty($get_data['start_date'] ?? null) && !empty($get_data['end_date'] ?? null)) { - // 1. If dates are provided, use the user's filter - $start = change_date_format($get_data['start_date'], 'd/m/Y', 'Y-m-d') . ' 00:00:00'; - $end = change_date_format($get_data['end_date'], 'd/m/Y', 'Y-m-d') . ' 23:59:59'; - - $query->where('files.created_at >=', $start) - ->where('files.created_at <=', $end); - } else { - if(empty($get_data['tab_type'] ?? null)){ - // 2. Default: If no dates are selected, show last 90 days (or all data) - $query->where('files.created_at >=', date('Y-m-d 00:00:00', strtotime('-90 days'))) - ->where('files.created_at <=', date('Y-m-d 23:59:59')); - } - } - - if(!empty($get_data['client_id'] ?? null)){ - $query->where('files.client_id', $get_data['client_id']); - } - - if(!empty($get_data['client_branch_id'] ?? null)){ - $query->where('files.client_branch_id', $get_data['client_branch_id']); - } - - if(!empty($get_data['policy_id'] ?? null)){ - $query->where('files.policy_id', $get_data['policy_id']); - } - - if(!empty($get_data['event_type'] ?? null)){ - $query->where('files.action', $get_data['event_type']); - } - - if (in_array($role_id, [2, 3])) { - // If the user is a Account Manager or Manager, filter by user_id - $query->where('cr.user_id', (int)$user_id); - } - - $data['fileList'] = $query->groupBy("files.id") - ->orderBy('files.created_at', 'desc') - ->find(); - - // dd($this->fileModel->getLastQuery()); - // dd($data['fileList']); - - $query2 = $this->batchFileModel->select(" - - batch_files.id, - batch_files.client_id, - batch_files.client_policy_id, - batch_files.batch_code, - batch_files.file_name, - batch_files.insurer_or_tpa, - batch_files.event_type, - batch_files.actions, - batch_files.count, - batch_files.created_by, - batch_files.created_at, - batch_files.updated_by, - batch_files.updated_at, - batch_files.is_active, - batch_files.amount, - batch_files.status, - batch_files.icici_status_flag, - batch_files.client_branch_id, - insurers.short_name as insurer_short_name, - tpa.short_name as tpa_short_name, - DATE_FORMAT(batch_files.policy_issue_date, '%d/%m/%Y') AS policy_issue_date, - - CASE - WHEN batch_files.status IN ('partially success', 'in-progress-partially', 'failed-7') - THEN batch_files.error_data - ELSE NULL - END AS error_data, - - clients.short_name as client_short_name, - client_branch.branch_name, - client_policy.policy_no, - policy_type.policy_type - - ") - ->join('client_policy', 'client_policy.id = batch_files.client_policy_id') - ->join('insurers', 'client_policy.insurer_id = insurers.id') - ->join('tpa', 'client_policy.tpa_id = tpa.id', 'left') - ->join('client_branch', 'client_branch.id = batch_files.client_branch_id') - ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') - ->join('clients', 'clients.id = client_policy.client_id') - ->join("client_rm cr", "cr.client_id = clients.id and cr.is_active = 1", 'left') - ->where('batch_files.is_active', 1); - - if (!empty($get_data['start_date'] ?? null) && !empty($get_data['end_date'] ?? null)) { - // 1. If dates are provided, use the user's filter - $start = change_date_format($get_data['start_date'], 'd/m/Y', 'Y-m-d') . ' 00:00:00'; - $end = change_date_format($get_data['end_date'], 'd/m/Y', 'Y-m-d') . ' 23:59:59'; - - $query2->where('batch_files.created_at >=', $start) - ->where('batch_files.created_at <=', $end); - - } else { - if(empty($get_data['tab_type'] ?? null)){ - // 2. Default: If no dates are selected, show last 90 days (or all data) - $query2->where('batch_files.created_at >=', date('Y-m-d 00:00:00', strtotime('-90 days'))) - ->where('batch_files.created_at <=', date('Y-m-d 23:59:59')); - } - } - - if(!empty($get_data['client_id'] ?? null)){ - $query2->where('batch_files.client_id', $get_data['client_id']); - } - - if(!empty($get_data['client_branch_id'] ?? null)){ - $query2->where('batch_files.client_branch_id', $get_data['client_branch_id']); - } - - if(!empty($get_data['policy_id'] ?? null)){ - $query2->where('batch_files.client_policy_id', $get_data['policy_id']); - } - - if(!empty($get_data['event_type'] ?? null)){ - $query2->where('batch_files.event_type', $get_data['event_type']); - } - - if(!empty($get_data['insurer_or_tpa'] ?? null)){ - $query2->where('batch_files.insurer_or_tpa', $get_data['insurer_or_tpa']); - } - - if(!empty($get_data['action_type'] ?? null)){ - $query2->where('batch_files.actions', $get_data['action_type']); - } - - if (in_array($role_id, [2, 3])) { - - // If the user is a Account Manager or Manager, filter by user_id - $query2->where('cr.user_id', (int)$user_id); - } - - $data['batch_list'] = $query2->groupBy("batch_files.id") - ->orderBy('batch_files.id', 'desc') - ->find(); - - // dd($data['fileList']);die(); if ($this->request->getMethod() == "get") { $this->loadLayout('import_export', $data); } @@ -7557,5 +7366,685 @@ class EmployeeController extends AdminController ]); } + /** + * DataTables AJAX: Data From Client file list (server-side pagination). + */ + public function fileListDataTable() + { + 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); + if ($length < 1) { + $length = 10; + } + $search = trim((string) ($this->request->getPost('search')['value'] ?? '')); + $filters = $this->buildUploadListFiltersFromRequest(); + + $db = \Config\Database::connect(); + + $countBuilder = $this->buildFileListQuery($filters, ''); + $countSql = $countBuilder->select('files.id')->groupBy('files.id')->getCompiledSelect(); + $recordsTotal = (int) ($db->query('SELECT COUNT(*) AS cnt FROM (' . $countSql . ') AS counted')->getRowArray()['cnt'] ?? 0); + + $filteredBuilder = $this->buildFileListQuery($filters, $search); + $filteredSql = $filteredBuilder->select('files.id')->groupBy('files.id')->getCompiledSelect(); + $recordsFiltered = ($search === '') + ? $recordsTotal + : (int) ($db->query('SELECT COUNT(*) AS cnt FROM (' . $filteredSql . ') AS counted')->getRowArray()['cnt'] ?? 0); + + $dataBuilder = $this->buildFileListQuery($filters, $search); + $rows = $dataBuilder + ->select($this->fileListSelectColumns(), false) + ->groupBy('files.id') + ->orderBy('files.created_at', 'DESC') + ->limit($length, $start) + ->get() + ->getResultArray(); + + $data = []; + foreach ($rows as $index => $row) { + $data[] = $this->formatFileListRowForDataTable($row, $start + $index + 1); + } + + return $this->response->setJSON([ + 'draw' => $draw, + 'recordsTotal' => $recordsTotal, + 'recordsFiltered' => $recordsFiltered, + 'data' => $data, + ]); + } + + /** + * DataTables AJAX: Insurer/TPA batch list (server-side pagination). + */ + public function batchListDataTable() + { + 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); + if ($length < 1) { + $length = 10; + } + $search = trim((string) ($this->request->getPost('search')['value'] ?? '')); + $filters = $this->buildUploadListFiltersFromRequest(); + + $db = \Config\Database::connect(); + + $countBuilder = $this->buildBatchListQuery($filters, ''); + $countSql = $countBuilder->select('batch_files.id')->groupBy('batch_files.id')->getCompiledSelect(); + $recordsTotal = (int) ($db->query('SELECT COUNT(*) AS cnt FROM (' . $countSql . ') AS counted')->getRowArray()['cnt'] ?? 0); + + $filteredBuilder = $this->buildBatchListQuery($filters, $search); + $filteredSql = $filteredBuilder->select('batch_files.id')->groupBy('batch_files.id')->getCompiledSelect(); + $recordsFiltered = ($search === '') + ? $recordsTotal + : (int) ($db->query('SELECT COUNT(*) AS cnt FROM (' . $filteredSql . ') AS counted')->getRowArray()['cnt'] ?? 0); + + $dataBuilder = $this->buildBatchListQuery($filters, $search); + $rows = $dataBuilder + ->select($this->batchListSelectColumns(), false) + ->groupBy('batch_files.id') + ->orderBy('batch_files.id', 'DESC') + ->limit($length, $start) + ->get() + ->getResultArray(); + + $insurerOrTpa = ['insurer' => 'Insurer', 'tpa' => 'TPA']; + $importOrExport = ['import' => 'Upload', 'export' => 'Download']; + + $data = []; + foreach ($rows as $index => $row) { + $data[] = $this->formatBatchListRowForDataTable($row, $start + $index + 1, $insurerOrTpa, $importOrExport); + } + + return $this->response->setJSON([ + 'draw' => $draw, + 'recordsTotal' => $recordsTotal, + 'recordsFiltered' => $recordsFiltered, + 'data' => $data, + ]); + } + + /** + * DataTables AJAX: HR uploaded files (server-side pagination). + */ + public function hrFileListDataTable() + { + 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); + if ($length < 1) { + $length = 10; + } + $search = trim((string) ($this->request->getPost('search')['value'] ?? '')); + $filters = $this->buildUploadListFiltersFromRequest(); + + // HR form fields (CRM search) + $filters['client_id'] = $this->request->getPost('client_id') ?: ($filters['client_id'] ?? null); + $filters['client_branch_id'] = $this->request->getPost('client_branch_id') ?: ($filters['client_branch_id'] ?? null); + $filters['policy_id'] = $this->request->getPost('policy_id') ?: ($filters['policy_id'] ?? null); + $filters['event_type'] = $this->request->getPost('file_action') ?: ($this->request->getPost('event_type') ?: ($filters['event_type'] ?? null)); + + $db = \Config\Database::connect(); + + $countBuilder = $this->buildHrFileListQuery($filters, ''); + $countSql = $countBuilder->select('hr_file_upload.id')->groupBy('hr_file_upload.id')->getCompiledSelect(); + $recordsTotal = (int) ($db->query('SELECT COUNT(*) AS cnt FROM (' . $countSql . ') AS counted')->getRowArray()['cnt'] ?? 0); + + $filteredBuilder = $this->buildHrFileListQuery($filters, $search); + $filteredSql = $filteredBuilder->select('hr_file_upload.id')->groupBy('hr_file_upload.id')->getCompiledSelect(); + $recordsFiltered = ($search === '') + ? $recordsTotal + : (int) ($db->query('SELECT COUNT(*) AS cnt FROM (' . $filteredSql . ') AS counted')->getRowArray()['cnt'] ?? 0); + + $dataBuilder = $this->buildHrFileListQuery($filters, $search); + $rows = $dataBuilder + ->select($this->hrFileListSelectColumns(), false) + ->groupBy('hr_file_upload.id') + ->orderBy('hr_file_upload.id', 'DESC') + ->limit($length, $start) + ->get() + ->getResultArray(); + + $data = []; + foreach ($rows as $index => $row) { + $data[] = $this->formatHrFileListRowForDataTable($row, $start + $index + 1); + } + + return $this->response->setJSON([ + 'draw' => $draw, + 'recordsTotal' => $recordsTotal, + 'recordsFiltered' => $recordsFiltered, + 'data' => $data, + ]); + } + + protected function buildUploadListFiltersFromRequest(): array + { + $post = $this->request->getPost(); + + $clientBranchId = $post['client_branch_id'] ?? ($post['branch_id'] ?? null); + if ($clientBranchId === '0' || $clientBranchId === 0) { + $clientBranchId = null; + } + + $policyId = $post['policy_id'] ?? ($post['client_policy_id'] ?? null); + if ($policyId === '0' || $policyId === 0) { + $policyId = null; + } + + $clientId = $post['client_id'] ?? null; + if ($clientId === '' || $clientId === '0' || $clientId === 0) { + $clientId = null; + } + + return [ + 'start_date' => !empty($post['start_date']) ? $post['start_date'] : null, + 'end_date' => !empty($post['end_date']) ? $post['end_date'] : null, + 'client_id' => $clientId, + 'client_branch_id'=> $clientBranchId, + 'policy_id' => $policyId, + 'event_type' => !empty($post['event_type']) ? $post['event_type'] : null, + 'insurer_or_tpa' => !empty($post['insurer_or_tpa']) ? $post['insurer_or_tpa'] : null, + 'action_type' => !empty($post['action_type']) ? $post['action_type'] : null, + 'use_default_date'=> !isset($post['use_default_date']) || (string) $post['use_default_date'] === '1', + ]; + } + + protected function applyDateFilter($builder, array $filters, string $column) + { + if (!empty($filters['start_date']) && !empty($filters['end_date'])) { + $start = change_date_format($filters['start_date'], 'd/m/Y', 'Y-m-d') . ' 00:00:00'; + $end = change_date_format($filters['end_date'], 'd/m/Y', 'Y-m-d') . ' 23:59:59'; + $builder->where($column . ' >=', $start)->where($column . ' <=', $end); + } elseif (!empty($filters['use_default_date'])) { + $builder->where($column . ' >=', date('Y-m-d 00:00:00', strtotime('-90 days'))) + ->where($column . ' <=', date('Y-m-d 23:59:59')); + } + + return $builder; + } + + protected function fileListSelectColumns(): string + { + return ' + files.id, + files.file_name, + files.created_by, + files.created_at, + files.is_active, + files.status, + files.client_id, + files.policy_id, + files.client_branch_id, + files.action, + files.uploaded_by, + up.emp_code, + c.short_name, + cb.branch_name, + cp.id as client_policy_id, + "0" as employee_count, + "0" as total, + policy_type.policy_type, + cp.policy_no, + CASE + WHEN files.hr_id IS NOT NULL THEN + CONCAT( + ( + SELECT lc.name + FROM level_contacts lc + WHERE lc.id = files.hr_id + LIMIT 1 + ), + " (HR)" + ) + ELSE up.first_name + END AS first_name + '; + } + + protected function buildFileListQuery(array $filters, string $search = '') + { + $db = \Config\Database::connect(); + $builder = $db->table('files'); + $builder + ->join('user_profiles up', 'files.created_by = up.id', 'left') + ->join('client_policy cp', 'files.policy_id = cp.id', 'left') + ->join('client_branch cb', 'files.client_branch_id = cb.id', 'left') + ->join('policy_type', 'policy_type.id = cp.policy_type_id') + ->join('clients c', 'files.client_id = c.id and files.client_id = cp.client_id', 'left') + ->join('client_rm cr', 'cr.client_id = c.id and cr.is_active = 1', 'left') + ->where('files.is_active', 1); + + $this->applyDateFilter($builder, $filters, 'files.created_at'); + + if (!empty($filters['client_id'])) { + $builder->where('files.client_id', $filters['client_id']); + } + if (!empty($filters['client_branch_id'])) { + $builder->where('files.client_branch_id', $filters['client_branch_id']); + } + if (!empty($filters['policy_id'])) { + $builder->where('files.policy_id', $filters['policy_id']); + } + if (!empty($filters['event_type'])) { + $builder->where('files.action', $filters['event_type']); + } + + $roleId = (int) get_role_id(); + if (in_array($roleId, [2, 3], true)) { + $builder->where('cr.user_id', (int) get_session_userid()); + } + + if ($search !== '') { + $builder->groupStart() + ->like('files.file_name', $search) + ->orLike('c.short_name', $search) + ->orLike('cb.branch_name', $search) + ->orLike('cp.policy_no', $search) + ->orLike('policy_type.policy_type', $search) + ->orLike('files.action', $search) + ->orLike('files.status', $search) + ->orLike('up.first_name', $search) + ->groupEnd(); + } + + return $builder; + } + + protected function formatFileListRowForDataTable(array $file, int $serialNo): array + { + $fileName = htmlspecialchars((string) ($file['file_name'] ?? ''), ENT_QUOTES, 'UTF-8'); + $policyDisplay = trim(($file['policy_type'] ?? '') . ' - ' . ($file['policy_no'] ?? '')); + $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i a') + . ' by ' . htmlspecialchars((string) ($file['first_name'] ?? ''), ENT_QUOTES, 'UTF-8') . ''; + + $status = (string) ($file['status'] ?? ''); + $action = (string) ($file['action'] ?? ''); + if ($status === 'failed') { + $statusHtml = $status . " "; + } elseif ($status === 'inprogress') { + if (in_array($action, ['inception', 'addition', 'dependent_addtion'], true)) { + $toolTip = 'Live(s) : ' . ($file['employee_count'] ?? '0') + . ' | Total premium : ₹ ' . format_indian_number($file['total'] ?? 0) + . ' | Click to reload'; + $statusHtml = '' . htmlspecialchars($status, ENT_QUOTES, 'UTF-8') . ''; + } else { + $statusHtml = '' . htmlspecialchars($status, ENT_QUOTES, 'UTF-8') . ''; + } + } elseif ($status === 'success') { + if (in_array($action, ['inception', 'addition', 'dependent_addtion'], true)) { + $toolTip = 'Live(s) : ' . ($file['employee_count'] ?? '0') + . ' | Total premium : ₹ ' . format_indian_number($file['total'] ?? 0); + $statusHtml = '' . htmlspecialchars($status, ENT_QUOTES, 'UTF-8') . ''; + } else { + $statusHtml = '' . htmlspecialchars($status, ENT_QUOTES, 'UTF-8') . ''; + } + } else { + $statusHtml = '' . htmlspecialchars($status, ENT_QUOTES, 'UTF-8') . ''; + } + + $reuploadPayload = htmlspecialchars(json_encode([ + 'client_id' => $file['client_id'] ?? null, + 'client_policy_id' => $file['client_policy_id'] ?? null, + 'client_branch_id' => $file['client_branch_id'] ?? null, + 'action' => $file['action'] ?? null, + ]), ENT_QUOTES, 'UTF-8'); + + $actionHtml = ''; + + return [ + 0 => '' . $serialNo . '', + 1 => '' . $fileName . '', + 2 => htmlspecialchars((string) ($file['short_name'] ?? ''), ENT_QUOTES, 'UTF-8'), + 3 => htmlspecialchars((string) ($file['branch_name'] ?? ''), ENT_QUOTES, 'UTF-8'), + 4 => htmlspecialchars($policyDisplay, ENT_QUOTES, 'UTF-8'), + 5 => htmlspecialchars($action, ENT_QUOTES, 'UTF-8'), + 6 => $userTime, + 7 => $statusHtml, + 8 => $actionHtml, + ]; + } + + protected function batchListSelectColumns(): string + { + return " + batch_files.id, + batch_files.client_id, + batch_files.client_policy_id, + batch_files.batch_code, + batch_files.file_name, + batch_files.insurer_or_tpa, + batch_files.event_type, + batch_files.actions, + batch_files.count, + batch_files.created_by, + batch_files.created_at, + batch_files.updated_by, + batch_files.updated_at, + batch_files.is_active, + batch_files.amount, + batch_files.status, + batch_files.icici_status_flag, + batch_files.client_branch_id, + insurers.short_name as insurer_short_name, + tpa.short_name as tpa_short_name, + DATE_FORMAT(batch_files.policy_issue_date, '%d/%m/%Y') AS policy_issue_date, + CASE + WHEN batch_files.status IN ('partially success', 'in-progress-partially', 'failed-7') + THEN batch_files.error_data + ELSE NULL + END AS error_data, + clients.short_name as client_short_name, + client_branch.branch_name, + client_policy.policy_no, + policy_type.policy_type + "; + } + + protected function buildBatchListQuery(array $filters, string $search = '') + { + $db = \Config\Database::connect(); + $builder = $db->table('batch_files'); + $builder + ->join('client_policy', 'client_policy.id = batch_files.client_policy_id') + ->join('insurers', 'client_policy.insurer_id = insurers.id') + ->join('tpa', 'client_policy.tpa_id = tpa.id', 'left') + ->join('client_branch', 'client_branch.id = batch_files.client_branch_id') + ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') + ->join('clients', 'clients.id = client_policy.client_id') + ->join('client_rm cr', 'cr.client_id = clients.id and cr.is_active = 1', 'left') + ->where('batch_files.is_active', 1); + + $this->applyDateFilter($builder, $filters, 'batch_files.created_at'); + + if (!empty($filters['client_id'])) { + $builder->where('batch_files.client_id', $filters['client_id']); + } + if (!empty($filters['client_branch_id'])) { + $builder->where('batch_files.client_branch_id', $filters['client_branch_id']); + } + if (!empty($filters['policy_id'])) { + $builder->where('batch_files.client_policy_id', $filters['policy_id']); + } + if (!empty($filters['event_type'])) { + $builder->where('batch_files.event_type', $filters['event_type']); + } + if (!empty($filters['insurer_or_tpa'])) { + $builder->where('batch_files.insurer_or_tpa', $filters['insurer_or_tpa']); + } + if (!empty($filters['action_type'])) { + $builder->where('batch_files.actions', $filters['action_type']); + } + + $roleId = (int) get_role_id(); + if (in_array($roleId, [2, 3], true)) { + $builder->where('cr.user_id', (int) get_session_userid()); + } + + if ($search !== '') { + $builder->groupStart() + ->like('batch_files.batch_code', $search) + ->orLike('batch_files.file_name', $search) + ->orLike('clients.short_name', $search) + ->orLike('client_branch.branch_name', $search) + ->orLike('client_policy.policy_no', $search) + ->orLike('policy_type.policy_type', $search) + ->orLike('batch_files.event_type', $search) + ->orLike('batch_files.insurer_or_tpa', $search) + ->orLike('batch_files.actions', $search) + ->orLike('batch_files.status', $search) + ->groupEnd(); + } + + return $builder; + } + + protected function formatBatchListRowForDataTable(array $file, int $serialNo, array $insurerOrTpa, array $importOrExport): array + { + $fileName = htmlspecialchars((string) ($file['file_name'] ?? ''), ENT_QUOTES, 'UTF-8'); + $policyDisplay = trim(($file['policy_type'] ?? '') . ' - ' . ($file['policy_no'] ?? '')); + $insLabel = $insurerOrTpa[$file['insurer_or_tpa'] ?? ''] ?? ''; + $insurerOrTpaDisplay = ($insLabel === 'TPA') + ? ($file['tpa_short_name'] ?? '') + : ($file['insurer_short_name'] ?? ''); + + $insurerCell = htmlspecialchars($insLabel, ENT_QUOTES, 'UTF-8') + . ' '; + + $actKey = $file['actions'] ?? ''; + $actLabel = $importOrExport[$actKey] ?? ucfirst((string) $actKey); + $actionCell = htmlspecialchars((string) $actLabel, ENT_QUOTES, 'UTF-8'); + if ($actKey === 'push') { + $tooltipText = $insurerOrTpaDisplay . ' TPA Push Status: ' . ($file['icici_status_flag'] ?? 'N/A') + . "\n\n\nNote: TPA ID can be fetched only after the TPA push status is completed."; + $actionCell .= ' '; + } + + $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i a') + . ' by ' . get_username($file['created_by'] ?? ''); + + $status = (string) ($file['status'] ?? ''); + $statusHtml = htmlspecialchars($status, ENT_QUOTES, 'UTF-8'); + if ($status === 'failed') { + $statusHtml = htmlspecialchars($status, ENT_QUOTES, 'UTF-8') + . '  '; + } elseif ($status === 'partially success') { + $statusHtml = htmlspecialchars($status, ENT_QUOTES, 'UTF-8'); + if (!empty($file['error_data']) && (string) $file['error_data'] !== '0') { + $statusHtml .= '  '; + } + } elseif ($status === 'in-progress-partially') { + $statusHtml = htmlspecialchars($status, ENT_QUOTES, 'UTF-8'); + if (!empty($file['error_data']) && function_exists('is_json_string') && !is_json_string($file['error_data'])) { + $statusHtml .= '  '; + } + } elseif ($status === 'failed-1') { + $title = ($file['event_type'] ?? '') === 'inception' + ? 'The list of employees provided has already been updated with the TPA ID.' + : 'The list of employees provided has already been updated with the ENDORSEMENT ID.'; + $statusHtml = 'failed '; + } elseif ($status === 'failed-2') { + $title = ($file['event_type'] ?? '') === 'inception' + ? 'The list of employees provided has already been updated with the UHID.' + : 'The list of employees provided has already been updated with the ENDORSEMENT ID.'; + $statusHtml = 'failed '; + } elseif ($status === 'failed-3') { + $statusHtml = 'failed '; + } elseif ($status === 'failed-4') { + $statusHtml = 'failed '; + } elseif ($status === 'failed-5') { + $statusHtml = 'failed '; + } elseif ($status === 'failed-6') { + $statusHtml = 'failed '; + } elseif ($status === 'failed-7') { + $statusHtml = 'failed '; + } elseif ($status === 'failed-8') { + $statusHtml = 'failed'; + } + + $menuHtml = ''; + + return [ + 0 => '' . $serialNo . '', + 1 => htmlspecialchars((string) ($file['batch_code'] ?? ''), ENT_QUOTES, 'UTF-8'), + 2 => '' . $fileName . '', + 3 => htmlspecialchars((string) ($file['client_short_name'] ?? ''), ENT_QUOTES, 'UTF-8'), + 4 => htmlspecialchars((string) ($file['branch_name'] ?? ''), ENT_QUOTES, 'UTF-8'), + 5 => '' + . htmlspecialchars($policyDisplay, ENT_QUOTES, 'UTF-8') . '', + 6 => htmlspecialchars((string) ($file['event_type'] ?? ''), ENT_QUOTES, 'UTF-8'), + 7 => $insurerCell, + 8 => $actionCell, + 9 => ($file['count'] === null || $file['count'] === '') ? '-' : htmlspecialchars((string) $file['count'], ENT_QUOTES, 'UTF-8'), + 10 => format_indian_number($file['amount'] ?? 0), + 11 => '' . $userTime . '', + 12 => $statusHtml, + 13 => $menuHtml, + ]; + } + + protected function hrFileListSelectColumns(): string + { + return " + hr_file_upload.id, + hr_file_upload.client_id, + hr_file_upload.client_branch_id, + hr_file_upload.policy_id, + hr_file_upload.policy_no, + hr_file_upload.file_name, + hr_file_upload.file_action, + hr_file_upload.created_at, + hr_file_upload.created_by, + hr_file_upload.status, + c.short_name, + cb.branch_name, + lc.name as first_name + "; + } + + protected function buildHrFileListQuery(array $filters, string $search = '') + { + $db = \Config\Database::connect(); + $builder = $db->table('hr_file_upload'); + $builder + ->join('clients c', 'c.id = hr_file_upload.client_id AND c.is_active = 1', 'left') + ->join('client_branch cb', 'cb.id = hr_file_upload.client_branch_id AND cb.is_active = 1', 'left') + ->join('level_contacts lc', 'lc.id = hr_file_upload.created_by AND lc.contact_type = "client" AND lc.is_active = 1', 'left') + ->join('client_rm cr', 'cr.client_id = c.id and cr.is_active = 1', 'left'); + + $this->applyDateFilter($builder, $filters, 'hr_file_upload.created_at'); + + if (!empty($filters['client_id'])) { + $builder->where('hr_file_upload.client_id', $filters['client_id']); + } + if (!empty($filters['client_branch_id'])) { + $builder->where('hr_file_upload.client_branch_id', $filters['client_branch_id']); + } + if (!empty($filters['policy_id'])) { + $builder->where('hr_file_upload.policy_id', $filters['policy_id']); + } + if (!empty($filters['event_type'])) { + $builder->where('hr_file_upload.file_action', $filters['event_type']); + } + + $roleId = (int) get_role_id(); + if (in_array($roleId, [2, 3], true)) { + $builder->where('cr.user_id', (int) get_session_userid()); + } + + if ($search !== '') { + $builder->groupStart() + ->like('hr_file_upload.file_name', $search) + ->orLike('c.short_name', $search) + ->orLike('cb.branch_name', $search) + ->orLike('hr_file_upload.policy_no', $search) + ->orLike('hr_file_upload.file_action', $search) + ->orLike('hr_file_upload.status', $search) + ->orLike('lc.name', $search) + ->groupEnd(); + } + + return $builder; + } + + protected function formatHrFileListRowForDataTable(array $file, int $serialNo): array + { + $fileName = htmlspecialchars((string) ($file['file_name'] ?? ''), ENT_QUOTES, 'UTF-8'); + $fileAction = (string) ($file['file_action'] ?? ''); + $fileActionLabel = ucwords(str_replace('_', ' ', strtolower($fileAction))); + $createdAt = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i A'); + $userTime = htmlspecialchars((string) $createdAt, ENT_QUOTES, 'UTF-8') + . ' by ' . htmlspecialchars((string) ($file['first_name'] ?? ''), ENT_QUOTES, 'UTF-8') . ''; + + $baseUrl = rtrim(base_url(), '/'); + $actionHtml = ''; + + return [ + 0 => '' . $serialNo . '', + 1 => '' . $fileName . '', + 2 => htmlspecialchars((string) ($file['short_name'] ?? ''), ENT_QUOTES, 'UTF-8'), + 3 => htmlspecialchars((string) ($file['branch_name'] ?? ''), ENT_QUOTES, 'UTF-8'), + 4 => htmlspecialchars((string) ($file['policy_no'] ?? ''), ENT_QUOTES, 'UTF-8'), + 5 => htmlspecialchars($fileActionLabel, ENT_QUOTES, 'UTF-8'), + 6 => $userTime, + 7 => htmlspecialchars((string) ($file['status'] ?? ''), ENT_QUOTES, 'UTF-8'), + 8 => $actionHtml, + ]; + } + } diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 8743c94e..580bb88c 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -7377,14 +7377,14 @@ class EmployeeRestController extends AdminController 'disclaimer' => $policy['disclaimer'], 'sum_insured_label' => $ticketMeta['sum_insured_label'], 'claim_subject' => $ticketMeta['claim_subject'], + 'terms_and_conditions' => [ + 'raw' => $termsArray, + 'display' => $displayTerms, + ], + 'premium_details' => $premiumDetails, + 'claim_details' => $claimDetails, + 'emp_details' => $empDetails, ], - 'terms_and_conditions' => [ - 'raw' => $termsArray, - 'display' => $displayTerms, - ], - 'premium_details' => $premiumDetails, - 'claim_details' => $claimDetails, - 'emp_details' => $empDetails, ]; } diff --git a/app/Views/batch_list.php b/app/Views/batch_list.php index 61d395e7..54da39b8 100755 --- a/app/Views/batch_list.php +++ b/app/Views/batch_list.php @@ -9,40 +9,17 @@ $batch_col_max_len = array_fill(0, $batch_col_count, 0); for ($i = 0; $i < $batch_col_count; $i++) { $batch_col_max_len[$i] = mb_strlen($batch_header_labels[$i]); } +$batch_col_max_len[1] = max($batch_col_max_len[1], 14); +$batch_col_max_len[2] = max($batch_col_max_len[2], 36); +$batch_col_max_len[3] = max($batch_col_max_len[3], 12); +$batch_col_max_len[4] = max($batch_col_max_len[4], 14); +$batch_col_max_len[5] = max($batch_col_max_len[5], 22); +$batch_col_max_len[6] = max($batch_col_max_len[6], 12); +$batch_col_max_len[11] = max($batch_col_max_len[11], 28); +$batch_col_max_len[12] = max($batch_col_max_len[12], 16); $insurer_or_tpa = $insurer_or_tpa ?? []; $import_or_export = $import_or_export ?? []; -if (!empty($batch_list) && is_array($batch_list)) { - foreach ($batch_list as $key => $file) { - $batch_col_max_len[0] = max($batch_col_max_len[0], mb_strlen((string) ($key + 1))); - $batch_col_max_len[1] = max($batch_col_max_len[1], mb_strlen((string) ($file['batch_code'] ?? ''))); - $batch_col_max_len[2] = max($batch_col_max_len[2], mb_strlen((string) ($file['file_name'] ?? ''))); - $batch_col_max_len[3] = max($batch_col_max_len[3], mb_strlen((string) ($file['client_short_name'] ?? ''))); - $batch_col_max_len[4] = max($batch_col_max_len[4], mb_strlen((string) ($file['branch_name'] ?? ''))); - $policy_display_len = trim( - (isset($file['policy_type']) ? $file['policy_type'] : '') - . ' - ' - . (isset($file['policy_no']) ? $file['policy_no'] : '') - ); - $batch_col_max_len[5] = max($batch_col_max_len[5], mb_strlen($policy_display_len)); - $batch_col_max_len[6] = max($batch_col_max_len[6], mb_strlen((string) ($file['event_type'] ?? ''))); - $insLabel = $insurer_or_tpa[$file['insurer_or_tpa'] ?? ''] ?? ''; - $batch_col_max_len[7] = max($batch_col_max_len[7], mb_strlen((string) $insLabel)); - $actKey = $file['actions'] ?? ''; - $actLabel = $import_or_export[$actKey] ?? ucfirst((string) $actKey); - $batch_col_max_len[8] = max($batch_col_max_len[8], mb_strlen((string) $actLabel)); - $countStr = ($file['count'] ?? null) === null ? '-' : (string) $file['count']; - $batch_col_max_len[9] = max($batch_col_max_len[9], mb_strlen($countStr)); - $batch_col_max_len[10] = max($batch_col_max_len[10], mb_strlen((string) format_indian_number($file['amount']))); - $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i a') - . ' by ' - . get_username($file['created_by'] ?? ''); - $batch_col_max_len[11] = max($batch_col_max_len[11], mb_strlen($userTime)); - $batch_col_max_len[12] = max($batch_col_max_len[12], mb_strlen((string) ($file['status'] ?? ''))); - $batch_col_max_len[13] = max($batch_col_max_len[13], 2); - } -} - $batch_col_min_px = [48, 72, 100, 72, 80, 120, 88, 96, 72, 56, 80, 160, 96, 52]; $batch_col_max_px = [64, 220, 480, 240, 240, 640, 200, 200, 140, 110, 160, 560, 320, 64]; $batch_col_width_px = []; @@ -292,190 +269,6 @@ for ($i = 0; $i < $batch_col_count; $i++) { - $file) { - ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - by - - - - - - - - -   - - - - - - - - -   - - - - - - - - -   - - - - - failed - - - - - failed - - - - failed - - - - failed - - - - failed - - - - failed - - - - failed - - - - failed - - - - - - - - - - - - - -
@@ -949,6 +742,25 @@ for ($i = 0; $i < $batch_col_count; $i++) { $.extend($.fn.dataTable.defaults, { scrollX: false, scrollY: false, scrollCollapse: false }); const batchListTable = $('#batch-list-table').DataTable({ + processing: true, + serverSide: true, + deferRender: true, + searchDelay: 400, + pageLength: 10, + columns: (function() { + var cols = []; + for (var i = 0; i < ; i++) { + cols.push({ data: String(i), orderable: false }); + } + return cols; + })(), + ajax: { + url: '', + type: 'POST', + data: function(d) { + return $.extend({}, d, window.uploadListFilters || {}); + } + }, 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>>", @@ -1017,9 +829,15 @@ for ($i = 0; $i < $batch_col_count; $i++) { }, autoWidth: false, paging: true, - responsive: false + ordering: false, + responsive: false, + drawCallback: function() { + $('[data-toggle="tooltip"]').tooltip({ container: 'body' }); + } }); + window.batchListTableInstance = batchListTable; + $.extend($.fn.dataTable.defaults, _dtDefScroll); // Keep TH and TD widths in sync after any table redraw (search/sort/paginate). diff --git a/app/Views/file_list.php b/app/Views/file_list.php index ccee91c9..69f674d3 100755 --- a/app/Views/file_list.php +++ b/app/Views/file_list.php @@ -9,32 +9,14 @@ $fl_col_max_len = array_fill(0, $fl_col_count, 0); for ($i = 0; $i < $fl_col_count; $i++) { $fl_col_max_len[$i] = mb_strlen($fl_header_labels[$i]); } -$fileList = $fileList ?? []; -if (!empty($fileList) && is_array($fileList)) { - foreach ($fileList as $key => $file) { - $fl_col_max_len[0] = max($fl_col_max_len[0], mb_strlen((string) ($key + 1))); - $fl_col_max_len[1] = max($fl_col_max_len[1], mb_strlen((string) ($file['file_name'] ?? ''))); - $fl_col_max_len[2] = max($fl_col_max_len[2], mb_strlen((string) ($file['short_name'] ?? ''))); - $fl_col_max_len[3] = max($fl_col_max_len[3], mb_strlen((string) ($file['branch_name'] ?? ''))); - $policy_display = trim( - (isset($file['policy_type']) ? $file['policy_type'] : '') - . ' - ' - . (isset($file['policy_no']) ? $file['policy_no'] : '') - ); - $fl_col_max_len[4] = max($fl_col_max_len[4], mb_strlen($policy_display)); - $fl_col_max_len[5] = max($fl_col_max_len[5], mb_strlen((string) ($file['action'] ?? ''))); - $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i a') - . ' by ' - . ($file['first_name'] ?? ''); - $fl_col_max_len[6] = max($fl_col_max_len[6], mb_strlen($userTime)); - $st = (string) ($file['status'] ?? ''); - $fl_col_max_len[7] = max($fl_col_max_len[7], mb_strlen($st)); - if ($st === 'inprogress' || $st === 'success') { - $fl_col_max_len[7] = max($fl_col_max_len[7], 12); - } - $fl_col_max_len[8] = max($fl_col_max_len[8], 4); - } -} +// Prefer readable defaults for server-side pages (row lengths unknown at render). +$fl_col_max_len[1] = max($fl_col_max_len[1], 28); +$fl_col_max_len[2] = max($fl_col_max_len[2], 12); +$fl_col_max_len[3] = max($fl_col_max_len[3], 14); +$fl_col_max_len[4] = max($fl_col_max_len[4], 22); +$fl_col_max_len[5] = max($fl_col_max_len[5], 14); +$fl_col_max_len[6] = max($fl_col_max_len[6], 28); +$fl_col_max_len[7] = max($fl_col_max_len[7], 12); $fl_col_min_px = [48, 100, 72, 80, 120, 88, 160, 96, 72]; $fl_col_max_px = [64, 320, 180, 180, 360, 160, 320, 200, 88]; $fl_col_width_px = nhance_dt_column_widths_px($fl_header_labels, $fl_col_max_len, $fl_col_min_px, $fl_col_max_px); @@ -117,11 +99,24 @@ $fl_col_width_px = nhance_dt_column_widths_px($fl_header_labels, $fl_col_max_len #file-list-table_wrapper .datatable-clear-icon{ right: 11px !important; } -#file-list-page .card-body > .table-responsive { + +/* + * One horizontal scrollbar (same as batch_list): + * - No .dataTables_scrollBody → outer .table-responsive scrolls wide columns. + * - With .dataTables_scrollBody → outer stays visible (custom.css / nh-dt-no-outer-scroll); + * only the inner DT strip scrolls. Do not force overflow-x:auto on the outer wrapper + * or you get a second scrollbar under the pagination row. + */ +#file-list-page .card-body > .table-responsive:not(:has(.dataTables_scrollBody)) { overflow-x: auto !important; -webkit-overflow-scrolling: touch; max-width: 100%; } +#file-list-page .card-body > .table-responsive:has(.dataTables_scrollBody) { + overflow-x: visible !important; + -webkit-overflow-scrolling: auto; + max-width: 100%; +}