diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 2128f042..d552bb46 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -16,6 +16,8 @@ use App\Filters\AuthClientApi; use App\Filters\CommissionApiFilter; use App\Filters\VerifyAppSignature; use App\Filters\Cors; +use App\Filters\SecurityInputFilter; +use App\Filters\GlobalPostFileUploadGuard; use App\Filters\AuthJWT; @@ -43,6 +45,8 @@ class Filters extends BaseConfig 'CommissionApiFilter'=> CommissionApiFilter::class, 'appSignature' => VerifyAppSignature::class, 'Cors' => Cors::class, + 'SecurityInputFilter' => SecurityInputFilter::class, + 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, ]; /** @@ -56,6 +60,8 @@ class Filters extends BaseConfig 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], 'Cors', + 'SecurityInputFilter', + 'GlobalPostFileUploadGuard' // 'csrf', // 'invalidchars', ], diff --git a/app/Config/Routes.php b/app/Config/Routes.php index dfa43a0a..c402419a 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -738,6 +738,12 @@ $routes->group("/ticket", ["filter" => "authMVC"], function ($routes) { $routes->get('getTpaClaimStatus',"ApiServiceController::getClaimStatus"); }); +$routes->group("/claim_mis", ["filter" => "authMVC"], function ($routes) { + $routes->get('list','TicketController::claimMisFileList'); + $routes->get('download','TicketController::downloadClaimMisFile'); + $routes->post('upload','TicketController::uploadClaimMisFile'); +}); + $routes->group("clientApi",["filter" => "AuthClientApi"], function ($routes){ $routes->post("getPolicyMaster","ClientAPIController::sendPolicyMaster"); diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php index f59de0f0..7c256f40 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -106,10 +106,11 @@ class ApiServiceController extends BaseController ->join('client_policy', 'employee_polices.client_policy_id = client_policy.id', 'left') ->where('employees.emp_code', $emp_code) ->where('employee_polices.client_policy_id', $client_policy_id) + ->where('employees.id', $id) ->where('employee_polices.is_active', 1) ->where('employees.is_active', 1) - ->where('employee_polices.status', 'active') - ->where('employees.emp_status', 'active') + ->whereIn('employee_polices.status', ['active', 'expired']) + ->whereIn('employees.emp_status', ['active', 'expired']) ->findAll(); diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 4853fea1..0b6470bc 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -519,6 +519,7 @@ class ClientController extends AdminController public function updateEmpAndPolicyStatus() { $return = $this->clientPolicyModel->updateStatus(); + print_rr($return); $this->myLogger->logme('error', 'Client Policy Status Update Count: {data}', ['data' => $return['client']]); $this->myLogger->logme('error', 'Employee Policy Status Update Count: {data}', ['data' => $return['emp']]); } diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 66e856b1..f4ceecc2 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -1517,10 +1517,10 @@ class EmployeeController extends AdminController ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id') ->join('employees', 'employees.id = employee_polices.employee_id') ->join('tpa', 'tpa.id = client_policy.tpa_id') - ->where('employees.emp_status', 'active') ->where('employees.is_active', '1') ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''") - ->where('employee_polices.status', 'active') + ->whereIn('employee_polices.status', ['active', 'expired']) + ->whereIn('employees.emp_status', ['active', 'expired']) ->where('employee_polices.is_active', '1') ->where('employee_polices.rand_string', $rand_string) ->first(); @@ -1543,6 +1543,7 @@ class EmployeeController extends AdminController //new step check in S3 if yes then fetch from S3 bucket $s3_key = 'ecard_'.$get_emp_code_and_client_policy_id['name'].'('.$get_emp_code_and_client_policy_id['emp_code'].')'.'_'.$get_emp_code_and_client_policy_id['tpa_id'].'.pdf'; + $s3_key = $this->sanitizeFilePart($s3_key); // echo $s3_key;die(); $s3 = \Config\Services::getS3Service(); if($s3->exists($s3_key) && $mode != 2) //2 => for bulk generate so skip s3 check and generate PDF @@ -3397,7 +3398,8 @@ class EmployeeController extends AdminController public function initiateWellnessOnboard($client_policy_id) { - $r = Jobs::addJob(['job_name' => 'initiateWellnessOnboardJob','payload' => ['client_policy_id' => $client_policy_id]]); + $r = Jobs::addJob(['job_name' => 'initiateWellnessOnboardJob','payload' => ['client_policy_id' => $client_policy_id]]); + //$this->initiateWellnessOnboardJob(['client_policy_id' => $client_policy_id]); return $this->respond(['status' => true, 'code' => 200, 'message' => 'Process started'], 200); } @@ -3428,7 +3430,7 @@ class EmployeeController extends AdminController // echo '==============================';die(); // $data = '[{"id":12847,"employee_id":"TEST_EMP_001","client_policy_id":null,"tpa_id":null,"uhid":null,"batch_code":null,"status":"active","pre_existing_alignments":null,"age_band":null,"basic_cover_si":"0","date_coverage":"2025-01-01","policy_end_date":"2025-12-31","days":"0","premium":"0","rata_premimum":"0","gst":"0","si_enhancement_date":null,"date_of_exit":null,"reason_for_exit":null,"claim_status":"0","created_by":null,"created_at":null,"updated_by":null,"updated_at":null,"is_active":"1","rand_string":null,"ecard_sent_status":"0","payable_employee":"0","file_id":null,"wellness_onboard":"0","name":"test name","relationship":"SELF","emp_code":"TEST_EMP_001","email_corporate":"test@gmail.com","mobile":"9797976565","dob":"1975-08-09"},{"id":12846,"employee_id":"TEST_EMP_001","client_policy_id":null,"tpa_id":null,"uhid":null,"batch_code":null,"status":"active","pre_existing_alignments":null,"age_band":null,"basic_cover_si":"0","date_coverage":"2025-01-01","policy_end_date":"2025-12-31","days":"0","premium":"0","rata_premimum":"0","gst":"0","si_enhancement_date":null,"date_of_exit":null,"reason_for_exit":null,"claim_status":"0","created_by":null,"created_at":null,"updated_by":null,"updated_at":null,"is_active":"1","rand_string":null,"ecard_sent_status":"0","payable_employee":"0","file_id":null,"wellness_onboard":"0","name":"dependent 1","relationship":"SON","emp_code":"TEST_EMP_001","email_corporate":"dependent1@gmail.com","mobile":"9898989898","dob":"2001-08-09"}]'; // $data = (array)json_decode($data,true); - // print_r($data); + // print_r(count($data)); // echo '==============================';die(); if(is_array($data) && count($data)) { @@ -3457,7 +3459,7 @@ class EmployeeController extends AdminController $familiesPayload[$empCode] = $this->buildFamilyPayload($empCode, $members); } - // print_r($familiesPayload);die(); + // print_rr($familiesPayload);die(); $apiResponse = $this->sendFamiliesToWellnessApi($familiesPayload); // print_r($apiResponse); $updatedData = $this->updateWellnessOnboardResponseToDB($apiResponse); @@ -3490,7 +3492,7 @@ class EmployeeController extends AdminController { // Use the first member as primary reference for policy level data $primary = $members[0]; - + // print_rr($primary);die(); // Map DB fields to your required "policyDetails" structure $policyStartDate = $primary['cp_policy_start_date'] ?? null; // $policyStartDate = '2025-01-01'; @@ -3546,6 +3548,7 @@ class EmployeeController extends AdminController public function sendFamiliesToWellnessApi(array $familiesPayload): array { // CI4 HTTP client + // print_rr($familiesPayload);die(); $client = \Config\Services::curlrequest();//die(); $endpointUrl = getenv('WELLNESS_ONBOARD_ENDPOINT_URL'); // Custom headers @@ -3555,7 +3558,7 @@ class EmployeeController extends AdminController ]; foreach ($familiesPayload as $empCode => &$family) { - + // print_rr($family);die(); try { $response = $client->post($endpointUrl, [ 'headers' => $headers, @@ -3573,6 +3576,8 @@ class EmployeeController extends AdminController 'rawBody' => $body, 'data' => $decoded, ]; + + } catch (\Throwable $e) { // In case of exception, store error info $family['apiResponse'] = [ @@ -3582,6 +3587,8 @@ class EmployeeController extends AdminController 'error' => $e->getMessage(), ]; } + + // print_rr($body );die(); } unset($family); // break reference diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 121db764..20bd8a31 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -2929,6 +2929,7 @@ class EmployeeRestController extends AdminController $data['claim_subject'] = "Claim GTLI"; $data['sum_insured_label'] = "Sum Assured"; } else if ($ClientPolicyValue['policy_type_id'] == 72){ + $policyGroup = 'other'; $data['ticket_type_id'] = 72; $data['ticket_settled_status_id'] = 76; $data['claim_subject'] = "Claim OPD"; @@ -3571,6 +3572,20 @@ class EmployeeRestController extends AdminController $get_docs_name = $this->request->getPost('claim_doc_names') ?? []; $policy_transaction_id = $this->request->getPost('policy_transaction_id') ?? null; + $client_policy_data = $this->clientPolicyModel->where('id', $received_data['client_policy_id'] ?? null)->first(); + + $isduplicate = checkDuplicateClaim([ + 'doa' => change_date_format($received_data['doa'] ?? '') ?? null, + 'emp_code' => $received_data['emp_code'] ?? null, + 'claim_amount' => $received_data['claim_amount'] ?? null, + 'policy_no' => $client_policy_data['policy_no'] ?? null + ]); + + if($isduplicate){ + $response = ['status' => false, 'code' => 404, 'message' => 'Claim already exist']; + return $this->respond($response, 200); + } + if(!empty($policy_transaction_id)){ $response = $this->retailClaimInitiate($received_data); return $this->respond($response, 200); @@ -3648,11 +3663,8 @@ class EmployeeRestController extends AdminController if (!empty($emp_ticket_data)) { - $insured_emp_data = $this->employeeModel->where('id', $insured_emp_id)->first(); + unset($received_data['relationship']); $fetchData = $emp_ticket_data[0]; - if(!empty($insured_emp_data)){ - $fetchData['relationship'] = strtolower($insured_emp_data['relationship']); - } $claimStatusQuery = $this->claimStatusModel ->select('id') @@ -3675,7 +3687,9 @@ class EmployeeRestController extends AdminController $fetchData['claim_type'] = 1; $fetchData = array_merge($fetchData, $received_data); - $fetchData['relationship'] = strtolower($fetchData['relationship']) ?? $fetchData['relationship']; + // $fetchData['relationship'] = strtolower($fetchData['relationship']) ?? $fetchData['relationship']; + $fetchData['relationship'] = isset($fetchData['relationship']) ? strtolower($fetchData['relationship']) : null; + // print_r($fetchData); die; $insert_status = $this->ticketMaster->insert($fetchData); $ticket_id = $this->ticketMaster->insertID(); diff --git a/app/Controllers/LoginController.php b/app/Controllers/LoginController.php index 451765c2..779c788b 100755 --- a/app/Controllers/LoginController.php +++ b/app/Controllers/LoginController.php @@ -11,6 +11,8 @@ use CodeIgniter\API\ResponseTrait; use App\Models\UserModel; use App\Models\AuthHistoryModel; +use App\Libraries\AuthLogout; + class LoginController extends BaseController { use ResponseTrait; @@ -45,7 +47,7 @@ class LoginController extends BaseController $user_team = $UserModel->getUserTeamsByUserID($user->id); // dd($user_team); - + session()->regenerate(true); $session_data = [ 'isLoggedIn' => True , 'userid' => $user->id, @@ -56,9 +58,14 @@ class LoginController extends BaseController $path = getenv('cookie.Path'); $domain = getenv('cookie.Domain'); $https = getenv('ccokie.secure'); - setcookie('session_data', json_encode($session_data), time() + 12 * 60 * 60, $path, $domain, $https, true); + // setcookie('session_data', json_encode($session_data), time() + 12 * 60 * 60, $path, $domain, $https, true); set_session_data($session_data); + // Bind session to device + set_session_data(['fingerprint' => hash('sha256', + ($this->request->getUserAgent()->getAgentString() . '|' . ($this->request->getIPAddress() + )))]); + log_message('error', 'Set The UserId : `'. $user->id .'` in Session'); log_message('error', 'User Login Sucessfully'); @@ -91,14 +98,23 @@ class LoginController extends BaseController public function logout() { - $path = getenv('cookie.Path'); - session()->destroy(); - // setcookie('session_data', '', time() - 3600, $path); - $path = getenv('cookie.Path'); - $domain = getenv('cookie.Domain'); - $https = getenv('cookie.secure'); - setcookie('session_data',null, time() -3600, $path, $domain, $https, true); - return redirect()->to(base_url('login')); + // $path = getenv('cookie.Path'); + // session()->regenerate(true); + // session()->destroy(); + + // $path = getenv('cookie.Path'); + // $domain = getenv('cookie.Domain'); + // $https = getenv('cookie.secure'); + + // setcookie('session_data',null, time() - 42000, $path, $domain, $https, true); + // // return redirect()->to(base_url('login')); + // return redirect()->to(base_url('login')) + // ->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + // ->setHeader('Pragma', 'no-cache') + // ->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT'); + + + return AuthLogout::logout(); } public function getUserDeviceInfo($userId, $type_of_user) diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index 79f5753b..06fbfb0c 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -1984,6 +1984,7 @@ class MasterController extends AdminController 'rules' => WRITEPATH . 'uploads/commission/rules', 'claim_sample_forms' => ROOTPATH . 'public/claim_sample_forms/', 'bds_dump_excel' => WRITEPATH . 'uploads/bds_dump_excel/', + 'claims_mis' => WRITEPATH . 'uploads/claims_mis/', ]; foreach ($folders as $folderName => $folderPath) { diff --git a/app/Controllers/PayoutController.php b/app/Controllers/PayoutController.php index 90d501dc..813dda75 100644 --- a/app/Controllers/PayoutController.php +++ b/app/Controllers/PayoutController.php @@ -335,7 +335,7 @@ class PayoutController extends BaseController $invoiceData = [ 'invoice_no' => $json['invoice_no'], - 'agent_id' => $json['agent_id'], + // 'agent_id' => $json['agent_id'] ?? null, 'invoice_date' => $json['invoice_date'], 'invoice_amount' => $json['invoice_amount'], ]; diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index 07b8db0e..308c5a07 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -24,6 +24,7 @@ use App\Models\ClaimFilesModel; use App\Models\ClaimDumpFileModel; use App\Models\VehicleModel; use App\Models\PartnerPolicyModel; +use App\Models\ClaimMisFileModel; use DOMDocument; use DOMXPath; @@ -67,6 +68,7 @@ class TicketController extends BaseController protected $claimDumpFileModel; protected $vehicleModel; protected $partnerPolicyModel; + protected $claimmisFileModel; public function __construct() { @@ -398,6 +400,7 @@ class TicketController extends BaseController $this->claimDumpFileModel = new ClaimDumpFileModel(); $this->vehicleModel = new VehicleModel(); $this->partnerPolicyModel = new PartnerPolicyModel(); + $this->claimmisFileModel = new ClaimMisFileModel(); } public function ticketList() @@ -1124,6 +1127,43 @@ class TicketController extends BaseController // $ticket_data = $this->getLastMatchedStatus($ticket_data, ); // print_rr($ticket_data); die; + $isduplicate = checkDuplicateClaim([ + 'doa' => change_date_format($ticket_data['doa'] ?? '') ?? null, + 'emp_code' => $ticket_data['emp_code'] ?? null, + 'claim_amount' => $ticket_data['claim_amount'] ?? null, + 'policy_no' => $ticket_data['policy_no'] ?? null + ]); + + if ($isduplicate) { + + $errorDetails = []; + + if (!empty($ticket_data['doa'])) { + $errorDetails[] = 'DOA: ' . change_date_format($ticket_data['doa']); + } + + if (!empty($ticket_data['claim_amount'])) { + $errorDetails[] = 'Claim Amount: ₹' . number_format($ticket_data['claim_amount'], 2); + } + + if (!empty($ticket_data['emp_code'])) { + $errorDetails[] = 'Emp Code: ' . $ticket_data['emp_code']; + } + + if (!empty($ticket_data['policy_no'])) { + $errorDetails[] = 'Policy No: ' . $ticket_data['policy_no']; + } + + $response = [ + 'status' => false, + 'code' => 409, + 'message' => 'Duplicate claim found for ' . implode(', ', $errorDetails) + ]; + + return $this->respond($response, 200); + } + + if ($ticket_data) { $return_value = $this->ticketMasterModel->insert($ticket_data); if ($return_value) { @@ -2943,4 +2983,83 @@ class TicketController extends BaseController return $this->respond(['status' => true, 'code' => 200, 'message' => 'IR docs saved successfully', 'data' => $required_docs], 200); } + + public function claimMisFileList() + { + $data['page_name'] = "Cliam MIS Files"; + $data['claim_mis_file_list'] = $this->claimmisFileModel + ->select('claims_mis_files.*, user_profiles.first_name as user_name') + ->join('user_profiles', 'claims_mis_files.created_by = user_profiles.id') + ->where('claims_mis_files.is_active', 1) + ->orderBy('claims_mis_files.id', 'desc') + ->findAll(); + $data['tpa_list'] = $this->TPAModel->where('is_active', 1)->findAll(); + + return $this->loadLayout('claim_mis_file_list', $data); + } + + public function uploadClaimMisFile() + { + $file = $this->request->getFile('file'); + $data = $this->request->getPost(); + + if(isset($data['from_date']) && !empty($data['from_date'])){ + $data['from_date'] = change_date_format($data['from_date'], 'd/m/Y', 'Y-m-d'); + } + + if(isset($data['to_date']) && !empty($data['to_date'])){ + $data['to_date'] = change_date_format($data['to_date'], 'd/m/Y', 'Y-m-d'); + } + + $file_path = WRITEPATH.'uploads/claims_mis'; + $file_name = file_Upload_for_lead($file, $file_path); + + if(!empty($file_name)){ + $data['file_name'] = $file_name; + } + + $response = $this->claimmisFileModel->insert($data); + + if($response){ + return $this->respond(['status'=>true, 'code'=>200, 'message'=>'MIS file uploaded successfully'], 200); + }else{ + return $this->respond(['status'=>true, 'code'=>500, 'message'=>'Failed to upload'], 200); + } + } + + public function downloadClaimMisFile() + { + try { + + $file_id = $this->request->getGet('id'); + + // Find record + $record = $this->claimmisFileModel->where('id', $file_id)->first(); + // dd($record); + + if (!$record) { + $data['message'] = 'File record not found'; + return view('errors/404', $data); + } + + $uploadPath = WRITEPATH . 'uploads/claims_mis/'; + $filePath = $uploadPath . $record['file_name']; + // dd($filePath); + + if (!file_exists($filePath)) { + $data['message'] = 'The Physical File Not Found'; + return view('errors/404', $data); + } + + // Force file download + return $this->response->download($filePath, null)->setFileName($record['file_name']); + + } catch (\Exception $e) { + // return $this->failServerError($e->getMessage()); + $this->myLogger->logme('error', 'Error occoured in downloadClaimMisFile : ' . $e->getMessage()); + $data['message'] = 'File record not found'; + return view('errors/404', $data); + } + } + } diff --git a/app/Filters/AuthMVC.php b/app/Filters/AuthMVC.php index 1e0be969..efda2976 100755 --- a/app/Filters/AuthMVC.php +++ b/app/Filters/AuthMVC.php @@ -5,13 +5,30 @@ use CodeIgniter\Filters\FilterInterface; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; +use App\Libraries\AuthLogout; + class AuthMVC implements FilterInterface { public function before(RequestInterface $request, $arguments = null) { - if (!check_session() && !check_cookie()) { - - return redirect()->to(base_url('/login')); + + if (!check_session()) + { + return AuthLogout::logout(); + } + + // if (!check_cookie()) + // { + // return AuthLogout::logout(); + // } + + // Fingerprint validation + $fp = hash('sha256', + $request->getUserAgent()->getAgentString() . '|' . $request->getIPAddress() + ); + + if (session()->get('fingerprint') !== $fp) { + return AuthLogout::logout(); } } diff --git a/app/Filters/Cors.php b/app/Filters/Cors.php index 6aae35d9..bb8d5b8b 100644 --- a/app/Filters/Cors.php +++ b/app/Filters/Cors.php @@ -143,7 +143,7 @@ class Cors implements FilterInterface // If wildcard present in configuration, allow any origin if (in_array('*', $this->allowedOrigins, true)) { - $this->log('Origin allowed: wildcard match', ['origin' => $origin]); + // $this->log('Origin allowed: wildcard match', ['origin' => $origin]); return true; } @@ -159,10 +159,10 @@ class Cors implements FilterInterface // 1. Exact match (including scheme and port) // Example: https://example.com matches https://example.com if (strcasecmp($allowed, $origin) === 0) { - $this->log('Origin allowed: exact match', [ - 'origin' => $origin, - 'matched_rule' => $allowed - ]); + // $this->log('Origin allowed: exact match', [ + // 'origin' => $origin, + // 'matched_rule' => $allowed + // ]); return true; } @@ -178,11 +178,11 @@ class Cors implements FilterInterface // Check if origin host ends with the allowed root domain if ($originHost === $allowedRoot || str_ends_with($originHost, '.' . $allowedRoot)) { - $this->log('Origin allowed: wildcard subdomain match', [ - 'origin' => $origin, - 'matched_rule' => $allowed, - 'origin_host' => $originHost - ]); + // $this->log('Origin allowed: wildcard subdomain match', [ + // 'origin' => $origin, + // 'matched_rule' => $allowed, + // 'origin_host' => $originHost + // ]); return true; } } @@ -191,11 +191,11 @@ class Cors implements FilterInterface // Example: example.com matches both http://example.com and https://example.com else { if (strcasecmp($allowed, $originHost) === 0) { - $this->log('Origin allowed: host match (scheme-less)', [ - 'origin' => $origin, - 'matched_rule' => $allowed, - 'origin_host' => $originHost - ]); + // $this->log('Origin allowed: host match (scheme-less)', [ + // 'origin' => $origin, + // 'matched_rule' => $allowed, + // 'origin_host' => $originHost + // ]); return true; } } @@ -320,11 +320,11 @@ class Cors implements FilterInterface // Preflight is sent by browsers before actual cross-origin requests // to check if the actual request is safe to send if ($method === 'OPTIONS') { - $this->log('Preflight request received', [ - 'origin' => $origin, - 'method' => $method, - 'uri' => (string) $request->getUri() - ]); + // $this->log('Preflight request received', [ + // 'origin' => $origin, + // 'method' => $method, + // 'uri' => (string) $request->getUri() + // ]); // Validate origin - reject if not allowed if (empty($origin) || !$this->isOriginAllowed($origin)) { @@ -346,10 +346,10 @@ class Cors implements FilterInterface $response->setStatusCode(204); $response->setBody(''); - $this->log('Preflight approved', [ - 'origin' => $origin, - 'allowed_methods' => $this->allowedMethods - ]); + // $this->log('Preflight approved', [ + // 'origin' => $origin, + // 'allowed_methods' => $this->allowedMethods + // ]); return $response; } @@ -392,10 +392,10 @@ class Cors implements FilterInterface // Add CORS headers to the response $this->addCorsHeaders($response, $request, $origin, false); - $this->log('CORS headers added to response', [ - 'origin' => $origin, - 'status' => $response->getStatusCode() - ]); + // $this->log('CORS headers added to response', [ + // 'origin' => $origin, + // 'status' => $response->getStatusCode() + // ]); } /** diff --git a/app/Filters/GlobalPostFileUploadGuard.php b/app/Filters/GlobalPostFileUploadGuard.php new file mode 100644 index 00000000..4cc82ba8 --- /dev/null +++ b/app/Filters/GlobalPostFileUploadGuard.php @@ -0,0 +1,147 @@ + ['jpg', 'jpeg'], + 'image/png' => ['png'], + 'image/gif' => ['gif'], + 'image/webp' => ['webp'], + 'image/svg+xml' => ['svg'], + 'application/pdf' => ['pdf'], + 'application/msword' => ['doc'], + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => ['docx'], + 'application/vnd.oasis.opendocument.text' => ['odt'], + 'text/rtf' => ['rtf'], + 'application/rtf' => ['rtf'], + 'application/vnd.ms-excel' => ['xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'], + 'application/vnd.oasis.opendocument.spreadsheet' => ['ods'], + 'text/csv' => ['csv'], + 'application/csv' => ['csv'], + 'text/plain' => ['txt', 'csv'], + ]; + + protected array $blockedExtensions = [ + 'php', 'phtml', 'pht', 'phar', 'php3', 'php4', 'php5', 'php7', 'php8', 'phps', + 'cgi', 'fcgi', 'pl', 'py', 'rb', 'lua', 'tcl', 'go', 'rs', 'jar', 'class', + 'exe', 'dll', 'com', 'bat', 'cmd', 'msi', 'vbs', 'ps1', 'scr', + 'sh', 'bash', 'zsh', 'apk', 'app', 'deb', 'rpm', 'bin', 'run', + 'js', 'mjs', 'jsp', 'asp', 'aspx', 'cer', 'swf', + 'env', 'ini', 'user.ini', 'htaccess', 'htpasswd', 'conf', 'config', 'log', 'sql', + 'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso', + 'lnk', 'url', 'reg', 'sys', 'drv', 'vxd', 'tmp', 'bak', 'old', 'backup', 'key', 'pem' + ]; + + public function before(RequestInterface $request, $arguments = null) + { + if ($request->getMethod() !== 'post') { + return; + } + + $files = $request->getFiles(); + if (empty($files)) { + return; + } + + foreach ($files as $inputName => $fileData) { + $this->validateFileInput($fileData, $inputName); + } + } + + private function validateFileInput($fileData, string $inputName): void + { + if (is_array($fileData)) { + foreach ($fileData as $file) { + $this->validateSingleFile($file, $inputName); + } + } else { + $this->validateSingleFile($fileData, $inputName); + } + } + + private function validateSingleFile($file, string $inputName): void + { + $request = Services::request(); + $clientIp = $request->getIPAddress(); + $uri = $request->getUri()->getPath(); + + if (!$file->isValid()) { + if ($file->getError() === UPLOAD_ERR_INI_SIZE || $file->getError() === UPLOAD_ERR_FORM_SIZE) { + $this->block("File exceeds server-side size limit", $clientIp, $uri, $inputName, $file->getClientName(), 'unknown', 'unknown', 0); + } + return; + } + + $originalName = $file->getClientName(); + $extension = strtolower($file->getExtension()); + $mime = $file->getMimeType(); + $size = $file->getSize(); + + // --- 1. Fixed Null Byte & Path Traversal Check --- + if (preg_match('/\0|[\/\\\]/', $originalName)) { + $this->block("Malicious filename characters", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 2. Double Extension Attack Check --- + if (preg_match('/\.(php|phtml|phar|exe|sh|bat|cmd|js|jsp|asp|aspx|py|pl)\./i', $originalName)) { + $this->block("Double extension attack", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 3. Forbidden Extension --- + if (in_array($extension, $this->blockedExtensions, true)) { + $this->block("Forbidden extension", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 4. File Size Limit --- + if ($size > $this->maxFileSize) { + $this->block("File too large", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 5. MIME Allow-list Check --- + if (!array_key_exists($mime, $this->allowedMimeMap)) { + $this->block("MIME type not allowed ($mime)", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 6. MIME-Extension Consistency --- + if (!in_array($extension, $this->allowedMimeMap[$mime], true)) { + $this->block("MIME-extension mismatch", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + } + + private function block(string $reason, string $ip, string $uri, string $field, string $filename, string $mime, string $ext, int $size): void + { + log_message('critical', + '[UPLOAD_BLOCKED] {reason} | IP: {ip} | URI: {uri} | Field: {field} | File: {file} | MIME: {mime} | EXT: {ext} | SIZE: {size}', + ['reason'=>$reason, 'ip'=>$ip, 'uri'=>$uri, 'field'=>$field, 'file'=>$filename, 'mime'=>$mime, 'ext'=>$ext, 'size'=>$size] + ); + + $response = Services::response(); + $response->setStatusCode(403) + ->setJSON([ + 'status' => 'error', + 'message' => 'File upload rejected: Security policy violation.', + 'debug' => (ENVIRONMENT === 'development') ? $reason : null + ]) + ->send(); + exit; + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {} +} \ No newline at end of file diff --git a/app/Filters/SecurityInputFilter.php b/app/Filters/SecurityInputFilter.php new file mode 100644 index 00000000..c23f7907 --- /dev/null +++ b/app/Filters/SecurityInputFilter.php @@ -0,0 +1,130 @@ +/i', + + // JavaScript execution vectors + '/javascript\s*:/i', + '/vbscript\s*:/i', + '/data\s*:\s*text\/html/i', + + // Inline event handlers (strong signal) + '/on\w+\s*=\s*["\']?/i', + + // Dangerous HTML tags + '/<\s*iframe\b/i', + '/<\s*object\b/i', + '/<\s*embed\b/i', + '/<\s*applet\b/i', + '/<\s*img\b/i', + + // Image-based execution + '/<\s*img\b[^>]*on\w+/i', + + // SVG-based execution (modern bypass) + '/<\s*svg\b/i', + '/<\s*math\b/i', + + // Meta refresh redirect + '/<\s*meta\b[^>]*http-equiv\s*=\s*["\']?refresh/i', + + // HTML injection via src/href + '/<\s*\w+\b[^>]*(src|href)\s*=\s*["\']?\s*(javascript|data)\s*:/i' + ]; + + + public function before(RequestInterface $request, $arguments = null) + { + $logger = Services::mylogger(); + $response = Services::response(); + + // Collect all user-controlled input + $inputs = array_merge( + $request->getGet(), + $request->getPost() + ); + + if (empty($inputs)) { + return; + } + + foreach ($inputs as $field => $value) { + if (is_array($value)) { + $value = json_encode($value); + } + + // Step 1: Canonicalization (VERY IMPORTANT) + $canonical = $this->canonicalize($value); + + // Step 2: Trim (hygiene) + $canonical = trim($canonical); + + // Step 3: Detection (signal-only) + if ($this->detectXss($canonical)) { + + // 🔐 Log intent, not data + $logger->logme('critical','SECURITY_BLOCKED_REQUEST - '. json_encode([ + 'ip' => $request->getIPAddress(), + 'method' => $request->getMethod(), + 'uri' => current_url(), + 'field' => $field, + 'attack' => 'XSS_PATTERN', + 'length' => strlen($canonical), + 'hash' => hash('sha256', $canonical), + ])); + + // ⛔ Block request + return $response + ->setStatusCode(403) + ->setJSON([ + 'status' => 403, + 'error' => 'Forbidden', + 'message' => 'Malicious input detected' + ]); + } + } + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + // no-op + } + + /** + * Canonicalization prevents encoded bypass + */ + private function canonicalize(string $value): string + { + $value = urldecode($value); + $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Remove invisible control characters + return preg_replace('/[\x00-\x1F\x7F]/u', '', $value); + } + + private function detectXss(string $value): bool + { + foreach ($this->xssPatterns as $pattern) { + if (preg_match($pattern, $value)) { + return true; + } + } + return false; + } +} diff --git a/app/Helpers/session_helper.php b/app/Helpers/session_helper.php index 31162658..640de0e7 100755 --- a/app/Helpers/session_helper.php +++ b/app/Helpers/session_helper.php @@ -21,7 +21,7 @@ if(!function_exists('check_cookie')){ 'userProfile' => $value['userProfile'], 'user_team' => $user_team, ]; - set_session_data($session_data); + // set_session_data($session_data); // $this->getUserDeviceInfo($user->id, 'NhanceUser'); // return redirect()->to(base_url('/dashboard/view')); return true; @@ -33,6 +33,7 @@ if(!function_exists('check_cookie')){ }else{ return false; } + } } if (!function_exists('check_session')) { @@ -40,7 +41,7 @@ if (!function_exists('check_session')) { { // $ci =& get_instance(); $session = \Config\Services::session(); - return $session->get('isLoggedIn'); + return $session->get('isLoggedIn') === true; } } @@ -201,7 +202,6 @@ if (!function_exists('get_chatbot_session_info')) { } -} diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index fe7898e3..15d873eb 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -6,6 +6,7 @@ use App\Models\BatchFileModelFileModel; use App\Controllers\GoogleDriveController; use App\Models\BatchFileModel; use App\Controllers\ApiServiceController; +use App\Models\TicketMasterModel; // File: app/Helpers/Uuid_helper.php @@ -1004,3 +1005,34 @@ if (!function_exists('canSendOtp')) { } } +if (!function_exists('checkDuplicateClaim')) { + + function checkDuplicateClaim(array $params): bool + { + $ticketMaster = new TicketMasterModel(); + $query = $ticketMaster->where('is_active', 1); + + if(empty($params['doa']) && empty($params['claim_amount'])){ + return false; + } + + $hasValidCondition = false; + + foreach ($params as $key => $value) { + if ($value !== null && $value !== '') { + $query->where($key, $value); + $hasValidCondition = true; + } + } + + if (!$hasValidCondition) { + return false; + } + + $result = $query->countAllResults(); + // print_r($ticketMaster->getLastQuery()->getQuery()); die; + if($result > 0){ return true; }else{ return false; } + } +} + + diff --git a/app/Libraries/AuthLogout.php b/app/Libraries/AuthLogout.php new file mode 100644 index 00000000..cfb10051 --- /dev/null +++ b/app/Libraries/AuthLogout.php @@ -0,0 +1,42 @@ +regenerate(true); + + // Destroy CI session + $session->destroy(); + + // Kill PHP session cookie safely + if (ini_get('session.use_cookies')) { + $params = session_get_cookie_params(); + + setcookie( + session_name(), // DO NOT hardcode cookie name + '', + time() - 42000, + $params['path'], + $params['domain'], + $params['secure'], + $params['httponly'] + ); + } + + session_write_close(); + + // Redirect with anti-cache headers + return redirect()->to(base_url('login')) + ->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->setHeader('Pragma', 'no-cache') + ->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT'); + } +} diff --git a/app/Models/ClaimMisFileModel.php b/app/Models/ClaimMisFileModel.php new file mode 100644 index 00000000..057f9cd0 --- /dev/null +++ b/app/Models/ClaimMisFileModel.php @@ -0,0 +1,57 @@ +join('insurer_branch', 'insurer_branch.id = cp.insurer_branch_id') ->join('tpa', 'tpa.id = cp.tpa_id') ->where("ep.tpa_id IS NOT NULL AND ep.tpa_id <> ''") - ->where('e.emp_status', 'active') ->where('e.is_active', '1') - ->where('ep.status', 'active') + ->whereIn('ep.status', ['active', 'expired']) + ->whereIn('e.emp_status', ['active', 'expired']) ->where('ep.is_active', '1') ->where('e.emp_code', $emp_code) ->where('ep.client_policy_id', $client_policy_id) @@ -1618,9 +1618,9 @@ class EmployeePolicyModel extends Model ->join('insurer_branch', 'insurer_branch.id = cp.insurer_branch_id') ->join('tpa', 'tpa.id = cp.tpa_id') ->where("ep.tpa_id IS NOT NULL AND ep.tpa_id <> ''") - ->where('e.emp_status', 'active') ->where('e.is_active', '1') - ->where('ep.status', 'active') + ->whereIn('ep.status', ['active', 'expired']) + ->whereIn('e.emp_status', ['active', 'expired']) ->where('ep.is_active', '1') ->where('ep.rand_string', $rand_string) ->get() diff --git a/app/Models/InvoiceModel.php b/app/Models/InvoiceModel.php index a2e241dc..a2284d5b 100644 --- a/app/Models/InvoiceModel.php +++ b/app/Models/InvoiceModel.php @@ -206,9 +206,8 @@ class InvoiceModel extends Model WHEN payout_status = 2 THEN 'Completed' END AS status_text, - partner_agent.name as agent_name ") - ->join('partner_agent', 'partner_invoice.agent_id = partner_agent.id') + // ->join('partner_agent', 'partner_invoice.agent_id = partner_agent.id') ->where('partner_invoice.is_active', 1) ->where('partner_invoice.id', $invoice_id) ->first(); diff --git a/app/Views/claim_mis_file_list.php b/app/Views/claim_mis_file_list.php new file mode 100644 index 00000000..4ce6d111 --- /dev/null +++ b/app/Views/claim_mis_file_list.php @@ -0,0 +1,388 @@ + + +
+
+
+ + + + + + + + + + + + $file) { + ?> + + + + + + + + + +
S.No File nameUser/TimeAction
' . $file['user_name'] . '' ?> + + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/app/Views/employee_data_list.php b/app/Views/employee_data_list.php index a11e3d85..517adfa5 100755 --- a/app/Views/employee_data_list.php +++ b/app/Views/employee_data_list.php @@ -197,20 +197,20 @@ - + View E-Card - + Send E-Card Mail - + Re-Generate E-Card - + Re-Generate E-Card diff --git a/app/Views/fedeploy.php b/app/Views/fedeploy.php index 906bf5f7..eca24795 100644 --- a/app/Views/fedeploy.php +++ b/app/Views/fedeploy.php @@ -9,35 +9,70 @@
- +
- + +
- +
+ diff --git a/app/Views/invoice_policy_mapping.php b/app/Views/invoice_policy_mapping.php index c103ec1d..3c357172 100644 --- a/app/Views/invoice_policy_mapping.php +++ b/app/Views/invoice_policy_mapping.php @@ -525,7 +525,8 @@ table.dataTable tbody td { padding: 4px 4px !important; } function loadPolicies() { // const agentId = getEl('agentSelect')?.value || ''; const posId = getEl('posSelect')?.value || ''; - console.log('-->',posId); + console.log(':) POS --> ',posId); + console.log(window.allPolicies); const policyTillDate = getEl('policyTillDate')?.value || ''; const list = getEl('policyListBody'); if (!list) return; @@ -623,7 +624,6 @@ table.dataTable tbody td { padding: 4px 4px !important; } if (selectedPolicies.size === 0) { summaryBar.classList.remove('show') - const summaryBar = getEl('summaryBar');; if (selectedCountBadge) selectedCountBadge.style.display = 'none'; totalPoliciesEl.textContent = '0'; totalAmountEl.textContent = '₹0.00'; diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index d4f88fbd..73c56916 100755 --- a/app/Views/layout/header.php +++ b/app/Views/layout/header.php @@ -1863,6 +1863,9 @@
  • Claim Dump Upload
  • +
  • + Claim MIS Upload +
  • diff --git a/app/Views/payout_list.php b/app/Views/payout_list.php index ab2bca29..9bc8d9c8 100644 --- a/app/Views/payout_list.php +++ b/app/Views/payout_list.php @@ -313,13 +313,13 @@ "<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>", lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]], buttons: [ - { - text: 'Add', - className: 'btn app-btn-primary mr-2', - action: function (e, dt, node, config) { - window.location.href = ""; - } - }, + // { + // text: 'Add', + // className: 'btn app-btn-primary mr-2', + // action: function (e, dt, node, config) { + // window.location.href = ""; + // } + // }, { extend: 'collection', text: ' Export ', diff --git a/app/Views/policy_transaction_inception_list.php b/app/Views/policy_transaction_inception_list.php index 482429bf..14e54f2b 100644 --- a/app/Views/policy_transaction_inception_list.php +++ b/app/Views/policy_transaction_inception_list.php @@ -334,7 +334,7 @@ table.dataTable tbody td {