Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
velz 2026-04-18 16:59:13 +05:30
commit 74dee4f797
24 changed files with 1570 additions and 313 deletions

View File

@ -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],
];
}

View File

@ -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',

View File

@ -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');

View File

@ -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'] = "";

View File

@ -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;

View File

@ -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)
{

View File

@ -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', ' ');

View File

@ -0,0 +1,256 @@
<?php
namespace App\Controllers;
use App\Models\SamlClientModel;
use App\Models\UserModel;
use OneLogin\Saml2\Auth as SamlAuth;
use OneLogin\Saml2\Error as SamlError;
use OneLogin\Saml2\Settings as SamlSettings;
class SamlController extends BaseController
{
private function loadMergedSettings(): array
{
$settings = require APPPATH . 'Libraries/Saml/settings.php';
$advanced = require APPPATH . 'Libraries/Saml/advanced_settings.php';
return array_merge($settings, $advanced);
}
private function getSamlAuth($clientId): SamlAuth
{
$model = new SamlClientModel();
$samlClient = $model->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<string, mixed> $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);
}
}

View File

@ -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' => "");
}
}

View File

@ -0,0 +1,28 @@
<?php
return [
'compress' => [
'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.
];

View File

@ -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-----

View File

@ -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-----

View File

@ -0,0 +1,46 @@
<?php
/**
* SAML SP settings and IdP placeholders.
* IdP values are replaced at runtime in SamlController::getSamlAuth() from `saml_client`.
*/
$app = config('App');
$base = rtrim((string) base_url(), '/');
$certDir = APPPATH . 'Libraries/Saml/certs/';
$spCert = is_file($certDir . 'sp.crt') ? file_get_contents($certDir . 'sp.crt') : '';
$spKey = is_file($certDir . 'sp.key') ? file_get_contents($certDir . 'sp.key') : '';
return [
'strict' => 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,
],
];

View File

@ -46,6 +46,7 @@ class EmployeeModel extends Model
"is_mpin_skipped",
"is_biometric_enabled",
"password",
"is_dependent_modified",
];
// Callbacks

View File

@ -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')

View File

