From f1a4d26386549ab0d3db5c489365e9f52e63381b Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Wed, 11 Mar 2026 17:08:28 +0530 Subject: [PATCH 1/8] CHANGE_CLAIMSICKET_TYPE_BASED_ON_POLICY_TYPE --- app/Config/Routes.php | 2 + app/Controllers/EmployeeRestController.php | 60 ++++++- app/Controllers/TestingController.php | 184 +++++++++++++++++++++ app/Controllers/TicketController.php | 8 +- app/Models/TicketMasterModel.php | 1 + app/Views/ticket_history.php | 2 +- 6 files changed, 249 insertions(+), 8 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index cf17885b..b9988f4a 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -449,6 +449,8 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { $routes->post('insufficientCdBalanceHrMailSend', 'EmployeeController::insufficientCdBalanceHrMailSend'); $routes->get('getTpaClaimDumpErrorData/(:any)', 'TicketServiceController::getTpaClaimDumpErrorData/$1'); $routes->get('croneDailyActivityReport', 'DashboardController::croneDailyActivityReport'); + $routes->get('insertSampleTpaApiData/(:any)', 'TestingController::insertSampleTpaApiData/$1'); + $routes->get('listEmployeeCountByClientPolicy', 'TestingController::listEmployeeCountByClientPolicy'); }); $routes->post("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail"); diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index df5dcfab..8d160ef5 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -2404,6 +2404,9 @@ class EmployeeRestController extends AdminController if ($this->request->is('get')) { + $client_id = $this->request->getGet('client_id') ?? null; + + $data['claim_status'] = $this->claimStatusModel ->select('id,ticket_type, display_name as claim_status') ->where('is_active', 1) @@ -2411,12 +2414,57 @@ class EmployeeRestController extends AdminController ->groupBy('display_name') ->findAll(); - $data['ticket_type'] = [ - ["ticket_type" => "1", "type_name" => "Claim-GMC"], - ["ticket_type" => "2", "type_name" => "Claim-GPA"], - ["ticket_type" => "3", "type_name" => "EDLI"], - ["ticket_type" => "4", "type_name" => "GTLI"], - ]; + if (!empty($client_id)) { + + if (is_string($client_id) && preg_match('/^[a-f0-9]{32}$/i', $client_id)) { + $client_data = $this->clientModel->where('MD5(id)', $client_id)->first(); + $client_id = $client_data['id'] ?? null; + } + + $client_data = $this->clientPolicyModel + ->where('client_id', $client_id) + ->where('is_active', 1) + ->groupBy('policy_type_id') + ->findAll(); + + $data['ticket_type'] = []; + $addedTypes = []; + + foreach ($client_data as $value) { + + if (in_array($value['policy_type_id'], [2,3,4,5]) && !in_array('1', $addedTypes)) { + $data['ticket_type'][] = ["ticket_type" => "1", "type_name" => "Claim-GMC"]; + $addedTypes[] = '1'; + + } elseif (in_array($value['policy_type_id'], [1]) && !in_array('2', $addedTypes)) { + $data['ticket_type'][] = ["ticket_type" => "2", "type_name" => "Claim-GPA"]; + $addedTypes[] = '2'; + + } elseif (in_array($value['policy_type_id'], [6]) && !in_array('3', $addedTypes)) { + $data['ticket_type'][] = ["ticket_type" => "3", "type_name" => "EDLI"]; + $addedTypes[] = '3'; + + } elseif (in_array($value['policy_type_id'], [7]) && !in_array('4', $addedTypes)) { + $data['ticket_type'][] = ["ticket_type" => "4", "type_name" => "GTLI"]; + $addedTypes[] = '4'; + + } elseif (in_array($value['policy_type_id'], [72]) && !in_array('72', $addedTypes)) { + $data['ticket_type'][] = ["ticket_type" => "72", "type_name" => "OPD"]; + $addedTypes[] = '72'; + } + } + + usort($data['ticket_type'], fn($a,$b) => $a['ticket_type'] <=> $b['ticket_type']); + + } else { + + $data['ticket_type'] = [ + ["ticket_type" => "1", "type_name" => "Claim-GMC"], + ["ticket_type" => "2", "type_name" => "Claim-GPA"], + ["ticket_type" => "3", "type_name" => "EDLI"], + ["ticket_type" => "4", "type_name" => "GTLI"], + ]; + } $claim_type = $this->ticketController->claimType; unset($claim_type[1][2]); diff --git a/app/Controllers/TestingController.php b/app/Controllers/TestingController.php index c83fe172..dce9636c 100644 --- a/app/Controllers/TestingController.php +++ b/app/Controllers/TestingController.php @@ -5,8 +5,11 @@ namespace App\Controllers; use App\Controllers\BaseController; use App\Models\EmployeePolicyModel; use App\Models\ClientPolicyModel; +use App\Models\TpaApiDataModel; +use App\Models\BatchFileModel; use App\Models\InsurerBranchModel; use App\Models\RFQModel; +use App\Models\EmployeeModel; use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\API\ResponseTrait; use Dompdf\Dompdf; @@ -1120,4 +1123,185 @@ class TestingController extends BaseController 'metabaseUrl' => 'https://nsights.nhanceindia.in', ]); } + + /** + * Insert sample data into tpa_api_data for testing variance report (Not in NHANCE, Not in TPA, Need to Review). + * Uses client_policy (policy_status=1, is_active=1), employee_policies (active), and employees. + * + * @param int|null $client_policy_id Optional. If not provided, first eligible policy is used. + * @return \CodeIgniter\HTTP\ResponseInterface + */ + public function insertSampleTpaApiData($client_policy_id = null) + { + $db = \Config\Database::connect(); + $clientPolicyModel = new ClientPolicyModel(); + $employeePolicyModel = new EmployeePolicyModel(); + $employeeModel = new EmployeeModel(); + $tpaApiDataModel = new TpaApiDataModel(); + $batchFileModel = new BatchFileModel(); + + // 1. Get policies: policy_status = 1, is_active = 1 + $policyBuilder = $clientPolicyModel + ->where('policy_status', 1) + ->where('is_active', 1); + if ($client_policy_id !== null && $client_policy_id !== '') { + $policyBuilder->where('id', (int) $client_policy_id); + } + $policies = $policyBuilder->orderBy('id', 'ASC')->findAll(); + if (empty($policies)) { + return $this->respond([ + 'status' => false, + 'message' => 'No active client policy found (policy_status=1, is_active=1).', + 'data' => [], + ], 400); + } + $policy = $policies[0]; + $client_policy_id = (int) $policy['id']; + $client_id = (int) $policy['client_id']; + $client_branch_id = !empty($policy['client_branch_id']) ? (int) $policy['client_branch_id'] : 0; + + // 2. Get related employees from employee_policies (active) + employees + $empPolicies = $db->table('employee_polices ep') + ->select('ep.id AS emp_policy_id, ep.employee_id, ep.tpa_id, e.emp_code, e.name, e.dob, e.gender, e.relationship') + ->join('employees e', 'e.id = ep.employee_id') + ->where('ep.client_policy_id', $client_policy_id) + ->where('ep.is_active', 1) + ->whereIn('ep.status', ['active', 'expired']) + ->where('e.is_active', 1) + ->get() + ->getResultArray(); + if (empty($empPolicies)) { + return $this->respond([ + 'status' => false, + 'message' => 'No active employee policies found for this client policy.', + 'data' => ['client_policy_id' => $client_policy_id], + ], 400); + } + + // 3. Create a test batch file so we have a file_id for tpa_api_data + $createdBy = function_exists('get_session_userid') ? get_session_userid() : 1; + $batchCode = 'TPA_SAMPLE_' . date('YmdHis') . '_' . bin2hex(random_bytes(4)); + $batchFileId = $batchFileModel->insert([ + 'client_id' => $client_id, + 'client_policy_id' => $client_policy_id, + 'client_branch_id' => $client_branch_id, + 'batch_code' => $batchCode, + 'file_name' => 'sample_tpa_data_test_' . date('Y-m-d_His') . '.xlsx', + 'insurer_or_tpa' => 'tpa', + 'event_type' => 'api', + 'actions' => 'fetch', + 'status' => 'partially success', + 'count' => 0, + 'created_by' => $createdBy, + 'is_active' => 1, + ]); + if (!$batchFileId) { + return $this->respond([ + 'status' => false, + 'message' => 'Failed to create test batch file.', + 'data' => [], + ], 500); + } + $file_id = (int) $batchFileId; + + $tpaApiDataModel->skipValidation(true); + $inserted = ['not_in_nhance' => 0, 'need_to_review' => 0]; + $toInsert = []; + + // 4. Not in NHANCE: insert TPA records with emp_codes that do NOT exist in NHANCE for this policy + $fakeEmpCodes = ['TPA_SAMPLE_NOTINNHANCE_1', 'TPA_SAMPLE_NOTINNHANCE_2']; + foreach ($fakeEmpCodes as $i => $empCode) { + $toInsert[] = [ + 'file_id' => $file_id, + 'emp_code' => $empCode, + 'name' => 'Sample TPA Only ' . ($i + 1), + 'dob' => '1990-01-' . str_pad((string)(15 + $i), 2, '0', STR_PAD_LEFT), + 'relation' => 'Self', + 'gender' => ($i % 2 === 0) ? 'M' : 'F', + 'self' => 'Sample TPA Only ' . ($i + 1), + 'tpa_id' => 'TPA' . (1000 + $i), + 'age' => 32 + $i, + 'is_active' => 1, + 'desc' => 'Sample data – Not in NHANCE', + 'created_by'=> $createdBy, + ]; + $inserted['not_in_nhance']++; + } + + // 5. Need to Review: same employee as in NHANCE but with different name/dob/gender + $needReview = array_slice($empPolicies, 0, min(2, count($empPolicies))); + foreach ($needReview as $emp) { + $dob = $emp['dob']; + if (is_string($dob) && preg_match('/^(\d{4})-(\d{2})-(\d{2})/', $dob, $m)) { + $altDob = $m[1] . '-' . $m[2] . '-' . str_pad((string)((int)$m[3] + 1), 2, '0', STR_PAD_LEFT); + } else { + $altDob = '1995-06-15'; + } + $toInsert[] = [ + 'file_id' => $file_id, + 'emp_code' => $emp['emp_code'], + 'name' => '[TPA Altered] ' . ($emp['name'] ?? 'Unknown'), + 'dob' => $altDob, + 'relation' => $emp['relationship'] ?? 'Self', + 'gender' => (strtoupper($emp['gender'] ?? 'M') === 'M') ? 'F' : 'M', + 'self' => $emp['name'] ?? 'Unknown', + 'tpa_id' => $emp['tpa_id'] ?? ('T' . $emp['employee_id']), + 'age' => 30, + 'is_active' => 1, + 'desc' => 'Sample data – Need to Review (mismatch)', + 'created_by'=> $createdBy, + ]; + $inserted['need_to_review']++; + } + + foreach ($toInsert as $row) { + $tpaApiDataModel->insert($row); + } + + // Not in TPA: we do NOT insert those into tpa_api_data; NHANCE already has employees. So any employee + // we did not add to tpa_api_data will appear as "Not in TPA". We added only "Need to Review" and + // "Not in NHANCE" rows; the rest of NHANCE employees remain without TPA rows => they show as Not in TPA. + + return $this->respond([ + 'status' => true, + 'message' => 'Sample TPA API data inserted successfully.', + 'data' => [ + 'file_id' => $file_id, + 'client_policy_id' => $client_policy_id, + 'client_id' => $client_id, + 'batch_code' => $batchCode, + 'inserted' => $inserted, + 'not_in_tpa_note' => 'Employees in NHANCE that were not added to TPA data will appear as "Not in TPA" when you run the variance report for this file.', + ], + ], 200); + } + + /** + * List employee count per client policy. + * No input parameters. Checks all client_policy records and counts linked employee_policies per policy. + * + * @return \CodeIgniter\HTTP\ResponseInterface + */ + public function listEmployeeCountByClientPolicy() + { + $db = \Config\Database::connect(); + $rows = $db->table('client_policy cp') + ->select('cp.id AS client_policy_id, COUNT(ep.id) AS employee_policy_count', false) + ->join('employee_polices ep', 'ep.client_policy_id = cp.id', 'left') + ->groupBy('cp.id') + ->orderBy('cp.id', 'ASC') + ->get() + ->getResultArray(); + $list = array_map(function ($row) { + return [ + 'client_policy_id' => (int) $row['client_policy_id'], + 'employee_policy_count' => (int) $row['employee_policy_count'], + ]; + }, $rows); + return $this->respond([ + 'status' => true, + 'message' => 'Employee count per client policy.', + 'data' => $list, + ], 200); + } } diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index 3833e4e0..986579e6 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -1777,8 +1777,12 @@ class TicketController extends BaseController $ticket_id = $this->request->getPost('ticket_master_id'); $old_ticket_data = $this->ticketMasterModel->where('id', $ticket_id)->where('is_active', 1)->first(); $ticket_data['claim_status_id'] = $this->getLastMatchedStatus($ticket_data, $old_ticket_data); + $ticket_data['last_updated_by'] = 'USER'; // print_rr($ticket_data); die; + $this->myLogger->logme('error', "[UPDATE_CLAIM] Ticket Master ID: {data}", ['data' => $ticket_id]); + $this->myLogger->logme('error', "[UPDATE_CLAIM] Old Ticket Data: {data}", ['data' => json_encode($old_ticket_data, JSON_PRETTY_PRINT)]); + $this->myLogger->logme('error', "[UPDATE_CLAIM] New Ticket Data: {data}", ['data' => json_encode($ticket_data, JSON_PRETTY_PRINT)]); if ($ticket_data) { $return_value = $this->ticketMasterModel->where('id', $ticket_id)->set($ticket_data)->update(); @@ -2400,6 +2404,8 @@ class TicketController extends BaseController th.old_value, th.new_value, th.created_at, + th.updated_by, + CONCAT_WS(' ', creator.first_name, creator.last_name) AS modified_by, -- Claim Status old_status.claim_status as old_status_value, @@ -2414,7 +2420,7 @@ class TicketController extends BaseController new_insured_emp.name as new_insured_id_name, ticket_master.ticket_type_id - + FROM ticket_history th diff --git a/app/Models/TicketMasterModel.php b/app/Models/TicketMasterModel.php index 13682edb..d78402b6 100644 --- a/app/Models/TicketMasterModel.php +++ b/app/Models/TicketMasterModel.php @@ -94,6 +94,7 @@ class TicketMasterModel extends Model 'tpa_claim_type', 'tpa_ailments', 'claim_dump_ref_id', + 'last_updated_by', ]; diff --git a/app/Views/ticket_history.php b/app/Views/ticket_history.php index 384a638d..fe1fc222 100644 --- a/app/Views/ticket_history.php +++ b/app/Views/ticket_history.php @@ -20,7 +20,7 @@ '.$row['new_value']; ?> - + From 283dc369dfb538fa152910da0c72689fbb434457 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 12 Mar 2026 11:42:29 +0530 Subject: [PATCH 2/8] FIX_ISSUES --- app/Controllers/EmployeeRestController.php | 6 ++--- app/Controllers/EmployeeServiceController.php | 25 +++++++++++++++++++ .../BaseTpaClaimImportService.php | 3 ++- app/Models/PolicyTransactionModel.php | 23 +++++++++++++---- app/Models/TpaApiDataModel.php | 4 ++- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 8d160ef5..40bbb7f9 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -2421,16 +2421,16 @@ class EmployeeRestController extends AdminController $client_id = $client_data['id'] ?? null; } - $client_data = $this->clientPolicyModel + $client_policy_data = $this->clientPolicyModel ->where('client_id', $client_id) ->where('is_active', 1) ->groupBy('policy_type_id') ->findAll(); - + $data['ticket_type'] = []; $addedTypes = []; - foreach ($client_data as $value) { + foreach ($client_policy_data as $value) { if (in_array($value['policy_type_id'], [2,3,4,5]) && !in_array('1', $addedTypes)) { $data['ticket_type'][] = ["ticket_type" => "1", "type_name" => "Claim-GMC"]; diff --git a/app/Controllers/EmployeeServiceController.php b/app/Controllers/EmployeeServiceController.php index bc4bfa7c..d6fa858f 100755 --- a/app/Controllers/EmployeeServiceController.php +++ b/app/Controllers/EmployeeServiceController.php @@ -2575,4 +2575,29 @@ class EmployeeServiceController extends AdminController return $result; } + + /** + * Returns the inception Excel column configuration used for + * validating and processing Employee Upload with Events files. + * This allows other controllers to generate compatible Excel files. + * + * @return array + */ + public function getInceptionExcelColumns(): array + { + return $this->inception_excel_columns; + } + + /** + * Returns the correction Excel column configuration used for + * validating and processing Employee correction files. + * This is reused by other controllers when they need to generate + * a correction-compatible Excel programmatically. + * + * @return array + */ + public function getCorrectionExcelColumns(): array + { + return $this->correction_excel_columns; + } } \ No newline at end of file diff --git a/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php b/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php index 3ccbcadd..566bb703 100644 --- a/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php +++ b/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php @@ -368,7 +368,8 @@ abstract class BaseTpaClaimImportService return $value; } } - return null; + + return 61; } /** diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php index 20da8dec..514b63d2 100644 --- a/app/Models/PolicyTransactionModel.php +++ b/app/Models/PolicyTransactionModel.php @@ -3785,7 +3785,7 @@ $totalBilled[$key] = ($totalBilled[$key] ?? 0) + (float) ($row['billed_amt'] ?? 0); // Store total_irda_amt once - if (!isset($totalIrdaMap[$key]) && ($row['total_irda_amt'] ?? 0) > 0) { + if (!isset($totalIrdaMap[$key])) { $totalIrdaMap[$key] = (float) $row['total_irda_amt']; } @@ -3802,11 +3802,24 @@ foreach ($result as $row) { $ptId = $row['pt_id'].'-'.$row['insurer_id']; if (!isset($ptSeen[$ptId])) { + + $totalIrdaVal = $totalIrdaMap[$ptId] ?? 0; + $totalBilledVal = $totalBilled[$ptId] ?? 0; + $addMinus = false; + + if($totalIrdaVal < 0){ + $totalIrdaVal = abs($totalIrdaVal); + $totalBilledVal = abs($totalBilledVal); + $addMinus = true; + } + // First entry → set unbilled amount - $row['unbilled_amount'] = round( - (float) (($totalIrdaMap[$ptId] ?? 0) - ($totalBilled[$ptId] ?? 0)), - 2 - ); + $row['unbilled_amount'] = round((float) ($totalIrdaVal - $totalBilledVal),2 ); + + if($addMinus){ + $row['unbilled_amount'] = ($row['unbilled_amount'] * -1); + } + $ptSeen[$ptId] = true; } else { // Other entries → zero diff --git a/app/Models/TpaApiDataModel.php b/app/Models/TpaApiDataModel.php index 50958fac..e63193b3 100644 --- a/app/Models/TpaApiDataModel.php +++ b/app/Models/TpaApiDataModel.php @@ -25,7 +25,9 @@ class TpaApiDataModel extends Model 'age', 'is_active', 'desc', - 'created_by' + 'created_by', + 'si', + 'doj' ]; // protected $useTimestamps = true; From d78343ace301d9221cf05249529d76150d468028 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 12 Mar 2026 12:45:35 +0530 Subject: [PATCH 3/8] CHANGE_THE_ALERT_MESSAGE --- app/Controllers/DashboardController.php | 28 ++++++++++++++++++++++--- app/Models/EmployeePolicyModel.php | 3 ++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/Controllers/DashboardController.php b/app/Controllers/DashboardController.php index b4d224fe..08a2b82a 100755 --- a/app/Controllers/DashboardController.php +++ b/app/Controllers/DashboardController.php @@ -721,21 +721,43 @@ class DashboardController extends AdminController return $this->respond(['status' => false, 'code' => 400, 'message' => 'No template found', 'message2' => 'Failed'], 200); } - $emp_data = $this->employeePolicyModel->getEmployeePolicyForEcard($policy_id); if (count($emp_data) == 0) { return $this->respond(['status' => false, 'code' => 400, 'message' => 'No employees found', 'message2' => 'Failed'], 200); } $ids = array_column($emp_data, 'id'); + + + $client_policy_data = $this->clientPolicyModel->where('id', $policy_id)->first(); + $sendMail = false; + + if ($client_policy_data['policy_type_id'] == 3 && $client_policy_data['is_addon'] == 3) { + $sendMail = true; + } else { + $relationships = array_column($emp_data, 'relationship'); + if (in_array('Self', $relationships)) { + $sendMail = true; + } + } + + if ($sendMail) { + $message = 'Mail Queued'; + Jobs::addJob(['job_name' => 'sendMailForDownloadingECard','payload' => ['ids' => $ids,'client_policy_id' => $policy_id]]); + $this->myLogger->logme('error', 'sendManualEcard - Mail Queued'); + } else { + $message = 'E-card has already been sent to those employees.'; + $this->myLogger->logme('error', 'sendManualEcard - E-card has already been sent to those employees.'); + } + // print_r(($ids)); die; // print_r($this->clientPolicyModel->getLastQuery()); die; // $this->myLogger->logme('error', "Policy details fetched: " . json_encode($client_policy_data)); - Jobs::addJob(['job_name' => 'sendMailForDownloadingECard', 'payload' => ['ids' => $ids, 'client_policy_id' => $policy_id]]); + // Jobs::addJob(['job_name' => 'sendMailForDownloadingECard', 'payload' => ['ids' => $ids, 'client_policy_id' => $policy_id]]); // $empEmpDataServiceController = new EmpDataServiceController(); // $empEmpDataServiceController->sendMailForDownloadingECard($ids); - return $this->respond(['status' => true, 'code' => 200, 'message' => 'Mail Queued'], 200); + return $this->respond(['status' => true, 'code' => 200, 'message' => $message], 200); } public function data_construct_for_bds($data) diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php index 92efedf8..689a4da2 100755 --- a/app/Models/EmployeePolicyModel.php +++ b/app/Models/EmployeePolicyModel.php @@ -374,7 +374,8 @@ class EmployeePolicyModel extends Model public function getEmployeePolicyForEcard($policy_id = 0) { $result = $this->select([ - 'employee_polices.id' + 'employee_polices.id', + 'emp.relationship', ]) ->join('employees emp', 'employee_polices.employee_id = emp.id'); if ($policy_id !=0 && !empty($policy_id)) { From e847af6bcbed6909a870a74ee30e4e0aee54bb28 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 12 Mar 2026 14:48:45 +0530 Subject: [PATCH 4/8] FIX_LIVE_ISSUE_MOTOR_POLICY_UPLOAD_ISSUE --- .../PolicyTransactionController.php | 41 ++++++++++--------- app/Helpers/excel_util_helper.php | 2 + app/Helpers/utility_helper.php | 13 ++++++ 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index c762866e..a272f609 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -5618,17 +5618,18 @@ class PolicyTransactionController extends BaseController $policy_end_date = trim($row[11]); $revenue_type = trim($row[12]); - $base_premium = trim($row[16]); - $non_commission_premium_amount = trim($row[17]); - $tp_premium = trim($row[18]); - $igst = trim($row[19]); - $cgst = trim($row[20]); - $sgst = trim($row[21]); - $stamp_duty = trim($row[22]); + $base_premium = cleanNumber($row[16]); + $non_commission_premium_amount = cleanNumber($row[17]); + $tp_premium = cleanNumber($row[18]); + $igst = cleanNumber($row[19]); + $cgst = cleanNumber($row[20]); + $sgst = cleanNumber($row[21]); + $stamp_duty = cleanNumber($row[22]); + $agreed_amount = cleanNumber($row[23]); + $agreed_bp_percentage = cleanNumber($row[24]); + $agreed_tp_percentage = cleanNumber($row[25]); + // $total = trim($row[23]); - $agreed_amount = trim($row[23]); - $agreed_bp_percentage = trim($row[24]); - $agreed_tp_percentage = trim($row[25]); // $actual_bp_amount = trim($row[27]); // $actual_tp_amount = trim($row[28]); // $actual_bp_percentage = trim($row[29]); @@ -5647,16 +5648,16 @@ class PolicyTransactionController extends BaseController $rewards = 0; $calculation = calculateMotorPolicyAmounts([ - 'base_premium' => trim($row[16]), - 'non_commission_premium_amount' => trim($row[17]), - 'tp_premium' => trim($row[18]), - 'igst' => trim($row[19]), - 'cgst' => trim($row[20]), - 'sgst' => trim($row[21]), - 'stamp_duty' => trim($row[22]), - 'agreed_amount' => trim($row[23]), - 'agreed_bp_percentage' => trim($row[24]), - 'agreed_tp_percentage' => trim($row[25]), + 'base_premium' => $base_premium, + 'non_commission_premium_amount' => $non_commission_premium_amount, + 'tp_premium' => $tp_premium, + 'igst' => $igst, + 'cgst' => $cgst, + 'sgst' => $sgst, + 'stamp_duty' => $stamp_duty, + 'agreed_amount' => $agreed_amount, + 'agreed_bp_percentage' => $agreed_bp_percentage, + 'agreed_tp_percentage' => $agreed_tp_percentage, 'standard_bp_percentage' => 15.00, 'standard_tp_percentage' => 2.5 ]); diff --git a/app/Helpers/excel_util_helper.php b/app/Helpers/excel_util_helper.php index 9419d6e1..f4540849 100755 --- a/app/Helpers/excel_util_helper.php +++ b/app/Helpers/excel_util_helper.php @@ -3072,6 +3072,8 @@ if (!function_exists('validate_mobile_value')) { if (!function_exists('validate_positive_number_value')) { function validate_positive_number_value($value) { + $value = cleanNumber($value); + if ($value === "" || $value === null) { return ['status' => true, 'error' => null]; } diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index c5237bc5..c0657c30 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -1382,3 +1382,16 @@ if (! function_exists('add_google_calender_event')) { } } } + +if (! function_exists('cleanNumber')) { + + function cleanNumber($value){ + if (empty($value)) { + return 0; + } + + $value = str_replace(',', '', trim($value)); + return is_numeric($value) ? (float)$value : 0; + } + +} \ No newline at end of file From 6e8b64b54384590e58deb26eba8bf70eb4936ebf Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 12 Mar 2026 15:03:45 +0530 Subject: [PATCH 5/8] FIX_TPA_API_INTEGRATION_RELATED_ISSUEs --- app/Controllers/EmployeeController.php | 589 ++++++++++++++++++- app/Controllers/FhplApiController.php | 85 +-- app/Controllers/HealthIndiaApiController.php | 89 +-- app/Controllers/MediAssistApiController.php | 299 +++++----- app/Controllers/VidalApiController.php | 154 +++-- app/Views/batch_list.php | 457 +++++++++++++- 6 files changed, 1385 insertions(+), 288 deletions(-) diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index fbff649a..9ad372f8 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -4055,12 +4055,50 @@ class EmployeeController extends AdminController ); } + $tab = $this->request->getGet('tab'); + + // If the user is proceeding from the "Not in Nhance" tab, + // generate an Employee Upload with Events compatible Excel file + // and trigger the usual upload pipeline. + if ($tab === 'not_in_nhance') { + $generationResult = $this->generateEmployeeUploadFromNotInNhance((int) $file_id, $file); + + if (!$generationResult['status']) { + return $this->respond( + [ + 'status' => false, + 'code' => 422, + 'message' => $generationResult['message'] ?? 'Unable to generate employee upload file from Not in Nhance data.', + 'data' => $generationResult['data'] ?? [], + ], + 200 + ); + } + } elseif ($tab === 'need_to_review') { + // For the "Need to Review" tab, generate a Correction Excel + // using the same overall pipeline as the Not in Nhance implementation. + $generationResult = $this->generateCorrectionUploadFromNeedToReview((int) $file_id, $file); + + if (!$generationResult['status']) { + return $this->respond( + [ + 'status' => false, + 'code' => 422, + 'message' => $generationResult['message'] ?? 'Unable to generate correction upload file from Need to Review data.', + 'data' => $generationResult['data'] ?? [], + ], + 200 + ); + } + } + $this->myLogger->logme( 'error', 'TPA variation review completed and proceed to next clicked', [ 'file_id' => $file_id, 'user_id' => get_session_userid(), + 'tab' => $tab, ] ); @@ -4068,7 +4106,11 @@ class EmployeeController extends AdminController [ 'status' => true, 'code' => 200, - 'message' => 'Proceed to next step recorded successfully.', + 'message' => $tab === 'not_in_nhance' + ? 'Employee upload file generated from Not in Nhance data and queued for processing.' + : ($tab === 'need_to_review' + ? 'Correction upload file generated from Need to Review data and queued for processing.' + : 'Proceed to next step recorded successfully.'), 'data' => [], ], 200 @@ -4092,6 +4134,551 @@ class EmployeeController extends AdminController } } + /** + * Generate an Employee Upload with Events compatible Excel file + * from the Not in Nhance TPA variation data and push it into the + * existing employee upload pipeline. + * + * @param int $batchFileId Batch file id used for TPA variation report. + * @param array $batchFile Batch file row from DB. + * + * @return array ['status' => bool, 'message' => string, 'data' => array] + */ + protected function generateEmployeeUploadFromNotInNhance(int $batchFileId, array $batchFile): array + { + try { + $clientId = (int) ($batchFile['client_id'] ?? 0); + $clientPolicyId = (int) ($batchFile['client_policy_id'] ?? 0); + $clientBranchId = (int) ($batchFile['client_branch_id'] ?? 0); + + if (!$clientId || !$clientPolicyId || !$clientBranchId) { + return [ + 'status' => false, + 'message' => 'Incomplete batch file information. Client / policy / branch missing.', + 'data' => [], + ]; + } + + $TpaApiDataModel = new TpaApiDataModel(); + + // Get master emp codes from Nhance for this client & policy + $masterEmpRows = $this->employeePolicyModel->getTPADataVariationReport( + $clientId, + $clientPolicyId, + $batchFileId, + [], + true + ); + if (!is_array($masterEmpRows)) { + $masterEmpRows = []; + } + $masterEmpCodes = array_column($masterEmpRows, 'emp_code'); + + // Fetch Not in Nhance rows for this batch file + $notInNhance = $TpaApiDataModel->select('*') + ->where('is_active', 1) + ->where('file_id', $batchFileId) + ->whereNotIn('emp_code', $masterEmpCodes) + ->findAll(); + + if (empty($notInNhance)) { + return [ + 'status' => false, + 'message' => 'No "Not in Nhance" records found for this file.', + 'data' => [], + ]; + } + + $empServiceController = new EmployeeServiceController(); + $inceptionColumns = $empServiceController->getInceptionExcelColumns(); + + if (empty($inceptionColumns)) { + return [ + 'status' => false, + 'message' => 'Unable to load inception Excel column configuration.', + 'data' => [], + ]; + } + + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setTitle('Employees'); + + // Header row from EmployeeServiceController column definitions + $colIndex = 1; + foreach ($inceptionColumns as $columnDef) { + $headerText = $columnDef['col_name'] ?? ''; + $columnLetter = Coordinate::stringFromColumnIndex($colIndex); + $sheet->setCellValue($columnLetter . '1', $headerText); + $colIndex++; + } + + // Helper to safely format dates as d-M-Y when possible + $formatDate = static function ($value): string { + if (empty($value)) { + return ''; + } + + $ts = strtotime($value); + if ($ts === false) { + return (string) $value; + } + + return date('d-M-Y', $ts); + }; + + // Map Not in Nhance TPA rows into the inception Excel structure + $rowIndex = 2; + $sno = 1; + + foreach ($notInNhance as $tpaRow) { + $colIndex = 1; + + foreach ($inceptionColumns as $key => $columnDef) { + $value = ''; + + switch ($key) { + case 'sno': + $value = $sno; + break; + case 'emp_id': + $value = $tpaRow['emp_code'] ?? ''; + break; + case 'name_of_emp_dep': + $value = $tpaRow['name'] ?? ''; + break; + case 'dob': + $value = $formatDate($tpaRow['dob'] ?? ''); + break; + case 'gender': + $value = $tpaRow['gender'] ?? ''; + break; + case 'relationship': + // Normalize relation text to match allowed values + $relation = (string) ($tpaRow['relation'] ?? ''); + $relation = trim(strtolower($relation)); + $map = [ + 'self' => 'Self', + 'employee' => 'Self', + 'spouse' => 'Spouse', + 'wife' => 'Spouse', + 'husband' => 'Spouse', + 'son' => 'Son', + 'daughter' => 'Daughter', + 'father' => 'Father', + 'mother' => 'Mother', + 'father-in-law' => 'Father in Law', + 'father in law' => 'Father in Law', + 'mother-in-law' => 'Mother in Law', + 'mother in law' => 'Mother in Law', + ]; + $value = $map[$relation] ?? ($tpaRow['relation'] ?? ''); + break; + case 'basic_cover_si': + $value = $tpaRow['si'] ?? ''; + break; + case 'doc': + // Use DOJ from TPA data as Date of Coverage best-effort + $value = $formatDate($tpaRow['doj'] ?? ''); + break; + case 'doj': + $value = $formatDate($tpaRow['doj'] ?? ''); + break; + case 'pre_existing_ailments': + // Default to "0" (No) so validation passes for mandatory field + $value = '0'; + break; + case 'change_event': + // For addition / dependent_addition, this is mandatory. + $value = 'addition'; + break; + default: + // Non-mapped columns (phone, email, etc.) left blank by default. + $value = ''; + break; + } + + $columnLetter = Coordinate::stringFromColumnIndex($colIndex); + $sheet->setCellValue($columnLetter . $rowIndex, $value); + $colIndex++; + } + + $rowIndex++; + $sno++; + } + + // Auto-size columns + $totalColumns = count($inceptionColumns); + for ($c = 1; $c <= $totalColumns; $c++) { + $columnLetter = Coordinate::stringFromColumnIndex($c); + $sheet->getColumnDimension($columnLetter)->setAutoSize(true); + } + + // Persist the Excel file to the same folder used by manual uploads + $fileName = sprintf( + 'not_in_nhance_employee_upload_%d_%s.xlsx', + $batchFileId, + date('Ymd_His') + ); + $filePath = WRITEPATH . 'uploads/excel/' . $fileName; + + $writer = new Xlsx($spreadsheet); + $writer->save($filePath); + + // Create a new entry in the files table so that the + // existing Employee Upload with Events pipeline can process it. + $loggedInUserId = $batchFile['created_by'] ?? get_session_userid(); + $action = 'addition'; + + $newFileId = $this->fileModel->insert([ + 'file_name' => $fileName, + 'client_id' => $clientId, + 'policy_id' => $clientPolicyId, + 'created_by' => $loggedInUserId, + 'status' => 'inprogress', + 'action' => $action, + 'client_branch_id'=> $clientBranchId, + 'uploaded_by' => 1, + 'hr_file_id' => null, + 'hr_id' => null, + ]); + + if (!$newFileId || !is_numeric($newFileId)) { + $this->myLogger->logme( + 'error', + 'Failed to insert generated Not in Nhance employee upload file into files table', + [ + 'batch_file_id' => $batchFileId, + 'client_id' => $clientId, + 'client_policy_id' => $clientPolicyId, + 'client_branch_id' => $clientBranchId, + 'file_name' => $fileName, + 'insert_result' => $newFileId, + ] + ); + + return [ + 'status' => false, + 'message' => 'Unable to create file record for generated employee upload.', + 'data' => [], + ]; + } + + + // Run the same format validation used for manual uploads. + $validationResult = $empServiceController->excelFileFormatValidation(['file_id' => $newFileId]); + + if (isset($validationResult['error_summary']) && count($validationResult['error_summary'])) { + return [ + 'status' => false, + 'message' => 'File upload was successful, but file format validation failed. Please review the error report.', + 'data' => ['file_id' => $newFileId], + ]; + } + + return [ + 'status' => true, + 'message' => 'Employee upload file generated from Not in Nhance data and queued for processing.', + 'data' => ['file_id' => $newFileId], + ]; + } catch (\Throwable $e) { + $this->myLogger->logme( + 'error', + 'Error while generating employee upload from Not in Nhance'. + json_encode( [ + 'batch_file_id' => $batchFileId, + 'exception_message' => $e->getMessage(), + 'exception_file' => $e->getFile(), + 'exception_line' => $e->getLine(), + 'exception_trace' => $e->getTraceAsString(), + 'client_id' => $batchFile['client_id'] ?? null, + 'client_policy_id' => $batchFile['client_policy_id'] ?? null, + 'client_branch_id' => $batchFile['client_branch_id'] ?? null, + ], JSON_PRETTY_PRINT) + ); + + return [ + 'status' => false, + 'message' => 'Unexpected error while generating employee upload file.', + 'data' => [], + ]; + } + } + + /** + * Generate a Correction Excel file from the Need to Review + * TPA variation data and push it into the existing correction + * upload pipeline. + * + * Each mismatched field (name, dob, relationship, email_corporate) + * becomes a separate row in the Excel, using the correction + * headers defined in EmployeeServiceController::$correction_excel_columns. + * + * @param int $batchFileId Batch file id used for TPA variation report. + * @param array $batchFile Batch file row from DB. + * + * @return array ['status' => bool, 'message' => string, 'data' => array] + */ + protected function generateCorrectionUploadFromNeedToReview(int $batchFileId, array $batchFile): array + { + try { + $clientId = (int) ($batchFile['client_id'] ?? 0); + $clientPolicyId = (int) ($batchFile['client_policy_id'] ?? 0); + $clientBranchId = (int) ($batchFile['client_branch_id'] ?? 0); + + if (!$clientId || !$clientPolicyId || !$clientBranchId) { + return [ + 'status' => false, + 'message' => 'Incomplete batch file information. Client / policy / branch missing.', + 'data' => [], + ]; + } + + $TpaApiDataModel = new TpaApiDataModel(); + + // Reuse the same DB + TPA reconciliation used in getTPADataVariationReport + $dbRows = $this->employeePolicyModel->getTPADataVariationReport( + $clientId, + $clientPolicyId, + $batchFileId + ); + + if (!is_array($dbRows) || !count($dbRows)) { + return [ + 'status' => false, + 'message' => 'No employee data found for Need to Review.', + 'data' => [], + ]; + } + + $mismatchRows = []; + + foreach ($dbRows as $dbRow) { + $tpaRows = $TpaApiDataModel->select('*') + ->where('emp_code', $dbRow['emp_code']) + ->where('file_id', $batchFileId) + ->where('is_active', 1) + ->findAll(); + + if (!count($tpaRows)) { + continue; + } + + $match = $this->reconcileDbWithTpa($dbRow, $tpaRows); + + if (($match['status'] ?? '') !== 'matched') { + continue; + } + + $tpaRecord = $match['tpa_record'] ?? []; + $notMatching = $match['not_matching'] ?? []; + + if (!is_array($notMatching) || !count($notMatching)) { + continue; + } + + // Only consider fields that are supported by the correction Excel headers + $allowedFields = ['name', 'dob', 'relationship', 'email_corporate']; + + foreach ($notMatching as $field) { + if (!in_array($field, $allowedFields, true)) { + continue; + } + + $mismatchRows[] = [ + 'emp_code' => $dbRow['emp_code'] ?? '', + 'name' => $dbRow['name'] ?? '', + 'field' => $field, + // Use TPA value as the corrected value to be applied in Nhance + 'value' => $tpaRecord[$field] ?? '', + ]; + } + } + + if (!count($mismatchRows)) { + return [ + 'status' => false, + 'message' => 'No mismatched records found to generate correction upload.', + 'data' => [], + ]; + } + + $empServiceController = new EmployeeServiceController(); + $correctionColumns = $empServiceController->getCorrectionExcelColumns(); + + if (empty($correctionColumns)) { + return [ + 'status' => false, + 'message' => 'Unable to load correction Excel column configuration.', + 'data' => [], + ]; + } + + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setTitle('Correction'); + + // Header row from EmployeeServiceController column definitions + $colIndex = 1; + foreach ($correctionColumns as $columnDef) { + $headerText = $columnDef['col_name'] ?? ''; + $columnLetter = Coordinate::stringFromColumnIndex($colIndex); + $sheet->setCellValue($columnLetter . '1', $headerText); + $colIndex++; + } + + $todayDisplay = date('d-M-Y'); + + $rowIndex = 2; + $sno = 1; + + foreach ($mismatchRows as $row) { + $colIndex = 1; + + $field_name = $row['field'] ?? ''; + $field_value = ($field_name == 'dob' ? change_date_format($row['value'] ?? '', 'Y-m-d', 'd-M-Y') : $row['value'] ?? '' ); + + foreach ($correctionColumns as $key => $columnDef) { + $value = ''; + + switch ($key) { + case 'sno': + $value = $sno; + break; + case 'emp_id': + $value = $row['emp_code'] ?? ''; + break; + case 'name_of_emp_dep': + $value = $row['name'] ?? ''; + break; + case 'field': + $value = $field_name; + break; + case 'value': + $value = $field_value ?? ''; + break; + case 'date_of_correction': + $value = $todayDisplay; + break; + case 'change_event': + $value = 'correction'; + break; + case 'remarks': + $value = ''; + break; + default: + $value = ''; + break; + } + + $columnLetter = Coordinate::stringFromColumnIndex($colIndex); + $sheet->setCellValue($columnLetter . $rowIndex, $value); + $colIndex++; + } + + $rowIndex++; + $sno++; + } + + // Auto-size columns + $totalColumns = count($correctionColumns); + for ($c = 1; $c <= $totalColumns; $c++) { + $columnLetter = Coordinate::stringFromColumnIndex($c); + $sheet->getColumnDimension($columnLetter)->setAutoSize(true); + } + + // Persist the Excel file to the same folder used by manual uploads + $fileName = sprintf( + 'need_to_review_correction_upload_%d_%s.xlsx', + $batchFileId, + date('Ymd_His') + ); + $filePath = WRITEPATH . 'uploads/excel/' . $fileName; + + $writer = new Xlsx($spreadsheet); + $writer->save($filePath); + + // Insert into files table so the existing correction pipeline can process it. + $loggedInUserId = $batchFile['created_by'] ?? get_session_userid(); + + $newFileId = $this->fileModel->insert([ + 'file_name' => $fileName, + 'client_id' => $clientId, + 'policy_id' => $clientPolicyId, + 'created_by' => $loggedInUserId, + 'status' => 'inprogress', + 'action' => 'correction', + 'client_branch_id'=> $clientBranchId, + 'uploaded_by' => 1, + 'hr_file_id' => null, + 'hr_id' => null, + ]); + + if (!$newFileId || !is_numeric($newFileId)) { + $this->myLogger->logme( + 'error', + 'Failed to insert generated Need to Review correction upload file into files table', + [ + 'batch_file_id' => $batchFileId, + 'client_id' => $clientId, + 'client_policy_id' => $clientPolicyId, + 'client_branch_id' => $clientBranchId, + 'file_name' => $fileName, + 'insert_result' => $newFileId, + ] + ); + + return [ + 'status' => false, + 'message' => 'Unable to create file record for generated correction upload.', + 'data' => [], + ]; + } + + // Run the same format validation used for manual uploads so that + // the correction file enters the normal processing pipeline. + $validationResult = $empServiceController->excelFileFormatValidation(['file_id' => $newFileId]); + + if (isset($validationResult['error_summary']) && count($validationResult['error_summary'])) { + return [ + 'status' => false, + 'message' => 'File upload was successful, but correction file format validation failed. Please review the error report.', + 'data' => ['file_id' => $newFileId], + ]; + } + + return [ + 'status' => true, + 'message' => 'Correction upload file generated from Need to Review data and queued for processing.', + 'data' => ['file_id' => $newFileId], + ]; + } catch (\Throwable $e) { + $this->myLogger->logme( + 'error', + 'Error while generating correction upload from Need to Review'. + json_encode( + [ + 'batch_file_id' => $batchFileId, + 'exception_message' => $e->getMessage(), + 'exception_file' => $e->getFile(), + 'exception_line' => $e->getLine(), + 'exception_trace' => $e->getTraceAsString(), + 'client_id' => $batchFile['client_id'] ?? null, + 'client_policy_id' => $batchFile['client_policy_id'] ?? null, + 'client_branch_id' => $batchFile['client_branch_id'] ?? null, + ], + JSON_PRETTY_PRINT + ) + ); + + return [ + 'status' => false, + 'message' => 'Unexpected error while generating correction upload file.', + 'data' => [], + ]; + } + } + // not in use once all functionality workes well in this funciton then remvoe this function function compareDbWithTpa(array $db, array $tpaRows): array diff --git a/app/Controllers/FhplApiController.php b/app/Controllers/FhplApiController.php index 8c3e76e1..48df5680 100644 --- a/app/Controllers/FhplApiController.php +++ b/app/Controllers/FhplApiController.php @@ -240,42 +240,57 @@ class FhplApiController extends BaseController } // Extract claim status - $claimData = $response['data'][0]; - $tpa_claim_no = $claimData['CLAIM_ID'] ?? ''; - $currentStatus = $claimData['CLAIM_STATUS'] ?? ''; - $tpa_claim_type = $claimData['CLAIM_TYPE'] ?? ''; - $tpa_ailments = $claimData['AILMENT'] ?? ''; + // $claimData = $response['data'][0]; + $allClaimData = $response['data']; - $validStatuses = [ - "In-Progress" => 5, - "Under Process" => 5, - "Query" => 4, - "Paid" => 11, - "Rejected" => 8, - "Approved" => 8, - "Required Information" => 4, - ]; + $currentStatus = ""; + foreach ($allClaimData as $claimData) { - $updateArray = [ - 'tpa_claim_status' => $currentStatus, - 'updated_at' => date('Y-m-d H:i:s'), - ]; - if (isset($validStatuses[$currentStatus])) { - $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + $tpa_claim_no = $claimData['CLAIM_ID'] ?? ''; + $currentStatus = $claimData['CLAIM_STATUS'] ?? ''; + $tpa_claim_type = $claimData['CLAIM_TYPE'] ?? ''; + $tpa_ailments = $claimData['AILMENT'] ?? ''; + $doa = !empty($claimData['DATE_OF_ADMISSION'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $claimData['DATE_OF_ADMISSION']))) : null; + + + $validStatuses = [ + "In-Progress" => 5, + "Under Process" => 5, + "Query" => 4, + "Paid" => 11, + "Rejected" => 8, + "Approved" => 8, + "Required Information" => 4, + ]; + + $updateArray = [ + 'tpa_claim_status' => $currentStatus, + 'updated_at' => date('Y-m-d H:i:s'), + 'last_updated_by' => 'API', + ]; + if (isset($validStatuses[$currentStatus])) { + $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + } + if (!empty($tpa_claim_type)) { + $updateArray['tpa_claim_type'] = $tpa_claim_type; + } + if (!empty($tpa_ailments)) { + $updateArray['tpa_ailments'] = $tpa_ailments; + } + if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) { + $updateArray['tpa_claim_id'] = $tpa_claim_no; + } + if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) { + $updateArray['claim_number'] = $tpa_claim_no; + } + + if($ticket['doa'] == $doa || $ticket['claim_number'] == $tpa_claim_no){ + $this->db->table('ticket_master')->where('id',$claimId)->update($updateArray); + log_message('error', "FHPL - Claim status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); + }else{ + log_message('error', "FHPL - Claim status NOT UPDATED | TicketID={$claimId} | TicketDOA={$ticket['doa']} | ClaimDOA={$doa} | Status={$currentStatus}"); + } } - if (!empty($tpa_claim_type)) { - $updateArray['tpa_claim_type'] = $tpa_claim_type; - } - if (!empty($tpa_ailments)) { - $updateArray['tpa_ailments'] = $tpa_ailments; - } - - - - $this->db->table('ticket_master')->where('id',$claimId)->update($updateArray); - log_message('error', "FHPL - Claim status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); - - return ['status' => true,'message' => 'Claim status updated.','updated_status' => $currentStatus,'api_response' => $response]; @@ -1022,6 +1037,10 @@ class FhplApiController extends BaseController 'tpa_id' => trim($row['TPA_TPADETAIL_ID'] ?? null), 'age' => is_numeric($row['AGE'] ?? null) ? (int) $row['AGE'] : null, + 'si' => $row['BASE_SUMINSURED'] ?? null, + 'doj' => !empty($row['DATE_OF_JOINING'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['DATE_OF_JOINING']))) : null, + + 'is_active' => 1, 'created_by' => $file_info[0]['created_by'] ?? null, ]; diff --git a/app/Controllers/HealthIndiaApiController.php b/app/Controllers/HealthIndiaApiController.php index 66e6d543..db036d7c 100644 --- a/app/Controllers/HealthIndiaApiController.php +++ b/app/Controllers/HealthIndiaApiController.php @@ -300,45 +300,59 @@ class HealthIndiaApiController extends BaseController } // Extract claim status - $claimData = $response['data']['result'][0]; - $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? ''; - $currentStatus = $claimData['claiM_STATUS'] ?? ''; - $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? ''; - $tpa_ailments = $claimData['ailment'] ?? ''; + // $claimData = $response['data']['result'][0]; + $allClaimData = $response['data']['result']; - $validStatuses = [ - "In-Progress" => 5, - "Under Process" => 5, - "Query" => 4, - "Paid" => 11, - "Rejected" => 8, - "Approved" => 8, - "Required Information" => 4, - "Intimated and File NOT received" => 4, - ]; + $currentStatus = ""; + foreach ($allClaimData as $claimData) { - $updateArray = [ - 'tpa_claim_status' => $currentStatus, - 'tpa_claim_id' => $tpa_claim_no, - 'claim_number' => $tpa_claim_no, - 'updated_at' => date('Y-m-d H:i:s'), - ]; - if (isset($validStatuses[$currentStatus])) { - $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? ''; + $currentStatus = $claimData['claiM_STATUS'] ?? ''; + $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? ''; + $tpa_ailments = $claimData['ailment'] ?? ''; + $doa = !empty($claimData['datE_OF_ADMISSION'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $claimData['datE_OF_ADMISSION']))) : null; + + $validStatuses = [ + "In-Progress" => 5, + "Under Process" => 5, + "Query" => 4, + "Paid" => 11, + "Rejected" => 8, + "Approved" => 8, + "Required Information" => 4, + "Intimated and File NOT received" => 4, + ]; + + $updateArray = [ + 'tpa_claim_status' => $currentStatus, + // 'tpa_claim_id' => $tpa_claim_no, + // 'claim_number' => $tpa_claim_no, + 'updated_at' => date('Y-m-d H:i:s'), + 'last_updated_by' => 'API', + ]; + if (isset($validStatuses[$currentStatus])) { + $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + } + if (!empty($tpa_claim_type)) { + $updateArray['tpa_claim_type'] = $tpa_claim_type; + } + if (!empty($tpa_ailments)) { + $updateArray['tpa_ailments'] = $tpa_ailments; + } + if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) { + $updateArray['tpa_claim_id'] = $tpa_claim_no; + } + if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) { + $updateArray['claim_number'] = $tpa_claim_no; + } + + if($ticket['doa'] == $doa || $ticket['claim_number'] == $tpa_claim_no){ + $this->db->table('ticket_master')->where('id',$claimId)->update($updateArray); + log_message('error', "HEALTH_INDIA - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); + }else{ + log_message('error', "HEALTH_INDIA - Claim status NOT UPDATED | TicketID={$claimId} | TicketDOA={$ticket['doa']} | ClaimDOA={$doa} | Status={$currentStatus}"); + } } - if (!empty($tpa_claim_type)) { - $updateArray['tpa_claim_type'] = $tpa_claim_type; - } - if (!empty($tpa_ailments)) { - $updateArray['tpa_ailments'] = $tpa_ailments; - } - - - - $this->db->table('ticket_master')->where('id',$claimId)->update($updateArray); - - log_message('error', "HEALTH_INDIA - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); - return [ 'status' => true, 'message' => 'Claim status updated.', @@ -1067,6 +1081,9 @@ class HealthIndiaApiController extends BaseController 'tpa_id' => trim($row['memberId'] ?? null), 'age' => is_numeric($row['age'] ?? null) ? (int) $row['age'] : null, + 'si' => $row['baseSumInsured'] ?? null, + 'doj' => !empty($row['dateofPolicyJoining'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['dateofPolicyJoining']))) : null, + 'is_active' => 1, 'created_by' => $file_info[0]['created_by'] ?? null, ]; diff --git a/app/Controllers/MediAssistApiController.php b/app/Controllers/MediAssistApiController.php index 05770e6f..4e210522 100644 --- a/app/Controllers/MediAssistApiController.php +++ b/app/Controllers/MediAssistApiController.php @@ -573,78 +573,89 @@ class MediAssistApiController extends BaseController } // Extract Claim Status - $claimData = $response['data']['claimsData'][0]; - $currentStatus = $claimData['claim_Current_Status'] ?? ''; - $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? ''; - $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? ''; - $tpa_ailments = ($claimData['ailment'] ?? '') . ' - ' . ($claimData['ailmenT_DESC'] ?? ''); + $allClaimData = $response['data']['claimsData']; - // VALID STATUS LIST - $validStatuses = [ - "Claim Received" => 1, - "In Progress" => 5, - "Processed" => 11, - "Claim Paid" => 11, - "Denied" => 13, - "Cancelled" => 13, - - "Information Awaited" => 4, - "Confirmation Awaited" => 4, - "Information Awaited Reminder" => 4, - "Information Awaited Final Reminder" => 4, - "Insurer Concurrence Awaited" => 6, - "Closed" => 12, - - "Physical Documents Awaited" => 9, - "Processed - Payment Initiated" => 10, - "Processed - Transaction Failed" => 10, - "Processed - Account Details Updated" => 10, - "Processed - Debit Note Raised With Insurer for Payment"=> 10, - "Processed - Payment Initiated by Insurer" => 10, - "Payment - Refunded to Insurer" => 14, - "Processed - Processing Payment" => 10, - "Processed - Physical Documents Awaited" => 9, - - // Extra Mappings (based on your DB list) - "NON ID" => 1, - "ID NOT GENERATED" => 2, - "CDA" => 3, - "REJECTED" => 8, - "APPROVED" => 9, - "PAYMENT INITIATED" => 10, - "SETTLED" => 11, - "RETURNED" => 14, - "UNDER PROCESS - TPA" => 61, - "DENIAL REVIEW AWAITED" => 66, - ]; + $currentStatus = ""; + foreach ($allClaimData as $claimData) { - $updateArray = [ - 'tpa_claim_status' => $currentStatus, - 'updated_at' => date('Y-m-d H:i:s'), - ]; + $currentStatus = $claimData['claim_Current_Status'] ?? ''; + $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? ''; + $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? ''; + $tpa_ailments = ($claimData['ailment'] ?? '') . ' - ' . ($claimData['ailmenT_DESC'] ?? ''); - if (isset($validStatuses[$currentStatus])) { - $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + // VALID STATUS LIST + $validStatuses = [ + "Claim Received" => 1, + "In Progress" => 5, + "Processed" => 11, + "Claim Paid" => 11, + "Denied" => 13, + "Cancelled" => 13, + + "Information Awaited" => 4, + "Confirmation Awaited" => 4, + "Information Awaited Reminder" => 4, + "Information Awaited Final Reminder" => 4, + "Insurer Concurrence Awaited" => 6, + "Closed" => 12, + + "Physical Documents Awaited" => 9, + "Processed - Payment Initiated" => 10, + "Processed - Transaction Failed" => 10, + "Processed - Account Details Updated" => 10, + "Processed - Debit Note Raised With Insurer for Payment"=> 10, + "Processed - Payment Initiated by Insurer" => 10, + "Payment - Refunded to Insurer" => 14, + "Processed - Processing Payment" => 10, + "Processed - Physical Documents Awaited" => 9, + + // Extra Mappings (based on your DB list) + "NON ID" => 1, + "ID NOT GENERATED" => 2, + "CDA" => 3, + "REJECTED" => 8, + "APPROVED" => 9, + "PAYMENT INITIATED" => 10, + "SETTLED" => 11, + "RETURNED" => 14, + "UNDER PROCESS - TPA" => 61, + "DENIAL REVIEW AWAITED" => 66, + ]; + + $updateArray = [ + 'tpa_claim_status' => $currentStatus, + 'updated_at' => date('Y-m-d H:i:s'), + 'last_updated_by' => 'API', + ]; + + if (isset($validStatuses[$currentStatus])) { + $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + } + if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) { + $updateArray['tpa_claim_id'] = $tpa_claim_no; + } + if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) { + $updateArray['claim_number'] = $tpa_claim_no; + } + if (!empty($tpa_claim_type)) { + $updateArray['tpa_claim_type'] = $tpa_claim_type; + } + if (!empty($tpa_ailments)) { + $updateArray['tpa_ailments'] = $tpa_ailments; + } + + + if($ticket['doa'] == $this->mediDate($claimData['datE_OF_ADMISSION'] ?? null) || $ticket['claim_number'] == $tpa_claim_no){ + // UPDATE ticket_master + $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); + + // LOG UPDATE + log_message('error',"MEDI_ASSIST - Claim Status SUCCESS | Updated ticket ID $claimId with Claim Status: $currentStatus"); + }else{ + log_message('error', "MEDI_ASSIST | Fetch Claim Status | Claim Status NOT UPDATED | TicketID={$claimId} | TicketDOA={$ticket['doa']} | ClaimDOA={$claimData['datE_OF_ADMISSION']} | Status={$currentStatus}"); + } + } - if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) { - $updateArray['tpa_claim_id'] = $tpa_claim_no; - } - if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) { - $updateArray['claim_number'] = $tpa_claim_no; - } - if (!empty($tpa_claim_type)) { - $updateArray['tpa_claim_type'] = $tpa_claim_type; - } - if (!empty($tpa_ailments)) { - $updateArray['tpa_ailments'] = $tpa_ailments; - } - - - // UPDATE ticket_master - $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); - - // LOG UPDATE - log_message('error',"MEDI_ASSIST - Claim Status SUCCESS | Updated ticket ID $claimId with Claim Status: $currentStatus"); return ['status' => true,'message' => 'Claim Status updated.','updated_status' => $currentStatus,'api_response' => $response]; } @@ -796,6 +807,10 @@ class MediAssistApiController extends BaseController 'gender' => strtoupper($row['benefSex'] ?? null), 'self' => strtolower($row['relName'] ?? '') === 'self' ? 1 : 0, + 'si' => $row['sum_insured'] ?? null, + 'doj' => $this->mediDate($row['benefWEF'] ?? null), + + 'tpa_id' => trim($row['benefMediAssistID'] ?? null), 'age' => is_numeric($row['benefAge'] ?? null) ? (int) $row['benefAge'] @@ -890,6 +905,9 @@ class MediAssistApiController extends BaseController // CALL API $response = call_third_party_api($url, $method, $headers, $body); + log_message('error','MEDI_ASSIST - 2 hours Claim Status API Response: ' . json_encode($response)); + + if ($response['status'] != true || empty($response['data']['claimsData'][0])) { log_message('error','MEDI_ASSIST - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response)); $error_data[$claimId] = [ @@ -900,77 +918,94 @@ class MediAssistApiController extends BaseController } // Extract Claim Status - $claimData = $response['data']['claimsData'][0]; - $currentStatus = $claimData['claim_Current_Status'] ?? ''; - $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? ''; - $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? ''; - $tpa_ailments = ($claimData['ailment'] ?? '') . ' - ' . ($claimData['ailmenT_DESC'] ?? ''); + // $allClaimData = $response['data']['claimsData'][0]; + $allClaimData = $response['data']['claimsData']; - // VALID STATUS LIST - $validStatuses = [ - "Claim Received" => 1, - "In Progress" => 5, - "Processed" => 11, - "Claim Paid" => 11, - "Denied" => 13, - "Cancelled" => 13, - - "Information Awaited" => 4, - "Confirmation Awaited" => 4, - "Information Awaited Reminder" => 4, - "Information Awaited Final Reminder" => 4, - "Insurer Concurrence Awaited" => 6, - "Closed" => 12, - - "Physical Documents Awaited" => 9, - "Processed - Payment Initiated" => 10, - "Processed - Transaction Failed" => 10, - "Processed - Account Details Updated" => 10, - "Processed - Debit Note Raised With Insurer for Payment"=> 10, - "Processed - Payment Initiated by Insurer" => 10, - "Payment - Refunded to Insurer" => 14, - "Processed - Processing Payment" => 10, - "Processed - Physical Documents Awaited" => 9, - - // Extra Mappings (based on your DB list) - "NON ID" => 1, - "ID NOT GENERATED" => 2, - "CDA" => 3, - "REJECTED" => 8, - "APPROVED" => 9, - "PAYMENT INITIATED" => 10, - "SETTLED" => 11, - "RETURNED" => 14, - "UNDER PROCESS - TPA" => 61, - "DENIAL REVIEW AWAITED" => 66, - ]; + foreach ($allClaimData as $claimData) { + + $currentStatus = $claimData['claim_Current_Status'] ?? ''; + $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? ''; + $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? ''; + $tpa_ailments = ($claimData['ailment'] ?? '') . ' - ' . ($claimData['ailmenT_DESC'] ?? ''); - $updateArray = [ - 'tpa_claim_status' => $currentStatus, - 'tpa_claim_id' => $tpa_claim_no, - 'claim_number' => $tpa_claim_no, - 'updated_at' => date('Y-m-d H:i:s'), - ]; - if (isset($validStatuses[$currentStatus])) { - $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; - } - if (!empty($tpa_claim_type)) { - $updateArray['tpa_claim_type'] = $tpa_claim_type; - } - if (!empty($tpa_ailments)) { - $updateArray['tpa_ailments'] = $tpa_ailments; - } + // VALID STATUS LIST + $validStatuses = [ - // UPDATE ticket_master - $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); - $status_updated_count ++; - - // LOG UPDATE - log_message('error',"MEDI_ASSIST - Claim Status SUCCESS | Updated ticket ID $claimId with Claim Status: $currentStatus"); + "Claim Received" => 1, + "In Progress" => 5, + "Processed" => 11, + "Claim Paid" => 11, + "Denied" => 13, + "Cancelled" => 13, + "Information Awaited" => 4, + "Confirmation Awaited" => 4, + "Information Awaited Reminder" => 4, + "Information Awaited Final Reminder" => 4, + "Insurer Concurrence Awaited" => 6, + "Closed" => 12, + + "Physical Documents Awaited" => 9, + "Processed - Payment Initiated" => 10, + "Processed - Transaction Failed" => 10, + "Processed - Account Details Updated" => 10, + "Processed - Debit Note Raised With Insurer for Payment"=> 10, + "Processed - Payment Initiated by Insurer" => 10, + "Payment - Refunded to Insurer" => 14, + "Processed - Processing Payment" => 10, + "Processed - Physical Documents Awaited" => 9, + + // Extra Mappings (based on your DB list) + "NON ID" => 1, + "ID NOT GENERATED" => 2, + "CDA" => 3, + "REJECTED" => 8, + "APPROVED" => 9, + "PAYMENT INITIATED" => 10, + "SETTLED" => 11, + "RETURNED" => 14, + "UNDER PROCESS - TPA" => 61, + "DENIAL REVIEW AWAITED" => 66, + ]; + + $updateArray = [ + 'tpa_claim_status' => $currentStatus, + 'updated_at' => date('Y-m-d H:i:s'), + 'last_updated_by' => 'API', + ]; + + if (isset($validStatuses[$currentStatus])) { + $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + } + if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) { + $updateArray['tpa_claim_id'] = $tpa_claim_no; + } + if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) { + $updateArray['claim_number'] = $tpa_claim_no; + } + if (!empty($tpa_claim_type)) { + $updateArray['tpa_claim_type'] = $tpa_claim_type; + } + if (!empty($tpa_ailments)) { + $updateArray['tpa_ailments'] = $tpa_ailments; + } + + if($ticket['doa'] == $this->mediDate($claimData['datE_OF_ADMISSION'] ?? null) || $ticket['claim_number'] == $tpa_claim_no){ + // UPDATE ticket_master + $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); + $status_updated_count ++; + + // LOG UPDATE + log_message('error',"MEDI_ASSIST - Claim Status SUCCESS | Updated ticket ID $claimId with Claim Status: $currentStatus"); + }else{ + log_message('error', "MEDI_ASSIST | 2 hours | Claim Status NOT UPDATED | TicketID={$claimId} | TicketDOA={$ticket['doa']} | ClaimDOA={$claimData['datE_OF_ADMISSION']} | Status={$currentStatus}"); + } + } } + log_message('error',"MEDI_ASSIST - Claim Status ENDED | 2 hours | Total Tickets={".count($TicketData)."} | Status Updated={$status_updated_count} | Errors={".count($error_data)."}"); + return $this->response->setJSON([ 'status' => true, 'message' => 'Claim Status updated.', diff --git a/app/Controllers/VidalApiController.php b/app/Controllers/VidalApiController.php index d4674302..92249118 100644 --- a/app/Controllers/VidalApiController.php +++ b/app/Controllers/VidalApiController.php @@ -495,40 +495,52 @@ class VidalApiController extends BaseController } // Extract claim status - $claimData = $response['data']['data']['claims'][0]; - $tpa_claim_no = $claimData['claimNumber'] ?? ''; - $currentStatus = $claimData['status'] ?? ''; - $tpa_claim_type = $claimData['claimType'] ?? ''; + // $claimData = $response['data']['data']['claims'][0]; + $allClaimData = $response['data']['data']['claims']; + + $currentStatus = ""; + foreach ($allClaimData as $claimData) { + + $tpa_claim_no = $claimData['claimNumber'] ?? ''; + $currentStatus = $claimData['status'] ?? ''; + $tpa_claim_type = $claimData['claimType'] ?? ''; + $doa = !empty($claimData['doa'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $claimData['doa']))) : null; - // VALID STATUS LIST - $validStatuses = [ - "In-Progress" => 5, - "Required Information" => 4, - "Paid" => 11, - "Rejected" => 8, - "Approved" => 8, - ]; - $updateArray = [ - 'tpa_claim_status' => $currentStatus, - 'tpa_claim_id' => $tpa_claim_no, - // 'claim_number' => $tpa_claim_no, // already updated - 'updated_at' => date('Y-m-d H:i:s'), - ]; - if (isset($validStatuses[$currentStatus])) { - $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + // VALID STATUS LIST + $validStatuses = [ + "In-Progress" => 5, + "Required Information" => 4, + "Paid" => 11, + "Rejected" => 8, + "Approved" => 8, + ]; + + $updateArray = [ + 'tpa_claim_status' => $currentStatus, + 'tpa_claim_id' => $tpa_claim_no, + // 'claim_number' => $tpa_claim_no, // already updated + 'updated_at' => date('Y-m-d H:i:s'), + 'last_updated_by' => 'API', + ]; + if (isset($validStatuses[$currentStatus])) { + $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + } + if (!empty($tpa_claim_type)) { + $updateArray['tpa_claim_type'] = $tpa_claim_type; + } + + if($ticket['doa'] == $doa || $ticket['claim_number'] == $tpa_claim_no){ + // UPDATE ticket_master + $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); + + // LOG UPDATE + log_message('error', "VIDAL - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); + }else{ + log_message('error', "VIDAL - Claim Status NOT UPDATED | TicketID={$claimId} | TicketDOA={$ticket['doa']} | ClaimDOA={$doa} | Status={$currentStatus}"); + } } - if (!empty($tpa_claim_type)) { - $updateArray['tpa_claim_type'] = $tpa_claim_type; - } - - - // UPDATE ticket_master - $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); - - // LOG UPDATE - log_message('error', "VIDAL - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); return ['status' => true,'message' => 'Claim status updated.','updated_status' => $currentStatus,'api_response' => $response]; } @@ -611,44 +623,62 @@ class VidalApiController extends BaseController } // Extract claim status - $claimData = $response['data']['data']['claims'][0]; - $tpa_claim_no = $claimData['claimNumber'] ?? ''; - $currentStatus = $claimData['status'] ?? ''; - $tpa_claim_type = $claimData['claimType'] ?? ''; + // $claimData = $response['data']['data']['claims'][0]; + $allClaimData = $response['data']['data']['claims']; + + foreach ($allClaimData as $claimData) { + + $tpa_claim_no = $claimData['claimNumber'] ?? ''; + $currentStatus = $claimData['status'] ?? ''; + $tpa_claim_type = $claimData['claimType'] ?? ''; + $doa = !empty($claimData['doa'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $claimData['doa']))) : null; - // VALID STATUS LIST - $validStatuses = [ - "In-Progress" => 5, - "Required Information" => 4, - "Paid" => 11, - "Rejected" => 8, - "Approved" => 8, - ]; + // VALID STATUS LIST + $validStatuses = [ + "In-Progress" => 5, + "Required Information" => 4, + "Paid" => 11, + "Rejected" => 8, + "Approved" => 8, + ]; - $updateArray = [ - 'tpa_claim_status' => $currentStatus, - 'tpa_claim_id' => $tpa_claim_no, - // 'claim_number' => $tpa_claim_no, // already updated - 'updated_at' => date('Y-m-d H:i:s'), - ]; - if (isset($validStatuses[$currentStatus])) { - $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + $updateArray = [ + 'tpa_claim_status' => $currentStatus, + // 'claim_number' => $tpa_claim_no, // already updated + 'updated_at' => date('Y-m-d H:i:s'), + 'last_updated_by' => 'API', + ]; + + if (isset($validStatuses[$currentStatus])) { + $updateArray['claim_status_id'] = $validStatuses[$currentStatus]; + } + if (!empty($tpa_claim_type)) { + $updateArray['tpa_claim_type'] = $tpa_claim_type; + } + if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) { + $updateArray['tpa_claim_id'] = $tpa_claim_no; + } + if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) { + $updateArray['claim_number'] = $tpa_claim_no; + } + + // UPDATE ticket_master + if($ticket['doa'] == $doa || $ticket['claim_number'] == $tpa_claim_no){ + $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); + + // LOG UPDATE + log_message('error', "VIDAL - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); + $status_updated_count ++; + }else{ + log_message('error', "VIDAL - Claim Status NOT UPDATED | TicketID={$claimId} | TicketDOA={$ticket['doa']} | ClaimDOA={$doa} | Status={$currentStatus}"); + } + } - if (!empty($tpa_claim_type)) { - $updateArray['tpa_claim_type'] = $tpa_claim_type; - } - - // UPDATE ticket_master - $this->db->table('ticket_master')->where('id', $claimId)->update($updateArray); - - // LOG UPDATE - log_message('error', "VIDAL - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus"); - - $status_updated_count ++; - } + log_message('error', "VIDAL - Claim Status ENDED | Total Tickets={".count($TicketData)."} | Status Updated={$status_updated_count} | Errors={".count($error_data)."}"); + return $this->response->setJSON([ 'status' => true, 'message' => 'Claim status updated.', diff --git a/app/Views/batch_list.php b/app/Views/batch_list.php index 9a461282..8468b459 100755 --- a/app/Views/batch_list.php +++ b/app/Views/batch_list.php @@ -13,7 +13,67 @@ overflow: hidden; text-overflow: ellipsis; } -.dataTables_length label {height: 21px !important;} + +.dataTables_length label { + height: 21px !important; +} + +/* TPA variation modal layout */ +#tpa_variation_modal .modal-dialog { + max-width: 95%; +} + +#tpa_variation_modal .modal-content { + max-height: 90vh; +} + +#tpa_variation_modal .modal-body { + max-height: calc(85vh - 50px); + overflow-y: auto; + direction: ltr; +} + +#tpa_variation_modal .table-responsive { + overflow-x: auto; +} + +#tpa_variation_modal table { + white-space: nowrap; + font-size: 11px; +} + +#tpa_variation_modal table thead th, +#tpa_variation_modal table tbody td { + padding: 2px 6px; + line-height: 1.1; +} + +/* Tabs spacing & styling */ +#tpa_variation_modal .nav-tabs { + border-bottom: 1px solid #dee2e6; + margin-bottom: 12px; + gap: 6px; +} + +#tpa_variation_modal .nav-tabs .nav-item { + margin-right: 6px; +} + +#tpa_variation_modal .nav-tabs .nav-link { + padding: 6px 14px; + border-radius: 4px 4px 0 0; +} + +#tpa_variation_modal .nav-tabs .nav-link.active { + background-color: #f8f9fa; + border-color: #dee2e6 #dee2e6 transparent; +} + +/* Modal footer buttons size */ +#tpa_variation_modal .modal-footer .btn { + padding: 4px 12px; + font-size: 12px; +}
@@ -72,6 +132,7 @@ by + @@ -157,36 +218,39 @@ - +
+ + - @@ -228,10 +292,252 @@ + + \ No newline at end of file From fc7941ed26515ea66456dcc8a56c9642bbae3764 Mon Sep 17 00:00:00 2001 From: "sanjeev.p" Date: Thu, 12 Mar 2026 15:25:56 +0530 Subject: [PATCH 6/8] FIX_FAQ_and_FE_Content --- .../AppContentManagementController.php | 242 ++++++++++++++++-- app/Views/client_onboarding.php | 2 +- app/Views/faq_list.php | 14 +- app/Views/frontend_content_list.php | 27 +- .../policy_transaction_inception_form.php | 20 +- .../policy_transaction_inception_list.php | 6 +- .../assets/images/sales_tracker_light_sb.png | Bin 0 -> 1815 bytes 7 files changed, 265 insertions(+), 46 deletions(-) create mode 100644 public/assets/images/sales_tracker_light_sb.png diff --git a/app/Controllers/AppContentManagementController.php b/app/Controllers/AppContentManagementController.php index c3bcde67..e13732b2 100755 --- a/app/Controllers/AppContentManagementController.php +++ b/app/Controllers/AppContentManagementController.php @@ -226,6 +226,14 @@ class AppContentManagementController extends AdminController if ($this->request->getMethod() === 'post') { + /** + * -------------------------------------------------------------------------- + * STEP 1: INITIAL VALIDATION + * -------------------------------------------------------------------------- + * These are the basic validation rules. For 'content' and 'notes', we only + * check if they are provided and within the allowed length. + * The more advanced security check for script tags happens next. + */ $rules = [ 'fe_id' => [ 'rules' => 'permit_empty|integer|is_natural', @@ -258,22 +266,20 @@ class AppContentManagementController extends AdminController 'regex_match' => 'Heading contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ], - 'content' => [ - 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'content' => [ + 'rules' => 'required|max_length[5000]', 'errors' => [ - 'required' => 'Content is required', - 'max_length' => 'Content cannot exceed 5000 characters', - 'regex_match' => 'Content contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'required' => 'Content is required', + 'max_length' => 'Content cannot exceed 5000 characters', ] ], 'notes' => [ - 'rules' => 'required|max_length[1500]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[1500]', 'errors' => [ - 'required' => 'Notes are required', - 'max_length' => 'Notes cannot exceed 1500 characters', - 'regex_match' => 'Notes contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'required' => 'Notes are required', + 'max_length' => 'Notes cannot exceed 1500 characters', ] - ] + ], ]; if (!$this->validate($rules)) { @@ -284,9 +290,60 @@ class AppContentManagementController extends AdminController 'errors' => $this->validator->getErrors() ]); } - $request_post_data = $this->request->getPost(); - $data = sanitizeInputArrayAdvanced($request_post_data); - $id = $data['fe_id'] ?? null; + + /************************************************************************** + * REFACTORED SANITIZATION LOGIC (XSS Protection) + ************************************************************************** + * + * Per the user's request, we are avoiding the generic `sanitizeInputArrayAdvanced` + * on the `content` and `notes` fields, as they require special HTML + * handling. + * + * The new process is: + * 1. Get the raw `content` and `notes` directly from the POST request. + * 2. Perform the critical XSS validation on this raw content using `hasXssTags()`. + * If it fails, the request is rejected immediately. This satisfies all + * the failure test cases (Tests 4-9). + * 3. Take all *other* POST data and sanitize it using the generic + * `sanitizeInputArrayAdvanced` function. + * 4. Sanitize the now-validated `content` and `notes` using our specific + * `sanitizeHtml()` function, which allows safe HTML. + * 5. Combine the sanitized data into a final array for database insertion. + * + *************************************************************************/ + + // Step 1: Get raw `content` and `notes`. + $rawContent = $this->request->getPost('content'); + $rawNotes = $this->request->getPost('notes'); + + // Step 2: Perform critical XSS validation on raw input. + $xssErrors = []; + if ($this->hasXssTags($rawContent)) { + $xssErrors['content'] = 'Content contains restricted tags. Script, iframe and event handlers are not allowed'; + } + if ($this->hasXssTags($rawNotes)) { + $xssErrors['notes'] = 'Notes contains restricted tags. Script, iframe and event handlers are not allowed'; + } + + if (!empty($xssErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $xssErrors + ]); + } + + // Step 3: Sanitize all *other* POST data. + $otherPostData = $this->request->getPost(); + unset($otherPostData['content'], $otherPostData['notes']); + $data = sanitizeInputArrayAdvanced($otherPostData); + + // Step 4 & 5: Sanitize and re-combine `content` and `notes`. + $data['content'] = $this->sanitizeHtml($rawContent); + $data['notes'] = $this->sanitizeHtml($rawNotes); + + $id = $data['fe_id'] ?? null; if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) { return $this->response->setStatusCode(400)->setJSON([ @@ -416,19 +473,17 @@ class AppContentManagementController extends AdminController ] ], 'question' => [ - 'rules' => 'required|max_length[1000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[1000]', 'errors' => [ 'required' => 'Question is required', 'max_length' => 'Question cannot exceed 1000 characters', - 'regex_match' => 'Question contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ], 'answer' => [ - 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[5000]', 'errors' => [ 'required' => 'Answer is required', 'max_length' => 'Answer cannot exceed 5000 characters', - 'regex_match' => 'Answer contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ] ]; @@ -443,9 +498,50 @@ class AppContentManagementController extends AdminController ]); } - $request_post_data = $this->request->getPost(); - $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data); - $data = array_filter($sanitized_post_data, fn($v) => $v !== '' && $v !== null); + /************************************************************************** + * XSS PROTECTION FOR 'question' and 'answer' + ************************************************************************** + * + * Applying the same security model as `frontend_content`. + * + * 1. Validate raw `question` and `answer` for malicious tags using `hasXssTags()`. + * If found, reject the request immediately. + * 2. Sanitize all *other* fields using the generic `sanitizeInputArrayAdvanced`. + * 3. Sanitize the `question` and `answer` using the HTML-aware `sanitizeHtml()` + * function to allow safe tags before saving. + * + *************************************************************************/ + + // Step 1: Validate raw input for XSS threats. + $rawQuestion = $this->request->getPost('question'); + $rawAnswer = $this->request->getPost('answer'); + $xssErrors = []; + + if ($this->hasXssTags($rawQuestion)) { + $xssErrors['question'] = 'Question contains restricted tags. Script, iframe and event handlers are not allowed'; + } + if ($this->hasXssTags($rawAnswer)) { + $xssErrors['answer'] = 'Answer contains restricted tags. Script, iframe and event handlers are not allowed'; + } + + if (!empty($xssErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => 'error', + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $xssErrors, + 'ref' => $ref + ]); + } + + // Step 2 & 3: Sanitize and combine data. + $otherPostData = $this->request->getPost(); + unset($otherPostData['question'], $otherPostData['answer']); + $data = sanitizeInputArrayAdvanced($otherPostData); + + $data['question'] = $this->sanitizeHtml($rawQuestion); + $data['answer'] = $this->sanitizeHtml($rawAnswer); + $id = $data['faq_id'] ?? null; if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) { @@ -470,12 +566,6 @@ class AppContentManagementController extends AdminController $msg = "Updated"; } - // if ($returnType === 'web') { - // return redirect()->back()->with($status ? 'success' : 'error', "FAQ $msg " . ($status ? 'successfully' : 'failed')); - // } - - // return $this->response->setJSON([ - // ])->setStatusCode($result ? 200 : 400); return $this->response->setJSON([ 'status' => $status ? 'success' : 'error', 'message' => "FAQ $msg " . ($status ? 'successfully' : 'failed'), @@ -611,4 +701,104 @@ class AppContentManagementController extends AdminController // } + + // Add these two private methods inside AppContentManagementController + + + /** + * ================================================================================= + * HTML SANITIZATION & VALIDATION HELPER METHODS + * ================================================================================= + * The following two methods are the core of the XSS protection logic. + */ + + + /** + * sanitizeHtml() + * + * This function cleans a string of HTML, ensuring it is safe to display in a browser. + * It allows a specific set of safe HTML tags and removes any dangerous attributes + * from those tags. + * + * @param string $input The raw HTML string from user input. + * @return string The cleaned, safe HTML string. + */ + private function sanitizeHtml(string $input): string + { + /** + * Define a whitelist of allowed HTML tags. Any tag not in this list will be + * completely removed. We are allowing basic formatting, lists, tables, etc. + */ + // ✅ Added , ,

-

,
,
, , 
for Jodit support + $allowed_tags = '