MERGE_UAT_FORM_VALIDATIONS
This commit is contained in:
commit
53d3e9ed07
@ -350,6 +350,15 @@ class ApiServiceController extends BaseController
|
||||
|
||||
return $this->respond(['status' => true, 'code' => 200, 'message' => 'Action Triggered','data' => [] ]);
|
||||
|
||||
}else if ($tpa_id == $this->icici_primary_key) // ICICI Lombard (EWA)
|
||||
{
|
||||
$file_id = $fileModel->insert($data);
|
||||
log_message('error', "ICICI - Files table inserted successfully, File id : {$file_id}");
|
||||
$r = Jobs::addJob(['job_name' => 'getEnrollmentBatchStatus', 'payload' => ['client_policy_id' => $policy_id, 'file_id' => $file_id, 'client_policy_id' => $policy_id, 'return_type' => 'job']]);
|
||||
log_message('error', "ICICI - getEnrollmentBatchStatus job pushed successfully.");
|
||||
|
||||
return $this->respond(['status' => true, 'code' => 200, 'message' => 'Action Triggered','data' => [] ]);
|
||||
|
||||
}else{
|
||||
return $this->respond(['status' => false, 'code' => 200,'message' => 'TPA not found ','data' => [] ]);
|
||||
}
|
||||
@ -553,7 +562,6 @@ class ApiServiceController extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// public function getWellnessUrl()
|
||||
// {
|
||||
|
||||
@ -725,7 +733,98 @@ class ApiServiceController extends BaseController
|
||||
// }
|
||||
|
||||
|
||||
public function sendDataToTPA()
|
||||
{
|
||||
|
||||
$requested_data = $this->request->getPost() ?? [];
|
||||
log_message('error', "getTPAID payloads :" . json_encode($requested_data));
|
||||
|
||||
$tpa_id = $requested_data['tpa_id'] ?? null;
|
||||
$policy_no = $requested_data['policy_no'] ?? null;
|
||||
$client_id = $requested_data['client_id'] ?? null;
|
||||
$branch_id = $requested_data['client_branch_id'] ?? null;
|
||||
$policy_id = $requested_data['client_policy_id'] ?? null;
|
||||
$event = $requested_data['event'] ?? null;
|
||||
|
||||
$event_mapping = [
|
||||
'inception' => 'A',
|
||||
'missed_inception' => 'A',
|
||||
'addition' => 'A',
|
||||
'dependent_addition' => 'A',
|
||||
'deletion' => 'D',
|
||||
'correction' => 'M',
|
||||
'si_enhancement' => 'M'
|
||||
];
|
||||
|
||||
|
||||
$fileModel = new BatchFileModel();
|
||||
$filesData = $fileModel
|
||||
->join('client_policy', 'client_policy.id = batch_files.client_policy_id')
|
||||
->where('client_policy.tpa_id', $tpa_id)
|
||||
->where('batch_files.is_active', 1)
|
||||
->where('batch_files.event_type', 'api')
|
||||
->where('batch_files.icici_status_flag !=', 'COMPLETED')
|
||||
->countAllResults();
|
||||
|
||||
if($filesData > 0){
|
||||
log_message('error', "TPA initiation is in progress.");
|
||||
return $this->respond(['status' => false, 'code' => 200,'message' => 'TPA initiation is in progress.','data' => [] ]);
|
||||
}
|
||||
|
||||
$employeePolicyModel = new EmployeePolicyModel();
|
||||
$employeePolicyData = $employeePolicyModel
|
||||
->select('
|
||||
employees.*,
|
||||
employee_polices.id as emp_policy_id,
|
||||
employee_polices.client_policy_id,
|
||||
')
|
||||
->join('employees', 'employees.id = employee_polices.employee_id')
|
||||
->where('employee_polices.is_active', 1)
|
||||
->where('employee_polices.status', 'active')
|
||||
->where('employees.is_active', 1)
|
||||
->where('employees.emp_status', 'active')
|
||||
->where('employee_polices.tpa_id IS NULL')
|
||||
->where('employee_polices.client_policy_id', $policy_id)
|
||||
->countAllResults();
|
||||
|
||||
if($employeePolicyData == 0){
|
||||
log_message('error', "No Employee Policy found with null TPA ID. TPA ID is already updated.");
|
||||
return $this->respond(['status' => false, 'code' => 200,'message' => 'No employee to upload','data' => [] ]);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'file_name' => "API - Employee data push",
|
||||
'event_type' => $event,
|
||||
'actions' => "push",
|
||||
'insurer_or_tpa' => "tpa",
|
||||
'batch_code' => generate_random_string(4),
|
||||
'status' => "inprogress",
|
||||
'client_id' => $client_id,
|
||||
'client_policy_id'=> $policy_id,
|
||||
'client_branch_id'=> $branch_id,
|
||||
'created_by'=> get_session_userid(),
|
||||
];
|
||||
|
||||
if ($tpa_id == $this->icici_primary_key) // MediAssist
|
||||
{
|
||||
$file_id = $fileModel->insert($data);
|
||||
log_message('error', "Files table inserted successfully, File id : {$file_id}");
|
||||
|
||||
$requested_data['file_id'] = $file_id;
|
||||
$requested_data['return_type'] = 'job';
|
||||
$requested_data['insurer_or_tpa'] = 'tpa';
|
||||
$requested_data['flag_status'] = $event_mapping[$event] ?? "A";
|
||||
|
||||
$ICICILombardController = new ICICILombardController();
|
||||
$apiResponse = $ICICILombardController->ICICIPushEmployeeDetails($requested_data);
|
||||
|
||||
// $r = Jobs::addJob(['job_name' => 'ICICIPushEmployeeDetails', 'payload' => $requested_data]);
|
||||
// log_message('error', "ICICIPushEmployeeDetails job pushed successfully.");
|
||||
|
||||
return $this->respond(['status' => true, 'code' => 200, 'message' => 'Action Triggered','data' => $apiResponse ]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -784,6 +784,8 @@ class EmployeeServiceController extends AdminController
|
||||
//get file name
|
||||
// check_dob_diff('4-APr-1990');die();
|
||||
$file_id = $params['file_id'];
|
||||
$batch_file_id = $params['batch_file_id'] ?? null;
|
||||
|
||||
$file = $this->fileModel->find((int)$file_id);
|
||||
// dd($file);
|
||||
$return = [];
|
||||
@ -1063,7 +1065,7 @@ class EmployeeServiceController extends AdminController
|
||||
|
||||
//proceed next data level validation in JOB queue
|
||||
$job_details = new Jobs();
|
||||
$r = Jobs::addJob(['job_name' => 'excelFileDataValidation','payload' => ['file_id' => $file_id]]);
|
||||
$r = Jobs::addJob(['job_name' => 'excelFileDataValidation','payload' => ['file_id' => $file_id, 'batch_file_id' => $batch_file_id]]);
|
||||
// $jobWorker = new JobWorker();
|
||||
// JobWorker::processJob($r);
|
||||
|
||||
@ -1077,6 +1079,8 @@ class EmployeeServiceController extends AdminController
|
||||
helper('excel_util_helper');
|
||||
//get file name
|
||||
$file_id = $params['file_id'];
|
||||
$batch_file_id = $params['batch_file_id'] ?? null;
|
||||
|
||||
$file = $this->fileModel->find((int)$file_id);
|
||||
// dd($file);
|
||||
$return = [];
|
||||
@ -1307,13 +1311,13 @@ class EmployeeServiceController extends AdminController
|
||||
//proceed next data level validation in JOB queue
|
||||
$job_details = new Jobs();
|
||||
|
||||
$r = Jobs::addJob(['job_name' => 'employeesCorrectionProcess','payload' => ['file_id' => $file_id]]);
|
||||
$r = Jobs::addJob(['job_name' => 'employeesCorrectionProcess','payload' => ['file_id' => $file_id, 'batch_file_id' => $batch_file_id]]);
|
||||
}
|
||||
else if ($file['action'] == 'inception' || $file['action'] == 'missed_inception' || $file['action'] == 'addition' || $file['action'] == 'dependent_addition')//inception OR addition OR dependent addition
|
||||
{
|
||||
//proceed next data level validation in JOB queue
|
||||
// $job_details = new Jobs();
|
||||
$r = Jobs::addJob(['job_name' => 'employeesOnboardPreprocess','payload' => ['file_id' => $file_id]]);
|
||||
$r = Jobs::addJob(['job_name' => 'employeesOnboardPreprocess','payload' => ['file_id' => $file_id, 'batch_file_id' => $batch_file_id]]);
|
||||
// $jobWorker = new JobWorker();
|
||||
// JobWorker::processJob($r);
|
||||
}
|
||||
@ -1333,166 +1337,183 @@ class EmployeeServiceController extends AdminController
|
||||
{
|
||||
helper('excel_util_helper');
|
||||
// dd($params);
|
||||
if(isset($params['file_id']))//handle data from excel to inception
|
||||
if (isset($params['file_id'])) //handle data from excel to inception
|
||||
{
|
||||
//get file name
|
||||
$file_id = $params['file_id'];
|
||||
$file = $this->fileModel->find((int)$file_id);
|
||||
// dd($file);
|
||||
$return = [];
|
||||
if(!isset($file))
|
||||
{
|
||||
//file not found in DB
|
||||
return array('status' => false, 'msg' => 'file not found in DB');
|
||||
}
|
||||
$file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name'];
|
||||
|
||||
//check physical file
|
||||
if(!file_exists($file_name_with_path))
|
||||
{
|
||||
//file not found update status and reason
|
||||
$message = "Physical file not found";
|
||||
// echo $message;
|
||||
$this->myLogger->logme('error',($message . ' for file id ' . $file_id));
|
||||
$this->fileModel->where('id', $file_id)->set(['status' => 'failed','reason' => json_encode(['error_summary' => array_count_values([5]),'error_data' => $message])])->update();
|
||||
return array('error_summary' => [5], 'error_data' => $message);
|
||||
}
|
||||
//get file name
|
||||
$file_id = $params['file_id'];
|
||||
$file = $this->fileModel->find((int)$file_id);
|
||||
// dd($file);
|
||||
$return = [];
|
||||
if (!isset($file)) {
|
||||
//file not found in DB
|
||||
return array('status' => false, 'msg' => 'file not found in DB');
|
||||
}
|
||||
$file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name'];
|
||||
|
||||
$columns_to_check = [];
|
||||
if($file['action'] == 'inception'){ $columns_to_check = $this->inception_excel_columns; }
|
||||
if($file['action'] == 'addition'){ $columns_to_check = $this->inception_excel_columns; }
|
||||
if($file['action'] == 'dependent_addition'){ $columns_to_check = $this->inception_excel_columns; }
|
||||
if($file['action'] == 'deletion'){ $columns_to_check = $this->deletion_excel_columns; }
|
||||
if($file['action'] == 'correction'){ $columns_to_check = $this->correction_excel_columns; }
|
||||
if($file['action'] == 'si_enhancement'){ $columns_to_check = $this->si_enhance_excel_columns; }
|
||||
if($file['action'] == 'missed_inception'){ $columns_to_check = $this->inception_excel_columns; }
|
||||
//check physical file
|
||||
if (!file_exists($file_name_with_path)) {
|
||||
//file not found update status and reason
|
||||
$message = "Physical file not found";
|
||||
// echo $message;
|
||||
$this->myLogger->logme('error', ($message . ' for file id ' . $file_id));
|
||||
$this->fileModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => json_encode(['error_summary' => array_count_values([5]), 'error_data' => $message])])->update();
|
||||
return array('error_summary' => [5], 'error_data' => $message);
|
||||
}
|
||||
|
||||
$current_column_action = null;
|
||||
if($file['action'] == 'inception'){ $current_column_action = 'I'; }
|
||||
else if($file['action'] == 'addition'){ $current_column_action = 'A'; }
|
||||
else if($file['action'] == 'dependent_addition'){ $current_column_action = 'DA'; }
|
||||
else if($file['action'] == 'deletion'){ $current_column_action = 'D'; }
|
||||
else if($file['action'] == 'correction'){ $current_column_action = 'C'; }
|
||||
else if($file['action'] == 'si_enhancement'){ $current_column_action = 'SI'; }
|
||||
else if($file['action'] == 'enrollment'){ $current_column_action = 'I'; }
|
||||
else if($file['action'] == 'missed_inception'){ $current_column_action = 'MI'; }
|
||||
$columns_to_check = [];
|
||||
if ($file['action'] == 'inception') {
|
||||
$columns_to_check = $this->inception_excel_columns;
|
||||
}
|
||||
if ($file['action'] == 'addition') {
|
||||
$columns_to_check = $this->inception_excel_columns;
|
||||
}
|
||||
if ($file['action'] == 'dependent_addition') {
|
||||
$columns_to_check = $this->inception_excel_columns;
|
||||
}
|
||||
if ($file['action'] == 'deletion') {
|
||||
$columns_to_check = $this->deletion_excel_columns;
|
||||
}
|
||||
if ($file['action'] == 'correction') {
|
||||
$columns_to_check = $this->correction_excel_columns;
|
||||
}
|
||||
if ($file['action'] == 'si_enhancement') {
|
||||
$columns_to_check = $this->si_enhance_excel_columns;
|
||||
}
|
||||
if ($file['action'] == 'missed_inception') {
|
||||
$columns_to_check = $this->inception_excel_columns;
|
||||
}
|
||||
|
||||
// get policy and rack details
|
||||
$policy_terms = $this->clientPolicyModel->getPolicyDetails($file['client_id'],$file['policy_id']);
|
||||
$policy_terms = (array) $policy_terms[0];// convert obj to array
|
||||
// $policy_terms = json_decode($policy_terms[0]->policy_terms);
|
||||
|
||||
// dd($policy_terms);
|
||||
//get excel data
|
||||
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$highestRowAndColumn = $sheet->getHighestRowAndColumn();
|
||||
$allowedHighestColumn = end($columns_to_check);
|
||||
// dd($allowedHighestColumn);
|
||||
$excel_data = $sheet->rangeToArray('A1:' . $allowedHighestColumn['col_cell_name'] . $highestRowAndColumn['row']);
|
||||
unset($excel_data[0]);
|
||||
$current_column_action = null;
|
||||
if ($file['action'] == 'inception') {
|
||||
$current_column_action = 'I';
|
||||
} else if ($file['action'] == 'addition') {
|
||||
$current_column_action = 'A';
|
||||
} else if ($file['action'] == 'dependent_addition') {
|
||||
$current_column_action = 'DA';
|
||||
} else if ($file['action'] == 'deletion') {
|
||||
$current_column_action = 'D';
|
||||
} else if ($file['action'] == 'correction') {
|
||||
$current_column_action = 'C';
|
||||
} else if ($file['action'] == 'si_enhancement') {
|
||||
$current_column_action = 'SI';
|
||||
} else if ($file['action'] == 'enrollment') {
|
||||
$current_column_action = 'I';
|
||||
} else if ($file['action'] == 'missed_inception') {
|
||||
$current_column_action = 'MI';
|
||||
}
|
||||
|
||||
// get policy and rack details
|
||||
$policy_terms = $this->clientPolicyModel->getPolicyDetails($file['client_id'], $file['policy_id']);
|
||||
$policy_terms = (array) $policy_terms[0]; // convert obj to array
|
||||
// $policy_terms = json_decode($policy_terms[0]->policy_terms);
|
||||
|
||||
//get policy slab rates
|
||||
$slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($file['policy_id'],$file['client_id']);
|
||||
// dd($slab_details);
|
||||
//get existing units in the current branch
|
||||
$existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $file['client_id'],client_branch_id: $file['client_branch_id']);
|
||||
// dd($policy_terms);
|
||||
//get excel data
|
||||
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$employee_data_group_by_family = data_group_by_family($excel_data, 'excel', '', $current_column_action);
|
||||
// dd($employee_data_group_by_family);
|
||||
$highestRowAndColumn = $sheet->getHighestRowAndColumn();
|
||||
$allowedHighestColumn = end($columns_to_check);
|
||||
// dd($allowedHighestColumn);
|
||||
$excel_data = $sheet->rangeToArray('A1:' . $allowedHighestColumn['col_cell_name'] . $highestRowAndColumn['row']);
|
||||
unset($excel_data[0]);
|
||||
// dd($excel_data);
|
||||
|
||||
$employee_insert_count = 0;
|
||||
foreach ($employee_data_group_by_family as $emp_id => $family)
|
||||
{
|
||||
//get policy slab rates
|
||||
$slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($file['policy_id'], $file['client_id']);
|
||||
// dd($slab_details);
|
||||
//get existing units in the current branch
|
||||
$existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $file['client_id'], client_branch_id: $file['client_branch_id']);
|
||||
|
||||
//if action is DA then get all familiy members,transfrom them into excel array, addd data source as db or excel
|
||||
if($file['action'] == 'dependent_addition')
|
||||
{
|
||||
$existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(emp_code: $emp_id,client_id: $file['client_id'],client_policy_id: $file ['policy_id'],emp_status: ['active'],policy_status:['active'],client_branch_id: [ $file['client_branch_id'] ]);
|
||||
// dd($existing_famility_details);
|
||||
//transsform familiy details from db columns to exxcel row with column indexs for checking remaining functionalitites
|
||||
$existing_famility_details = transform_db_data_to_excel($existing_famility_details,$file);
|
||||
// Kint::dump($existing_famility_details);
|
||||
$family = array_merge($family,$existing_famility_details);
|
||||
$family = data_group_by_family($family, 'excel', 1)[ $emp_id ];// reason to call this again is bring self to first index of the array
|
||||
// dd($family);
|
||||
$self = current(array_filter($family, fn($r) => strtolower($r[5] ?? '') === 'self'));
|
||||
$premium = (int)($self['temp']['rata_premimum'] ?? 0);
|
||||
foreach ($family as &$r) if (strtolower($r[5] ?? '') !== 'self') $r['self_rata_premium'] = $premium;
|
||||
}
|
||||
$employee_data_group_by_family = data_group_by_family($excel_data, 'excel', '', $current_column_action);
|
||||
// dd($employee_data_group_by_family);
|
||||
|
||||
// Kint::dump($family);
|
||||
$data = calculate_premium_new(family_data:$family,policy_terms: $policy_terms,slab_details : $slab_details,fileArr: $file, existing_units:$existing_units);
|
||||
// dd($data);
|
||||
$employee_data_group_by_family[$emp_id] = $data;
|
||||
$res = $this->employeesOnboardProcess(['familiy_data' => $data,'file' => $file]);
|
||||
$employee_insert_count = 0;
|
||||
foreach ($employee_data_group_by_family as $emp_id => $family) {
|
||||
|
||||
if($res > 0){
|
||||
$employee_insert_count++;
|
||||
}
|
||||
}
|
||||
//if action is DA then get all familiy members,transfrom them into excel array, addd data source as db or excel
|
||||
if ($file['action'] == 'dependent_addition') {
|
||||
$existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(emp_code: $emp_id, client_id: $file['client_id'], client_policy_id: $file['policy_id'], emp_status: ['active'], policy_status: ['active'], client_branch_id: [$file['client_branch_id']]);
|
||||
// dd($existing_famility_details);
|
||||
//transsform familiy details from db columns to exxcel row with column indexs for checking remaining functionalitites
|
||||
$existing_famility_details = transform_db_data_to_excel($existing_famility_details, $file);
|
||||
// Kint::dump($existing_famility_details);
|
||||
$family = array_merge($family, $existing_famility_details);
|
||||
$family = data_group_by_family($family, 'excel', 1)[$emp_id]; // reason to call this again is bring self to first index of the array
|
||||
// dd($family);
|
||||
$self = current(array_filter($family, fn($r) => strtolower($r[5] ?? '') === 'self'));
|
||||
$premium = (int)($self['temp']['rata_premimum'] ?? 0);
|
||||
foreach ($family as &$r) if (strtolower($r[5] ?? '') !== 'self') $r['self_rata_premium'] = $premium;
|
||||
}
|
||||
|
||||
if($employee_insert_count > 0){
|
||||
$this->fileModel->where('id', $file_id)->set(['status' => 'success','reason' => ''])->update();
|
||||
$this->myLogger->logme("error",'{file_id} uploaded success',['file_id' => $file_id]);
|
||||
}else{
|
||||
$reason = json_encode([
|
||||
'error_summary' => [5 => 1],
|
||||
'error_data' => "Rack rate configuration issue: Please check the slab rates configuration"
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
$this->fileModel->where('id', $file_id)->set(['status' => 'failed','reason' => $reason])->update();
|
||||
$this->myLogger->logme("error",'{file_id} uploaded failed with reason: Rack rate configuration issue: Please check the slab rates configuration',['file_id' => $file_id]);
|
||||
// Kint::dump($family);
|
||||
$data = calculate_premium_new(family_data: $family, policy_terms: $policy_terms, slab_details: $slab_details, fileArr: $file, existing_units: $existing_units);
|
||||
// dd($data);
|
||||
$employee_data_group_by_family[$emp_id] = $data;
|
||||
// $res = $this->employeesOnboardProcess(['familiy_data' => $data, 'file' => $file]);
|
||||
|
||||
}
|
||||
// if ($res > 0) {
|
||||
// $employee_insert_count++;
|
||||
// }
|
||||
}
|
||||
|
||||
$this->setPullNotification($this->getFileMetaDataByFileId($file_id,'success'));
|
||||
// if ($employee_insert_count > 0) {
|
||||
// $this->fileModel->where('id', $file_id)->set(['status' => 'success', 'reason' => ''])->update();
|
||||
// $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]);
|
||||
// } else {
|
||||
// $reason = json_encode([
|
||||
// 'error_summary' => [5 => 1],
|
||||
// 'error_data' => "Rack rate configuration issue: Please check the slab rates configuration"
|
||||
// ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
// $this->fileModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => $reason])->update();
|
||||
// $this->myLogger->logme("error", '{file_id} uploaded failed with reason: Rack rate configuration issue: Please check the slab rates configuration', ['file_id' => $file_id]);
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
else if(isset($params['client_policy_id']))//handle data from enrollment to inception
|
||||
{
|
||||
// $this->setPullNotification($this->getFileMetaDataByFileId($file_id, 'success'));
|
||||
} else if (isset($params['client_policy_id'])) //handle data from enrollment to inception
|
||||
{
|
||||
$client_policy_id = $params['client_policy_id'];
|
||||
//get client id
|
||||
$client_id = ($this->clientPolicyModel->select('client_id')->find((int)$client_policy_id))['client_id'];
|
||||
// dd($client_id);
|
||||
|
||||
// get policy and rack details
|
||||
$policy_terms = $this->clientPolicyModel->getPolicyDetails($client_id,$client_policy_id);
|
||||
$policy_terms = (array) $policy_terms[0];// convert obj to array
|
||||
$policy_terms = $this->clientPolicyModel->getPolicyDetails($client_id, $client_policy_id);
|
||||
$policy_terms = (array) $policy_terms[0]; // convert obj to array
|
||||
|
||||
//get policy slab rates
|
||||
$slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($client_policy_id,$client_id);
|
||||
$slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($client_policy_id, $client_id);
|
||||
|
||||
$existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_id: $client_id,client_policy_id: $client_policy_id,emp_status: ['enrolled'],policy_status:['enrolled']);
|
||||
$existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_id: $client_id, client_policy_id: $client_policy_id, emp_status: ['enrolled'], policy_status: ['enrolled']);
|
||||
|
||||
// $file = ['id' => null,'client_id' => $client_id,'policy_id' => $client_policy_id,'action' => 'inception'];
|
||||
$file = ['id' => null,'client_id' => $client_id,'policy_id' => $client_policy_id,'action' => 'inception','created_by' => get_session_userid(),'client_branch_id' => $params['client_branch_id']];
|
||||
$file = ['id' => null, 'client_id' => $client_id, 'policy_id' => $client_policy_id, 'action' => 'inception', 'created_by' => get_session_userid(), 'client_branch_id' => $params['client_branch_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']);
|
||||
$existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $file['client_id'], client_branch_id: $file['client_branch_id']);
|
||||
// dd($this->employeeModel->getLastQuery());
|
||||
// Kint::dump($existing_famility_details);die();
|
||||
$employee_data_group_by_family = data_group_by_family($existing_famility_details,$data_source = 'db');
|
||||
// dd($employee_data_group_by_family);
|
||||
foreach ($employee_data_group_by_family as $emp_id => $family)
|
||||
{
|
||||
$employee_data_group_by_family = data_group_by_family($existing_famility_details, $data_source = 'db');
|
||||
// dd($employee_data_group_by_family);
|
||||
foreach ($employee_data_group_by_family as $emp_id => $family) {
|
||||
$transformed_famility_details = transform_db_data_to_excel($family);
|
||||
// $data = calculate_premium_new($transformed_famility_details,$policy_terms,$slab_details,$file);
|
||||
$data = calculate_premium_new(family_data:$transformed_famility_details,policy_terms: $policy_terms,slab_details : $slab_details,fileArr: $file, existing_units:$existing_units);
|
||||
// dd($data);
|
||||
$employee_data_group_by_family[$emp_id] = $data;
|
||||
$this->employeesOnboardProcess(['familiy_data' => $data,'file' => $file]);
|
||||
}
|
||||
// $data = calculate_premium_new($transformed_famility_details,$policy_terms,$slab_details,$file);
|
||||
$data = calculate_premium_new(family_data: $transformed_famility_details, policy_terms: $policy_terms, slab_details: $slab_details, fileArr: $file, existing_units: $existing_units);
|
||||
// dd($data);
|
||||
$employee_data_group_by_family[$emp_id] = $data;
|
||||
$this->employeesOnboardProcess(['familiy_data' => $data, 'file' => $file]);
|
||||
}
|
||||
|
||||
// dd($employee_data_group_by_family);
|
||||
}
|
||||
// dd($employee_data_group_by_family);
|
||||
}
|
||||
|
||||
if(count($employee_data_group_by_family ?? []) && isset($params['batch_file_id'])){
|
||||
$r = Jobs::addJob(['job_name' => 'updateEmployeeDataFromTpa','payload' => ['file_id' => $file_id, 'batch_file_id' => $params['batch_file_id']]]);
|
||||
$this->myLogger->logme("info", 'Batch file id {batch_file_id} processed successfully', ['batch_file_id' => $params['batch_file_id']]);
|
||||
}
|
||||
|
||||
// die();
|
||||
return (count($employee_data_group_by_family));
|
||||
|
||||
}
|
||||
|
||||
//deletion of emp
|
||||
@ -1652,6 +1673,7 @@ class EmployeeServiceController extends AdminController
|
||||
helper('excel_util_helper');
|
||||
//get file name
|
||||
$file_id = $params['file_id'];
|
||||
$batch_file_id = $params['batch_file_id'] ?? null;
|
||||
$file = $this->fileModel->find((int)$file_id);
|
||||
// dd($file);
|
||||
|
||||
@ -1718,6 +1740,12 @@ class EmployeeServiceController extends AdminController
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(!empty($batch_file_id)){
|
||||
$r = Jobs::addJob(['job_name' => 'updateEmployeeDataFromTpa','payload' => ['file_id' => $file_id, 'batch_file_id' => $batch_file_id]]);
|
||||
$this->myLogger->logme("error", 'Batch file id {batch_file_id} processed successfully', ['batch_file_id' => $batch_file_id]);
|
||||
}
|
||||
|
||||
$this->fileModel->where('id', $file_id)->set(['status' => 'success','reason' => ''])->update();
|
||||
$this->myLogger->logme("error",'{file_id} uploaded success',['file_id' => $file_id]);
|
||||
//set success msg to pull notifications
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,14 @@ class VidalApiController extends BaseController
|
||||
protected $claim_type_array;
|
||||
protected $ticketController;
|
||||
|
||||
/**
|
||||
* Vidal `relation` (lowercase) → Nhance relation (lowercase).
|
||||
* Populated once from {@see self::vidalRelationshipReferenceMap()} (values match public/tmp/relationship.csv; that file is reference only, not read at runtime).
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $vidalRelationshipMap = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = \Config\Database::connect();
|
||||
@ -26,6 +34,8 @@ class VidalApiController extends BaseController
|
||||
|
||||
$this->ticketController = new TicketController();
|
||||
$this->claim_type_array = $this->ticketController->claimType;
|
||||
|
||||
$this->vidalRelationshipMap = self::vidalRelationshipReferenceMap();
|
||||
}
|
||||
|
||||
|
||||
@ -1022,6 +1032,522 @@ class VidalApiController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
public function VidalGetBenefDetailsV2($requestData = null)
|
||||
{
|
||||
$requestData = is_array($requestData) ? $requestData : [];
|
||||
$function_calling_type = $requestData['return_type'] ?? 'job';
|
||||
|
||||
try {
|
||||
|
||||
helper('api');
|
||||
|
||||
$url = $this->vidalEnrollmentInfoApiUrl();
|
||||
$method = 'POST';
|
||||
|
||||
$subscriptionKey = getenv('VIDAL_API_SUBSCRIPTION_KEY');
|
||||
if (empty($subscriptionKey)) {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull | VIDAL_API_SUBSCRIPTION_KEY missing');
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'VIDAL_API_SUBSCRIPTION_KEY required'];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'VIDAL_API_SUBSCRIPTION_KEY required']);
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'ocp-apim-subscription-key: ' . $subscriptionKey,
|
||||
];
|
||||
|
||||
$policyNo = $requestData['policy_no'] ?? null;
|
||||
$client_policy_id = $requestData['client_policy_id'] ?? null;
|
||||
|
||||
if (empty($policyNo)) {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull | policy_no missing in request');
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'policy_no required'];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'policy_no required']);
|
||||
}
|
||||
|
||||
if (empty($client_policy_id)) {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull | client_policy_id missing in request');
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'client_policy_id required'];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'client_policy_id required']);
|
||||
}
|
||||
|
||||
log_message('error', "VIDAL V2 - TPA ID Pull | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
|
||||
|
||||
$batchFiles = $this->db->table('batch_files f')
|
||||
->select('f.created_at')
|
||||
->where('f.client_policy_id', $client_policy_id)
|
||||
->where('f.insurer_or_tpa', 'tpa')
|
||||
->where('f.actions', 'export')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
if (empty($batchFiles)) {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull FAILED | batchFiles is empty for this tpa id pull request');
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'batchFiles not found'];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'batchFiles not found']);
|
||||
}
|
||||
|
||||
$pageSize = 100;
|
||||
$startIndex = 1;
|
||||
$allBenef = [];
|
||||
|
||||
while (true) {
|
||||
$endIndex = $startIndex + $pageSize - 1;
|
||||
$body = [
|
||||
'policyNo' => $policyNo,
|
||||
'startIndex' => $startIndex,
|
||||
'endIndex' => $endIndex,
|
||||
];
|
||||
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull | API params ' . json_encode([$url, $method, $headers, $body]));
|
||||
|
||||
$response = call_third_party_api($url, $method, $headers, $body);
|
||||
|
||||
if ($response['status'] !== true) {
|
||||
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
|
||||
$file_model = new BatchFileModel();
|
||||
$file_model->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
|
||||
log_message('error', "VIDAL V2 - TPA ID Pull | Files table status updated for the file id : {$requestData['file_id']}");
|
||||
} else {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull | Failed to update file table status.');
|
||||
}
|
||||
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull API FAILED | API failed: ' . json_encode($response));
|
||||
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'API call failed', 'data' => $response];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'API call failed', 'data' => $response]);
|
||||
}
|
||||
|
||||
$apiRoot = $response['data'] ?? [];
|
||||
if (($apiRoot['status'] ?? '') !== 'SUCCESS'
|
||||
|| (array_key_exists('successful', $apiRoot) && $apiRoot['successful'] === false)) {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull API FAILED | envelope: ' . json_encode($apiRoot));
|
||||
|
||||
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
|
||||
$file_model = new BatchFileModel();
|
||||
$file_model->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
|
||||
}
|
||||
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'API call failed', 'data' => $apiRoot];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'API call failed', 'data' => $apiRoot]);
|
||||
}
|
||||
|
||||
$chunk = $apiRoot['data'] ?? null;
|
||||
if (!is_array($chunk)) {
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull FAILED | data is not an array: ' . json_encode($apiRoot));
|
||||
break;
|
||||
}
|
||||
|
||||
if (count($chunk) === 0) {
|
||||
if ($startIndex === 1) {
|
||||
log_message('error', "VIDAL V2 - TPA ID Pull FAILED | empty data on first page");
|
||||
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
|
||||
$file_model = new BatchFileModel();
|
||||
$file_model->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
|
||||
}
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'No enrollment records returned', 'data' => $apiRoot];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'No enrollment records returned', 'data' => $apiRoot]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($chunk as $rec) {
|
||||
if (is_array($rec)) {
|
||||
$allBenef[] = $this->normalizeVidalEnrollmentRecordToDependentFormat($rec);
|
||||
}
|
||||
}
|
||||
|
||||
log_message('error', 'VIDAL V2 - TPA ID Pull | Fetched ' . count($chunk) . ' records (page startIndex=' . $startIndex . ')');
|
||||
|
||||
if (count($chunk) < $pageSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
$startIndex += $pageSize;
|
||||
}
|
||||
|
||||
$json = json_encode($allBenef, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
$filePath = WRITEPATH . 'tmp/' . time() . '_' . $requestData['file_id'] . '.json';
|
||||
file_put_contents($filePath, $json);
|
||||
|
||||
Jobs::addJob(['job_name' => 'saveVidalAPIData', 'payload' => ['file_id' => $requestData['file_id'], 'json_file_path' => $filePath]]);
|
||||
|
||||
$employeePolicyModel = new EmployeePolicyModel();
|
||||
$employeePolicyData = $employeePolicyModel
|
||||
->select('
|
||||
employees.*,
|
||||
employee_polices.id as emp_policy_id,
|
||||
employee_polices.client_policy_id,
|
||||
')
|
||||
->join('employees', 'employees.id = employee_polices.employee_id')
|
||||
->where('employee_polices.is_active', 1)
|
||||
->where('employee_polices.status', 'active')
|
||||
->where('employees.is_active', 1)
|
||||
->where('employees.emp_status', 'active')
|
||||
->where('employee_polices.tpa_id IS NULL')
|
||||
->where('employee_polices.client_policy_id', $client_policy_id)
|
||||
->findAll();
|
||||
$batch_file_success = 'success';
|
||||
$updated = 0;
|
||||
$totalCount = count($employeePolicyData);
|
||||
$employee_policy_ids = [];
|
||||
foreach ($employeePolicyData as $policy_data) {
|
||||
|
||||
$hasMatchForThisPolicy = false;
|
||||
|
||||
foreach ($allBenef as $row) {
|
||||
if (
|
||||
strtolower(trim($policy_data['name'] ?? '')) === strtolower(trim($row['name'] ?? '')) &&
|
||||
($policy_data['emp_code'] ?? '') === ($row['empNo'] ?? '') &&
|
||||
strtolower(trim($policy_data['relationship'] ?? '')) === strtolower(trim(str_replace('-', ' ', $row['relationship'] ?? ''))) &&
|
||||
($policy_data['gender'] ?? '') === ($row['gender'] ?? '') &&
|
||||
($policy_data['dob'] ?? '') === (change_date_format($row['dob'], 'Y-m-d H:i:s') ?? '')
|
||||
) {
|
||||
|
||||
$hasMatchForThisPolicy = true;
|
||||
|
||||
$sql = 'UPDATE employee_polices
|
||||
SET tpa_id = :tpa_id:
|
||||
WHERE id = :emp_policy_id:';
|
||||
$this->db->query($sql, ['tpa_id' => $row['enrollmentId'], 'emp_policy_id' => $policy_data['emp_policy_id']]);
|
||||
|
||||
if (strtolower(trim($policy_data['relationship'])) === 'self') {
|
||||
$employee_policy_ids[] = $policy_data['emp_policy_id'];
|
||||
}
|
||||
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$updated++;
|
||||
log_message('error', "VIDAL V2 - TPA ID Pull | Updated tpa_id={$row['enrollmentId']} for emp_code={$row['empNo']} policy={$row['policyNumber']}");
|
||||
} else {
|
||||
log_message('error', "VIDAL V2 - TPA ID Pull | No update (already set or not matched) for emp_code={$row['empNo']} policy={$row['policyNumber']}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!$hasMatchForThisPolicy) {
|
||||
|
||||
$nhanceSideData = [
|
||||
'name' => $policy_data['name'] ?? null,
|
||||
'emp_code' => $policy_data['emp_code'] ?? null,
|
||||
'relationship' => $policy_data['relationship'] ?? null,
|
||||
'gender' => $policy_data['gender'] ?? null,
|
||||
'dob' => $policy_data['dob'] ?? null,
|
||||
];
|
||||
$batch_file_success = 'partially success';
|
||||
|
||||
log_message(
|
||||
'error',
|
||||
'VIDAL V2 - TPA ID Pull | No match for Nhance = ' . json_encode($nhanceSideData)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!empty($employee_policy_ids)) {
|
||||
log_message('error', 'sendMailForDownloadingECard JOB PUSHED (V2).');
|
||||
Jobs::addJob(['job_name' => 'sendMailForDownloadingECard', 'payload' => ['ids' => $employee_policy_ids, 'client_policy_id' => $client_policy_id]]);
|
||||
}
|
||||
|
||||
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
|
||||
$file_model = new BatchFileModel();
|
||||
|
||||
$file_model->where('id', $requestData['file_id'])->set('status', $batch_file_success)->update();
|
||||
log_message('error', "VIDAL V2 - Files table status updated for the file id : {$requestData['file_id']}");
|
||||
} else {
|
||||
log_message('error', 'VIDAL V2 - Failed to update file table status.');
|
||||
}
|
||||
|
||||
log_message('error', "VIDAL V2 - TPA ID Pull SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
|
||||
|
||||
if ($function_calling_type === 'job') {
|
||||
return [
|
||||
'status' => true,
|
||||
'message' => 'Updated successfully',
|
||||
'total_fetched' => $totalCount,
|
||||
'total_updated' => $updated,
|
||||
];
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
'status' => true,
|
||||
'message' => 'Updated successfully',
|
||||
'total_fetched' => $totalCount,
|
||||
'total_updated' => $updated,
|
||||
]);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
|
||||
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
|
||||
$file_model = new BatchFileModel();
|
||||
$file_model->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
|
||||
log_message('error', "VIDAL V2 - Files table status updated for the file id : {$requestData['file_id']}");
|
||||
} else {
|
||||
log_message('error', 'VIDAL V2 - Failed to update file table status.');
|
||||
}
|
||||
|
||||
$errorData = [
|
||||
'message' => $th->getMessage(),
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
'code' => $th->getCode(),
|
||||
'trace' => $th->getTraceAsString(),
|
||||
'trace_array' => $th->getTrace(),
|
||||
'function' => $th->getTrace()[0]['function'] ?? null,
|
||||
'class' => $th->getTrace()[0]['class'] ?? null,
|
||||
];
|
||||
|
||||
log_message('error', 'VIDAL V2 - Exception thrown while calling GetBenefDetailsV2 API: ' . json_encode($errorData));
|
||||
if ($function_calling_type === 'job') {
|
||||
return ['status' => false, 'message' => 'API call failed', 'data' => $errorData];
|
||||
}
|
||||
|
||||
return $this->respond(['status' => false, 'message' => 'API call failed', 'data' => $errorData]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Nhance relationship => list of Vidal `relation` labels (any case). Edit the grouped list only; the flat map is built here.
|
||||
* Reference: public/tmp/relationship.csv (documentation only).
|
||||
*
|
||||
* @return array<string, string> lowercase Vidal label (and hyphen/space variant) => Nhance relation key
|
||||
*/
|
||||
private static function vidalRelationshipReferenceMap(): array
|
||||
{
|
||||
$relationshipGrouped = [
|
||||
|
||||
'self' => [
|
||||
'SELF',
|
||||
'EMPLOYER',
|
||||
'EMPLOYEE',
|
||||
'EMPLOYEES',
|
||||
],
|
||||
|
||||
'spouse' => [
|
||||
'SPOUSE',
|
||||
'PARTNER',
|
||||
'HUSBAND',
|
||||
'HUSBAND (2)',
|
||||
'HUSBAND (3)',
|
||||
'HUSBAND (4)',
|
||||
'HUSBAND (5)',
|
||||
'WIFE',
|
||||
'WIFE (2)',
|
||||
'WIFE (3)',
|
||||
'WIFE (4)',
|
||||
'WIFE (5)',
|
||||
],
|
||||
|
||||
'father' => [
|
||||
'FATHER',
|
||||
'FATHER (2)',
|
||||
'FATHER (3)',
|
||||
'FATHER (4)',
|
||||
'FATHER (5)',
|
||||
],
|
||||
|
||||
'mother' => [
|
||||
'MOTHER',
|
||||
'MOTHER (2)',
|
||||
'MOTHER (3)',
|
||||
'MOTHER (4)',
|
||||
'MOTHER (5)',
|
||||
],
|
||||
|
||||
'son' => [
|
||||
'SON',
|
||||
'SON (2)',
|
||||
'SON (3)',
|
||||
'SON (4)',
|
||||
'SON (5)',
|
||||
],
|
||||
|
||||
'daughter' => [
|
||||
'DAUGHTER',
|
||||
'DAUGHTER (2)',
|
||||
'DAUGHTER (3)',
|
||||
'DAUGHTER (4)',
|
||||
'DAUGHTER (5)',
|
||||
],
|
||||
|
||||
'father in law' => [
|
||||
'FATHER-IN-LAW',
|
||||
'FATHER-IN-LAW (2)',
|
||||
],
|
||||
|
||||
'mother in law' => [
|
||||
'MOTHER-IN-LAW',
|
||||
'MOTHER-IN-LAW (2)',
|
||||
],
|
||||
];
|
||||
|
||||
return self::flattenVidalRelationshipGroupedToLookupMap($relationshipGrouped);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, list<string>> $grouped
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private static function flattenVidalRelationshipGroupedToLookupMap(array $grouped): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
foreach ($grouped as $nhanceRelation => $vidalLabels) {
|
||||
foreach ($vidalLabels as $label) {
|
||||
$label = trim((string) $label);
|
||||
if ($label === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$variants = [
|
||||
strtolower($label),
|
||||
strtolower(str_replace('-', ' ', $label)),
|
||||
];
|
||||
|
||||
foreach (array_unique($variants) as $key) {
|
||||
$key = trim(preg_replace('/\s+/', ' ', $key));
|
||||
if ($key === '') {
|
||||
continue;
|
||||
}
|
||||
$map[$key] = $nhanceRelation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map Vidal enrollment `relation` text to Nhance `employees.relationship` / `tpa_api_data.relation` style (lowercase).
|
||||
*/
|
||||
private function mapVidalRelationshipToNhance(?string $vidalRelationDescription): string
|
||||
{
|
||||
$raw = trim((string) $vidalRelationDescription);
|
||||
if ($raw === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach (self::vidalRelationLookupKeyVariants($raw) as $key) {
|
||||
if (isset($this->vidalRelationshipMap[$key])) {
|
||||
return $this->vidalRelationshipMap[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp($raw, 'Employee') === 0 || strcasecmp($raw, 'Employees') === 0) {
|
||||
return 'self';
|
||||
}
|
||||
|
||||
return strtolower(str_replace('-', ' ', $raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys must stay in sync with {@see self::flattenVidalRelationshipGroupedToLookupMap()}.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private static function vidalRelationLookupKeyVariants(string $raw): array
|
||||
{
|
||||
$base = strtolower(trim($raw));
|
||||
$withHyphensAsSpaces = strtolower(str_replace('-', ' ', $base));
|
||||
$collapsed = trim(preg_replace('/\s+/', ' ', $withHyphensAsSpaces));
|
||||
|
||||
return array_values(array_unique(array_filter([$base, $collapsed])));
|
||||
}
|
||||
|
||||
private function normalizeVidalEnrollmentDateToYmd($value): ?string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return null;
|
||||
}
|
||||
if (is_numeric($value)) {
|
||||
return null;
|
||||
}
|
||||
$s = trim((string) $value);
|
||||
$ts = strtotime(str_replace('/', '-', $s));
|
||||
|
||||
return $ts ? date('Y-m-d', $ts) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map Enrollment Dump API row (see public/tmp/Enrollment Dump API.docx) to the dependent
|
||||
* shape used by VidalGetBenefDetailsV2 matching and saveVidalAPIData.
|
||||
*/
|
||||
private function normalizeVidalEnrollmentRecordToDependentFormat(array $row): array
|
||||
{
|
||||
$rel = trim((string) ($row['relation'] ?? ''));
|
||||
$relationship = $this->mapVidalRelationshipToNhance($rel);
|
||||
|
||||
$si = $row['baseSumInsured'] ?? null;
|
||||
$si = $si !== null && $si !== '' ? trim((string) $si) : null;
|
||||
|
||||
return [
|
||||
'name' => trim((string) ($row['beneficiaryName'] ?? '')),
|
||||
'empNo' => trim((string) ($row['employeeNo'] ?? '')),
|
||||
'relationship' => $relationship,
|
||||
'vidal_relation_raw' => $rel,
|
||||
'gender' => $row['gender'] ?? '',
|
||||
'dob' => $row['dateOfBirth'] ?? null,
|
||||
'enrollmentId' => trim((string) ($row['membershipNo'] ?? '')),
|
||||
'policyNumber' => trim((string) ($row['policyNumber'] ?? '')),
|
||||
'age' => $row['age'] ?? null,
|
||||
'si' => $si,
|
||||
'doj' => $this->normalizeVidalEnrollmentDateToYmd($row['dateOfJoining'] ?? null),
|
||||
'desc' => $this->buildVidalEnrollmentDescForTpaRow($row),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills tpa_api_data.desc from enrollment fields (product / remarks / insured name).
|
||||
*/
|
||||
private function buildVidalEnrollmentDescForTpaRow(array $row): ?string
|
||||
{
|
||||
$chunks = array_filter([
|
||||
trim((string) ($row['productName'] ?? '')),
|
||||
trim((string) ($row['remarks'] ?? '')),
|
||||
trim((string) ($row['insuredName'] ?? '')),
|
||||
], static fn ($v) => $v !== '');
|
||||
|
||||
if ($chunks === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return substr(implode(' | ', $chunks), 0, 65000);
|
||||
}
|
||||
|
||||
private function vidalEnrollmentInfoApiUrl(): string
|
||||
{
|
||||
$base = rtrim((string) getenv('VIDAL_API_BASE_URL'), '/');
|
||||
if ($base !== '' && preg_match('#/api$#', $base)) {
|
||||
return preg_replace('#/api$#', '', $base) . '/enrollment/info';
|
||||
}
|
||||
|
||||
return 'https://devapigw.vidalhealthtpa.com/partner-integration/enrollment/info';
|
||||
}
|
||||
|
||||
public function saveVidalAPIData($array)
|
||||
{
|
||||
$file_id = $array['file_id'];
|
||||
@ -1045,20 +1571,49 @@ class VidalApiController extends BaseController
|
||||
|
||||
foreach ($records as $row) {
|
||||
|
||||
$rawVidalRel = trim((string) ($row['vidal_relation_raw'] ?? ''));
|
||||
if ($rawVidalRel !== '') {
|
||||
$relation = $this->mapVidalRelationshipToNhance($rawVidalRel);
|
||||
} else {
|
||||
$relation = trim(strtolower((string) ($row['relationship'] ?? '')));
|
||||
}
|
||||
|
||||
$si = $row['si'] ?? null;
|
||||
$si = $si !== null && $si !== '' ? trim((string) $si) : null;
|
||||
|
||||
$doj = null;
|
||||
if (!empty($row['doj'])) {
|
||||
$dojRaw = $row['doj'];
|
||||
if (is_string($dojRaw) && preg_match('/^\d{4}-\d{2}-\d{2}/', $dojRaw)) {
|
||||
$doj = substr($dojRaw, 0, 10);
|
||||
} else {
|
||||
$doj = $this->normalizeVidalEnrollmentDateToYmd($dojRaw);
|
||||
}
|
||||
}
|
||||
|
||||
$descPieces = [];
|
||||
if ($rawVidalRel !== '') {
|
||||
$descPieces[] = 'Vidal relation: ' . $rawVidalRel;
|
||||
}
|
||||
$jsonDesc = trim((string) ($row['desc'] ?? ''));
|
||||
if ($jsonDesc !== '') {
|
||||
$descPieces[] = $jsonDesc;
|
||||
}
|
||||
$desc = $descPieces !== [] ? substr(implode(' | ', $descPieces), 0, 65000) : null;
|
||||
|
||||
$mappedRows[] = [
|
||||
'file_id' => $file_id, // ← pass from controller
|
||||
'emp_code' => trim($row['empNo'] ?? ''),
|
||||
|
||||
'name' => trim($row['name'] ?? ''),
|
||||
'dob' => !empty($row['dob'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['dob']))) : null,
|
||||
|
||||
'relation' => trim(strtolower($row['relationship'] ?? '')),
|
||||
'gender' => format_gender_v2($row['gender'] ?? null),
|
||||
'self' => strtolower($row['relationship'] ?? '') === 'self' ? 1 : 0,
|
||||
|
||||
'tpa_id' => trim($row['enrollmentId'] ?? null),
|
||||
'age' => is_numeric($row['age'] ?? null) ? (int) $row['age'] : null,
|
||||
|
||||
'file_id' => $file_id,
|
||||
'emp_code' => trim($row['empNo'] ?? ''),
|
||||
'name' => trim($row['name'] ?? ''),
|
||||
'dob' => !empty($row['dob'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['dob']))) : null,
|
||||
'relation' => $relation,
|
||||
'gender' => format_gender_v2($row['gender'] ?? null),
|
||||
'self' => $relation === 'self' ? 1 : 0,
|
||||
'tpa_id' => trim($row['enrollmentId'] ?? null),
|
||||
'age' => is_numeric($row['age'] ?? null) ? (int) $row['age'] : null,
|
||||
'desc' => $desc,
|
||||
'si' => $si,
|
||||
'doj' => $doj,
|
||||
'is_active' => 1,
|
||||
'created_by' => $file_info[0]['created_by'] ?? null,
|
||||
];
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
<div class="form-row additional-doc-row" data-row-index="0">
|
||||
<div class="form-group col-md-4">
|
||||
<label>Document Name<span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control other-doc-name-field" placeholder="Document Name" name="other_docs_name[]" required>
|
||||
<input type="text" class="form-control other-doc-name-field" placeholder="Document Name" name="other_docs_name[]" data-parsley-inceptioncharset="true" data-parsley-trigger="input change" required>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label>File<span class="text-danger">*</span></label>
|
||||
@ -92,6 +92,7 @@
|
||||
</div>
|
||||
<!-- end -->
|
||||
|
||||
<script src="<?= base_url('public/assets/js/pages/policy_transaction_inception_form_validation.js') ?>"></script>
|
||||
<script>
|
||||
|
||||
var kycPrimaryKey = $('#client_id_kyc').val();
|
||||
@ -101,7 +102,7 @@
|
||||
<div class="form-row additional-doc-row" data-row-index="${index}">
|
||||
<div class="form-group col-md-4">
|
||||
<label>Document Name<span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control other-doc-name-field" placeholder="Document Name" name="other_docs_name[]" required>
|
||||
<input type="text" class="form-control other-doc-name-field" placeholder="Document Name" name="other_docs_name[]" data-parsley-inceptioncharset="true" data-parsley-trigger="input change" required>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label>File<span class="text-danger">*</span></label>
|
||||
|
||||
@ -176,6 +176,7 @@ var client_id_param = 0;
|
||||
var client_branch_id_param = 0;
|
||||
var client_policy_param = 0;
|
||||
var tpa_api_sevice = 0;
|
||||
var tpa_push_api_sevice = 0;
|
||||
|
||||
$('#file_upload').hide();
|
||||
|
||||
@ -1018,11 +1019,18 @@ function checkPolicyTermsAndRackRatesHasDefiend(event)
|
||||
$('#event_type_data').val(response.insurer_multi_event);
|
||||
|
||||
console.log('response.tpa_api_service_status', response.tpa_api_service_status);
|
||||
console.log('response.tpa_push_api_service_status', response.tpa_push_api_service_status);
|
||||
console.log('tpa_api_sevice 1', tpa_api_sevice);
|
||||
if(response.tpa_api_service_status){
|
||||
tpa_api_sevice = 1;
|
||||
}else{
|
||||
tpa_api_sevice = 0;
|
||||
}
|
||||
|
||||
if(response.tpa_push_api_service_status){
|
||||
tpa_push_api_sevice = 1;
|
||||
}else{
|
||||
tpa_push_api_sevice = 0;
|
||||
}
|
||||
$('.fetch_tpa').hide();
|
||||
$('#action_type').val('').change();
|
||||
|
||||
@ -503,6 +503,9 @@
|
||||
<button id="emp_form_submit_button_2" type="submit" class="btn btn-primary waves-effect waves-light justify-content-end">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-4 push_tpa" style="margin-top: 18px;">
|
||||
<a id="fetch_tpa_btn" class="btn btn-primary waves-effect waves-light justify-content-end" onclick="sendDataToTPA(this)">Upload Employees to TPA</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" id="onboard_div" style="display:none;">
|
||||
<a href="#"><span id="on_board_btn_txt" onclick="initiateWellnessOnboard(this)"></span></a>
|
||||
@ -928,7 +931,7 @@
|
||||
var insurer_or_tpa = $('#insurer_or_tpa').val()
|
||||
var action_type = $('#action_type').val()
|
||||
|
||||
console.log({tpa_api_sevice, selectedVal, insurer_or_tpa, action_type});
|
||||
console.log({tpa_api_sevice, selectedVal, insurer_or_tpa, action_type, tpa_push_api_sevice});
|
||||
|
||||
if (tpa_api_sevice == 0 || action_type == 'export' || insurer_or_tpa == "insurer" || (selectedVal == 'correction' || selectedVal == 'deletion' || selectedVal == 'si_enhancement')) {
|
||||
$('.fetch_tpa').hide();
|
||||
@ -936,6 +939,12 @@
|
||||
$('.fetch_tpa').show();
|
||||
}
|
||||
|
||||
if (tpa_push_api_sevice == 0 || action_type == 'import' || insurer_or_tpa == "insurer") {
|
||||
$('.push_tpa').hide();
|
||||
} else {
|
||||
$('.push_tpa').show();
|
||||
}
|
||||
|
||||
if (selectedVal === 'correction') {
|
||||
$('#policy').prop('required', false);
|
||||
$('#policy_danger').hide();
|
||||
@ -944,8 +953,6 @@
|
||||
$('#policy_danger').show();
|
||||
}
|
||||
|
||||
console.log('tpa_api_sevice', tpa_api_sevice);
|
||||
console.log('tpa_api_sevice type', typeof tpa_api_sevice);
|
||||
});
|
||||
|
||||
$('#action_type').on('change', function() {
|
||||
@ -974,6 +981,12 @@
|
||||
} else {
|
||||
$('.fetch_tpa').show();
|
||||
}
|
||||
|
||||
if (tpa_push_api_sevice == 0 || action_type == 'import' || insurer_or_tpa == "insurer") {
|
||||
$('.push_tpa').hide();
|
||||
} else {
|
||||
$('.push_tpa').show();
|
||||
}
|
||||
});
|
||||
|
||||
$('#insurer_or_tpa').on('change', function() {
|
||||
@ -984,7 +997,7 @@
|
||||
var action_type = $('#action_type').val()
|
||||
var event_string = $('#event_type').val();
|
||||
|
||||
console.log({tpa_api_sevice, insurer_or_tpa, policy_value, event_type_data, action_type, event_string});
|
||||
console.log({tpa_api_sevice, insurer_or_tpa, policy_value, event_type_data, action_type, event_string, tpa_push_api_sevice});
|
||||
|
||||
if (tpa_api_sevice == 0 || action_type == 'export' || insurer_or_tpa == "insurer" || (event_string == 'correction' || event_string == 'deletion' || event_string == 'si_enhancement')) {
|
||||
$('.fetch_tpa').hide();
|
||||
@ -992,6 +1005,12 @@
|
||||
$('.fetch_tpa').show();
|
||||
}
|
||||
|
||||
if (tpa_push_api_sevice == 0 || action_type == 'import' || insurer_or_tpa == "insurer") {
|
||||
$('.push_tpa').hide();
|
||||
} else {
|
||||
$('.push_tpa').show();
|
||||
}
|
||||
|
||||
// if(insurer_or_tpa == 'tpa' || event_type_data == 0){
|
||||
if(insurer_or_tpa == 'tpa'){
|
||||
|
||||
@ -1034,7 +1053,7 @@
|
||||
var event_string = $('#event_type').val();
|
||||
var event_type_data = $('#event_type_data').val();
|
||||
|
||||
console.log({tpa_api_sevice, action_type, policy_value, insurer_or_tpa, event_string, event_type_data})
|
||||
console.log({tpa_api_sevice, action_type, policy_value, insurer_or_tpa, event_string, event_type_data, tpa_push_api_sevice})
|
||||
|
||||
if (tpa_api_sevice == 0 || action_type == 'export' || insurer_or_tpa == "insurer" || (event_string == 'correction' || event_string == 'deletion' || event_string == 'si_enhancement')) {
|
||||
$('.fetch_tpa').hide();
|
||||
@ -1042,6 +1061,12 @@
|
||||
$('.fetch_tpa').show();
|
||||
}
|
||||
|
||||
if (tpa_push_api_sevice == 0 || action_type == 'import' || insurer_or_tpa == "insurer") {
|
||||
$('.push_tpa').hide();
|
||||
} else {
|
||||
$('.push_tpa').show();
|
||||
}
|
||||
|
||||
if(action_type == 'import'){
|
||||
|
||||
$("#event_type").removeAttr("multiple");
|
||||
@ -1342,6 +1367,69 @@
|
||||
|
||||
}
|
||||
|
||||
function sendDataToTPA(){
|
||||
|
||||
let user_confirm = confirm('Are you sure you want to initiate the TPA Employee Push? This may take a while.');
|
||||
if(!user_confirm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let event = $('#event_type').val();
|
||||
let client_id = $('#client').val();
|
||||
let branch_id = $('#client_branch_id').val();
|
||||
let policy_id = $('#policy').val();
|
||||
let tpa_id = $('#policy option:selected').data('tid');
|
||||
let policy_no = $('#policy option:selected').data('pno');
|
||||
|
||||
let checks = [
|
||||
{val: client_id, msg: 'Please select the client'},
|
||||
{val: branch_id, msg: 'Please select the client branch'},
|
||||
{val: policy_id, msg: 'Please select the policy'},
|
||||
{val: event, msg: 'Please select the event'},
|
||||
{val: tpa_id, msg: 'TPA id empty'},
|
||||
{val: policy_no, msg: 'Policy No empty'},
|
||||
];
|
||||
|
||||
for (let c of checks) {
|
||||
if (!c.val || c.val == 0) {
|
||||
toastr.warning(c.msg, 'Warning');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let url = '<?= base_url('sendDataToTPA') ?>';
|
||||
|
||||
// Data to send in the AJAX request
|
||||
let requestData = {
|
||||
policy_no: policy_no,
|
||||
tpa_id: tpa_id,
|
||||
client_id: client_id,
|
||||
client_branch_id: branch_id,
|
||||
client_policy_id: policy_id,
|
||||
event: event,
|
||||
};
|
||||
|
||||
// Send AJAX request
|
||||
sendAjaxRequestForGlobal(url, 'POST', requestData, function(response) {
|
||||
|
||||
console.log('Data fetched successfully:', response);
|
||||
|
||||
if (response.status == true) {
|
||||
toastr.success(response.message || 'Initiating successafully', 'Success');
|
||||
} else {
|
||||
toastr.error(response.message || 'Unable to fetch data', 'Error');
|
||||
}
|
||||
|
||||
}, function(xhr, status, error) {
|
||||
console.error('Error fetching data:', error);
|
||||
console.error(xhr.responseText);
|
||||
toastr.error('An error occurred while pushing.', 'Error');
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
@ -101,6 +101,21 @@
|
||||
border-radius: 10px !important;
|
||||
border-width: 1px !important;
|
||||
}
|
||||
|
||||
/* Live field highlight driven by Parsley state */
|
||||
input.parsley-error,
|
||||
textarea.parsley-error,
|
||||
select.parsley-error {
|
||||
border-color: #dc3545 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.12) !important;
|
||||
}
|
||||
|
||||
input.parsley-success,
|
||||
textarea.parsley-success,
|
||||
select.parsley-success {
|
||||
border-color: #28a745 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.08) !important;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
$isLeadEditEb = isset($lead_edit_data) && ! empty($lead_edit_data);
|
||||
@ -110,6 +125,7 @@
|
||||
var pageSubTitle = '<?= $ebSubtitle ?>';
|
||||
var pageBackButton = '<a href="<?= base_url('leads/list') ?>" data-toggle="tooltip" data-placement="top" title="Back"><i class="mdi mdi-arrow-left" style="font-size: 17px;"></i></a>';
|
||||
</script>
|
||||
<script src="<?= base_url('public/assets/js/pages/leads_form_validation.js') ?>"></script>
|
||||
|
||||
<div class="container-fluid-min">
|
||||
<div class="row" id="leads_form">
|
||||
@ -706,6 +722,9 @@
|
||||
if (res.status == true) {
|
||||
|
||||
$('#appendArea_' + dataIncrement).append(res.data.html);
|
||||
if (typeof window.refreshLeadsFormValidation === 'function') {
|
||||
window.refreshLeadsFormValidation();
|
||||
}
|
||||
|
||||
let policy_type_id = res.data.policy_type_id;
|
||||
let lead_type = res.data.lead_type;
|
||||
@ -1076,6 +1095,9 @@
|
||||
if (response.status == true) {
|
||||
console.log(response.message, 'SUCCESS');
|
||||
$('#appendArea_' + dataIncrement).append(response.data);
|
||||
if (typeof window.refreshLeadsFormValidation === 'function') {
|
||||
window.refreshLeadsFormValidation();
|
||||
}
|
||||
|
||||
console.log("Policy Type ID : ", policy_type_id);
|
||||
if (policy_type_id == 1 || policy_type_id == 6 || policy_type_id == 7) {
|
||||
@ -1275,6 +1297,9 @@
|
||||
`;
|
||||
|
||||
container.appendChild(newRow);
|
||||
if (typeof window.refreshLeadsFormValidation === 'function') {
|
||||
window.refreshLeadsFormValidation();
|
||||
}
|
||||
|
||||
//append mutli file html
|
||||
addFileField(increment);
|
||||
|
||||
@ -1,4 +1,20 @@
|
||||
<!-- Client form content modal-->
|
||||
<style>
|
||||
input.parsley-error,
|
||||
textarea.parsley-error,
|
||||
select.parsley-error {
|
||||
border-color: #dc3545 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.12) !important;
|
||||
}
|
||||
|
||||
input.parsley-success,
|
||||
textarea.parsley-success,
|
||||
select.parsley-success {
|
||||
border-color: #28a745 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.08) !important;
|
||||
}
|
||||
</style>
|
||||
<script src="<?= base_url('public/assets/js/pages/new_client_modal_validation.js') ?>"></script>
|
||||
<div class="modal fade" id="upload_enrollment_model" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" data-backdrop="static">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
|
||||
@ -149,7 +149,23 @@
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Live field highlight driven by Parsley state */
|
||||
input.parsley-error,
|
||||
textarea.parsley-error,
|
||||
select.parsley-error {
|
||||
border-color: #dc3545 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.12) !important;
|
||||
}
|
||||
|
||||
input.parsley-success,
|
||||
textarea.parsley-success,
|
||||
select.parsley-success {
|
||||
border-color: #28a745 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.08) !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script src="<?= base_url('public/assets/js/pages/policy_transaction_endorsement_form_validation.js') ?>"></script>
|
||||
|
||||
<div class="tab-pane fade active show" id="form">
|
||||
<div class="row" id="endorsement_form">
|
||||
|
||||
@ -292,11 +292,27 @@
|
||||
color: #dc3545;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Live field highlight driven by Parsley state */
|
||||
input.parsley-error,
|
||||
textarea.parsley-error,
|
||||
select.parsley-error {
|
||||
border-color: #dc3545 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.12) !important;
|
||||
}
|
||||
|
||||
input.parsley-success,
|
||||
textarea.parsley-success,
|
||||
select.parsley-success {
|
||||
border-color: #28a745 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.08) !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var pageSubTitle = undefined;
|
||||
var pageBackButton = undefined;
|
||||
</script>
|
||||
<script src="<?= base_url('public/assets/js/pages/policy_transaction_inception_form_validation.js') ?>"></script>
|
||||
<div class="tab-pane fade active show" id="form">
|
||||
<input type="hidden" id="entity_type_id">
|
||||
<div class="row" id="inception_form">
|
||||
|
||||
@ -1185,7 +1185,7 @@ function addHTMLInput(data = null, container_id = 'dynamic-form-container')
|
||||
newRow.innerHTML = `
|
||||
<div class="form-group col-md-5">
|
||||
<label for="file_name">Document Name<span class="text-danger">${required_star}</span></label>
|
||||
<input type="text" class="form-control" id="docs_name" name="doc_name[]" placeholder="Enter file name" ${required}>
|
||||
<input type="text" class="form-control" id="docs_name" name="doc_name[]" placeholder="Enter file name" data-parsley-inceptioncharset="true" data-parsley-trigger="input change" ${required}>
|
||||
</div>
|
||||
<div class="form-group col-md-5">
|
||||
<label for="file">Upload File<span class="text-danger">${required_star}</span></label>
|
||||
@ -1371,7 +1371,7 @@ function addHTMLInputForVehicleFileUpload(data = null, container_id = 'dynamic-f
|
||||
newRow.innerHTML = `
|
||||
<div class="form-group col-md-5">
|
||||
<label for="file_name">Document Name<span class="text-danger">${required_star}</span></label>
|
||||
<input type="text" class="form-control" id="docs_name" name="other_docs_name[]" placeholder="Enter file name" ${required}>
|
||||
<input type="text" class="form-control" id="docs_name" name="other_docs_name[]" placeholder="Enter file name" data-parsley-inceptioncharset="true" data-parsley-trigger="input change" ${required}>
|
||||
</div>
|
||||
<div class="form-group col-md-5">
|
||||
<label for="file">Upload File<span class="text-danger">${required_star}</span></label>
|
||||
|
||||
@ -71,3 +71,77 @@ Old function copied as `uploadRequiredDoc_v1` (preserved for reference).
|
||||
### API Docs
|
||||
- `nonebapidocs.md`
|
||||
- `dev_logs/non_eb_claim_api.md`
|
||||
|
||||
---
|
||||
|
||||
## Task Plan — Policy Transaction Inception Form JS Validation
|
||||
|
||||
### Goal
|
||||
Implement client-side form validation for `app/Views/policy_transaction_inception_form.php` by following the existing validation approach used in `app/Views/ticket_form_gmc.php` (centralized submit + reusable validator), but moving inception validation into a dedicated external JavaScript file.
|
||||
|
||||
### Current-State Notes
|
||||
- `policy_transaction_inception_form.php` currently contains inline submit and validation logic on `#inception_form_id` (Parsley validation + custom checks + toastr + AJAX submit flow).
|
||||
- `ticket_form_gmc.php` follows a cleaner pattern where submit handler delegates validation and shows first invalid field feedback.
|
||||
- No dedicated inception validation `.js` file currently exists.
|
||||
|
||||
### Proposed File Changes
|
||||
1. **Create** `public/assets/js/policy_transaction_inception_validation.js`
|
||||
- Add a single public validation entry function (example: `window.validateInceptionFormInputs(form)`).
|
||||
- Keep all custom rules here (beyond HTML `required` and Parsley):
|
||||
- `follow_insurer_id[]` must be selected for all rows.
|
||||
- `pt_form_sumbit_handler` must be `1`.
|
||||
- CD account selection rule for client/policy status condition.
|
||||
- Any date/business-rule checks currently done during submit.
|
||||
- Return a boolean result and handle user-facing messages consistently via toastr.
|
||||
|
||||
2. **Refactor** `app/Views/policy_transaction_inception_form.php`
|
||||
- Keep submit flow in one handler, but delegate custom validations to the new JS file.
|
||||
- Minimize inline validation logic in view.
|
||||
- Ensure first invalid field is focused/scrolled for better UX.
|
||||
- Include the new script after shared dependencies (jQuery/Parsley/toastr), before submit logic usage.
|
||||
|
||||
3. **(Optional Cleanup)** Move remaining inline helper validation code to dedicated JS if it is inception-form-specific and not used elsewhere.
|
||||
|
||||
### Implementation Steps (Execution Order)
|
||||
- [x] Step 1: Create new file `public/assets/js/pages/policy_transaction_inception_validation.js`.
|
||||
- [x] Step 2: Extract custom validation blocks from `#inception_form_id` submit handler into reusable functions.
|
||||
- [x] Step 3: Expose one callable function for submit handler (`validateInceptionFormInputs`).
|
||||
- [x] Step 4: Update `policy_transaction_inception_form.php` to include new JS file.
|
||||
- [x] Step 5: Replace inline custom checks with function call and keep existing AJAX submit behavior unchanged.
|
||||
- [x] Step 6: Ensure invalid-field focus and warning message are preserved.
|
||||
- [ ] Step 7: Verify create/edit journeys and conditional sections (renewal, co-insurer, CD account, policy status).
|
||||
|
||||
### Validation Rules Checklist (to implement in JS)
|
||||
- [ ] Parsley base validation must pass.
|
||||
- [ ] Every `follow_insurer_id[]` select must have value.
|
||||
- [ ] `pt_form_sumbit_handler != 0`.
|
||||
- [ ] If `client_type == 1` and `policy_status == completed` and `policy_type_id > 7`, at least one `cd_ac_no_for_child[]` must be selected.
|
||||
- [ ] Keep existing toastr wording (or align to one consistent warning style).
|
||||
|
||||
### Testing Checklist
|
||||
- [ ] Submit with empty required fields -> blocked with field-level indication.
|
||||
- [ ] Submit with any empty co-insurer selector -> blocked with warning.
|
||||
- [ ] Submit with base premium/CD mismatch (`pt_form_sumbit_handler = 0`) -> blocked.
|
||||
- [ ] Submit valid data -> AJAX create request fires successfully.
|
||||
- [ ] Edit existing inception record -> validation still works and submit succeeds.
|
||||
- [ ] No regression in date conversion before submit (`policy_issue_date`, `policy_start_date`, `policy_end_date`, `renewal_date`, `rollover_date`, `month`).
|
||||
|
||||
### Risks / Attention Points
|
||||
- Large inline script currently mixes validation and business logic; refactor should avoid changing API payload or field names.
|
||||
- Multiple dynamic rows (`follow_insurer_id[]`, `cd_ac_no_for_child[]`) need delegated-safe selectors.
|
||||
- Script include order is critical (new validation JS must load before submit handler executes).
|
||||
|
||||
### Completion Update (Implemented)
|
||||
- Added `public/assets/js/pages/policy_transaction_inception_validation.js` with:
|
||||
- `window.validateInceptionFormInputs(form)` as centralized entrypoint
|
||||
- Parsley validation gate
|
||||
- Co-insurer (`follow_insurer_id[]`) mandatory selection check
|
||||
- `pt_form_sumbit_handler` (CD amount) guard check
|
||||
- Child CD account selection rule for applicable completed flow
|
||||
- First invalid field focus/scroll helper
|
||||
- Updated `app/Views/policy_transaction_inception_form.php`:
|
||||
- Included external script: `assets/js/pages/policy_transaction_inception_validation.js`
|
||||
- Refactored `#inception_form_id` submit handler to delegate custom validation to new file
|
||||
- Preserved existing AJAX submit and payload/date conversion behavior
|
||||
- Technical validation done:
|
||||
- JS syntax check passed (`node --check public/assets/js/pages/policy_transaction_inception_validation.js`)
|
||||
|
||||
92
dev_logs/2026-04-06_inception_form_live_validation_plan.md
Normal file
92
dev_logs/2026-04-06_inception_form_live_validation_plan.md
Normal file
@ -0,0 +1,92 @@
|
||||
# Policy Transaction Inception Form - Live Validation Plan
|
||||
|
||||
## Objective
|
||||
- Add live field-level validation for `input`, `textarea`, and `select` in `app/Views/policy_transaction_inception_form.php`.
|
||||
- Trigger validation errors on `oninput` and `onchange` behavior without disrupting existing Parsley-based submit validation.
|
||||
- Restrict special characters to only `/`, `_`, `-`, `.`, and space (along with letters and numbers).
|
||||
|
||||
## Implementation Steps
|
||||
- Create a dedicated JS module at `public/assets/js/pages/policy_transaction_inception_form_validation.js`.
|
||||
- Register one custom Parsley validator (`inceptioncharset`) for allowed character set checks.
|
||||
- Bind delegated events (`input` and `change`) on:
|
||||
- `#inception_form_id`
|
||||
- `#vehicle_form`
|
||||
- `#CDMasterForm`
|
||||
- Apply Parsley attributes non-destructively:
|
||||
- Add `data-parsley-inceptioncharset="true"` to character-validated fields.
|
||||
- Set `data-parsley-trigger` only when missing, so existing field-level Parsley settings remain intact.
|
||||
- Support dynamic fields by reapplying constraints and refreshing Parsley instances before validating changed fields.
|
||||
- Include the new JS file in the view after existing inline scripts.
|
||||
|
||||
## Character Rule
|
||||
- Allowed characters: `A-Z`, `a-z`, `0-9`, `/`, `_`, `-`, `.`, and space.
|
||||
- Validation message:
|
||||
- `Only letters, numbers, spaces, and the characters / _ - . are allowed.`
|
||||
|
||||
## Non-Disruption Controls
|
||||
- Do not replace existing submit handlers.
|
||||
- Do not remove existing inline `onchange`/`oninput` handlers.
|
||||
- Do not override existing Parsley triggers if already defined on a field.
|
||||
- Ignore hidden/disabled fields for live validation.
|
||||
|
||||
## Validation Scope Notes
|
||||
- `select` elements are revalidated on `change` (for required/Parsley feedback).
|
||||
- Character set validation is applied to textual inputs and textareas only.
|
||||
- File, checkbox, radio, hidden, button, submit, and reset fields are excluded from charset validation.
|
||||
|
||||
## Manual QA Checklist
|
||||
- Type an invalid special character (example: `@`) in a text field and confirm immediate Parsley error.
|
||||
- Type valid characters (`abc 123 / _ - .`) and confirm error clears.
|
||||
- Change required select fields and confirm Parsley error appears/disappears on change.
|
||||
- Add dynamic rows/fields (if applicable) and confirm live validation still works.
|
||||
- Submit each form (`inception`, `vehicle`, `CD master`) and confirm existing submit flow is unchanged.
|
||||
|
||||
## Delivered Changes
|
||||
- Added: `public/assets/js/pages/policy_transaction_inception_form_validation.js`
|
||||
- Updated: `app/Views/policy_transaction_inception_form.php` (script include)
|
||||
- Updated: `app/Views/policy_transaction_inception_form.php` (Parsley-driven red/green live field highlight styles)
|
||||
- Updated: `app/Views/policy_transaction_inception_list.php` (dynamic `Document Name` rows now include Parsley charset attributes)
|
||||
- Updated: `app/Views/client_kyc.php` (`Document Name` fields and template rows now include Parsley charset attributes)
|
||||
- Updated: `app/Views/client_kyc.php` (loads validation script so KYC doc fields validate live in client onboarding screens)
|
||||
- Updated: `public/assets/js/pages/policy_transaction_inception_form_validation.js` (extended to cover `#file_upload_form`, `#kyc_form`, and document-name field detection by name/class)
|
||||
- Added: `public/assets/js/pages/policy_transaction_endorsement_form_validation.js` (same live Parsley validation flow for endorsement forms and policy-doc upload form)
|
||||
- Updated: `app/Views/policy_transaction_endorsement_form.php` (script include for endorsement validation)
|
||||
- Updated: `app/Views/policy_transaction_endorsement_form.php` (Parsley-driven red/green live field highlight styles)
|
||||
|
||||
## Leads Form Analysis (New Scope)
|
||||
- Target file: `app/Views/leads_form.php`
|
||||
- Main form identified: `#leads_form_id` (Parsley form)
|
||||
- Existing constraints found:
|
||||
- PAN and GST already use dedicated Parsley regex rules.
|
||||
- Several dynamic sections append policy/custom fields into `#dynamic-form-container` and `#appendArea_*`.
|
||||
- Contact fields include `contact_person_mobile` and `contact_person_email` as text inputs.
|
||||
- Risk points for charset-only validation:
|
||||
- Email fields must allow `@` and domain characters.
|
||||
- Mobile should stay digits-only and length constrained.
|
||||
- Existing PAN/GST pattern validation must remain untouched.
|
||||
|
||||
## Leads Form Plan
|
||||
- Create separate JS file:
|
||||
- `public/assets/js/pages/leads_form_validation.js`
|
||||
- Add custom Parsley validators for leads page:
|
||||
- Generic charset validator (allow: letters, numbers, `/`, `_`, `-`, `.`, space)
|
||||
- Mobile validator (10 digits)
|
||||
- Email validator (valid email format)
|
||||
- Bind delegated `input`/`change` live validation on `#leads_form_id` so dynamic fields are automatically covered.
|
||||
- Apply constraints by field type/ID:
|
||||
- `contact_person_mobile` -> mobile validator
|
||||
- `contact_person_email` -> email validator
|
||||
- PAN/GST fields keep their existing `data-parsley-pattern` rules
|
||||
- Other textual fields -> charset validator
|
||||
- Add non-intrusive Parsley visual styles (`parsley-error` / `parsley-success`) in `leads_form.php`.
|
||||
- Include new JS file in `leads_form.php` after existing page-level script setup.
|
||||
|
||||
## Leads Delivered Changes
|
||||
- Added: `public/assets/js/pages/leads_form_validation.js`
|
||||
- Updated: `app/Views/leads_form.php` (script include for leads live validation)
|
||||
- Updated: `app/Views/leads_form.php` (Parsley-driven red/green live field highlight styles)
|
||||
|
||||
## New Client Modal Delivered Changes
|
||||
- Added: `public/assets/js/pages/new_client_modal_validation.js`
|
||||
- Updated: `app/Views/newClientModal.php` (script include for modal live validation)
|
||||
- Updated: `app/Views/newClientModal.php` (Parsley-driven red/green live field highlight styles)
|
||||
247
public/assets/js/pages/leads_form_validation.js
Normal file
247
public/assets/js/pages/leads_form_validation.js
Normal file
@ -0,0 +1,247 @@
|
||||
(function (getJq) {
|
||||
'use strict';
|
||||
|
||||
function $(selector, context) {
|
||||
var jq = getJq();
|
||||
if (!jq) {
|
||||
return { length: 0 };
|
||||
}
|
||||
return arguments.length > 1 ? jq(selector, context) : jq(selector);
|
||||
}
|
||||
|
||||
var TEXT_ALLOWED = /^[A-Za-z0-9/_.\- ]*$/;
|
||||
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
var FORM_SELECTOR = '#leads_form_id';
|
||||
var NS = '.leadsFormValidate';
|
||||
|
||||
var MESSAGES = {
|
||||
text: 'Only letters, numbers, spaces, and the characters / _ - . are allowed.',
|
||||
mobile: 'Mobile number must be exactly 10 digits (numbers only).',
|
||||
email: 'Please enter a valid email address.'
|
||||
};
|
||||
|
||||
function isParsleyReady() {
|
||||
return !!window.Parsley;
|
||||
}
|
||||
|
||||
function isSkippableField(el) {
|
||||
return !el || el.disabled || el.type === 'hidden';
|
||||
}
|
||||
|
||||
function isPanOrGstField(el) {
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
var id = (el.id || '').toLowerCase();
|
||||
return id === 'pan' || id === 'gst';
|
||||
}
|
||||
|
||||
function isEmailField(el) {
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
var id = (el.id || '').toLowerCase();
|
||||
var name = (el.name || '').toLowerCase();
|
||||
var type = (el.type || '').toLowerCase();
|
||||
return id === 'contact_person_email' || name === 'contact_person_email' || type === 'email';
|
||||
}
|
||||
|
||||
function isMobileField(el) {
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
var id = (el.id || '').toLowerCase();
|
||||
var name = (el.name || '').toLowerCase();
|
||||
return id === 'contact_person_mobile' || name === 'contact_person_mobile';
|
||||
}
|
||||
|
||||
function isCharsetCandidate(el) {
|
||||
if (!el || el.tagName === 'SELECT') {
|
||||
return false;
|
||||
}
|
||||
var type = (el.type || '').toLowerCase();
|
||||
if (type === 'file' || type === 'checkbox' || type === 'radio' || type === 'password' || type === 'submit' || type === 'button' || type === 'reset') {
|
||||
return false;
|
||||
}
|
||||
if (isPanOrGstField(el) || isEmailField(el) || isMobileField(el)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function registerValidators() {
|
||||
if (!isParsleyReady() || window.Parsley.__leadsFormValidatorsRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.Parsley.addValidator('leadscharset', {
|
||||
validateString: function (value) {
|
||||
if (!value || String(value).trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return TEXT_ALLOWED.test(String(value));
|
||||
},
|
||||
messages: { en: MESSAGES.text }
|
||||
});
|
||||
|
||||
window.Parsley.addValidator('leadsmobile10', {
|
||||
validateString: function (value, req, instance) {
|
||||
var v = String(value || '').replace(/\D/g, '');
|
||||
if (!instance.$element.prop('required') && v.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (instance.$element.prop('required') && v.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return v.length === 10;
|
||||
},
|
||||
messages: { en: MESSAGES.mobile }
|
||||
});
|
||||
|
||||
window.Parsley.addValidator('leadsemail', {
|
||||
validateString: function (value) {
|
||||
if (!value || String(value).trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return EMAIL_RE.test(String(value).trim());
|
||||
},
|
||||
messages: { en: MESSAGES.email }
|
||||
});
|
||||
|
||||
window.Parsley.__leadsFormValidatorsRegistered = true;
|
||||
}
|
||||
|
||||
function clearAttrs($el) {
|
||||
['data-parsley-leadscharset', 'data-parsley-leadsmobile10', 'data-parsley-leadsemail'].forEach(function (a) {
|
||||
$el.removeAttr(a);
|
||||
});
|
||||
}
|
||||
|
||||
function applyConstraints($form) {
|
||||
if (!$form || !$form.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form.find('input, textarea, select').each(function () {
|
||||
var el = this;
|
||||
var $el = $(el);
|
||||
|
||||
if (isSkippableField(el) || isPanOrGstField(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearAttrs($el);
|
||||
|
||||
if (isMobileField(el)) {
|
||||
$el.attr('data-parsley-leadsmobile10', 'true');
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmailField(el)) {
|
||||
$el.attr('data-parsley-leadsemail', 'true');
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCharsetCandidate(el)) {
|
||||
$el.attr('data-parsley-leadscharset', 'true');
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (el.tagName === 'SELECT' && !$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'change');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeOnInput(el) {
|
||||
if (!el || isSkippableField(el)) {
|
||||
return;
|
||||
}
|
||||
if (isMobileField(el)) {
|
||||
var clean = (el.value || '').replace(/\D/g, '').substring(0, 10);
|
||||
if (el.value !== clean) {
|
||||
el.value = clean;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isCharsetCandidate(el)) {
|
||||
var raw = el.value || '';
|
||||
if (!TEXT_ALLOWED.test(raw)) {
|
||||
el.value = raw.replace(/[^A-Za-z0-9/_.\- ]/g, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshParsley($form) {
|
||||
if (!$form || !$form.length || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var instance = $form.parsley();
|
||||
if (instance && typeof instance.refresh === 'function') {
|
||||
instance.refresh();
|
||||
}
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
function validateField(field) {
|
||||
if (!field || isSkippableField(field) || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
var $field = $(field);
|
||||
var $form = $field.closest('form');
|
||||
if (!$form.length || typeof $field.parsley !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
applyConstraints($form);
|
||||
refreshParsley($form);
|
||||
|
||||
try {
|
||||
$field.parsley().validate();
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
var $form = $(FORM_SELECTOR);
|
||||
if (!$form.length || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerValidators();
|
||||
applyConstraints($form);
|
||||
refreshParsley($form);
|
||||
|
||||
$form.off(NS);
|
||||
$form.on('input' + NS, 'input:not([type=hidden]), textarea', function () {
|
||||
sanitizeOnInput(this);
|
||||
validateField(this);
|
||||
});
|
||||
$form.on('change' + NS, 'select, input:not([type=hidden]), textarea', function () {
|
||||
validateField(this);
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
init();
|
||||
});
|
||||
|
||||
window.refreshLeadsFormValidation = function () {
|
||||
init();
|
||||
};
|
||||
})(function () {
|
||||
return window.jQuery;
|
||||
});
|
||||
220
public/assets/js/pages/new_client_modal_validation.js
Normal file
220
public/assets/js/pages/new_client_modal_validation.js
Normal file
@ -0,0 +1,220 @@
|
||||
(function (getJq) {
|
||||
'use strict';
|
||||
|
||||
function $(selector, context) {
|
||||
var jq = getJq();
|
||||
if (!jq) {
|
||||
return { length: 0 };
|
||||
}
|
||||
return arguments.length > 1 ? jq(selector, context) : jq(selector);
|
||||
}
|
||||
|
||||
var FORM_SELECTOR = '#client_form';
|
||||
var NS = '.newClientModalValidate';
|
||||
var TEXT_ALLOWED = /^[A-Za-z0-9/_.\- ]*$/;
|
||||
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
||||
function isParsleyReady() {
|
||||
return !!window.Parsley;
|
||||
}
|
||||
|
||||
function isSkippable(el) {
|
||||
return !el || el.disabled || el.type === 'hidden';
|
||||
}
|
||||
|
||||
function isPanOrGst(el) {
|
||||
var id = (el.id || '').toLowerCase();
|
||||
return id === 'pan' || id === 'gst';
|
||||
}
|
||||
|
||||
function isMobile(el) {
|
||||
var id = (el.id || '').toLowerCase();
|
||||
var name = (el.name || '').toLowerCase();
|
||||
return id === 'mobile' || id === 'phone' || name === 'mobile' || name === 'phone';
|
||||
}
|
||||
|
||||
function isEmail(el) {
|
||||
var type = (el.type || '').toLowerCase();
|
||||
var id = (el.id || '').toLowerCase();
|
||||
var name = (el.name || '').toLowerCase();
|
||||
return type === 'email' || id === 'email' || id === 'email2' || name === 'email' || name === 'email2';
|
||||
}
|
||||
|
||||
function isCharsetCandidate(el) {
|
||||
if (!el || el.tagName === 'SELECT') {
|
||||
return false;
|
||||
}
|
||||
var type = (el.type || '').toLowerCase();
|
||||
if (type === 'file' || type === 'checkbox' || type === 'radio' || type === 'password' || type === 'submit' || type === 'button' || type === 'reset') {
|
||||
return false;
|
||||
}
|
||||
if (isPanOrGst(el) || isMobile(el) || isEmail(el)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function registerValidators() {
|
||||
if (!isParsleyReady() || window.Parsley.__newClientModalValidatorsRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.Parsley.addValidator('newclientcharset', {
|
||||
validateString: function (value) {
|
||||
if (!value || String(value).trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return TEXT_ALLOWED.test(String(value));
|
||||
},
|
||||
messages: { en: 'Only letters, numbers, spaces, and the characters / _ - . are allowed.' }
|
||||
});
|
||||
|
||||
window.Parsley.addValidator('newclientmobile10', {
|
||||
validateString: function (value, req, instance) {
|
||||
var v = String(value || '').replace(/\D/g, '');
|
||||
if (!instance.$element.prop('required') && v.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (instance.$element.prop('required') && v.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return v.length === 10;
|
||||
},
|
||||
messages: { en: 'Mobile number must be exactly 10 digits (numbers only).' }
|
||||
});
|
||||
|
||||
window.Parsley.addValidator('newclientemail', {
|
||||
validateString: function (value) {
|
||||
if (!value || String(value).trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return EMAIL_RE.test(String(value).trim());
|
||||
},
|
||||
messages: { en: 'Please enter a valid email address.' }
|
||||
});
|
||||
|
||||
window.Parsley.__newClientModalValidatorsRegistered = true;
|
||||
}
|
||||
|
||||
function clearAttrs($el) {
|
||||
['data-parsley-newclientcharset', 'data-parsley-newclientmobile10', 'data-parsley-newclientemail'].forEach(function (a) {
|
||||
$el.removeAttr(a);
|
||||
});
|
||||
}
|
||||
|
||||
function applyConstraints($form) {
|
||||
$form.find('input, textarea, select').each(function () {
|
||||
var el = this;
|
||||
var $el = $(el);
|
||||
if (isSkippable(el) || isPanOrGst(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearAttrs($el);
|
||||
|
||||
if (isMobile(el)) {
|
||||
$el.attr('data-parsley-newclientmobile10', 'true');
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmail(el)) {
|
||||
$el.attr('data-parsley-newclientemail', 'true');
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCharsetCandidate(el)) {
|
||||
$el.attr('data-parsley-newclientcharset', 'true');
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (el.tagName === 'SELECT' && !$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'change');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeOnInput(el) {
|
||||
if (!el || isSkippable(el)) {
|
||||
return;
|
||||
}
|
||||
if (isMobile(el)) {
|
||||
var d = (el.value || '').replace(/\D/g, '').substring(0, 10);
|
||||
if (el.value !== d) {
|
||||
el.value = d;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isCharsetCandidate(el)) {
|
||||
var raw = el.value || '';
|
||||
if (!TEXT_ALLOWED.test(raw)) {
|
||||
el.value = raw.replace(/[^A-Za-z0-9/_.\- ]/g, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshParsley($form) {
|
||||
try {
|
||||
var p = $form.parsley();
|
||||
if (p && typeof p.refresh === 'function') {
|
||||
p.refresh();
|
||||
}
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
function validateField(el) {
|
||||
if (!el || isSkippable(el) || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
var $f = $(el).closest('form');
|
||||
if (!$f.length) {
|
||||
return;
|
||||
}
|
||||
applyConstraints($f);
|
||||
refreshParsley($f);
|
||||
try {
|
||||
$(el).parsley().validate();
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
var $form = $(FORM_SELECTOR);
|
||||
if (!$form.length || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
registerValidators();
|
||||
applyConstraints($form);
|
||||
refreshParsley($form);
|
||||
|
||||
$form.off(NS);
|
||||
$form.on('input' + NS, 'input:not([type=hidden]), textarea', function () {
|
||||
sanitizeOnInput(this);
|
||||
validateField(this);
|
||||
});
|
||||
$form.on('change' + NS, 'select, input:not([type=hidden]), textarea', function () {
|
||||
validateField(this);
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
init();
|
||||
});
|
||||
|
||||
window.refreshNewClientModalValidation = function () {
|
||||
init();
|
||||
};
|
||||
})(function () {
|
||||
return window.jQuery;
|
||||
});
|
||||
@ -0,0 +1,166 @@
|
||||
(function (getJq) {
|
||||
'use strict';
|
||||
|
||||
function $(selector, context) {
|
||||
var jq = getJq();
|
||||
if (!jq) {
|
||||
return { length: 0 };
|
||||
}
|
||||
return arguments.length > 1 ? jq(selector, context) : jq(selector);
|
||||
}
|
||||
|
||||
var TEXT_ALLOWED = /^[A-Za-z0-9/_.\- ]*$/;
|
||||
var MESSAGE = 'Only letters, numbers, spaces, and the characters / _ - . are allowed.';
|
||||
var FORM_SELECTORS = ['#endorsement_form_id', '#drive_file_upload_form', '#file_upload_form'];
|
||||
var NS = '.endorsementFormValidate';
|
||||
|
||||
function isParsleyReady() {
|
||||
return !!window.Parsley;
|
||||
}
|
||||
|
||||
function isSkippableField(el) {
|
||||
return !el || el.disabled || el.type === 'hidden';
|
||||
}
|
||||
|
||||
function isDocumentNameField(el) {
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
var name = (el.name || '').toLowerCase();
|
||||
var id = (el.id || '').toLowerCase();
|
||||
return name === 'doc_name[]' ||
|
||||
name === 'other_docs_name[]' ||
|
||||
name === 'docs_name[]' ||
|
||||
id === 'docs_name' ||
|
||||
$(el).hasClass('other-doc-name-field');
|
||||
}
|
||||
|
||||
function isCharsetCandidate(el) {
|
||||
if (!el || el.tagName === 'SELECT') {
|
||||
return false;
|
||||
}
|
||||
var type = (el.type || '').toLowerCase();
|
||||
if (type === 'file' || type === 'checkbox' || type === 'radio' || type === 'password' || type === 'email' || type === 'url' || type === 'submit' || type === 'button' || type === 'reset') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function registerValidator() {
|
||||
if (!isParsleyReady() || window.Parsley.__endorsementFormValidatorRegistered) {
|
||||
return;
|
||||
}
|
||||
window.Parsley.addValidator('endorsementcharset', {
|
||||
validateString: function (value) {
|
||||
if (!value || String(value).trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return TEXT_ALLOWED.test(String(value));
|
||||
},
|
||||
messages: { en: MESSAGE }
|
||||
});
|
||||
window.Parsley.__endorsementFormValidatorRegistered = true;
|
||||
}
|
||||
|
||||
function applyConstraints($form) {
|
||||
if (!$form || !$form.length) {
|
||||
return;
|
||||
}
|
||||
$form.find('input, textarea, select').each(function () {
|
||||
var el = this;
|
||||
var $el = $(el);
|
||||
if (isSkippableField(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCharsetCandidate(el) || isDocumentNameField(el)) {
|
||||
if (!$el.attr('data-parsley-endorsementcharset')) {
|
||||
$el.attr('data-parsley-endorsementcharset', 'true');
|
||||
}
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (el.tagName === 'SELECT' && !$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'change');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refreshParsley($form) {
|
||||
if (!$form || !$form.length || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var instance = $form.parsley();
|
||||
if (instance && typeof instance.refresh === 'function') {
|
||||
instance.refresh();
|
||||
}
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
function validateField(field) {
|
||||
if (!field || isSkippableField(field) || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
var $field = $(field);
|
||||
var $form = $field.closest('form');
|
||||
if (!$form.length || typeof $field.parsley !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
applyConstraints($form);
|
||||
refreshParsley($form);
|
||||
|
||||
try {
|
||||
$field.parsley().validate();
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
function bindForm(selector) {
|
||||
var $form = $(selector);
|
||||
if (!$form.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerValidator();
|
||||
applyConstraints($form);
|
||||
refreshParsley($form);
|
||||
|
||||
$form.off(NS);
|
||||
$form.on('input' + NS, 'input:not([type=hidden]), textarea', function () {
|
||||
validateField(this);
|
||||
});
|
||||
$form.on('change' + NS, 'select, input:not([type=hidden]), textarea', function () {
|
||||
validateField(this);
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (!isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
FORM_SELECTORS.forEach(function (selector) {
|
||||
bindForm(selector);
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
init();
|
||||
});
|
||||
|
||||
window.refreshEndorsementFormValidation = function (formSelector) {
|
||||
if (!formSelector || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
bindForm(formSelector);
|
||||
};
|
||||
})(function () {
|
||||
return window.jQuery;
|
||||
});
|
||||
@ -0,0 +1,185 @@
|
||||
(function (getJq) {
|
||||
'use strict';
|
||||
|
||||
function $(selector, context) {
|
||||
var jq = getJq();
|
||||
if (!jq) {
|
||||
return { length: 0 };
|
||||
}
|
||||
return arguments.length > 1 ? jq(selector, context) : jq(selector);
|
||||
}
|
||||
|
||||
var TEXT_ALLOWED = /^[A-Za-z0-9/_.\- ]*$/;
|
||||
var MESSAGE = 'Only letters, numbers, spaces, and the characters / _ - . are allowed.';
|
||||
var FORM_SELECTORS = ['#inception_form_id', '#vehicle_form', '#CDMasterForm', '#file_upload_form', '#kyc_form'];
|
||||
var INCEPTION_NS = '.inceptionFormValidate';
|
||||
|
||||
function isParsleyReady() {
|
||||
return !!window.Parsley;
|
||||
}
|
||||
|
||||
function isSkippableField(el) {
|
||||
if (!el) {
|
||||
return true;
|
||||
}
|
||||
if (el.disabled) {
|
||||
return true;
|
||||
}
|
||||
if (el.type === 'hidden') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isCharsetCandidate(el) {
|
||||
if (!el || el.tagName === 'SELECT') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = (el.type || '').toLowerCase();
|
||||
if (type === 'file' || type === 'checkbox' || type === 'radio' || type === 'password' || type === 'email' || type === 'url' || type === 'submit' || type === 'button' || type === 'reset') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isDocumentNameField(el) {
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
var name = (el.name || '').toLowerCase();
|
||||
var id = (el.id || '').toLowerCase();
|
||||
return name === 'doc_name[]' ||
|
||||
name === 'other_docs_name[]' ||
|
||||
name === 'docs_name[]' ||
|
||||
id === 'docs_name' ||
|
||||
$(el).hasClass('other-doc-name-field');
|
||||
}
|
||||
|
||||
function registerValidator() {
|
||||
if (!isParsleyReady() || window.Parsley.__inceptionFormValidatorRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.Parsley.addValidator('inceptioncharset', {
|
||||
validateString: function (value) {
|
||||
if (!value || String(value).trim() === '') {
|
||||
return true;
|
||||
}
|
||||
return TEXT_ALLOWED.test(String(value));
|
||||
},
|
||||
messages: { en: MESSAGE }
|
||||
});
|
||||
|
||||
window.Parsley.__inceptionFormValidatorRegistered = true;
|
||||
}
|
||||
|
||||
function applyConstraints($form) {
|
||||
if (!$form || !$form.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form.find('input, textarea, select').each(function () {
|
||||
var el = this;
|
||||
var $el = $(el);
|
||||
|
||||
if (isSkippableField(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCharsetCandidate(el) || isDocumentNameField(el)) {
|
||||
if (!$el.attr('data-parsley-inceptioncharset')) {
|
||||
$el.attr('data-parsley-inceptioncharset', 'true');
|
||||
}
|
||||
if (!$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'input change');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (el.tagName === 'SELECT' && !$el.attr('data-parsley-trigger')) {
|
||||
$el.attr('data-parsley-trigger', 'change');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refreshParsleyInstance($form) {
|
||||
if (!$form || !$form.length || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var parsleyInstance = $form.parsley();
|
||||
if (parsleyInstance && typeof parsleyInstance.refresh === 'function') {
|
||||
parsleyInstance.refresh();
|
||||
}
|
||||
} catch (e) {
|
||||
// no-op; keep existing form flow unchanged
|
||||
}
|
||||
}
|
||||
|
||||
function validateField(field) {
|
||||
if (!field || isSkippableField(field) || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $field = $(field);
|
||||
var $form = $field.closest('form');
|
||||
if (!$form.length || typeof $field.parsley !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure dynamic fields also receive constraints before validation.
|
||||
applyConstraints($form);
|
||||
refreshParsleyInstance($form);
|
||||
|
||||
try {
|
||||
$field.parsley().validate();
|
||||
} catch (e) {
|
||||
// no-op; avoid interfering with existing page scripts
|
||||
}
|
||||
}
|
||||
|
||||
function bindFormEvents(selector) {
|
||||
var $form = $(selector);
|
||||
if (!$form.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerValidator();
|
||||
applyConstraints($form);
|
||||
refreshParsleyInstance($form);
|
||||
|
||||
$form.off(INCEPTION_NS);
|
||||
|
||||
$form.on('input' + INCEPTION_NS, 'input:not([type=hidden]), textarea', function () {
|
||||
validateField(this);
|
||||
});
|
||||
|
||||
$form.on('change' + INCEPTION_NS, 'select, input:not([type=hidden]), textarea', function () {
|
||||
validateField(this);
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (!isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
FORM_SELECTORS.forEach(function (selector) {
|
||||
bindFormEvents(selector);
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
init();
|
||||
});
|
||||
|
||||
window.refreshInceptionFormValidation = function (formSelector) {
|
||||
if (!formSelector || !isParsleyReady()) {
|
||||
return;
|
||||
}
|
||||
bindFormEvents(formSelector);
|
||||
};
|
||||
})(function () {
|
||||
return window.jQuery;
|
||||
});
|
||||
157
public/dev_logs/2026-04-06_opd_policy_terms_72_plan.md
Normal file
157
public/dev_logs/2026-04-06_opd_policy_terms_72_plan.md
Normal file
@ -0,0 +1,157 @@
|
||||
# 2026-04-06 — OPD Policy Terms Plan (`policy_type_id = 72`)
|
||||
|
||||
## Context
|
||||
|
||||
- Policy type: `72`
|
||||
- Policy terms label: `OPD Policy Terms`
|
||||
- Requested fields/content:
|
||||
- `Mode of Serviceability`
|
||||
- `Eligibility`
|
||||
- `Total Sum Insured limit - INR 15000`
|
||||
- `In Person Doctor Consultation`
|
||||
- `Prescribed Lab test (Pathology & Radiology)`
|
||||
- `Prescribed Pharmacy`
|
||||
- `Dental`
|
||||
- `Vision`
|
||||
- `Vaccination for children & adults`
|
||||
- Target view: `app/Views/other_policy_terms.php`
|
||||
|
||||
## Problem Identified
|
||||
|
||||
- OPD fields were visible in UI but not saved to DB for `policy_type_id = 72`.
|
||||
- Root cause: `app/Controllers/ClientController.php` in `otherPolicyTermsFormSubmit()` uses a strict field mapping for policy `72` and did not include the newly added OPD keys.
|
||||
- Impact: Submitted payload contained OPD fields, but controller dropped them before `policy_terms` JSON update.
|
||||
|
||||
## Fix Plan
|
||||
|
||||
1. Update `policy_type_id = 72` save mapping
|
||||
- Add OPD keys to `$data` construction in `otherPolicyTermsFormSubmit()`.
|
||||
- Include defaults where applicable (`total_sum_insured_limit` fallback to `INR 15000`).
|
||||
|
||||
2. Keep existing family floater/age mapping unchanged
|
||||
- Preserve current business logic for `family_floater`, `family_floaters`, and `age_ratio`.
|
||||
- Add OPD terms in additive mode only.
|
||||
|
||||
3. Validate controller integrity
|
||||
- Run PHP syntax check for `ClientController.php`.
|
||||
- Confirm no changes to unrelated policy type save flow.
|
||||
|
||||
## New Requirement Plan - `_display` Checkbox -> `enrollment_display_key` for `other_policy_terms`
|
||||
|
||||
### Reference behavior (from `app/Views/policy_gmc_terms.php`)
|
||||
|
||||
- Each term row includes a checkbox with `name` ending in `_display`.
|
||||
- Only checked display keys are reflected in `enrollment_display_key`.
|
||||
- Existing loader flow reads `enrollment_display_key` and restores checkbox states.
|
||||
|
||||
### Problem to solve in `other_policy_terms`
|
||||
|
||||
- For policy type `72`, OPD fields currently do not have `*_display` checkboxes.
|
||||
- In controller, `otherPolicyTermsDisplayKeyConstruct()` currently builds `enrollment_display_key` only from special condition label/input pairs, not from `*_display` checkboxes.
|
||||
- Result: checkbox-driven display selection is not persisted/reloaded for OPD terms.
|
||||
|
||||
### Implementation plan
|
||||
|
||||
1. Add `*_display` checkboxes to OPD rows in `app/Views/other_policy_terms.php`
|
||||
- For each OPD field (`mode_of_serviceability`, `eligibility`, `total_sum_insured_limit`, etc.), add a checkbox input:
|
||||
- `name="<field_key>_display"`
|
||||
- `id="<field_key>_display"`
|
||||
- class `unchecked`
|
||||
- default checked
|
||||
- Keep checkbox + label + value input row layout aligned with existing non-72 dynamic term rows.
|
||||
|
||||
2. Update `otherPolicyTermsDisplayKeyConstruct()` in `app/Controllers/ClientController.php`
|
||||
- Extend logic to parse all incoming keys ending with `_display`.
|
||||
- For each checked display key, map base key to human-readable label and value from the corresponding base field.
|
||||
- Preserve current special-condition mapping behavior; merge both outputs into one `enrollment_display_key`.
|
||||
|
||||
3. Keep save flow backward compatible
|
||||
- Do not alter existing `policy_type_id == 72` family floater and age mapping.
|
||||
- Ensure OPD values and `enrollment_display_key` are both saved in `policy_terms`.
|
||||
- Keep non-72 flow unchanged.
|
||||
|
||||
4. Restore checkbox states on load
|
||||
- Reuse existing `processJsonObject`-style behavior in `other_policy_terms` (if missing, add equivalent) to set `*_display` checked state based on `enrollment_display_key`.
|
||||
- Verify for both newly created and previously saved records.
|
||||
|
||||
5. Validate end-to-end
|
||||
- Save with mixed checked/unchecked OPD display checkboxes.
|
||||
- Confirm DB JSON includes expected `enrollment_display_key` entries.
|
||||
- Reload and verify display checkbox states are restored.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
1. Place OPD terms section immediately after `familyFloaterDiv_others_two`
|
||||
- Keep `familyFloaterDiv_others_two` as the first visible block for policy `72`.
|
||||
- Insert OPD terms container directly below it in the DOM order (not before it).
|
||||
- Ensure the OPD section appears before special conditions.
|
||||
|
||||
2. Add OPD-specific policy terms UI block
|
||||
- Add dedicated OPD template/HTML for `policy_type_id = 72`.
|
||||
- Render OPD rows as labeled text inputs with stable keys (`mode_of_serviceability`, `eligibility`, etc.).
|
||||
- Keep field names in snake_case so they serialize cleanly into `policy_terms` JSON.
|
||||
|
||||
3. Handle fixed sum insured limit cleanly
|
||||
- Add a separate OPD field key like `total_sum_insured_limit`.
|
||||
- Set default value as `15000` (or `INR 15000` based on UI format) for new entries.
|
||||
- Keep numeric sanitization consistent with existing sum insured input behavior where applicable.
|
||||
|
||||
4. Preserve existing `policy_type_id = 72` family floater behavior
|
||||
- Do not remove current family floater section/logic already tied to `policy_type_id == 72`.
|
||||
- Ensure OPD terms are additive and do not break `family_floater`, `family_floaters`, and `age_ratio` handling.
|
||||
|
||||
5. Populate saved data on edit
|
||||
- Reuse existing JSON hydration flow (`Object.keys(jsonObject)` loop) so OPD fields auto-populate by `name`.
|
||||
- Confirm keys in UI match keys stored in policy terms JSON exactly.
|
||||
|
||||
6. Validate display behavior
|
||||
- Confirm form section opens for `policy_type_id > 5`.
|
||||
- Confirm non-72 cleanup (`if(policy_type_id != 72)`) does not remove OPD fields when policy type is 72.
|
||||
- Confirm OPD fields are not rendered for unrelated policy types.
|
||||
- Confirm visual order is `familyFloaterDiv_others_two` -> OPD terms -> special conditions.
|
||||
|
||||
7. QA checklist
|
||||
- Create a new policy terms record for `policy_type_id = 72` with all OPD values.
|
||||
- Reload and verify values repopulate correctly.
|
||||
- Verify submit and autosave payload include OPD keys in `policy_terms`.
|
||||
- Verify no regressions for policy types `6` and `7`.
|
||||
|
||||
## Suggested Field Keys
|
||||
|
||||
- `mode_of_serviceability`
|
||||
- `eligibility`
|
||||
- `total_sum_insured_limit`
|
||||
- `in_person_doctor_consultation`
|
||||
- `prescribed_lab_test_pathology_radiology`
|
||||
- `prescribed_pharmacy`
|
||||
- `dental`
|
||||
- `vision`
|
||||
- `vaccination_for_children_and_adults`
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] Place OPD section after `familyFloaterDiv_others_two` in UI order.
|
||||
- [x] Add `policy_type == 72` OPD HTML block in `appendPolicyTermsHTML()`.
|
||||
- [x] Ensure defaults are applied for total sum insured limit.
|
||||
- [x] Verify bind/populate works from existing JSON loader.
|
||||
- [x] Fix OPD term persistence in `ClientController::otherPolicyTermsFormSubmit()` for `policy_type_id = 72`.
|
||||
- [x] Add temporary debug logging for OPD72 save payload in controller.
|
||||
- [x] Add `*_display` checkboxes for OPD term rows in `other_policy_terms.php`.
|
||||
- [x] Extend `otherPolicyTermsDisplayKeyConstruct()` to include checked `*_display` keys.
|
||||
- [x] Ensure `enrollment_display_key` restores OPD checkbox states in `other_policy_terms.php`.
|
||||
- [ ] Verify DB `policy_terms.enrollment_display_key` for mixed checked/unchecked OPD fields.
|
||||
- [ ] Run manual UI verification for create/edit/submit/autosave.
|
||||
- [x] Confirm no regressions for other policy types (code-level condition check and syntax validation completed).
|
||||
- [ ] Remove temporary debug logging after verification.
|
||||
|
||||
## Verification Notes
|
||||
|
||||
- PHP syntax check passed for `app/Views/other_policy_terms.php` (`php -l`).
|
||||
- PHP syntax check passed for `app/Controllers/ClientController.php` (`php -l`).
|
||||
- Verified `policy_type_id == 72` now renders OPD fields in both create and edit flows.
|
||||
- Verified OPD fields are now rendered in a dedicated container placed after `familyFloaterDiv_others_two`.
|
||||
- Verified non-`72` cleanup blocks remain scoped (`sumInsuredDiv`/family floater removals are still excluded for `72`).
|
||||
- Added temporary controller debug log (`OPD72 save payload`) to confirm persisted key/value mapping during manual test.
|
||||
- Added OPD `*_display` checkboxes and controller mapping so checked fields are now included in `enrollment_display_key`.
|
||||
- Added `processOtherEnrollmentDisplayKey()` in `other_policy_terms.php` to restore OPD display checkbox states from saved `enrollment_display_key`.
|
||||
- Manual browser verification is still required for submit + autosave end-to-end confirmation.
|
||||
Loading…
Reference in New Issue
Block a user