@ -0,0 +1,31 @@
<?php
namespace App\Models;
use CodeIgniter\Model;
class SamlClientModel extends Model
{
protected $table = 'saml_client';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $allowedFields = [
'client_id',
'email_domain',
'saml_entity_id',
'saml_sso_url',
'saml_slo_url',
'saml_x509_cert',
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $dateFormat = 'datetime';
public function getByDomain(string $domain): ?array
{
$domain = strtolower(trim($domain));
return $this->where('LOWER(email_domain)', $domain)->first();
}
}

View File

@ -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 {

View File

@ -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);

View File

@ -200,6 +200,9 @@
</td>
<td>
<?php
if(!empty($employee['newly_added'])){
echo "<p>" . $employee['newly_added'] . "</p>";
}
if(!empty($employee['name_first_old']) ){
echo "<p> Name : " . $employee['name_first_old'] . ' => ' . $employee['name_last_new'] . "</p>";
}
@ -209,13 +212,13 @@
if(!empty($employee['gender_first_old'])){
echo "<p> Gender : " . $employee['gender_first_old'] . ' => ' . $employee['gender_last_new'] . "</p>";
}
if(!empty($employee['newly_added'])){
echo "<p>" . $employee['newly_added'] . "</p>";
// if(!empty($employee['removed_count'])){
// echo "<p>" . $employee['removed_count'] . " People removed </p>";
// }
if(!empty($employee['removed_summary'])){
echo "<p>" . $employee['removed_summary'] . " </p>";
}
if(!empty($employee['removed_count'])){
echo "<p>" . $employee['removed_count'] . " People removed </p>";
}
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') {
$('<a>', {
href: response.downloadUrl,
download: '',

View File

@ -128,7 +128,7 @@
<a class="dropdown-item" href="<?= base_url("util/download-file-list/") . $file['id']; ?>"><i class="mdi mdi-download mr-2 text-muted font-18 vertical-middle"></i>Download</a>
<a data-id="<?php echo $file['id'] ?>" data-toggle="modal" data-target="#full-width-modal-emp-list" class="dropdown-item view_emp_list" href="#"><i class="mdi mdi-eye mr-2 text-muted font-18 vertical-middle"></i>View</a>
<?php if ($file['status'] == 'Success') { ?>
<?php if ($file['status'] == 'success') { ?>
<a data-id="<?php echo $file['id'] ?>" class="dropdown-item truncate2" href="#"><i class="mdi mdi-delete mr-2 text-muted font-18 vertical-middle"></i>Truncate</a>
<?php } ?>
@ -166,31 +166,37 @@
</div><!-- /.modal -->
<!-- Center modal content for reupload file-->
<div class="modal fade" id="file-upload-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="myCenterModalLabel">ReUpload the file</h4>
<h4 class="modal-title">ReUpload the file</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<form class="parsley-examples" id="uploadForm" action="<?php echo base_url() . 'employee/upload' ?>"
enctype="multipart/form-data">
<!-- Added data-parsley-validate for auto initialization -->
<form class="parsley-examples" id="uploadForm" enctype="multipart/form-data" data-parsley-validate>
<input type="hidden" id="file_client_id" name="client_id">
<input type="hidden" id="file_policy_id" name="policy_id">
<input type="hidden" id="file_branch_id" name="client_branch_id">
<input type="hidden" id="file_enrollment_open_date" name="enrollment_open_date">
<input type="hidden" id="file_enrollment_close_date" name="enrollment_close_date">
<input type="hidden" id="file_upload_actions" name="upload-action-type">
<input type="file" id="fileInput" name="emplist" required
accept=" application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel,application/vnd.oasis.opendocument.spreadsheet">
<button type="submit" class="btn btn-primary">Upload</button>
<div class="form-group mb-3">
<label for="fileInput">Choose Excel File</label>
<input type="file" id="fileInput" name="emplist" class="form-control-file" required
accept=".xlsx, .xls, .ods">
</div>
<div class="text-right">
<button type="submit" id="uploadBtn" class="btn btn-primary">Upload Now</button>
</div>
</form>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</div>
</div>
</div>
<script>
@ -421,65 +427,62 @@ function handleNoDataFound(response, fileId) {
}
}
$('#uploadForm').submit(function() {
$('#uploadForm').on('submit', function(e) {
// 1. STOP the default page reload
e.preventDefault();
var isValid = $('#uploadForm').parsley().validate();
// 2. Validate using Parsley
var form = $(this);
var isValid = form.parsley().validate();
if (!isValid) {
console.log('Form is Empty', 'Warning');
return;
console.warn('Form validation failed');
return false;
}
// Create FormData object
var formData = new FormData($(this)[0]);
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
// 3. UI Feedback (Disable button to prevent multiple clicks)
var $btn = $('#uploadBtn');
$btn.prop('disabled', true).text('Uploading...');
// return false;
// 4. Prepare Data
var formData = new FormData(this);
// 5. API Call
$.ajax({
url: $(this).attr("action"),
url: '<?= base_url("employee/upload") ?>',
type: "POST",
data: formData,
processData: false, // Prevent jQuery from automatically processing the data
contentType: false, // Let jQuery handle the content type
processData: false,
contentType: false,
headers: {
// "Content-Type":"multipart/form-data",
"X-Requested-With": "XMLHttpRequest"
},
success: function(response) {
console.log('API Response:', response);
console.log(response);
$('#uploadForm')[0].reset();
if (response.code === 200 && response.dataStatus === true && response
.data !== "") {
toastr.success(
'File upload successs, Data validation is in-progress',
'Success');
$('.close').click()
window.location.reload(true);
} else if (response.code === 404 && response.dataStatus === false) {
console.error('no data found', response);
// alert(response.message);
toastr.error(response.message, 'Failed');
window.location.reload(true);
if (response.code == 200 && response.dataStatus == true) {
toastr.success('File upload success, Data validation is in-progress', 'Success');
$('.close').click(); // Close Modal
form[0].reset(); // Clear Form
} else {
console.error('Something went wrong!');
// alert('Something went wrong! Try later');
toastr.error('Something went wrong! Try later', 'Error');
window.location.reload(true);
toastr.error(response.message || 'Upload failed', 'Error');
$btn.prop('disabled', false).text('Upload'); // Re-enable if failed
}
},
error: function(xhr, status, error) {
// Request failed, handle error
console.error("Request failed:", status, error);
toastr.error('Something went wrong! Try later', 'Error');
$('#uploadForm')[0].reset();
window.location.reload(true);
error: function(xhr) {
console.error("Critical Error:", xhr.responseText);
toastr.error('Something went wrong on the server', 'Error');
$btn.prop('disabled', false).text('Upload');
},
complete: function() {
// This ensures the reload only happens AFTER the API process is totally done
console.log("Process complete. Reloading...");
setTimeout(function() {
window.location.reload();
}, 500);
}
});
})
});
$('body').on('click', '.reload', function() {

View File

@ -1,4 +1,136 @@
<style>
.underline-input {
border: none;
border-bottom: 1px solid #6c757d;
outline: none;
padding: 2px 6px;
font-size: 15px;
background: transparent;
}
#OtherPolicyTermsForm .policy-term-main-label {
width: auto !important;
min-width: 0;
max-width: none;
height: auto;
padding-top: 8px;
margin-bottom: 0;
font-weight: 600;
}
#OtherPolicyTermsForm .policy-72-sum-input-group.input-group {
width: 100% !important;
max-width: 440px;
}
#OtherPolicyTermsForm #familyFloaterDiv_others .form-check-inline .form-check-input {
margin-right: 4px;
}
#OtherPolicyTermsForm #familyFloaterDiv_others .form-check-inline .form-check-label {
margin-right: 14px;
}
.btn-si-add-teal {
background-color: #00a8b5;
border: 1px solid #00a8b5;
color: #fff;
font-size: 1.35rem;
line-height: 1;
padding: 0.4rem 0.85rem;
border-radius: 0 4px 4px 0;
}
.btn-si-add-teal:hover {
background-color: #008e99;
border-color: #008e99;
color: #fff;
}
.policy-72-family-grid {
padding-top: 4px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.policy-72-ff-table {
width: 100%;
min-width: 860px;
table-layout: auto;
}
.policy-72-ff-table td {
vertical-align: top;
padding: 3px 6px;
}
.policy-72-ff-table .ff-age-wrap {
display: flex;
align-items: center;
gap: 6px;
}
.policy-72-ff-table .ff-elders-wrap {
display: flex;
align-items: center;
gap: 8px;
}
.policy-72-ff-table .ff-pay-wrap {
display: inline-flex;
align-items: center;
gap: 6px;
}
.policy-72-other-members-age-row {
display: none;
}
.policy-72-other-members-age-row.policy-72-other-ages-open {
display: table-row;
}
.policy-72-ff-table .ff-field-label {
white-space: nowrap;
font-size: 0.9rem;
color: #212529;
}
.policy-72-ff-table .ff-pay-wrap .ff-field-label {
white-space: nowrap;
font-size: 12px;
line-height: 1.2;
}
.policy-72-ff-table .ff-age-input {
width: 68px;
min-width: 48px;
}
.policy-72-ff-table .ff-elders-count-input {
width: 64px;
background: #d3d3d3;
}
.policy-72-ff-table .ff-pay-label-col .ff-field-label {
display: inline-block;
margin-right: 4px;
}
.policy-72-ff-table .ff-pay-check-col .form-check-input {
margin-left: 0;
}
.policy-72-ff-table .ff-pay-label-top,
.policy-72-ff-table .ff-pay-check-top {
vertical-align: top !important;
padding-top: 3px;
}
.policy-72-ff-table .ff-pay-check-top .form-check-input {
margin-top: 2px !important;
}
.button-like {
display: inline-block;
padding: 8px 15px;
@ -88,7 +220,146 @@ label {
<input type="hidden" name="policy_id" id="gpa_policy_id" />
<input type="hidden" id="emp_count" />
<div id="sumInsuredDiv" class="row align-items-start mb-3" style="display:none;">
<div class="col-md-4 col-lg-3">
<label for="sum_insured_others_72" class="form-label policy-term-main-label">Sum Insured</label>
</div>
<div class="col-md-8 col-lg-7">
<div class="input-group policy-72-sum-input-group">
<input type="text" name="sum_insureds" id="sum_insured_others_72" class="form-control" style="border-radius: 4px 0 0 4px;" onkeypress="return onlyNumbers(event)" onkeyup=" formatNumber(this); si_keup_num_to_word2(this)">
<button type="button" class="btn btn-si-add-teal si-add-more" onclick="appendOtherSIAddMore()">+</button>
</div>
<div id="numberToWordOthers_72" class="policy-term-number-words fst-italic text-muted small mt-1"></div>
</div>
</div>
<div style="margin-top: 10px;margin-bottom:15px;" id="sum_insured_add_more"></div>
<div id="append_html_for_other_policy_terms"></div>
<div id="familyFloaterDiv_others" class="row align-items-center mb-1" style="display:none;">
<div class="col-md-4 col-lg-3">
<label class="form-label policy-term-main-label mb-0">Family Floater</label>
</div>
<div class="col-md-8 col-lg-7">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="familyFloaterYes_others" name="family_floater" value="1">
<label class="form-check-label" for="familyFloaterYes_others" style="width: auto !important;">Yes</label>
<input class="form-check-input" type="radio" id="familyFloaterNo_others" name="family_floater" value="0">
<label class="form-check-label" for="familyFloaterNo_others" style="width: auto !important;">No</label>
</div>
</div>
</div>
<div id="familyFloaterDiv_others_two" class="row mb-3" style="display:none;">
<div class="col-md-4 col-lg-3 d-none d-md-block"></div>
<div class="col-md-8 col-lg-8 policy-72-family-grid">
<table class="policy-72-ff-table">
<tbody>
<tr>
<td style="width: 11%;"><span style="margin-right: 20px;" class="text-dark fw-semibold">Self:</span></td>
<td style="width: 11%;">
<input class="form-check-input mt-0" type="checkbox" name="family_floaters[]" value="self" id="self_others" checked>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Min Age:</span>
<input class="underline-input ff-age-input min_age" type="number" name="self_min_age" id="self_min_age_others" value="18">
</div>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Max Age:</span>
<input class="underline-input ff-age-input max_age" type="number" name="self_max_age" id="self_max_age_others" value="60">
</div>
</td>
<td class="ff-pay-label-top" style="width: 11%;"><span class="ff-field-label" style="margin-right: 20px;font-size: 12px;">Is Payable by employee:</span></td>
<td class="ff-pay-check-top" style="width: 11%;">
<input class="form-check-input mt-0" type="checkbox" name="is_payable_employee_for_self" id="is_payable_employee_for_self_others" value="1" checked>
</td>
</tr>
<tr>
<td style="width: 11%;"><span style="margin-right: 20px;" class="text-dark fw-semibold">Spouse:</span></td>
<td style="width: 11%;">
<input class="form-check-input mt-0" type="checkbox" name="family_floaters[]" value="spouse" id="spouse_others" checked>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Min Age:</span>
<input class="underline-input ff-age-input min_age" type="number" name="spouse_min_age" id="spouse_min_age_others" value="18">
</div>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Max Age:</span>
<input class="underline-input ff-age-input max_age" type="number" name="spouse_max_age" id="spouse_max_age_others" value="60">
</div>
</td>
<td class="ff-pay-label-top" style="width: 11%;"><span class="ff-field-label" style="margin-right: 20px;font-size: 12px;">Is Payable by employee:</span></td>
<td class="ff-pay-check-top" style="width: 11%;">
<input class="form-check-input mt-0" type="checkbox" name="is_payable_employee_for_spouse" id="is_payable_employee_for_spouse_others" value="1">
</td>
</tr>
<tr>
<td style="width: 11%;"><span class="text-dark fw-semibold">Children:</span></td>
<td style="width: 11%;">
<select name="family_floaters[]" id="children_others" class="form-select form-control d-inline-block" style="width: 86px;">
<option value="0">None</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Min Age:</span>
<input class="underline-input ff-age-input min_age" type="number" name="child_min_age" id="child_min_age_others" value="0">
</div>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Max Age:</span>
<input class="underline-input ff-age-input max_age" type="number" name="child_max_age" id="child_max_age_others" value="25">
</div>
</td>
<td class="ff-pay-label-top" style="width: 11%;"><span class="ff-field-label" style="margin-right: 20px;font-size: 12px;">Is Payable by employee:</span></td>
<td class="ff-pay-check-top" style="width: 11%;">
<input class="form-check-input mt-0" type="checkbox" name="is_payable_employee_for_child" id="is_payable_employee_for_child_others" value="1">
</td>
</tr>
<tr>
<td colspan="2"><span class="text-dark">Select Other Members:</span></td>
<td colspan="4">
<select name="family_floaters[]" id="family_floaters_others" class="form-select form-control" style="max-width: 430px;">
<option value="0">None</option>
<option value="1P">Only one parent (Either Father / Mother)</option>
<option value="2P">Only two parents (Father+Mother)</option>
<option value="1PIL">Only one parent in law (Either MIL / FIL)</option>
<option value="2PIL">Only two parents in law (FIL + MIL)</option>
<option value="2EPORPIL">Parents or PIL (Any two of Father, Mother, MIL, FIL)</option>
<option value="EPORPIL">Either Parents or PIL (Parents or Parents In Law)</option>
<option value="4EPORPIL">Parents + PIL (Father + Mother + MIL + FIL)</option>
</select>
</td>
</tr>
<tr id="other_members_age_row" class="policy-72-other-members-age-row">
<td colspan="2" style="width: 22%;">
<div class="ff-elders-wrap"><span class="ff-field-label" style="margin-right: 20px;">Elders Count:</span>
<input class="underline-input ff-elders-count-input" type="number" name="elder_member_count" id="member_count_others" value="0" readonly>
</div>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Min Age:</span>
<input class="underline-input ff-age-input" type="number" name="other_member_min_age" id="other_member_min_age_others" value="18">
</div>
</td>
<td style="width: 28%;">
<div class="ff-age-wrap"><span class="ff-field-label" style="margin-right: 20px;">Max Age:</span>
<input class="underline-input ff-age-input" type="number" name="other_member_max_age" id="other_member_max_age_others" value="60">
</div>
</td>
<td class="ff-pay-label-top" style="width: 11%;"><span class="ff-field-label" style="margin-right: 20px;font-size: 12px;">Is Payable by employee:</span></td>
<td class="ff-pay-check-top" style="width: 11%;">
<input class="form-check-input mt-0" type="checkbox" name="is_payable_employee_for_elders" id="is_payable_employee_for_elders_others" value="1">
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="append_html_for_other_policy_terms_72_after_family"></div>
<hr>
@ -102,9 +373,7 @@ label {
<button type="submit" class="btn btn-primary waves-effect waves-light mr-1" id="btnOtherTermsSubmit"
style="margin-top: 100px;">Submit</button>
</div>
</div>
</form>
</form>
</div>
@ -267,9 +536,9 @@ $('body').on('click', '.btnPolicyMaster', function() {
//special conditions fields
let gpaJsonObjectForSpecialCondition = JSON.parse(res.data);
Object.keys(gpaJsonObjectForSpecialCondition).forEach(function(key) {
if (key.includes("other_special_condition_label") || key.includes(
"other_special_condition_input")) {
if (key.includes("other_special_condition_label")) {
if (key.includes("special_condition_label") || key.includes("special_condition_input") ||
key.includes("other_special_condition_label") || key.includes("other_special_condition_input")) {
if (key.includes("special_condition_label") || key.includes("other_special_condition_label")) {
for (let index = 0; index <
gpaJsonObjectForSpecialCondition[key].length; index++) {
specialConditionForOthers();
@ -297,9 +566,12 @@ $('body').on('click', '.btnPolicyMaster', function() {
}
if (key.includes("multiple_sum_insured")) {
gpaJsonObjectForSpecialCondition[key].forEach((value, index) => {
appendOtherSIAddMore(value);
});
const value = gpaJsonObjectForSpecialCondition[key];
if (Array.isArray(value)) {
value.forEach(item => appendOtherSIAddMore(item));
} else if (typeof value === 'object' && value !== null) {
Object.values(value).forEach(item => appendOtherSIAddMore(item));
}
}
});
@ -345,12 +617,58 @@ $('body').on('click', '.btnPolicyMaster', function() {
}
}
if (policy_type_id == 72) {
if (key == "family_floater") {
$('#familyFloaterYes_others').prop('checked', jsonObject[key] == 1);
$('#familyFloaterNo_others').prop('checked', jsonObject[key] != 1);
}
if (key.includes("family_floaters") && jsonObject[key]) {
$('#children_others').val(String(jsonObject[key].childrens != null ? jsonObject[key].childrens : 0));
$('#self_others').prop('checked', jsonObject[key].self != 0);
$('#spouse_others').prop('checked', jsonObject[key].spouse != 0);
if (jsonObject[key]['either-parents-pil'] == 1) $('#family_floaters_others').val('EPORPIL');
else if (jsonObject[key].parents == 1 && jsonObject[key]['parents-in-law'] == 1) $('#family_floaters_others').val('2EPORPIL');
else if (jsonObject[key].parents == 2 && jsonObject[key]['parents-in-law'] == 2) $('#family_floaters_others').val('4EPORPIL');
else if (jsonObject[key].parents == 1) $('#family_floaters_others').val('1P');
else if (jsonObject[key].parents == 2) $('#family_floaters_others').val('2P');
else if (jsonObject[key]['parents-in-law'] == 1) $('#family_floaters_others').val('1PIL');
else if (jsonObject[key]['parents-in-law'] == 2) $('#family_floaters_others').val('2PIL');
else if (jsonObject[key]['either-parents-pil'] == 2) $('#family_floaters_others').val('2EPORPIL');
else $('#family_floaters_others').val('0');
}
if (key.includes("age_ratio") && jsonObject[key]) {
$('#self_min_age_others').val(jsonObject[key].self.min);
$('#self_max_age_others').val(jsonObject[key].self.max);
$('#spouse_min_age_others').val(jsonObject[key].spouse.min);
$('#spouse_max_age_others').val(jsonObject[key].spouse.max);
$('#child_min_age_others').val(jsonObject[key].child.min);
$('#child_max_age_others').val(jsonObject[key].child.max);
$('#other_member_min_age_others').val(jsonObject[key].elders.min);
$('#other_member_max_age_others').val(jsonObject[key].elders.max);
}
if (key.includes("enrollment_display_key") && jsonObject[key]) {
processOtherEnrollmentDisplayKey(jsonObject[key]);
}
}
});
if (policy_type_id == 72) {
if (jsonObject.is_payable_employee) {
var pe = jsonObject.is_payable_employee;
$('#is_payable_employee_for_self_others').prop('checked', pe.self == 1);
$('#is_payable_employee_for_spouse_others').prop('checked', pe.spouse == 1);
$('#is_payable_employee_for_child_others').prop('checked', pe.childern == 1);
$('#is_payable_employee_for_elders_others').prop('checked', pe.elders == 1);
}
initPolicy72FamilyFloaterUi();
}
}
$('#sum_insured_others').trigger('keyup');
$('#sum_insured_others_72').trigger('keyup');
$(".multiple_sum_insured").trigger("keyup");
@ -395,11 +713,11 @@ function specialConditionForOthers(count = 0) {
var appendElement = `<div class="form-group col-md-6 form-group-client-policy-masters removeDom">
<label for="specialconditionlabel" class="special_condition_label[]" style="width: 450px;position: relative;bottom: 6px;">
<input class="form-control" name="other_special_condition_label[]" id="other_special_condition_label[]" style="position: relative;right: 15px;">
<input class="form-control" name="special_condition_label[]" id="special_condition_label[]" style="position: relative;right: 15px;">
<span class="specialConditionClose" style="color: red; float: right;position: relative;bottom: 28px;left: 15px;">X</span>
</label>
<input type="text" name="other_special_condition_input[]" id="other_special_condition_input[]" class="form-control s special_condition_input[]">
<input type="text" name="special_condition_input[]" id="special_condition_input[]" class="form-control s special_condition_input[]">
</div>`;
console.log($(this));
$('.other_special_condition').each(function() {
@ -454,16 +772,48 @@ function si_keup_num_to_word2(input) {
var result = convertCommaNumberToWords(inputNumber);
$("#numberToWordOthers").text(result);
$("#numberToWordOthers_72").text(result);
} else {
$("#numberToWordOthers").text("");
$("#numberToWordOthers_72").text("");
}
};
function syncPolicy72ElderMemberCount() {
var map = { '0': 0, '1P': 1, '2P': 2, '1PIL': 1, '2PIL': 2, '2EPORPIL': 2, 'EPORPIL': 1, '4EPORPIL': 4 };
var v = $('#family_floaters_others').val();
var elderCount = map[v] !== undefined ? map[v] : 0;
$('#member_count_others').val(elderCount);
}
function togglePolicy72OtherMembersAgeRow() {
var v = $('#family_floaters_others').val();
if (v && v !== '0') {
$('#other_members_age_row').addClass('policy-72-other-ages-open').css('display', 'table-row');
} else {
$('#other_members_age_row').removeClass('policy-72-other-ages-open').css('display', 'none');
}
}
function initPolicy72FamilyFloaterUi() {
syncPolicy72ElderMemberCount();
togglePolicy72OtherMembersAgeRow();
}
$(document).on('change', '#family_floaters_others', function() {
syncPolicy72ElderMemberCount();
togglePolicy72OtherMembersAgeRow();
});
function appendPolicyTermsHTML(policy_type) {
var termsHTML = ""
$('#append_html_for_other_policy_terms').empty();
var termsHTML = "";
var targetContainer = '#append_html_for_other_policy_terms';
if (policy_type == 72) {
targetContainer = '#append_html_for_other_policy_terms_72_after_family';
}
$(targetContainer).empty();
if (policy_type == 7) {
@ -666,9 +1016,34 @@ function appendPolicyTermsHTML(policy_type) {
</div>
`
} else if (policy_type == 72) {
termsHTML = `
<div class="form-group OPD_POLICY_TERMS">
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="mode_of_serviceability_display" id="mode_of_serviceability_display" class="unchecked" checked></div><div class="col-md-5"><label for="mode_of_serviceability">Mode of Serviceability</label></div><div class="col-md-6"><input type="text" name="mode_of_serviceability" id="mode_of_serviceability" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="eligibility_display" id="eligibility_display" class="unchecked" checked></div><div class="col-md-5"><label for="eligibility">Eligibility</label></div><div class="col-md-6"><input type="text" name="eligibility" id="eligibility" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="total_sum_insured_limit_display" id="total_sum_insured_limit_display" class="unchecked" checked></div><div class="col-md-5"><label for="total_sum_insured_limit">Total Sum Insured limit</label></div><div class="col-md-6"><input type="text" name="total_sum_insured_limit" id="total_sum_insured_limit" class="form-control" value="INR 15000"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="in_person_doctor_consultation_display" id="in_person_doctor_consultation_display" class="unchecked" checked></div><div class="col-md-5"><label for="in_person_doctor_consultation">In Person Doctor Consultation</label></div><div class="col-md-6"><input type="text" name="in_person_doctor_consultation" id="in_person_doctor_consultation" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="prescribed_lab_test_pathology_radiology_display" id="prescribed_lab_test_pathology_radiology_display" class="unchecked" checked></div><div class="col-md-5"><label for="prescribed_lab_test_pathology_radiology">Prescribed Lab test (Pathology & Radiology)</label></div><div class="col-md-6"><input type="text" name="prescribed_lab_test_pathology_radiology" id="prescribed_lab_test_pathology_radiology" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="prescribed_pharmacy_display" id="prescribed_pharmacy_display" class="unchecked" checked></div><div class="col-md-5"><label for="prescribed_pharmacy">Prescribed Pharmacy</label></div><div class="col-md-6"><input type="text" name="prescribed_pharmacy" id="prescribed_pharmacy" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="dental_display" id="dental_display" class="unchecked" checked></div><div class="col-md-5"><label for="dental">Dental</label></div><div class="col-md-6"><input type="text" name="dental" id="dental" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="vision_display" id="vision_display" class="unchecked" checked></div><div class="col-md-5"><label for="vision">Vision</label></div><div class="col-md-6"><input type="text" name="vision" id="vision" class="form-control"></div></div>
<div class="row" style="margin-bottom: 10px;"><div class="col-md-1"><input type="checkbox" style="margin-top: 12px" name="vaccination_for_children_and_adults_display" id="vaccination_for_children_and_adults_display" class="unchecked" checked></div><div class="col-md-5"><label for="vaccination_for_children_and_adults">Vaccination for children & adults</label></div><div class="col-md-6"><input type="text" name="vaccination_for_children_and_adults" id="vaccination_for_children_and_adults" class="form-control"></div></div>
</div>`;
}
$('#append_html_for_other_policy_terms').append(termsHTML);
if (policy_type == 72) {
$('#sumInsuredDiv').show();
$('#familyFloaterDiv_others').show();
$('#familyFloaterDiv_others_two').show();
initPolicy72FamilyFloaterUi();
} else {
$('#sumInsuredDiv').hide();
$('#familyFloaterDiv_others').hide();
$('#familyFloaterDiv_others_two').hide();
$('#append_html_for_other_policy_terms_72_after_family').empty();
}
$(targetContainer).append(termsHTML);
}
@ -699,4 +1074,30 @@ function appendOtherSIAddMore(data = null) {
addMoreContainer.insertAdjacentHTML('beforeend', html);
}
function processOtherEnrollmentDisplayKey(displayObject) {
if (!displayObject || typeof displayObject !== 'object' || Array.isArray(displayObject)) {
return;
}
const displayMap = {
'Mode Of Serviceability': 'mode_of_serviceability_display',
'Eligibility': 'eligibility_display',
'Total Sum Insured Limit': 'total_sum_insured_limit_display',
'In Person Doctor Consultation': 'in_person_doctor_consultation_display',
'Prescribed Lab Test Pathology Radiology': 'prescribed_lab_test_pathology_radiology_display',
'Prescribed Pharmacy': 'prescribed_pharmacy_display',
'Dental': 'dental_display',
'Vision': 'vision_display',
'Vaccination For Children And Adults': 'vaccination_for_children_and_adults_display'
};
$('#append_html_for_other_policy_terms_72_after_family .unchecked').prop('checked', false);
Object.keys(displayObject).forEach(function(label) {
const checkboxId = displayMap[label];
if (checkboxId && displayObject[label] !== '' && displayObject[label] !== null && displayObject[label] !== undefined) {
$('#' + checkboxId).prop('checked', true);
}
});
}
</script>

View File

@ -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",

27
public/2026-04-08.md Normal file
View File

@ -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).

View File

@ -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.