diff --git a/app/Config/Acl.php b/app/Config/Acl.php index 1fbea05..0ef07e7 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -14,8 +14,8 @@ class Acl '#^/loginPos#' => ['public' => true], '#^/getVerifyPosMobileNo#' => ['public' => true], '#^/getVerifiedPosUserData#' => ['public' => true], - '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]], - '#^/fedeploy#' => ['roles' => [ADMIN_ROLE_ID]], + '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], + '#^/fedeploy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], // ===================== PUBLIC DOWNLOADS / FORMS ===================== '#^/download-#' => ['public' => true], @@ -59,13 +59,13 @@ class Acl // ===================== LOGS ===================== '#^/logs#' => [ - 'roles' => [ADMIN_ROLE_ID], + 'roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [] ], // ===================== INTERNAL TEST ===================== '#^/test#' => [ - 'roles' => [ADMIN_ROLE_ID], + 'roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [] ], @@ -78,8 +78,10 @@ class Acl // ===================== DEFAULT DENY (ZERO TRUST) ===================== '#^/#' => [ - 'roles' => [ADMIN_ROLE_ID], + 'roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [] ], + // ===================== SAML ===================== + '#^/saml#' => ['public' => true], ]; } diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 96d34a1..67cae46 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -66,7 +66,7 @@ class Filters extends BaseConfig public array $globals = [ 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], - 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*','processjob', 'getPreEmployeePolicyCount']], + 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*','processjob', 'getPreEmployeePolicyCount','/saml/*']], 'Cors', 'SecurityInputFilter' => ['except' => ['/client/notification/create','test_mail'] ], 'GlobalPostFileUploadGuard', diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 8459a62..08fcb2b 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -571,3 +571,18 @@ $routes->group('test',function($routes){ $routes->get('logo_renaming','TestingController::logo_renaming'); }); + + + +//saml - routes +// $routes->group("employeeRest", ['filter' => ['appSignature','AuthApiRateLimitFilter'] ], function ($routes) { + + $routes->get('saml/login', 'SamlController::login'); + $routes->match(['get', 'post'], 'saml/slo', 'SamlController::slo'); + +// }); + +$routes->post('saml/acs', 'SamlController::acs'); +$routes->get('saml/logout', 'SamlController::logout'); +$routes->get('saml/metadata', 'SamlController::metadata'); + diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 3d989a0..d8c4243 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -1260,7 +1260,7 @@ class ClientController extends AdminController $data['is_addon'] = 1; // Base Policy - } else if ($policy_type_id == 4 || $policy_type_id == 5) { + } else if ($policy_type_id == 4 || $policy_type_id == 5 || $policy_type_id == 72) { $data['is_addon'] = 2; // SI TOPUP @@ -1416,7 +1416,7 @@ class ClientController extends AdminController $data['is_addon'] = 1; // Base Policy - } else if ($policy_type_id == 4 || $policy_type_id == 5) { + } else if ($policy_type_id == 4 || $policy_type_id == 5 || $policy_type_id == 72) { $data['is_addon'] = 2; // SI TOPUP @@ -2108,7 +2108,7 @@ class ClientController extends AdminController $subject = $record['policy_type']; $policy_type_id = $record['policy_type_id']; - if (preg_match($gmc_pattern, $subject)) { + if (preg_match($gmc_pattern, $subject) || $policy_type_id == 72) { $search_term = 'GMC'; } else if (preg_match($gpa_pattern, $subject) || $policy_type_id == 6 || $policy_type_id == 7) { $search_term = 'GPA'; @@ -3330,20 +3330,119 @@ class ClientController extends AdminController $client_policy_id = $this->request->getPost("client_policy_id"); $policy_terms = $this->request->getPost("policy_terms"); - - if (!empty($policy_terms)) { - $policy_terms = json_decode($policy_terms, true); - $policy_terms['is_payable_employee']['self'] = 0; - $policy_terms = json_encode($policy_terms); - } - - + $policy_terms = json_decode($policy_terms, true); $record = $this->clientPolicyModel->where('id', $client_policy_id)->first(); + if (empty($policy_terms)) { + return $this->respond(['status' => false, 'code' => 404, 'message' => 'Policy terms data could not be empty', 'formdata' => $this->request->getPost()], 200); + } + if ($record) { + $data = []; - $update = $this->clientPolicyModel->where('id', $client_policy_id)->set('policy_terms', $policy_terms)->update(); + if ((int)$record['policy_type_id'] === 72) { + $data['sum_insured'] = $policy_terms['sum_insured'] ?? 0; + $data['multiple_sum_insured'] = $policy_terms['multiple_sum_insured'] ?? []; + $data['family_floater'] = $policy_terms['family_floater'] ?? 0; + $data['family_floaters'] = $policy_terms['family_floaters'] ?? []; + $data['age_ratio']['self']['min'] = $policy_terms['self_min_age'] ?? 0; + $data['age_ratio']['self']['max'] = $policy_terms['self_max_age'] ?? 0; + $data['age_ratio']['spouse']['min'] = $policy_terms['spouse_min_age'] ?? 0; + $data['age_ratio']['spouse']['max'] = $policy_terms['spouse_max_age'] ?? 0; + $data['age_ratio']['child']['min'] = $policy_terms['child_min_age'] ?? 0; + $data['age_ratio']['child']['max'] = $policy_terms['child_max_age'] ?? 0; + $data['age_ratio']['elders']['min'] = $policy_terms['other_member_min_age'] ?? 0; + $data['age_ratio']['elders']['max'] = $policy_terms['other_member_max_age'] ?? 0; + + $temp_family_floaters = $data['family_floaters']; + $data['family_floaters'] = []; + $data['family_floaters']['self'] = in_array("self", $temp_family_floaters) ? 1 : 0; + $data['family_floaters']['spouse'] = in_array("spouse", $temp_family_floaters) ? 1 : 0; + + if (count($temp_family_floaters)) { + $children_index = 0; + $elders_index = 1; + if (count($temp_family_floaters) == 3) { + $children_index = 1; + $elders_index = 2; + } else if (count($temp_family_floaters) >= 4) { + $children_index = 2; + $elders_index = 3; + } + + $data['family_floaters']['childrens'] = (int)($temp_family_floaters[$children_index] ?? 0); + $elders_type = $temp_family_floaters[$elders_index] ?? '0'; + + if ($elders_type == '1P') { + $data['family_floaters']['parents'] = 1; + $data['family_floaters']['parents-in-law'] = 0; + $data['family_floaters']['either-parents-pil'] = 0; + } else if ($elders_type == '2P') { + $data['family_floaters']['parents'] = 2; + $data['family_floaters']['parents-in-law'] = 0; + $data['family_floaters']['either-parents-pil'] = 0; + } else if ($elders_type == '1PIL') { + $data['family_floaters']['parents'] = 0; + $data['family_floaters']['parents-in-law'] = 1; + $data['family_floaters']['either-parents-pil'] = 0; + } else if ($elders_type == '2PIL') { + $data['family_floaters']['parents'] = 0; + $data['family_floaters']['parents-in-law'] = 2; + $data['family_floaters']['either-parents-pil'] = 0; + } else if ($elders_type == '2EPORPIL') { + $data['family_floaters']['parents'] = 0; + $data['family_floaters']['parents-in-law'] = 0; + $data['family_floaters']['either-parents-pil'] = 2; + } else if ($elders_type == 'EPORPIL') { + $data['family_floaters']['parents'] = 0; + $data['family_floaters']['parents-in-law'] = 0; + $data['family_floaters']['either-parents-pil'] = 1; + } else if ($elders_type == '4EPORPIL') { + $data['family_floaters']['parents'] = 2; + $data['family_floaters']['parents-in-law'] = 2; + $data['family_floaters']['either-parents-pil'] = 0; + } else { + $data['family_floaters']['parents'] = 0; + $data['family_floaters']['parents-in-law'] = 0; + $data['family_floaters']['either-parents-pil'] = 0; + } + } + + $data['family_floaters']['elders_count'] = $this->request->getPost("elder_member_count") ? $this->request->getPost("elder_member_count") : 0; + $data['mode_of_serviceability'] = $policy_terms['mode_of_serviceability'] ?? ''; + $data['eligibility'] = $policy_terms['eligibility'] ?? ''; + $data['total_sum_insured_limit'] = $policy_terms['total_sum_insured_limit'] ?? 'INR 15000'; + $data['in_person_doctor_consultation'] = $policy_terms['in_person_doctor_consultation'] ?? ''; + $data['prescribed_lab_test_pathology_radiology'] = $policy_terms['prescribed_lab_test_pathology_radiology'] ?? ''; + $data['prescribed_pharmacy'] = $policy_terms['prescribed_pharmacy'] ?? ''; + $data['dental'] = $policy_terms['dental'] ?? ''; + $data['vision'] = $policy_terms['vision'] ?? ''; + $data['vaccination_for_children_and_adults'] = $policy_terms['vaccination_for_children_and_adults'] ?? ''; + $data['special_condition_label'] = $policy_terms['special_condition_label'] ?? []; + $data['special_condition_input'] = $policy_terms['special_condition_input'] ?? []; + $data['enrollment_display_key'] = $this->otherPolicyTermsDisplayKeyConstruct($policy_terms); + $data['is_payable_employee'] = [ + 'self' => $this->request->getPost('is_payable_employee_for_self') ? 1 : 0, + 'spouse' => $this->request->getPost('is_payable_employee_for_spouse') ? 1 : 0, + 'childern' => $this->request->getPost('is_payable_employee_for_child') ? 1 : 0, + 'elders' => $this->request->getPost('is_payable_employee_for_elders') ? 1 : 0, + ]; + } else { + foreach ($policy_terms as $key => $value) { + if (str_ends_with($key, '_display')) { + $original_key = substr($key, 0, -8); + $newKey = implode(' ', array_map('ucfirst', explode('_', $original_key))); + $data['enrollment_display_key'][$newKey] = $policy_terms[$original_key] ?? " "; + } else { + $data[$key] = $value; + } + } + $data['is_payable_employee']['self'] = 0; + } + + $policy_terms_json = json_encode($data); + $update = $this->clientPolicyModel->where('id', $client_policy_id)->set('policy_terms', $policy_terms_json)->update(); if ($update) { return $this->respond(['status' => true, 'code' => 200, 'message' => 'Data updated successfully', 'client_policy_id' => $client_policy_id], 200); } else { @@ -3355,6 +3454,49 @@ class ClientController extends AdminController } } + public function otherPolicyTermsDisplayKeyConstruct($data) + { + $labels = $data['special_condition_label'] ?? []; + $values = $data['special_condition_input'] ?? []; + $special_conditions = []; + $display_fields = []; + + foreach ($labels as $i => $label) { + $value = $values[$i] ?? ''; + if (trim((string)$label) === '' || trim((string)$value) === '') { + continue; + } + $special_conditions[$label] = $value; + } + + $labelMap = [ + 'mode_of_serviceability' => 'Mode Of Serviceability', + 'eligibility' => 'Eligibility', + 'total_sum_insured_limit' => 'Total Sum Insured Limit', + 'in_person_doctor_consultation' => 'In Person Doctor Consultation', + 'prescribed_lab_test_pathology_radiology' => 'Prescribed Lab Test Pathology Radiology', + 'prescribed_pharmacy' => 'Prescribed Pharmacy', + 'dental' => 'Dental', + 'vision' => 'Vision', + 'vaccination_for_children_and_adults' => 'Vaccination For Children And Adults', + ]; + + foreach ($data as $key => $value) { + if (!str_ends_with($key, '_display') || empty($value)) { + continue; + } + $baseKey = substr($key, 0, -8); + $baseValue = $data[$baseKey] ?? ''; + if (trim((string)$baseValue) === '') { + continue; + } + $label = $labelMap[$baseKey] ?? ucwords(str_replace('_', ' ', $baseKey)); + $display_fields[$label] = $baseValue; + } + + return array_merge($display_fields, $special_conditions); + } + public function checkPolicyType($policy_type_id, $client_branch_id, $client_id) { @@ -4128,7 +4270,7 @@ class ClientController extends AdminController $payable_arr = ["self" => 1,"spouse" => 1,"childern" => 1,"elders" => 1,]; - } else if (in_array($data[$i]['policy_type_id'], [4, 5])) { + } else if (in_array($data[$i]['policy_type_id'], [4, 5, 72])) { $payable_arr = ["self" => 1,"spouse" => 1,"childern" => 1,"elders" => 1,]; } @@ -4136,7 +4278,7 @@ class ClientController extends AdminController // Initialize an empty array for the ordered policy terms $orderedPolicyTerms = []; - if(in_array($data[$i]['policy_type_id'], [2,3,4,5])){ + if(in_array($data[$i]['policy_type_id'], [2,3,4,5,72])){ // Set default value of copayzonewisecopay to "empty" // $ans = isset($policyTerms['copayzonewisecopay']) ? $policyTerms['copayzonewisecopay'] : 'empty'; @@ -4239,7 +4381,7 @@ class ClientController extends AdminController } } - if(in_array($data[$i]['policy_type_id'], [2,3,4,5])){ + if(in_array($data[$i]['policy_type_id'], [2,3,4,5,72])){ if (!isset($policyTerms['waiver_of_90_days_waiting_period'])) { $policyTerms['waiver_of_90_days_waiting_period'] = ""; diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 8541d19..2245a06 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -239,7 +239,7 @@ class EmployeeRestController extends AdminController ->where('is_active', 1) ->first(); - if(in_array($clientPolicyData['policy_type_id'], [3,4,5])){ + if(in_array($clientPolicyData['policy_type_id'], [3,4,5,72])){ $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($clientPolicyData['base_policy'], $data[0]->emp_code); }else{ $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($data[0]->client_policy_id, $data[0]->emp_code); @@ -284,6 +284,7 @@ class EmployeeRestController extends AdminController $item->gender = $this->GenderMap($item->relationship , $item->emp_code); $item->dob = $this->convertDateFormatYMD($item->dob); $item->emp_status = 'draft'; + $item->is_dependent_modified = 1; $item->band = $this->getSelfBand($item->emp_code,$item->client_id,$item->client_branch_id); // dd($item); $employee = $this->employeeModel->insert($item); @@ -564,7 +565,7 @@ class EmployeeRestController extends AdminController $this->employeeModel->where('id', $this->request->getGet('id') ) ->where('is_active', 1 ) - ->set(['emp_status' => 'truncated', 'is_active' => 0]) + ->set(['emp_status' => 'truncated', 'is_active' => 0, 'is_dependent_modified' => 0]) ->update(); } @@ -609,7 +610,7 @@ class EmployeeRestController extends AdminController ->where('is_active', 1) ->first(); - if(in_array($clientPolicyData['policy_type_id'], [3,4,5])){ + if(in_array($clientPolicyData['policy_type_id'], [3,4,5,72])){ $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($clientPolicyData['base_policy'], $requestData[0]->emp_code); }else{ $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($requestData[0]->client_policy_id, $requestData[0]->emp_code); @@ -2621,7 +2622,7 @@ class EmployeeRestController extends AdminController //array_push($PolicyData, $responce); - }else if($array['is_addon'] == 2 && $array['policy_type_id'] == 4)//Topup policy + }else if(($array['is_addon'] == 2 && $array['policy_type_id'] == 4))//Topup policy { @@ -2685,6 +2686,70 @@ class EmployeeRestController extends AdminController } + }else if(($array['is_addon'] == 2 && $array['policy_type_id'] == 72))//OPD policy + { + + + $whereArray = []; + foreach ( $decodedArray->family_floaters as $key => $value) { + if($value != 0){ + if($key == 'parents'){ $text = ["parent"]; } + else if($key == 'childrens'){ $text = ["child"]; } + else if($key == 'parents-in-law'){ $text = ["parent_in_law"];} + else if($key ==='either-parents-pil') { $text = ["parent", "parent_in_law"];} + else{ $text = [$key]; } + $whereArray = array_merge($whereArray, $text); + } + } + + + $getAddOnType = $this->clientPolicyModel->where('id',$array['base_policy'])->where('policy_status', 1)->get()->getRow(); + $basePolicyAddOnType = $getAddOnType->is_addon; + // if is_addon value is 1 it is GMC if not it is one of the Add On policy + if($basePolicyAddOnType == 1){ $is_addon_value = 0; }else{ $is_addon_value = 1; } + $only_si_array = []; + $only_si_value = 0; + $only_si_premium_value = 0; + $only_si_gst_value = 0; + $BasePolicyEmployeeData = $this->employeeModel->where('is_active', 1 )->where('emp_code',$this->request->getGet('emp_code'))->where('client_id',$this->request->getGet('client_id'))->where('is_addon_value',$is_addon_value)->whereIn('family_floater_key',$whereArray)->findAll(); + foreach ($BasePolicyEmployeeData as $key => $value) { + + $employee_policy = $this->employeePolicyModel->where('employee_id',$value['id'])->where('client_policy_id',$array['id'])->where('is_active', 1 )->get()->getRow(); + if(isset($employee_policy->basic_cover_si)){ $only_si_value = ($only_si_value == 0) ? $employee_policy->basic_cover_si : $only_si_value; } + if(isset($employee_policy->payable_employee) && $employee_policy->payable_employee == 1) + { + if(isset($employee_policy->rata_premimum)){ $only_si_premium_value = $only_si_premium_value + $employee_policy->rata_premimum;} + if(isset($employee_policy->gst)){ $only_si_gst_value = $only_si_gst_value + $employee_policy->gst;} + } + $temp3['is_value_exist'] = true; + $temp3['data']['employee_id'] = $value['id']; + $temp3['data']['relationship'] = $value['relationship']; + $temp3['data']['name'] = $value['name']; + $temp3['data']['dob'] = $this->convertDateFormatDMY($value['dob']); + $temp3['data']['client_policy_id'] = $array['id']; + $temp3['data']['basic_cover_si'] = isset($employee_policy->basic_cover_si) ? $employee_policy->basic_cover_si : null; + $temp3['data']['premium'] = isset($employee_policy->premium) ? $employee_policy->premium : null; + array_push($only_si_array,$temp3); + + } + + $responce['family_floaters_of_only_si_array'] = $only_si_array; + $responce['family_floaters_of_only_si_value'] = $only_si_value; + if($array['is_premium_summery']){ + $responce['family_floaters_of_only_si_premium_value'] = round($only_si_premium_value); + $responce['family_floaters_of_only_si_gst_value'] = $only_si_gst_value; + }else{ + $responce['family_floaters_of_only_si_premium_value'] = 0; + $responce['family_floaters_of_only_si_gst_value'] = 0; + } + + + + if($this->request->getGet('policy') == 'GMC-OPD'){ + return $this->respond(['status' => 'success','code' => 200,'data' => ['gmc_opd'=>$responce]], 200); + } + + }else if($array['is_addon'] == 2 && $array['policy_type_id'] == 5)//Parents Topup policy { @@ -2789,7 +2854,7 @@ class EmployeeRestController extends AdminController ->where('is_active', 1) ->first(); - if(in_array($clientPolicyData['policy_type_id'], [3,4,5])){ + if(in_array($clientPolicyData['policy_type_id'], [3,4,5,72])){ $policy = $this->findThePolicyIsOpenForEnrollment($clientPolicyData['base_policy'], $emp_code); }else{ $policy = $this->findThePolicyIsOpenForEnrollment($value, $emp_code); @@ -2905,205 +2970,193 @@ class EmployeeRestController extends AdminController //Post method - which receives client_policy id and empcode of the family. //Pull records againest emp code and calculate premium // retun array - public function calculatePremium($clientPolicyId = null , $empCode = null, $default_si = null , $client_branch_id = null)//family level + public function calculatePremium($clientPolicyId = null, $empCode = null, $default_si = null, $client_branch_id = null) //family level { - // dd($clientPolicyId, $empCode, $default_si, $client_branch_id); - helper('excel_util_helper'); - - if($this->request){ // - $client_policy_id = $this->request->getVar('client_policy_id') ?? $clientPolicyId; - $emp_code = $this->request->getVar('emp_code') ?? $empCode; - $default_si = $this->request->getVar('si') ?? $default_si;// si amt which choosed in add on policy - $client_branch_id = $this->request->getVar('client_branch_id') ?? $client_branch_id; - }else{ - //Cli and enrollment - $client_policy_id = $clientPolicyId; - $emp_code = $empCode; - $default_si = $default_si;// si amt which choosed in add on policy - $client_branch_id =$client_branch_id; - } - // dd($client_policy_id); - - - $client_id = ($this->clientPolicyModel->select('client_id')->find($client_policy_id))['client_id']; - // get policy and rack details - $policy_terms = $this->clientPolicyModel->getPolicyDetails($client_id,$client_policy_id); - $policy_type = $policy_terms[0]->is_addon; - $base_policy = $policy_terms[0]->base_policy; - $policy_terms = (array) $policy_terms[0];// convert obj to array - - //get policy slab rates - $slab_details = $this->policesModel->getPolicySlabRatesForEmpOnboard($client_policy_id,$client_id); - // print_r($slab_details);die(); - - $existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_id: $client_id,client_policy_id: $client_policy_id,emp_code: $emp_code,emp_status:['draft','enrolled'],policy_status:['draft','enrolled']); - // kint::dump($existing_famility_decalculatePremiumtails); - - //get the Auto SI amount - $auto_si_data = update_si_with_auto_si($client_id, $client_policy_id, $emp_code, $client_branch_id, $existing_famility_details); - log_message('error', '----- Auto SI Amount : {data} -----', ['data' => $auto_si_data]); - - //Change the basic cover si to the auto si amount if the auto_si_amount is not null - if(!empty($auto_si_data)){ - foreach ($existing_famility_details as $emp_code => &$records) { - $records['basic_cover_si'] = $auto_si_data; - } - unset($record); - } - - // dd($existing_famility_details); - - if(!count($existing_famility_details) && $policy_type == 2)//top up addon only - { - //get basepolicy id then pull emplist from base policy if only current policy is DA addon policy and emplist is zero - // echo 'inside'; - // $client_policy_id = $base_policy; - $existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_id: $client_id,client_policy_id: $base_policy,emp_code: $emp_code,emp_status:['draft','enrolled'],policy_status:['draft','enrolled']); - } - - $file = ['id' => null,'client_id' => $client_id,'policy_id' => $client_policy_id,'action' => 'inception']; - // dd($this->employeeModel->getLastQuery()); - // print_r($existing_famility_details);die(); - $employee_data_group_by_family = data_group_by_family($existing_famility_details,$data_source = 'db'); - // print_rr(($employee_data_group_by_family));die(); - - - $existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $client_id,client_branch_id: $client_branch_id); - - foreach ($employee_data_group_by_family as $emp_id => $family) - { - $transformed_famility_details = transform_db_data_to_excel($family); - - $data = calculate_premium_new(family_data: $transformed_famility_details,policy_terms:$policy_terms,slab_details:$slab_details,fileArr: $file,existing_units: $existing_units,default_si : $default_si); - // print_r($data); - $employee_data_group_by_family[$emp_id] = $data; - - foreach ($data as $value) { + // dd($clientPolicyId, $empCode, $default_si, $client_branch_id); + helper('excel_util_helper'); - if(!empty($value)){ - $newData = []; - $newData['employee_id'] = $value['temp']['emp_id']; - $newData['client_policy_id'] = $value['policy_details']['client_policy_id']; - $newData['status'] = "draft"; - $newData['basic_cover_si'] = $value['policy_details']['basic_cover_si']; - $newData['date_coverage'] = $value['policy_details']['date_coverage']; - $newData['policy_end_date'] = $value['policy_details']['policy_end_date']; - $newData['days'] = $value['policy_details']['days']; - + if ($this->request) { // + $client_policy_id = $this->request->getVar('client_policy_id') ?? $clientPolicyId; + $emp_code = $this->request->getVar('emp_code') ?? $empCode; + $default_si = $this->request->getVar('si') ?? $default_si; // si amt which choosed in add on policy + $client_branch_id = $this->request->getVar('client_branch_id') ?? $client_branch_id; + } else { + //Cli and enrollment + $client_policy_id = $clientPolicyId; + $emp_code = $empCode; + $default_si = $default_si; // si amt which choosed in add on policy + $client_branch_id = $client_branch_id; + } + // dd($client_policy_id); - $isExistingEmpAndPolicy = $this->employeePolicyModel->where('employee_id',$value['temp']['emp_id'])->where('client_policy_id',$value['policy_details']['client_policy_id'])->where('is_active', 1)->get()->getRow(); - if($isExistingEmpAndPolicy) - { - $this->employeePolicyModel->where('employee_id',$value['temp']['emp_id'])->where('client_policy_id',$value['policy_details']['client_policy_id'])->where('is_active', 1)->set($newData)->update(); - }else{ - $this->employeePolicyModel->insert($newData); + + $client_id = ($this->clientPolicyModel->select('client_id')->find($client_policy_id))['client_id']; + // get policy and rack details + $policy_terms = $this->clientPolicyModel->getPolicyDetails($client_id, $client_policy_id); + $policy_type = $policy_terms[0]->is_addon; + $base_policy = $policy_terms[0]->base_policy; + $policy_terms = (array) $policy_terms[0]; // convert obj to array + + //get policy slab rates + $slab_details = $this->policesModel->getPolicySlabRatesForEmpOnboard($client_policy_id, $client_id); + // print_r($slab_details);die(); + + $existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_id: $client_id, client_policy_id: $client_policy_id, emp_code: $emp_code, emp_status: ['draft', 'enrolled'], policy_status: ['draft', 'enrolled']); + // kint::dump($existing_famility_decalculatePremiumtails); + + //get the Auto SI amount + $auto_si_data = update_si_with_auto_si($client_id, $client_policy_id, $emp_code, $client_branch_id, $existing_famility_details); + log_message('error', '----- Auto SI Amount : {data} -----', ['data' => $auto_si_data]); + + //Change the basic cover si to the auto si amount if the auto_si_amount is not null + if (!empty($auto_si_data)) { + foreach ($existing_famility_details as $emp_code => &$records) { + $records['basic_cover_si'] = $auto_si_data; } + unset($record); } - } + // dd($existing_famility_details); - if(empty($clientPolicyId)){ - if(isset($policy_terms['policy_terms'])){ - $policyTermsJson = json_decode($policy_terms['policy_terms'], true); - // print_r($employee_data_group_by_family);die(); - - foreach ($employee_data_group_by_family[$emp_code] as $key => &$value) { - - if(!empty($value)){ - - if(strtolower($value['relationship']) == 'self' && $policyTermsJson['is_payable_employee']['self'] == 0){ - $value['policy_details']['rata_premimum'] = 0; - $value['policy_details']['premium'] = 0; - $value['policy_details']['gst'] = 0; - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['self']; - - }else if(strtolower($value['relationship']) == 'self' && $policyTermsJson['is_payable_employee']['self'] == 1){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['self']; - } - - if(strtolower($value['relationship']) == 'spouse' && $policyTermsJson['is_payable_employee']['spouse'] == 0){ - $value['policy_details']['rata_premimum'] = 0; - $value['policy_details']['premium'] = 0; - $value['policy_details']['gst'] = 0; - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['spouse']; - - }else if(strtolower($value['relationship']) == 'spouse' && $policyTermsJson['is_payable_employee']['spouse'] == 1){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['spouse']; - } - - if((strtolower($value['relationship']) == 'son' || strtolower($value['relationship']) == 'daughter') && $policyTermsJson['is_payable_employee']['childern'] == 0){ - $value['policy_details']['rata_premimum'] = 0; - $value['policy_details']['premium'] = 0; - $value['policy_details']['gst'] = 0; - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['childern']; - - }else if((strtolower($value['relationship']) == 'son' || strtolower($value['relationship']) == 'daughter') && $policyTermsJson['is_payable_employee']['childern'] == 1){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['childern']; - } - - if((strtolower($value['relationship']) == 'father in law' || strtolower($value['relationship']) == 'mother in law' || strtolower($value['relationship']) == 'father' || strtolower($value['relationship']) == 'mother' ) && $policyTermsJson['is_payable_employee']['elders'] == 0){ - $value['policy_details']['rata_premimum'] = 0; - $value['policy_details']['premium'] = 0; - $value['policy_details']['gst'] = 0; - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['elders']; - - }else if((strtolower($value['relationship']) == 'father in law' || strtolower($value['relationship']) == 'mother in law' || strtolower($value['relationship']) == 'father' || strtolower($value['relationship']) == 'mother' ) && $policyTermsJson['is_payable_employee']['elders'] == 1){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['elders']; - } - - }else{ - unset($employee_data_group_by_family[$emp_code][$key]); - } - } - unset($value); - - $employee_data_group_by_family[$emp_code] = array_values($employee_data_group_by_family[$emp_code]); + if (!count($existing_famility_details) && $policy_type == 2) //top up addon only + { + //get basepolicy id then pull emplist from base policy if only current policy is DA addon policy and emplist is zero + // echo 'inside'; + // $client_policy_id = $base_policy; + $existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_id: $client_id, client_policy_id: $base_policy, emp_code: $emp_code, emp_status: ['draft', 'enrolled'], policy_status: ['draft', 'enrolled']); } - }else{ - if(isset($policy_terms['policy_terms'])){ - $policyTermsJson = json_decode($policy_terms['policy_terms'], true); + $file = ['id' => null, 'client_id' => $client_id, 'policy_id' => $client_policy_id, 'action' => 'inception']; + // dd($this->employeeModel->getLastQuery()); + // print_r($existing_famility_details);die(); + $employee_data_group_by_family = data_group_by_family($existing_famility_details, $data_source = 'db'); + // print_rr(($employee_data_group_by_family));die(); - foreach ($employee_data_group_by_family[$emp_code] as $key => &$value) { - if(!empty($value)){ - if(strtolower($value['relationship']) == 'self'){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['self']; + $existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $client_id, client_branch_id: $client_branch_id); + + foreach ($employee_data_group_by_family as $emp_id => $family) { + $transformed_famility_details = transform_db_data_to_excel($family); + + $data = calculate_premium_new(family_data: $transformed_famility_details, policy_terms: $policy_terms, slab_details: $slab_details, fileArr: $file, existing_units: $existing_units, default_si: $default_si); + // print_r($data); + $employee_data_group_by_family[$emp_id] = $data; + + foreach ($data as $value) { + + if (!empty($value)) { + $newData = []; + $newData['employee_id'] = $value['temp']['emp_id']; + $newData['client_policy_id'] = $value['policy_details']['client_policy_id']; + $newData['status'] = "draft"; + $newData['basic_cover_si'] = $value['policy_details']['basic_cover_si']; + $newData['date_coverage'] = $value['policy_details']['date_coverage']; + $newData['policy_end_date'] = $value['policy_details']['policy_end_date']; + $newData['days'] = $value['policy_details']['days']; + + + $isExistingEmpAndPolicy = $this->employeePolicyModel->where('employee_id', $value['temp']['emp_id'])->where('client_policy_id', $value['policy_details']['client_policy_id'])->where('is_active', 1)->get()->getRow(); + if ($isExistingEmpAndPolicy) { + $this->employeePolicyModel->where('employee_id', $value['temp']['emp_id'])->where('client_policy_id', $value['policy_details']['client_policy_id'])->where('is_active', 1)->set($newData)->update(); + } else { + $this->employeePolicyModel->insert($newData); } - - if(strtolower($value['relationship']) == 'spouse'){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['spouse']; - } - - if((strtolower($value['relationship']) == 'son' || strtolower($value['relationship']) == 'daughter')){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['childern']; - } - - if((strtolower($value['relationship']) == 'father in law' || strtolower($value['relationship']) == 'mother in law' || strtolower($value['relationship']) == 'father' || strtolower($value['relationship']) == 'mother' )){ - $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['elders']; - } - }else{ - unset($employee_data_group_by_family[$emp_code][$key]); - } + } } - unset($value); - $employee_data_group_by_family[$emp_code] = array_values($employee_data_group_by_family[$emp_code]); + if (empty($clientPolicyId)) { + if (isset($policy_terms['policy_terms'])) { + $policyTermsJson = json_decode($policy_terms['policy_terms'], true); + // print_r($employee_data_group_by_family);die(); + + foreach ($employee_data_group_by_family[$emp_code] as $key => &$value) { + + if (!empty($value)) { + + if (strtolower($value['relationship']) == 'self' && $policyTermsJson['is_payable_employee']['self'] == 0) { + $value['policy_details']['rata_premimum'] = 0; + $value['policy_details']['premium'] = 0; + $value['policy_details']['gst'] = 0; + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['self']; + } else if (strtolower($value['relationship']) == 'self' && $policyTermsJson['is_payable_employee']['self'] == 1) { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['self']; + } + + if (strtolower($value['relationship']) == 'spouse' && $policyTermsJson['is_payable_employee']['spouse'] == 0) { + $value['policy_details']['rata_premimum'] = 0; + $value['policy_details']['premium'] = 0; + $value['policy_details']['gst'] = 0; + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['spouse']; + } else if (strtolower($value['relationship']) == 'spouse' && $policyTermsJson['is_payable_employee']['spouse'] == 1) { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['spouse']; + } + + if ((strtolower($value['relationship']) == 'son' || strtolower($value['relationship']) == 'daughter') && $policyTermsJson['is_payable_employee']['childern'] == 0) { + $value['policy_details']['rata_premimum'] = 0; + $value['policy_details']['premium'] = 0; + $value['policy_details']['gst'] = 0; + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['childern']; + } else if ((strtolower($value['relationship']) == 'son' || strtolower($value['relationship']) == 'daughter') && $policyTermsJson['is_payable_employee']['childern'] == 1) { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['childern']; + } + + if ((strtolower($value['relationship']) == 'father in law' || strtolower($value['relationship']) == 'mother in law' || strtolower($value['relationship']) == 'father' || strtolower($value['relationship']) == 'mother') && $policyTermsJson['is_payable_employee']['elders'] == 0) { + $value['policy_details']['rata_premimum'] = 0; + $value['policy_details']['premium'] = 0; + $value['policy_details']['gst'] = 0; + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['elders']; + } else if ((strtolower($value['relationship']) == 'father in law' || strtolower($value['relationship']) == 'mother in law' || strtolower($value['relationship']) == 'father' || strtolower($value['relationship']) == 'mother') && $policyTermsJson['is_payable_employee']['elders'] == 1) { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['elders']; + } + } else { + unset($employee_data_group_by_family[$emp_code][$key]); + } + } + unset($value); + + $employee_data_group_by_family[$emp_code] = array_values($employee_data_group_by_family[$emp_code]); + } + } else { + if (isset($policy_terms['policy_terms'])) { + + $policyTermsJson = json_decode($policy_terms['policy_terms'], true); + + foreach ($employee_data_group_by_family[$emp_code] as $key => &$value) { + if (!empty($value)) { + + if (strtolower($value['relationship']) == 'self') { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['self']; + } + + if (strtolower($value['relationship']) == 'spouse') { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['spouse']; + } + + if ((strtolower($value['relationship']) == 'son' || strtolower($value['relationship']) == 'daughter')) { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['childern']; + } + + if ((strtolower($value['relationship']) == 'father in law' || strtolower($value['relationship']) == 'mother in law' || strtolower($value['relationship']) == 'father' || strtolower($value['relationship']) == 'mother')) { + $value['policy_details']['payable_employee'] = $policyTermsJson['is_payable_employee']['elders']; + } + } else { + unset($employee_data_group_by_family[$emp_code][$key]); + } + } + unset($value); + + $employee_data_group_by_family[$emp_code] = array_values($employee_data_group_by_family[$emp_code]); + } + } + } + // die(); + if ($clientPolicyId != null && $empCode != null) { + // dd ($employee_data_group_by_family); + return $employee_data_group_by_family; + } else { + // dd ($employee_data_group_by_family); + return $this->respond(['status' => 'success', 'code' => (count($employee_data_group_by_family) ? 200 : 200), 'data' => [$employee_data_group_by_family]], 200); } - } - - - } - // die(); - if($clientPolicyId != null && $empCode != null) - { - // dd ($employee_data_group_by_family); - return $employee_data_group_by_family; - }else{ - // dd ($employee_data_group_by_family); - return $this->respond(['status' => 'success','code' => (count($employee_data_group_by_family) ? 200 : 200),'data' => [$employee_data_group_by_family] ], 200); - } - } @@ -3255,10 +3308,19 @@ class EmployeeRestController extends AdminController { try { - $clientPolicy = $this->clientPolicyModel->where('id',$this->request->getGet('client_policy_id')) - ->where('open_for_enrollment',1)->findAll(); + $clientPolicy = $this->clientPolicyModel->where('id',$this->request->getGet('client_policy_id'))->findAll(); + + if(count($clientPolicy ?? []) == 0){ + return $this->respond(['status' => 'failed','code' => 404, 'message' => 'Client policy not found', 'data' => [] ], 200); + } + + if(in_array($clientPolicy[0]['policy_type_id'], [3,4,5,72])){ + $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($clientPolicy[0]['base_policy'], $this->request->getGet('emp_code')); + }else{ + $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($this->request->getGet('client_policy_id'), $this->request->getGet('emp_code')); + } - if(count($clientPolicy)) + if($openForEnrollment) { @@ -3270,6 +3332,11 @@ class EmployeeRestController extends AdminController $empData = $this->employeeModel->where('emp_code',$this->request->getGet('emp_code')) ->where('is_addon_value', 0 ) ->findAll(); + }else if($clientPolicy[0]['policy_type_id'] == 72)//OPD + { + $empData = $this->employeeModel->where('emp_code',$this->request->getGet('emp_code')) + ->where('is_addon_value', 0) + ->findAll(); }else if($clientPolicy[0]['policy_type_id'] == 5)//GMC-Parent-Topup { $empData = $this->employeeModel->where('emp_code',$this->request->getGet('emp_code')) @@ -3283,7 +3350,7 @@ class EmployeeRestController extends AdminController $this->employeePolicyModel->where('client_policy_id',$this->request->getGet('client_policy_id') ) ->where('employee_id', $value['id'] ) - ->set(array('is_active'=> 0 )) + ->set(array('is_active'=> 0 , 'status' => 'truncated')) ->update(); } @@ -3318,12 +3385,12 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'success','code' => 200,'data' =>[] ], 200); }else{ - return $this->respond(['status' => 'failed','code' => 404,'data' => [] ], 200); + return $this->respond(['status' => 'failed', 'message' => 'Enrollment closed for this policy','code' => 404,'data' => [] ], 200); } } catch (\Exception $e) { - return $this->respond(['status' => 'failed','code' => 500,'data' => $e->getMessage()], 500); + return $this->respond(['status' => 'failed','code' => 500,'data' => $e->getMessage()], 200); } } @@ -4472,7 +4539,7 @@ class EmployeeRestController extends AdminController ->where('is_active', 1) ->first(); - if(in_array($clientPolicyData['policy_type_id'] ?? null, [3,4,5])){ + if(in_array($clientPolicyData['policy_type_id'] ?? null, [3,4,5,72])){ $policy = $this->employeePolicyModel ->select('employee_polices.enrollment_open_date, employee_polices.enrollment_close_date') @@ -4517,7 +4584,14 @@ class EmployeeRestController extends AdminController WHERE policy_type_id = 4 AND base_policy = gmc_client_policy_id LIMIT 1 - ) AS gmc_topup_policy_id + ) AS gmc_topup_policy_id, + + ( + SELECT id FROM client_policy + WHERE policy_type_id = 72 + AND base_policy = gmc_client_policy_id + LIMIT 1 + ) AS opd_topup_policy_id ") ->join('employee_polices', 'employees.id = employee_polices.employee_id') ->join('client_policy', 'employee_polices.client_policy_id = client_policy.id') @@ -4554,6 +4628,7 @@ class EmployeeRestController extends AdminController $policyIds[] = $data['gmc_topup_policy_id']; $policyIds[] = $data['gmc_parent_policy_id']; + $policyIds[] = $data['opd_topup_policy_id'] ?? null; $policyIds[] = $getParentTopUp['gmc_parent_topup_policy_id'] ?? null; return $policyIds; diff --git a/app/Controllers/EmployeeServiceController.php b/app/Controllers/EmployeeServiceController.php index 69c1d0f..3dbf417 100755 --- a/app/Controllers/EmployeeServiceController.php +++ b/app/Controllers/EmployeeServiceController.php @@ -116,7 +116,9 @@ class EmployeeServiceController extends AdminController 'is_mandatory' => true, 'data_type' => 'str', 'format' => null, - 'allowed_values' => null + 'allowed_values' => null, + 'custom' => 'check_emp_code_duplicate', + 'params' => ['self_data', 'row'] ], 'name_of_emp_dep' => [ 'col_idx' => 2, @@ -797,6 +799,19 @@ class EmployeeServiceController extends AdminController $existing_mobilenos = $this->employeePolicyModel->getExisitingMobileNos(client_policy_id: $file['policy_id']); //get existing units in the current branch $existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $file['client_id'],client_branch_id: $file['client_branch_id']); + + $self_data = $this->employeeModel + ->select('employees.id, employees.name, employees.emp_code') + ->join('employee_polices ep', 'employees.id = ep.employee_id') + ->where('employees.is_active', 1) + ->where('ep.is_active', 1) + ->whereIn('emp_status', ['draft', 'enrolled']) + ->whereIn('status', ['draft', 'enrolled']) + ->where('LOWER(relationship)', 'self') + ->where('client_id', $file['client_id']) + ->findAll(); + + // dd($excel_data); foreach ($excel_data as $row_key => $row) { diff --git a/app/Controllers/RestAuthenticationController.php b/app/Controllers/RestAuthenticationController.php index 02bf50f..aecf3a0 100755 --- a/app/Controllers/RestAuthenticationController.php +++ b/app/Controllers/RestAuthenticationController.php @@ -1329,7 +1329,7 @@ class RestAuthenticationController extends AdminController $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - checkMpin: Mpin - Exist"); log_message('error', ' '); log_message('error', '************************ PRE END ********************************'); - return $this->respond(['status' => 'success','code' => 200,'data' => "", 'message' => "Mpin - exist" , 'Mpin' =>$employeeData["mpin"], 'is_mpin_skipped' => $employeeData['is_mpin_skipped'] ?? 0, 'is_biometric_enabled' => $employeeData['is_biometric_enabled'] ?? 0 ],200); + return $this->respond(['status' => 'success','code' => 200,'data' => "", 'message' => "Mpin - exist" , 'Mpin' =>$employeeData["mpin"], 'is_mpin_skipped' => $employeeData['is_mpin_skipped'] ?? '0', 'is_biometric_enabled' => $employeeData['is_biometric_enabled'] ?? '0' ],200); } else { $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - checkMpin: Mpin - not found in PRE so call the thirdpartapi to the POST to check the MPIN"); log_message('error', ' '); diff --git a/app/Controllers/SamlController.php b/app/Controllers/SamlController.php new file mode 100644 index 0000000..12b4c53 --- /dev/null +++ b/app/Controllers/SamlController.php @@ -0,0 +1,256 @@ +where('id', $clientId)->first(); + + if (! $samlClient) { + throw new \RuntimeException('Invalid SAML client with ID: ' . $clientId); + } + + $settings = $this->loadMergedSettings(); + + $settings['idp'] = [ + 'entityId' => $samlClient['saml_entity_id'], + 'singleSignOnService' => [ + 'url' => $samlClient['saml_sso_url'], + ], + 'singleLogoutService' => [ + 'url' => $samlClient['saml_slo_url'] ?? '', + ], + 'x509cert' => $samlClient['saml_x509_cert'], + ]; + + return new SamlAuth($settings); + } + + public function login() + { + try { + + $email = $this->request->getGet('email'); + + if (! $email) { + return $this->response->setStatusCode(400)->setBody('Email required'); + } + + $email = trim((string) $email); + $at = strrchr($email, '@'); + if ($at === false) { + return $this->response->setStatusCode(400)->setBody('Invalid email'); + } + + $domain = strtolower(substr($at, 1)); + + $model = new SamlClientModel(); + $samlClient = $model->getByDomain($domain); + + if (! $samlClient) { + return $this->response->setStatusCode(404)->setBody('SAML not configured for this domain'); + } + + // dd($samlClient); + + $auth = $this->getSamlAuth($samlClient['id']); + + } catch (\Throwable $e) { + return redirect()->to(site_url('login'))->with('error', $e->getMessage()); + } + + $url = $auth->login(null, [], false, false, true); + + return redirect()->to($url); + } + + public function acs() + { + try { + $clientId = $this->request->getGet('client_id'); + if (! $clientId) { + return $this->response->setStatusCode(400)->setBody('Client ID required'); + } + + $auth = $this->getSamlAuth($clientId); + } catch (\Throwable $e) { + return redirect()->to(site_url('login'))->with('error', $e->getMessage()); + } + + $auth->processResponse(); + + if (! $auth->isAuthenticated()) { + return $this->response->setJSON($auth->getErrors()); + } + + $attributes = $auth->getAttributes(); + $nameId = $auth->getNameId(); + + $email = $this->resolveEmailFromSaml($nameId, $attributes); + + $UserModel = new UserModel(); + $user = $UserModel->getUserByEmail($email); + + if (! $user || $user->is_active === '0') { + session()->remove('saml_client_id'); + + return redirect()->to(site_url('login'))->with('error', 'User not registered or inactive'); + } + + $user_team = $UserModel->getUserTeamsByUserID($user->id); + + session()->regenerate(true); + + $session_data = [ + 'isLoggedIn' => true, + 'userid' => $user->id, + 'userData' => $user, + 'userProfile' => null, + 'user_team' => $user_team, + 'saml_name_id' => $nameId, + 'saml_attrs' => $attributes, + ]; + set_session_data($session_data); + set_session_data(['fingerprint' => generateFingerprint()]); + + $this->getUserDeviceInfo($user->id, 'NhanceUser'); + + return redirect()->to(site_url('dashboard/view')); + } + + protected function getUserDeviceInfo(int $userId, string $type_of_user): void + { + $userAgent = $this->request->getUserAgent(); + $datd = [ + 'user_id' => $userId, + 'user_type' => $type_of_user, + 'ip' => $this->request->getIPAddress(), + 'platform' => $userAgent->getPlatform(), + 'broswer' => $userAgent->getBrowser(), + ]; + $AuthHistoryModel = new \App\Models\AuthHistoryModel(); + $AuthHistoryModel->insert($datd); + } + + /** + * @param array $attributes + */ + private function resolveEmailFromSaml(?string $nameId, array $attributes): string + { + if ($nameId && filter_var($nameId, FILTER_VALIDATE_EMAIL)) { + return $nameId; + } + + $keys = [ + 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', + 'http://schemas.microsoft.com/identity/claims/emailaddress', + 'email', + 'Email', + 'mail', + ]; + + foreach ($keys as $k) { + if (! empty($attributes[$k][0])) { + return (string) $attributes[$k][0]; + } + } + + foreach ($attributes as $vals) { + if (is_array($vals) && ! empty($vals[0]) && filter_var($vals[0], FILTER_VALIDATE_EMAIL)) { + return (string) $vals[0]; + } + } + + return (string) $nameId; + } + + public function logout() + { + try { + $clientId = $this->request->getGet('client_id'); + if (! $clientId) { + return $this->response->setStatusCode(400)->setBody('Client ID required'); + } + + $auth = $this->getSamlAuth($clientId); + $url = $auth->logout(null, [], null, null, true); + } catch (SamlError $e) { + session()->destroy(); + + return redirect()->to(site_url('login')); + } catch (\Throwable $e) { + session()->destroy(); + + return redirect()->to(site_url('login')); + } + + session()->destroy(); + + return redirect()->to($url); + } + + public function slo() + { + try { + $clientId = $this->request->getGet('client_id'); + if (! $clientId) { + return $this->response->setStatusCode(400)->setBody('Client ID required'); + } + + $auth = $this->getSamlAuth($clientId); + } catch (\Throwable $e) { + return redirect()->to(site_url('login')); + } + + try { + $redirectUrl = $auth->processSLO(false, null, false, null, true); + } catch (SamlError $e) { + return redirect()->to(site_url('login')); + } + + if (! empty($auth->getErrors())) { + return $this->response->setJSON($auth->getErrors()); + } + + if ($redirectUrl) { + return redirect()->to($redirectUrl); + } + + return redirect()->to(site_url('login')); + } + + public function metadata() + { + $settings = $this->loadMergedSettings(); + + try { + $samlSettings = new SamlSettings($settings, true); + $metadata = $samlSettings->getSPMetadata(); + } catch (\Throwable $e) { + return $this->response->setStatusCode(500)->setBody($e->getMessage()); + } + + return $this->response + ->setHeader('Content-Type', 'application/xml; charset=utf-8') + ->setBody($metadata); + } +} diff --git a/app/Helpers/excel_util_helper.php b/app/Helpers/excel_util_helper.php index a6b6222..c1f6159 100755 --- a/app/Helpers/excel_util_helper.php +++ b/app/Helpers/excel_util_helper.php @@ -2369,5 +2369,17 @@ if(!function_exists('modify_si_for_the_family')) // --------AUTO SI Functions End--------------------------------------------------------------------------------------- +if(!function_exists('check_emp_code_duplicate')) +{ + function check_emp_code_duplicate($data, $row) + { + foreach ($data as $member) { + if(strtolower($row[5]) == 'self' && $member['emp_code'] == trim($row[1])) { + return array('status' => false,'error' => "This employee code already exist for this client"); + } + } + return array('status' => true,'error' => ""); + } +} diff --git a/app/Libraries/Saml/advanced_settings.php b/app/Libraries/Saml/advanced_settings.php new file mode 100644 index 0000000..8c95d56 --- /dev/null +++ b/app/Libraries/Saml/advanced_settings.php @@ -0,0 +1,28 @@ + [ + 'requests' => true, + 'responses' => true, + ], + 'security' => [ + 'nameIdEncrypted' => false, + 'authnRequestsSigned' => false, + 'logoutRequestSigned' => false, + 'logoutResponseSigned' => false, + 'signMetadata' => false, + 'wantMessagesSigned' => false, + 'wantAssertionsEncrypted' => false, + 'wantAssertionsSigned' => false, + 'wantNameId' => true, + 'wantNameIdEncrypted' => false, + 'requestedAuthnContext' => false, + 'wantXMLValidation' => true, + 'relaxDestinationValidation' => false, + 'destinationStrictlyMatches' => false, + 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + 'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256', + 'lowercaseUrlencoding' => false, + ], + // Add contactPerson/organization only when fully populated. +]; diff --git a/app/Libraries/Saml/certs/sp.crt b/app/Libraries/Saml/certs/sp.crt new file mode 100644 index 0000000..3626dec --- /dev/null +++ b/app/Libraries/Saml/certs/sp.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID6zCCAtOgAwIBAgIJAPhw7kma+NxNMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJJTjELMAkGA1UECAwCVE4xEDAOBgNVBAcMB0NIRU5OQUkxEzARBgNVBAoM +ClZFTkJBSVQuaW4xCzAJBgNVBAsMAklUMRMwEQYDVQQDDApWRU5CQUlULmluMSYw +JAYJKoZIhvcNAQkBFhdhZG1pbkB2ZW5iYWluZm90ZWNoLmNvbTAeFw0yNjA0MDYw +NjU4MjlaFw0yNzA0MDYwNjU4MjlaMIGLMQswCQYDVQQGEwJJTjELMAkGA1UECAwC +VE4xEDAOBgNVBAcMB0NIRU5OQUkxEzARBgNVBAoMClZFTkJBSVQuaW4xCzAJBgNV +BAsMAklUMRMwEQYDVQQDDApWRU5CQUlULmluMSYwJAYJKoZIhvcNAQkBFhdhZG1p +bkB2ZW5iYWluZm90ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBANF5AMk4JGwyGbkJaVDWOJ2ff5ewc4ihZym0YprpsJHcj9dHHc3qo77rp2jn +gyz8iSHM4kt4Ebuw8GganW0bRYWp4ZfrkhEr/kdaO2bKeT7BAllRnukzVO2X40+I ++ZbwiJZ6D67JhYmm2ccp8BfQvNZ++Yb0reI8AtrHl2g1VzdgCV9l/WbiAGkVQzE5 ++bb4YMhKyuoLu4ReSwx/SJ+oW5DIPU097c1r/riy4qd4+GqPtof2TGT0oYsSU5S5 +4NJhoH7FCj6pGxY0R02sGuFesDZA7D6c4YZ7bo50MvGlY/S23yJciUgNU1zGfalE +jES4ShODrSzldW9mh26zLmSvaq8CAwEAAaNQME4wHQYDVR0OBBYEFKqTqxHi6Nui +cybKtVEkkicJp23kMB8GA1UdIwQYMBaAFKqTqxHi6NuicybKtVEkkicJp23kMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFQV3bLrvj9qVNkRYVhOhYEy +t6/NRIPMLokUzKJSXnEQKFkUDbZWGf18Rryk7CUR2PiuZJMnU83eoQp16PAhDVkT +VkHB0qTCg5LvZVYr/Dd2qbWRnILK1hLIDRnPSFAEZWkrH7EER8VwReYAFITD2CGP +KV/g7MJqr88iGrlH/JAI/z//uArlt5A8H/x4LC/p+mZb4sMmnym6Fl0Md5JOnm+S +ZnD6SvY2XJsYhvFP3ikmct0cqVIfxgNTnL5NcWlve3z+ktYgqj5egp3iWLQkemKz +4rPN+z26CK4bCiNwobVpqRMBMtZp6/kQfKHSakQjS0M2+zanaTsdhuPIcT2qWbo= +-----END CERTIFICATE----- diff --git a/app/Libraries/Saml/certs/sp.key b/app/Libraries/Saml/certs/sp.key new file mode 100644 index 0000000..8913676 --- /dev/null +++ b/app/Libraries/Saml/certs/sp.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDReQDJOCRsMhm5 +CWlQ1jidn3+XsHOIoWcptGKa6bCR3I/XRx3N6qO+66do54Ms/IkhzOJLeBG7sPBo +Gp1tG0WFqeGX65IRK/5HWjtmynk+wQJZUZ7pM1Ttl+NPiPmW8IiWeg+uyYWJptnH +KfAX0LzWfvmG9K3iPALax5doNVc3YAlfZf1m4gBpFUMxOfm2+GDISsrqC7uEXksM +f0ifqFuQyD1NPe3Na/64suKnePhqj7aH9kxk9KGLElOUueDSYaB+xQo+qRsWNEdN +rBrhXrA2QOw+nOGGe26OdDLxpWP0tt8iXIlIDVNcxn2pRIxEuEoTg60s5XVvZodu +sy5kr2qvAgMBAAECggEBAMyqXrM8EJJKTUm2wVjDRiPz8DWkqO2pTeO4pNNZWzTY +/Q3JJXzJMl5bX4GnGkq9H7uPtNcqJKFvWyVMQ96T09SqTIokF96BTnwm1H01fUts +R8A/eHW/us4+JlHSspLgx4PHFUWhDsGU7ZmkBzstryQggetza+Xs3pkmhG/EFkg5 +3kMLk+OriMOnMMgva1sPm4x9gn7Zo2aK/Zk1tMGq48M+tmno8XpPmDKYG9GLUZ9E +pkYvGB7QiiQXERnmzpmHs6K4myd5w+UT5SzDz1dz9HddwBNYzYP0J4z6zwTuSean +1OHPV7WndN6Zqv6C7Ecw3JmiHNEPqY/wbCI8/SLhZSECgYEA+2DZKct1h9GWfBL/ +oTWV2FIamAyis602wFgsUKJIGAGAZgIq6IXChch/bWKBBima7xYzm3drtbZMo7qz +khNik1QuODLDvFg17QxoTwl6e45T65jsPVXLkbEwclddahE3sUyzNGlLezWMaFZk +CCz8NtUToLh5O1QQBvVsxi0LGx8CgYEA1VLrU3z6S9N8BoYdERB3nqdh9w/xlU2D +Cb7/U/X5J8T8rl0mzAAdVrDxxCySk/Gq/7tlpl6jTL8kfUD97g7/clINRJZK/gEy +HORWOOsEMYpP6/gxI8Ddrl0fDSDUnsq28rj3pB0BIzr0Xm3oS/w1U1MrC+LpcJ7K +SS36NHPbTnECgYArcVtWa8EODdyR6L6g35/b2KSb7mMX5jF2IEbYUJNhArFr76f2 +s1cgw7ux7boalIogE5groAHPT4gDK7ro3czFZWDveWZ2YFBBfUlxj1PJkplSOAVr +vC4IKbUTraGJORyE2ZqGzkOrMV/okDWNbCjSWRShTAA3jpmOek+oGBS5RQKBgHZb +3WmjLBSqMGRGQRZYtqX2ZOp5lCasrQnZST1Ceo1QRIpR8Na7MYwJ/PpFaMZhDel6 +Bjo6xAwu+YXta3aMJ7s8P1RQtycbbryNDDHkY51BCnr4Z/tYZSb7T+Eu2AmKm9ss +OWp7FUiAy1khTgPq2YNz36xmp/Luh3n24p37sjBhAoGBAOzA3AEILoL7WqgqXRLd +VDqZ5ZMjmFhKal+ljMgDOEBXjrcg/E6gsHX3PXGaPXEs72UySACcyN6j849ERCE9 +ikwyRE2FksS4iaUzEsyT7vssM0IqeVa45lO3GYXvD35YznHkXdaZpo4kIqOBF1W0 +n1Ut6itRUNQIUDuTqNE61n40 +-----END PRIVATE KEY----- diff --git a/app/Libraries/Saml/settings.php b/app/Libraries/Saml/settings.php new file mode 100644 index 0000000..62b8cab --- /dev/null +++ b/app/Libraries/Saml/settings.php @@ -0,0 +1,46 @@ + true, + 'debug' => false, + 'baseurl' => $base . '/', + + 'sp' => [ + 'entityId' => $base . '/saml/metadata', + 'assertionConsumerService' => [ + 'url' => $base . '/saml/acs', + // 'url' => 'https://venbait.in/nhance/app/dev/#/login', + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + ], + 'singleLogoutService' => [ + 'url' => $base . '/saml/slo', + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ], + 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', + 'x509cert' => $spCert, + 'privateKey' => $spKey, + ], + + // Placeholder IdP (must pass Settings validation; replaced before Auth by DB row) + 'idp' => [ + 'entityId' => $base . '/saml/placeholder-idp', + 'singleSignOnService' => [ + 'url' => $base . '/saml/placeholder-sso', + ], + 'singleLogoutService' => [ + 'url' => '', + ], + 'x509cert' => $spCert, + ], +]; diff --git a/app/Models/EmployeeModel.php b/app/Models/EmployeeModel.php index c5bd85b..d6dfa27 100755 --- a/app/Models/EmployeeModel.php +++ b/app/Models/EmployeeModel.php @@ -46,6 +46,7 @@ class EmployeeModel extends Model "is_mpin_skipped", "is_biometric_enabled", "password", + "is_dependent_modified", ]; // Callbacks diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php index 92c2905..9ee48ef 100755 --- a/app/Models/EmployeePolicyModel.php +++ b/app/Models/EmployeePolicyModel.php @@ -140,22 +140,46 @@ class EmployeePolicyModel extends Model '(SELECT old_value FROM auditing_history WHERE pk = emp.id AND field_name = "gender" AND table_name = "employees" ORDER BY id ASC LIMIT 1) AS gender_first_old', '(SELECT new_value FROM auditing_history WHERE pk = emp.id AND field_name = "gender" AND table_name = "employees" ORDER BY id DESC LIMIT 1) AS gender_last_new', - '(CASE - WHEN emp.relationship = "Self" - THEN (SELECT COUNT(id) FROM employees WHERE emp_code = emp.emp_code AND is_active = 0 AND emp_status != "truncated") + "(CASE + WHEN emp.relationship = 'Self' + THEN ( + SELECT IF(COUNT(e.id) > 0, + CONCAT( + COUNT(e.id), + ' people removed ( ', + GROUP_CONCAT(CONCAT(e.name, ' - ', e.relationship) SEPARATOR ', '), + ' )' + ), + NULL) + FROM employees e + JOIN employee_polices ep ON e.id = ep.employee_id + WHERE e.emp_code = emp.emp_code + AND (e.is_dependent_modified = 0 OR (e.is_active = 0 AND e.emp_status != 'truncated')) + AND ep.client_policy_id = employee_polices.client_policy_id + ) ELSE NULL - END) AS removed_count', + END) AS removed_summary", + + "(IF(COALESCE(emp.is_dependent_modified, 0) = 1, 'Newly Added, ', + CASE + WHEN emp.relationship != 'Self' + AND emp.file_id IS NULL + AND emp.created_by = ( + SELECT e_sub.id + FROM employees e_sub + JOIN employee_polices ep_sub ON e_sub.id = ep_sub.employee_id + WHERE e_sub.emp_code = emp.emp_code + AND e_sub.relationship = 'Self' + AND e_sub.is_active = 1 + AND ep_sub.client_policy_id = employee_polices.client_policy_id + LIMIT 1 + ) + + THEN 'Newly Added ' + ELSE NULL + END + )) AS newly_added", - '(CASE - WHEN emp.relationship != "Self" AND emp.created_at != ( - SELECT created_at - FROM employees - WHERE emp_code = emp.emp_code AND relationship = "Self" AND is_active = 1 - LIMIT 1 - ) - THEN "Newly Added" - ELSE NULL - END) AS newly_added', $status_query ], false) ->join('employees emp', 'employee_polices.employee_id = emp.id') diff --git a/app/Models/SamlClientModel.php b/app/Models/SamlClientModel.php new file mode 100644 index 0000000..3ccffda --- /dev/null +++ b/app/Models/SamlClientModel.php @@ -0,0 +1,31 @@ +where('LOWER(email_domain)', $domain)->first(); + } +} diff --git a/app/Models/UserModel.php b/app/Models/UserModel.php index 49b8440..0541cbf 100755 --- a/app/Models/UserModel.php +++ b/app/Models/UserModel.php @@ -77,7 +77,7 @@ class UserModel extends Model public function getUserByEmail($email){ - $userData = $this->where('email', $email)->get(); + $userData = $this->where('email', $email)->where('is_active', 1)->get(); if ($userData->getNumRows() > 0) { return $userData->getRow(); } else { @@ -87,7 +87,7 @@ class UserModel extends Model public function getUserById($id){ - $userData = $this->where('id', $id)->get(); + $userData = $this->where('id', $id)->where('is_active', 1)->get(); if ($userData->getNumRows() > 0) { return $userData->getRow(); } else { diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php index ad919af..ec60594 100755 --- a/app/Views/client_policy.php +++ b/app/Views/client_policy.php @@ -1141,7 +1141,7 @@ $('body').on('click', '.btnPolicyEdit', function() { // } - if (res.data.policy_type_id == '4' || res.data.policy_type_id == '5') { + if (res.data.policy_type_id == '4' || res.data.policy_type_id == '5' || res.data.policy_type_id == '72') { $('#base_policy_id').show(); $('#base_policy').prop('required', true); @@ -1645,7 +1645,7 @@ $('#policy_type').change(function() { }); - if ($(this).val() == 4 || $(this).val() == 5) { + if ($(this).val() == 4 || $(this).val() == 5 || $(this).val() == 72) { $("#insurer").next(".select2-container").css({ 'pointer-events': 'auto', @@ -1689,7 +1689,7 @@ $('#policy_type').change(function() { toastr.warning('Please Change the Policy Terms after Submit the Policy!', 'Info'); } - if ($(this).val() == '4' || $(this).val() == '5') { + if ($(this).val() == '4' || $(this).val() == '5' || $(this).val() == '72') { $('#base_policy_id').show(); $('#base_policy').prop('required', true); @@ -2189,7 +2189,7 @@ function getClientPolicyDataForEdit(client_policy_id) { $('#is_premium_summery').prop('checked', false); } - if (res.data.policy_type_id == '4' || res.data.policy_type_id == '5') { + if (res.data.policy_type_id == '4' || res.data.policy_type_id == '5' || res.data.policy_type_id == '72') { $('#base_policy_id').show(); $('#base_policy').prop('required', true); diff --git a/app/Views/employee_data_list.php b/app/Views/employee_data_list.php index c8f094b..7659250 100755 --- a/app/Views/employee_data_list.php +++ b/app/Views/employee_data_list.php @@ -200,6 +200,9 @@ " . $employee['newly_added'] . "

"; + } if(!empty($employee['name_first_old']) ){ echo "

Name : " . $employee['name_first_old'] . ' => ' . $employee['name_last_new'] . "

"; } @@ -209,13 +212,13 @@ if(!empty($employee['gender_first_old'])){ echo "

Gender : " . $employee['gender_first_old'] . ' => ' . $employee['gender_last_new'] . "

"; } - if(!empty($employee['newly_added'])){ - echo "

" . $employee['newly_added'] . "

"; + // if(!empty($employee['removed_count'])){ + // echo "

" . $employee['removed_count'] . " People removed

"; + // } + if(!empty($employee['removed_summary'])){ + echo "

" . $employee['removed_summary'] . "

"; } - if(!empty($employee['removed_count'])){ - echo "

" . $employee['removed_count'] . " People removed

"; - } - if(empty($employee['name_first_old']) && empty($employee['dob_first_old']) && empty($employee['gender_first_old']) && empty($employee['removed_count'] ) && empty($employee['newly_added'] )){ + if(empty($employee['name_first_old']) && empty($employee['dob_first_old']) && empty($employee['gender_first_old']) && empty($employee['removed_summary'] ) && empty($employee['newly_added'] )){ echo " - "; } ?> @@ -844,7 +847,7 @@ function downloadInception(){ empName: empName }, success: function(response) { - if (response.status === 'Success') { + if (response.status === 'success') { $('', { href: response.downloadUrl, download: '', diff --git a/app/Views/file_list.php b/app/Views/file_list.php index 993ebe6..1e765aa 100755 --- a/app/Views/file_list.php +++ b/app/Views/file_list.php @@ -128,7 +128,7 @@ ">Download View - + Truncate @@ -166,31 +166,37 @@ - + + + \ No newline at end of file diff --git a/composer.json b/composer.json index e2f8787..718fd8f 100755 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "google/apiclient": "^2.18", "kreait/firebase-php": "^7.0", "laminas/laminas-escaper": "^2.9", + "onelogin/php-saml": "^4.3", "php-amqplib/php-amqplib": "^2.8", "phpmailer/phpmailer": "^6.9", "phpoffice/phpspreadsheet": "^2.1", diff --git a/public/2026-04-08.md b/public/2026-04-08.md new file mode 100644 index 0000000..9e5b16a --- /dev/null +++ b/public/2026-04-08.md @@ -0,0 +1,27 @@ +# Daily progress — 2026-04-08 + +## Policy Terms UI (policy type 72) — `other_policy_terms.php` + +- Reworked Sum Insured row: label column alignment, `input-group` with teal **+** button, amount-in-words as small italic muted text. +- Reworked Family Floater section: removed light-cyan panel; indented member grid under the value column to match target layout. +- Added column layout with **Min Age:** / **Max Age:** underline inputs and **Is Payable by employee:** checkboxes for Self, Spouse, Children; elders row when “Other Members” is not None. +- Renamed Other Members block to **Select Other Members:** with full-width dropdown; elder min/max ages and elder payable checkbox shown only when a non-None option is selected. +- `elder_member_count` moved to hidden input; sync on dropdown change and init. +- Fixed invalid form HTML (form closing order). +- AJAX: load `is_payable_employee` from saved terms; fix children count `0` not applying to dropdown; default `family_floaters_others` to None when no parent rule matches. +- Added `initPolicy72FamilyFloaterUi`, `syncPolicy72ElderMemberCount`, `togglePolicy72OtherMembersAgeRow` and delegated change handler. + +## Alignment fix (reference: `public/img/Pasted image.png`) + +- Replaced flex “rows” with a single **CSS Grid** (`.policy-72-ff-grid`): fixed-width column 1 (`248px`) for Self/Spouse/Children controls so **Min Age** / **Max Age** / **Is Payable** line up vertically across rows. +- **Other members** age row uses a **spacer cell** in column 1 plus `display: contents` on the wrapper when visible, so elder Min/Max/Payable align with the same columns as above (no longer shifted left). +- Toggle for that row now uses class **`policy-72-other-ages-open`** instead of jQuery `.show()/.hide()` so grid placement stays correct. +- Narrow viewports: horizontal scroll on `.policy-72-family-grid` with `min-width` on the grid to preserve alignment. + +## Backend — `ClientController.php` + +- Policy type 72: `is_payable_employee` now read from POST checkboxes (`is_payable_employee_for_self`, `_spouse`, `_child`, `_elders`) instead of hardcoded zeros. + +## Process / repo hygiene + +- Established daily progress log in `public/` as `YYYY-MM-DD.md` (append same file for the calendar day; do not create duplicate dated files). diff --git a/public/policy_type_72_alignment_plan.md b/public/policy_type_72_alignment_plan.md new file mode 100644 index 0000000..3d27392 --- /dev/null +++ b/public/policy_type_72_alignment_plan.md @@ -0,0 +1,124 @@ +# Policy Type 72 Alignment Plan (Match Policy Type 4) + +## Objective +Handle `policy_type_id = 72` exactly like `policy_type_id = 4` in client policy add/edit behavior, and ensure terms + rack-rate are handled through the Other Policy Terms flow. + +## Scope +- `app/Controllers/ClientController.php` +- `app/Views/client_policy.php` +- Related UI terms/rack-rate triggers that currently branch by policy type IDs. + +## Task List + +### 1) Baseline Mapping and Safe-Change Preparation +- Identify every conditional in controller/view where `4` or `[4,5]` controls add-on type, policy form behavior, payable defaults, terms enrichment, or rack-rate/terms routing. +- Confirm whether any places currently treat `72` as a standalone flow (if yes, mark for de-duplication to avoid divergence). +- Keep existing behavior for all other policy types unchanged. + +### 2) Client Policy Add/Edit Logic (Controller) +- In create/edit paths where `is_addon` is set: + - Extend conditions from `($policy_type_id == 4 || $policy_type_id == 5)` to include `72` where the intent is SI top-up style behavior (same as type `4`). +- Validate resulting `is_addon` value for `72` matches the existing value used for `4`. +- Verify base-policy dependency logic remains consistent with type `4` handling. + +### 3) Client Policy Add/Edit UI Behavior (View) +- Update policy-type change handlers so `72` follows the same UI branch currently used by `4`: + - show/hide sections (`#first`, `#second`, `#third`) + - base policy visibility/required flags + - insurer/TPA visual state logic +- Update edit-form population branches where `res.data.policy_type_id == '4' || '5'` to include `'72'`. +- Ensure warning/notification behavior remains intentional (only where currently tied to type `5` should remain type `5` unless business asks otherwise). + +### 4) Terms and Rack-Rate Routing to Other Policy Terms +- Confirm terms action (`btnPolicyMaster`) and rack-rate action (`btnPolicyModel`) for type `72` route through the same "other policy terms" flow used for non-GMC/GPA special cases, as requested. +- Where logic checks `[4,5]` for terms data preparation, include `72` if that block is the one used by type `4`. +- Validate that no GMC/GPA-specific terms template or transformation is incorrectly applied to type `72`. + +### 5) Policy Terms Normalization/Export Consistency (Controller) +- In policy terms normalization blocks using `[2,3,4,5]` and `[4,5]`, include `72` where type `4` behavior is intended: + - `is_payable_employee` default structure + - waiting period / maternity / ICU / infertility / enrollment display key defaults +- Confirm output payload shape for type `72` matches type `4`. + +### 6) Regression Checks +- Add Policy: create with type `72`, verify same required fields and UI transitions as type `4`. +- Edit Policy: open existing type `72` record and verify form prefill + section visibility parity with type `4`. +- Terms: open Terms for type `72`; confirm it goes to Other Policy Terms and saves/reloads correctly. +- Rack Rate: open Rack Rate for type `72`; confirm it follows the intended non-special routing and data persists. +- Sanity-check that type `4` behavior is unchanged and type `5` behavior is not accidentally altered. + +### 7) QA Notes / Acceptance Criteria +- `72` and `4` produce identical behavior for client policy add/edit and related controller flags. +- `72` terms/rack-rate are handled via Other Policy Terms path. +- No regressions for policy types `1,2,3,5,6,7`. +- Existing policies continue to load and edit without UI/runtime errors. + +## Suggested Implementation Order +1. Update controller create/edit `is_addon` branches. +2. Update view add/edit conditionals for form behavior. +3. Update controller terms-normalization arrays/branches. +4. Validate terms/rack-rate routing for type `72`. +5. Execute regression checklist and document outcomes. + +## Phase 2: Replicate `nhance` Policy Terms Process for Type 72 + +### Reference Baseline +- Source behavior to mirror: + - `/var/www/html/nhance/app/Controllers/ClientController.php` + - `/var/www/html/nhance/app/Views/other_policy_terms.php` +- Target implementation files in this project: + - `app/Controllers/ClientController.php` + - `app/Views/other_policy_terms.php` (or equivalent included terms view if path differs in this repo) + +### Split Task Plan + +#### A) Gap Analysis Split +- Compare type `72` flow in source vs target for: + - terms open (`btnPolicyMaster` -> `getterms`) + - terms save (`client/terms/other_terms`) + - dynamic form render (`appendPolicyTermsHTML(72)`) + - display-key reconstruction (`processOtherEnrollmentDisplayKey`, backend display map build) +- Prepare a field matrix for type `72` keys: + - base keys (`sum_insured`, `multiple_sum_insured`, `family_floater`, `family_floaters`, `age_ratio`) + - OPD keys (`mode_of_serviceability`, `eligibility`, `total_sum_insured_limit`, etc.) + - special condition arrays and display checkboxes + +#### B) View Parity Split (`other_policy_terms.php`) +- Ensure terms launcher logic for type `72` uses the Other Policy Terms screen (same as source behavior). +- Ensure type `72` template block exists inside `appendPolicyTermsHTML(policy_type)` with the exact field set from source. +- Ensure type `72` post-family container behavior is kept (`append_html_for_other_policy_terms_72_after_family`) where applicable. +- Ensure existing JSON bind logic restores: + - family floater radio/select + ages + - OPD fields + - enrollment display checkbox state +- Keep non-72 behavior unchanged (including generic >5 flow). + +#### C) Controller Save/Load Parity Split (`ClientController.php`) +- In `other_terms` save flow: + - apply type `72` mapping for family structure + age ratio and OPD fields + - construct enrollment display payload exactly as reference process + - retain special condition arrays and dynamic key handling +- In `getterms`/list response flow: + - ensure persisted `policy_terms` JSON for `72` returns all expected keys for view hydration +- In post-save normalization: + - apply `is_payable_employee` default structure for `72` as per source behavior + +#### D) Integration Split (Client Policy Page + Terms Trigger) +- Verify `btnPolicyMaster` sends `data-typeid="72"` and opens Other Policy Terms path. +- Verify rack-rate remains in Other Policy Terms-driven behavior for type `72` and does not route to GMC/GPA-specific modals. +- Confirm required UI clears/reset logic does not wipe 72-only DOM containers incorrectly. + +#### E) Validation Split +- Create a new type `72` policy, open terms, fill all 72 fields, save, reopen, and verify persistence. +- Edit existing type `72` policy terms and verify: + - dynamic additional SI rows persist + - family floater and age ranges rehydrate correctly + - display-key checkboxes match saved state +- Regression check type `4` path remains unchanged. + +### Acceptance Criteria for This Split +- Type `72` policy terms in this repo behave the same as the referenced `nhance` controller/view flow. +- Data shape for stored `policy_terms` (including `enrollment_display_key`) is compatible with existing rendering/export in this repo. +- No regression in other policy types or terms screens. + +