myLogger = \Config\Services::mylogger(); $this->employeeModel = new EmployeeModel(); $this->employeePolicyModel = new EmployeePolicyModel(); $this->clientModel = new ClientModel(); $this->clientBranchModel = new ClientBranchModel(); $this->fileModel = new FileModel(); $this->batchListModel = new BatchListModel(); $this->batchFileModel = new BatchFileModel(); $this->empEndorsementModel = new EmpEndorsementModel(); $this->clientPolicyModel = new ClientPolicyModel(); $this->TPAModel = new TPAModel(); $this->policiesModel = new PolicesModel(); $this->insurerModel = new InsurerModel(); $this->cashDepositModel = new ClientDepositModel(); $this->PolicyPremium2Model = new PolicyPremium2Model(); $this->auditHistory = new AuditHistoryModel(); $this->userModel = new userModel(); $this->partnerEndorsementRequestModel = new PartnerEndorsementRequestModel(); $this->LevelContactModel = new LevelContactModel(); $this->UserActivityHistoryModel = new UserActivityHistoryModel(); } public function list() { // $s3 = \Config\Services::getS3Service(); // $file = WRITEPATH.'uploads/excel/inception.ods'; // print_rr($s3->exists('inception_1766475604.ods')); // print_rr($s3->getPresignedUrl('inception_1766.ods')); // print_rr($s3->upload($file)); // print_rr($s3->download('inception_1766475604.ods',__DIR__)); // die(); // $model = new UserModel(); $data = []; $data['status'] = ['draft' => 'Draft', 'enrolled' => 'Enrolled', 'active' => 'Active', 'inactive' => 'In-Active', 'pending' => 'Pending']; if (count($this->request->getGet())) { $filterData = $this->request->getGet(); // Convert the status field to an array if it exists in the request data if (isset($filterData['status']) && !empty($filterData['status'])) { // $filterData['status'] = explode(",", $filterData['status']); }else{ $filterData['status'] = []; } // Fetch employees with the modified $filterData array $data['employees'] = $this->employeePolicyModel->getEmployeePolicy( client_id: $filterData['client_id'] ?? null, policy_id: $filterData['policy_id'] ?? null, branch_id: $filterData['branch_id'] ?? null, emp_code : $filterData['emp_code'] ?? null, emp_name : $filterData['emp_name'] ?? null, status : $filterData['status'] ?? [], ); // log_message('error',json_encode($data['employees'])); // Set getData in $data array with the processed $filterData $data['getData'] = $filterData; // return view('employee_list',$data); $html = view('employee_data_list', $data); return $this->respond(['status' => true, 'html' => $html], 200); } // dd($this->employeeModel->getLastQuery()); // dd( $data['getData']); // dd($this->request->getGet()); $this->myLogger->logme('error', 'list called'); $data['tab_name'] = 'Members'; $data['page_name'] = "Members"; $this->loadLayout('employee_list', $data); } public function getClientWithPolicies() { try { //echo $this->request->isAJAX();die(); $result = $this->clientModel->clientsWithPolicies(); // dd($result); // print_r($result);die(); if (!count($result)) { return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'no data found'], 200); } else { return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $result], 200); } } catch (\Throwable $th) { return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => $th->getMessage()], 500); } } public function getUploadedFileError() { $file_id = $this->request->uri->getSegment(3); // dd($segments[2]); // die(); // $file_id = $this->request->getGet(); // echo $file_id;die(); $file = $this->fileModel->find((int)$file_id); // print_r($result);die(); if (!isset($file)) { return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'no data found'], 200); } else { return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $file['reason'], 'is_comparison_skipped' => $file['is_comparison_skipped'], 'policy_id' => $file['policy_id']], 200); } } //handles employee & dependent bulk upload with events like inception,addition,deletion, correction and SI enhancements public function employeesUplodWithEvents($post_data = null) { // $empDataServiceController = new EmpDataServiceController(); // !dd($empDataServiceController->importInceptionUpdateTPAandUHID(['file_id' => 79])); // $job_details = new Jobs(); // $r = Jobs::addJob(['job_name' => 'add','payload' => ['a' => 10, 'b' => 35]]); // print_r($r);//die(); // // $jobWorker = new JobWorker(); // JobWorker::processJob($r); // die(); // echo $this->request->getMethod();die(); // print_r($this->request->getFiles('emplist'));print_r($this->request->getPost('emplist')); // print_r($this->request->getPost('clients')); // print_r($this->request->getPost('policies')); // print_r($this->request->getPost('upload-action-type')); // die(); // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->excelFileDataValidation(['file_id' => '933']); // dd($res); // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->employeeDisembark(['file_id' => '586']); // dd($res); // $existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(client_policy_id: '2'); // dd($existing_famility_details); // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->employeesSIEnhanceProcess(['file_id' => '38']); // dd($res); // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->employeesCorrectionProcess(['file_id' => '37']); // // dd($res); // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->employeesOnboardPreprocess(['client_policy_id' => '3']); // dd($res); // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->employeeDisembark(['file_id' => '36']); // dd($res); // if(isset($res['error_summary']) && count($res['error_summary'])) // { // $res['error_summary'] = (array_count_values($res['error_summary'])); // $failure_reason = ((json_encode($res))); // // dd($failure_reason); // $this->fileModel->where('id', '12')->set(['status' => 'failed','reason' => $failure_reason])->update(); // dd($failure_reason); // } // $this->truncateFileData(747, 5) ; // print_rr($this->cloneWorksheet()); // die(); if (!empty($post_data) || $this->request->is('post') == 'post') { //validate uploaded file $filename = ''; $fileSize = ''; if (empty($post_data)) { $validated = $this->validate([ 'emplist' => [ 'uploaded[emplist]', 'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]', 'max_size[emplist,16384]', ], ]); } else { $validated = validateExcelFile($post_data['file_name']); } if ($validated) { $avatar = isset($post_data['file_name']) ? $post_data['file_name'] : $this->request->getFile('emplist'); if (!$avatar) { $this->myLogger->logme("error", 'File not found'); if (!empty($post_data)) { return ['status' => false, 'message' => 'File not found']; } else { return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400); } } $fileSizeBytes = (is_object($avatar) && method_exists($avatar, 'getSize')) ? (int) $avatar->getSize() : 0; $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/excel/', UPLOAD_EXT_EXCEL); if ($filename !== '') { $fileSize = $fileSizeBytes / (1024 * 1024); // Convert to MB $this->myLogger->logme("error", 'File move successful'); } else { $this->myLogger->logme("error", 'File move failed'); if (!empty($post_data)) { return ['status' => false, 'message' => 'File move failed']; } else { return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => 'File move failed'], 500); } } } else { $this->myLogger->logme("error", 'Upload failed Invalid file'); if (!empty($post_data)) { return ['status' => false, 'message' => 'Invalid file']; } else { return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404); } } //process post variable entry in file table $loggedInUserID = $post_data['created_by'] ?? get_session_userid(); $client_id = isset($post_data['client_id']) ? $post_data['client_id'] : $this->request->getPost('client_id'); $policy_id = isset($post_data['policy_id']) ? $post_data['policy_id'] : $this->request->getPost('policy_id'); $branch_id = isset($post_data['client_branch_id']) ? $post_data['client_branch_id'] : $this->request->getPost('branch_id'); $action = isset($post_data['file_action']) ? $post_data['file_action'] : $this->request->getPost('upload-action-type'); if (empty($post_data)) { $hr_file_id = $this->request->getPost('hr_file_id') ?? null; } else { $hr_file_id = $post_data['hr_file_id'] ?? null; } $hr_id = $post_data['created_by'] ?? null; $status = 'inprogress'; $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id, 'uploaded_by' => 1, 'hr_file_id' => $hr_file_id, 'hr_id' => $hr_id]); //here field policy_id have client_policy_id and not policy id from policy master $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]); if ($action == "all") { $r = Jobs::addJob(['job_name' => 'excelMultieventFileFormateValidation', 'payload' => ['file_id' => $file_id]]); $this->myLogger->logme("error", '{file_id} is greather than 1MB, validating with job queue', ['file_id' => $file_id]); } else { //start validation process if ($fileSize < 1) // if file size less than 1 { $empServiceController = new EmployeeServiceController(); $result = $empServiceController->excelFileFormatValidation(['file_id' => $file_id]); $this->myLogger->logme("error", '{file_id} is less than 1MB, validating on the fly', ['file_id' => $file_id]); //endof validation process if (isset($result['error_summary']) && count($result['error_summary'])) { if (!empty($post_data)) { return ['status' => false, 'message' => 'File rejected with errors', 'file_id' => $file_id]; } else { return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'File rejected with errors'], 200); } } } else //if file size greater than 1 add the file as job { $job_details = new Jobs(); $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation', 'payload' => ['file_id' => $file_id]]); $this->myLogger->logme("error", '{file_id} is greather than 1MB, validating with job queue', ['file_id' => $file_id]); } } if (!empty($post_data)) { return ['status' => true, 'message' => 'File upload successs, Data validation is in-progress', 'file_id' => $file_id]; } else { return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200); } } $get_data = $this->request->getGet(); // dd($get_data); $data['tab_name'] = 'View Inception'; $data['page_name'] = 'View Inception'; //for TPA/insurer upload $data['events'] = ['inception' => 'Inception (Employee + Dependents)', 'missed_inception' => 'Missed Inception (Employee + Dependents)', 'addition' => 'Addition (Employee + Dependents)', 'dependent_addition' => 'Dependent Addition (Only Dependents)', 'deletion' => 'Deletion', 'correction' => 'Correction', 'si_enhancement' => 'SI Enhancement']; //for inception upload $data['actions'] = ['all' => 'All', 'inception' => 'Inception (Employee + Dependents)', 'missed_inception' => 'Missed Inception (Employee + Dependents)', 'addition' => 'Addition (Employee + Dependents)', 'dependent_addition' => 'Dependent Addition (Only Dependents)', 'deletion' => 'Deletion', 'correction' => 'Correction', 'si_enhancement' => 'SI Enhancement']; // $data['actions'] = ['inception' => 'Inception (Employee + Dependents)', 'missed_inception' => 'Missed Inception (Employee + Dependents)', 'addition' => 'Addition (Employee + Dependents)', 'dependent_addition' => 'Dependent Addition (Only Dependents)', 'deletion' => 'Deletion', 'correction' => 'Correction', 'si_enhancement' => 'SI Enhancement','enrollment' => 'Enrolment']; // $data['import_or_export'] = ['import' => 'Import', 'export' => 'Export']; $data['import_or_export'] = ['import' => 'Upload', 'export' => 'Download']; $data['insurer_or_tpa'] = ['insurer' => 'Insurer', 'tpa' => 'TPA']; // $data['fileList'] = $this->fileModel // ->select(['files.*', 'up.emp_code', 'up.first_name', 'pm.name as policy_name', 'c.short_name', 'cp.id as client_policy_id']) // ->join('user_profiles up', 'files.created_by = up.id') // ->join('client_policy cp', 'files.policy_id = cp.id', 'left') // ->join('policies pm', 'cp.policy_id = pm.id', 'left') // ->join('clients c', 'files.client_id = c.id and files.client_id = cp.client_id', 'left') // ->where('files.created_by', get_session_userid())->orderBy('files.created_at', 'desc')->findAll(); // dd($this->fileModel->getLastQuery()); $role_id = get_role_id(); $user_id = get_session_userid(); $query = $this->fileModel ->select([ 'files.id', 'files.file_name', 'files.created_by', 'files.created_at', 'files.is_active', 'files.status', 'files.client_id', 'files.policy_id', 'files.client_branch_id', 'files.action', 'files.uploaded_by', 'up.emp_code', // 'up.first_name', 'c.short_name', 'cb.branch_name', 'cp.id as client_policy_id', '"0" as employee_count', '"0" as total', 'policy_type.policy_type', 'cp.policy_no', "CASE WHEN files.hr_id IS NOT NULL THEN CONCAT( ( SELECT lc.name FROM level_contacts lc WHERE lc.id = files.hr_id LIMIT 1 ), ' (HR)' ) ELSE up.first_name END AS first_name " ]) ->join('user_profiles up', 'files.created_by = up.id', 'left') ->join('client_policy cp', 'files.policy_id = cp.id', 'left') ->join('client_branch cb', 'files.client_branch_id = cb.id', 'left') ->join('policy_type', 'policy_type.id = cp.policy_type_id') ->join('clients c', 'files.client_id = c.id and files.client_id = cp.client_id', 'left') ->join("client_rm cr", "cr.client_id = c.id and cr.is_active = 1", 'left') ->where('files.is_active', 1); if (!empty($get_data['start_date'] ?? null) && !empty($get_data['end_date'] ?? null)) { // 1. If dates are provided, use the user's filter $start = change_date_format($get_data['start_date'], 'd/m/Y', 'Y-m-d') . ' 00:00:00'; $end = change_date_format($get_data['end_date'], 'd/m/Y', 'Y-m-d') . ' 23:59:59'; $query->where('files.created_at >=', $start) ->where('files.created_at <=', $end); } else { if(empty($get_data['tab_type'] ?? null)){ // 2. Default: If no dates are selected, show last 90 days (or all data) $query->where('files.created_at >=', date('Y-m-d 00:00:00', strtotime('-90 days'))) ->where('files.created_at <=', date('Y-m-d 23:59:59')); } } if(!empty($get_data['client_id'] ?? null)){ $query->where('files.client_id', $get_data['client_id']); } if(!empty($get_data['client_branch_id'] ?? null)){ $query->where('files.client_branch_id', $get_data['client_branch_id']); } if(!empty($get_data['policy_id'] ?? null)){ $query->where('files.policy_id', $get_data['policy_id']); } if(!empty($get_data['event_type'] ?? null)){ $query->where('files.action', $get_data['event_type']); } if (in_array($role_id, [2, 3])) { // If the user is a Account Manager or Manager, filter by user_id $query->where('cr.user_id', (int)$user_id); } $data['fileList'] = $query->groupBy("files.id") ->orderBy('files.created_at', 'desc') ->find(); // dd($this->fileModel->getLastQuery()); // dd($data['fileList']); $query2 = $this->batchFileModel->select(" batch_files.id, batch_files.client_id, batch_files.client_policy_id, batch_files.batch_code, batch_files.file_name, batch_files.insurer_or_tpa, batch_files.event_type, batch_files.actions, batch_files.count, batch_files.created_by, batch_files.created_at, batch_files.updated_by, batch_files.updated_at, batch_files.is_active, batch_files.amount, batch_files.status, batch_files.icici_status_flag, batch_files.client_branch_id, insurers.short_name as insurer_short_name, tpa.short_name as tpa_short_name, DATE_FORMAT(batch_files.policy_issue_date, '%d/%m/%Y') AS policy_issue_date, CASE WHEN batch_files.status IN ('partially success', 'in-progress-partially', 'failed-7') THEN batch_files.error_data ELSE NULL END AS error_data, clients.short_name as client_short_name, client_branch.branch_name, client_policy.policy_no, policy_type.policy_type ") ->join('client_policy', 'client_policy.id = batch_files.client_policy_id') ->join('insurers', 'client_policy.insurer_id = insurers.id') ->join('tpa', 'client_policy.tpa_id = tpa.id', 'left') ->join('client_branch', 'client_branch.id = batch_files.client_branch_id') ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') ->join('clients', 'clients.id = client_policy.client_id') ->join("client_rm cr", "cr.client_id = clients.id and cr.is_active = 1", 'left') ->where('batch_files.is_active', 1); if (!empty($get_data['start_date'] ?? null) && !empty($get_data['end_date'] ?? null)) { // 1. If dates are provided, use the user's filter $start = change_date_format($get_data['start_date'], 'd/m/Y', 'Y-m-d') . ' 00:00:00'; $end = change_date_format($get_data['end_date'], 'd/m/Y', 'Y-m-d') . ' 23:59:59'; $query2->where('batch_files.created_at >=', $start) ->where('batch_files.created_at <=', $end); } else { if(empty($get_data['tab_type'] ?? null)){ // 2. Default: If no dates are selected, show last 90 days (or all data) $query2->where('batch_files.created_at >=', date('Y-m-d 00:00:00', strtotime('-90 days'))) ->where('batch_files.created_at <=', date('Y-m-d 23:59:59')); } } if(!empty($get_data['client_id'] ?? null)){ $query2->where('batch_files.client_id', $get_data['client_id']); } if(!empty($get_data['client_branch_id'] ?? null)){ $query2->where('batch_files.client_branch_id', $get_data['client_branch_id']); } if(!empty($get_data['policy_id'] ?? null)){ $query2->where('batch_files.client_policy_id', $get_data['policy_id']); } if(!empty($get_data['event_type'] ?? null)){ $query2->where('batch_files.event_type', $get_data['event_type']); } if(!empty($get_data['insurer_or_tpa'] ?? null)){ $query2->where('batch_files.insurer_or_tpa', $get_data['insurer_or_tpa']); } if(!empty($get_data['action_type'] ?? null)){ $query2->where('batch_files.actions', $get_data['action_type']); } if (in_array($role_id, [2, 3])) { // If the user is a Account Manager or Manager, filter by user_id $query2->where('cr.user_id', (int)$user_id); } $data['batch_list'] = $query2->groupBy("batch_files.id") ->orderBy('batch_files.id', 'desc') ->find(); // dd($data['fileList']);die(); if ($this->request->getMethod() == "get") { $this->loadLayout('import_export', $data); } } public function getExcelFileErrors($file_id, $retun_type = null) { $file_data = $this->fileModel->where('id', $file_id)->first(); $error = json_decode($file_data['reason'] ?? '{}', true); if(!empty($error) && $retun_type == 'api'){ $send = isset($error['error_summary'][5]) || isset($error['error_summary'][6]) ? true : false; if($send){ $string = $error['error_data'] ?? 'System error'; $errorMap = [ "Column order conflict" => "Invalid file format. Please use the sample file.", ]; $message = $string; // Default to the original error foreach ($errorMap as $keyword => $friendlyMessage) { if (strpos($string, $keyword) !== false) { $message = $friendlyMessage; break; // Stop looking once we find a match } } return $this->respond(['status' => false, 'code' => 404, 'message' => $message, 'data' => []], 200); } } // $file_id = $this->request->uri->getSegment(3); $empServiceController = new EmployeeServiceController(); // Render views and capture output $result = $empServiceController->getExcelErrorData($file_id); if($retun_type == 'api'){ if(!empty($result)){ return $this->respond(['status' => true, 'code' => 200, 'message' => 'Error data feteched successfully', 'data' => $result], 200); }else{ return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to fetch error data', 'data' => []], 200); } } if ($result != 0) { $result['file_id'] = $file_id; echo view('excel_errors', $result); } else if ($result == 0) { $data['message'] = 'File Not Found Physically'; return view('errors/404', $data); } else { echo view('errors/html/production'); } } /** * The below function Downloads a sample Excel file based on the provided action type. * * @param string|null $actionType The type of action : * * - inception * - correction * - si_enhancement for selecting the appropriate sample Excel file. * * @return redirect back with an error message if the file is not found, otherwise sends the file to the user for download. */ public function downloadSampleExcelFile($actionType = null) { // $actionType = $this->request->getGet(); $filePath = ''; // Path to your file if ($actionType == 'inception') { $filePath = ROOTPATH . 'public/sample_excel/sample_inception.xls'; } else if ($actionType == 'correction') { $filePath = ROOTPATH . 'public/sample_excel/sample_correction.xls'; } else if ($actionType == 'si_enhancement') { $filePath = ROOTPATH . 'public/sample_excel/sample_si_enhancement.xls'; } else if ($actionType == 'dependent_addition') { $filePath = ROOTPATH . 'public/sample_excel/sample_dependent_addition.xls'; } else if ($actionType == 'addition') { $filePath = ROOTPATH . 'public/sample_excel/sample_addition.xls'; } else if ($actionType == 'deletion') { $filePath = ROOTPATH . 'public/sample_excel/sample_deletion.xls'; } else if ($actionType == 'enrollment') { $filePath = ROOTPATH . 'public/sample_excel/enrollment.xlsx'; }else if ($actionType == 'missed_inception') { $filePath = ROOTPATH . 'public/sample_excel/sample_inception.xls'; }else if ($actionType == 'member_data') { $filePath = ROOTPATH . 'public/sample_excel/Sample_Member_Data.xlsx'; }else if ($actionType == 'all') { $filePath = ROOTPATH . 'public/sample_excel/sample_multievent_file.xlsx'; }else if ($actionType == 'bds_upload') { $filePath = ROOTPATH . 'public/sample_excel/sample_bds_bulk_upload_excel.xlsx'; }else if ($actionType == 'claim_dump_upload') { $filePath = ROOTPATH . 'public/sample_excel/sample_claim_dump_upload_excel.xlsx'; } // Check if the file exists if (file_exists($filePath)) { // Set the appropriate MIME type $mimeType = mime_content_type($filePath); // Send the file to the client for download return $this->response->download($filePath, null, $mimeType); } else { // File not found, show an error message or redirect echo view('errors/404.php', ['message' => 'Sample file not found']); // return redirect()->back()->with('error', 'Sample file not found'); } } /** * The below function are Handles import and export operations based on the provided parameters. * * This function logs the call, retrieves necessary data, generates a filename, * and then either exports data to an Excel file or imports data from an Excel file * depending on the provided action type and event type. * * @return void Redirects the user to the appropriate page with flash messages indicating success or failure. */ public function importExport() { $array = $this->request->getPost('event_type'); if (is_array($array)) { $event_type = 'MultipleEvents'; } else { $event_type = $this->request->getPost('event_type'); } $this->myLogger->logme('error', 'Import Export -- Function called'); $empDataServiceController = new EmpDataServiceController(); $client_id = $this->request->getPost('client_id'); $client_policy_id = $this->request->getPost('client_policy_id'); $client_branch_id = $this->request->getPost('client_branch_id'); $insurer_or_tpa = $this->request->getPost('insurer_or_tpa'); $actions = $this->request->getPost('action_type'); $policy_issue_date = $this->request->getPost('policy_issue_date') ?? null; $client_data = $this->clientPolicyModel->getCliendDataForExcelFileName($client_policy_id); $file_name = generate_filename($client_data['short_name'], $event_type, $actions, $insurer_or_tpa, $client_data['policy_type'], $client_data['branch_code']); // dd($client_data, $file_name); $batch_data = [ 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'client_branch_id' => $client_branch_id, 'insurer_or_tpa' => $insurer_or_tpa, 'event_type' => $event_type, 'actions' => $actions, 'file_name' => $file_name, ]; $batch_data['policy_issue_date'] = !empty($policy_issue_date) ? change_date_format($policy_issue_date, 'd/m/Y', 'Y-m-d') : null; if ($actions == 'export') { if ($event_type == 'inception' || $event_type == 'addition' || $event_type == 'dependent_addition' || $event_type == 'missed_inception' || ($event_type == 'MultipleEvents' && $insurer_or_tpa == 'tpa')) { $return = $empDataServiceController->generateExcelForAdditionandInception($batch_data); if ($return === 0) { session()->setFlashdata('error', "Insufficient deposit amount."); return redirect()->to(base_url('employee/upload')); }else if($return === 5){ session()->setFlashdata('error', "The policy does not have a CD account number."); return redirect()->to(base_url('employee/upload')); } else if($return === 6){ session()->setFlashdata('error', "The Insurer does not have an Excel export template format."); return redirect()->to(base_url('employee/upload')); } if (!$return) { if ($insurer_or_tpa == 'tpa') { session()->setFlashdata('error', "No data was found for this action."); return redirect()->to(base_url('employee/upload')); } else if ($insurer_or_tpa == 'insurer') { session()->setFlashdata('error', "No data was found for this action."); return redirect()->to(base_url('employee/upload')); } } else { $this->myLogger->logme('error', 'Successfully exported Excel file in {data}.', ['data' => $event_type]); } } else if ($event_type == 'correction') { $return = $empDataServiceController->generateExcelForCorrection($batch_data); if($return === 6){ session()->setFlashdata('error', "The Insurer does not have an Excel export template format."); return redirect()->to(base_url('employee/upload')); } if (!$return) { session()->setFlashdata('error', 'No data found about this action'); return redirect()->to(base_url('employee/upload')); } else { $this->myLogger->logme('error', 'Successfully exported Excel file in Correction.'); } } else if ($event_type == 'si_enhancement') { $return = $empDataServiceController->generateExcelForSIEnhancement($batch_data); if ($return === 0) { session()->setFlashdata('error', "Insufficient deposit amount."); return redirect()->to(base_url('employee/upload')); }else if($return === 5){ session()->setFlashdata('error', "The policy does not have a CD account number."); return redirect()->to(base_url('employee/upload')); }else if($return === 6){ session()->setFlashdata('error', "The Insurer does not have an Excel export template format."); return redirect()->to(base_url('employee/upload')); } if (!$return) { session()->setFlashdata('error', 'No data found about this action'); return redirect()->to(base_url('employee/upload')); } else { $this->myLogger->logme('error', 'Successfully exported Excel file in SI_Enhancement.'); } } else if ($event_type == 'deletion') { $return = $empDataServiceController->generateExcelForDeletion($batch_data); if($return === 6){ session()->setFlashdata('error', "The Insurer does not have an Excel export template format."); return redirect()->to(base_url('employee/upload')); } if (!$return) { session()->setFlashdata('error', 'No data found about this action'); return redirect()->to(base_url('employee/upload')); } else { $this->myLogger->logme('error', 'Successfully exported Excel file in Deletion.'); } } else if($event_type == 'MultipleEvents'){ $batch_data['event_type'] = $array; $return = $empDataServiceController->generateExcelForAllEventType($batch_data); if ($return === 0) { session()->setFlashdata('error', "Insufficient deposit amount."); return redirect()->to(base_url('employee/upload')); }else if($return === 5){ session()->setFlashdata('error', "The policy does not have a CD account number."); return redirect()->to(base_url('employee/upload')); } else if($return === 6){ session()->setFlashdata('error', "The Insurer does not have an Excel export template format."); return redirect()->to(base_url('employee/upload')); } if (!$return) { session()->setFlashdata('error', 'No data found about this action'); return redirect()->to(base_url('employee/upload')); } else { $this->myLogger->logme('error', 'Excel exported successfully.'); } } } else if ($actions == 'import') { if($insurer_or_tpa == "tpa" && in_array($event_type, ['correction', 'deletion', 'si_enhancement'])){ session()->setFlashdata('error', "TPA upload is not applicable for this event."); return redirect()->to(base_url('employee/upload')); } $batch_data['file'] = $this->request->getFile('import_file_data'); $file = $this->request->getFile('import_file_data'); $filename = storage_file_Upload($file, WRITEPATH . 'uploads/import_excel/', UPLOAD_EXT_EXCEL); if ($filename === '') { session()->setFlashdata('error', 'File upload failed'); return redirect()->to(base_url('employee/upload')); } $this->myLogger->logme('error', 'Inception Import file name : {data}', ['data' => $filename]); $random_number_count = 4; $batch_data['batch_code'] = generate_random_string($random_number_count); $batch_data['created_by'] = get_session_userid(); $batch_data['status'] = 'pending'; $batch_data['file_name'] = $filename; if ($event_type == 'inception' || $event_type == 'addition' || $event_type == 'dependent_addition' || $event_type == 'missed_inception') { $file_id = $this->batchFileModel->insert($batch_data); $job_details = new Jobs(); $r = Jobs::addJob(['job_name' => 'importInceptionFileValidation', 'payload' => ['file_id' => $file_id]]); $return = 1; // $return = $empDataServiceController->importInceptionFileValidation(['file_id' => $file_id]); if ($return == 1) { session()->setFlashdata('success', 'File Uploaded Successfully File is being validated.'); return redirect()->to(base_url('employee/upload')); } else { session()->setFlashdata($return['status'] ?? 'error', $return['message'] ?? 'Something went wrong! Try Later'); return redirect()->to(base_url('employee/upload')); } } else if ($event_type == 'correction') { $file_id = $this->batchFileModel->insert($batch_data); $job_details = new Jobs(); $r = Jobs::addJob(['job_name' => 'importCorrectionValidation', 'payload' => ['file_id' => $file_id]]); $return = 1; // $return = $empDataServiceController->importCorrectionValidation(['file_id' => $file_id]); if ($return == 1) { session()->setFlashdata('success', 'File Uploaded Successfully File is being validated.'); return redirect()->to(base_url('employee/upload')); } else { session()->setFlashdata('error', $return); return redirect()->to(base_url('employee/upload')); } } else if ($event_type == 'si_enhancement') { $file_id = $this->batchFileModel->insert($batch_data); $job_details = new Jobs(); $r = Jobs::addJob(['job_name' => 'importSIEnhancementValidation', 'payload' => ['file_id' => $file_id]]); $return = 1; // $return = $empDataServiceController->importSIEnhancementValidation(['file_id' => $file_id]); if ($return == 1) { session()->setFlashdata('success', 'File Uploaded Successfully File is being validated.'); return redirect()->to(base_url('employee/upload')); } else { session()->setFlashdata('error', $return); return redirect()->to(base_url('employee/upload')); } } else if ($event_type == 'deletion') { $file_id = $this->batchFileModel->insert($batch_data); $job_details = new Jobs(); $r = Jobs::addJob(['job_name' => 'importDeletionValidation', 'payload' => ['file_id' => $file_id]]); $return = 1; // $return = $empDataServiceController->importDeletionValidation(['file_id' => $file_id]); if ($return == 1) { session()->setFlashdata('success', 'File Uploaded Successfully File is being validated.'); return redirect()->to(base_url('employee/upload')); } else { session()->setFlashdata('error', $return); return redirect()->to(base_url('employee/upload')); } } } } // ------------------------------------------------------------------------------------------- /** * Below function displays the endorsement list page. * * This method retrieves filter data from the request and fetches the endorsement list * based on the provided filters such as client ID, policy ID, and status. */ public function endorsementList() { $data = []; $data['status'] = ['pending' => 'Pending', 'inprogress' => 'In-Progress', 'complete' => 'Complete']; if (count($this->request->getGet())) { $filterData = $this->request->getGet(); $data['employees'] = $this->employeePolicyModel->getEmployeeEndorsementList( client_id: $filterData['client_id'], policy_id: $filterData['policy_id'], status: $filterData['status'], branch_id: $filterData['branch_id'] ); $data['getData'] = $filterData; // echo "
";
            
        }

        $this->myLogger->logme('error', 'list called');
        
        $data['tab_name']  = "Endorsements";
        $data['page_name'] = "Endorsements";

        $this->loadLayout('endorsement_list', $data);
    }

    
    /**
     * Below function displays the Enrollment list page.
     * 
     * This method retrieves filter data from the request and fetches the Enrollment list
     * based on the provided filters such as client , client_branch , employee - ( Log-in-or-not , ENrolled-or-not).
     */

     public function enrollmentClientList()
     {
        $role_id = get_role_id();
        $user_id = get_session_userid();

        $data = [];
        $client_list = $this->clientModel->join("client_rm","client_rm.client_id = clients.id",'left')->where('clients.is_active', 1);
        if (in_array($role_id, [2, 3])) {
            
            // If the user is a Account Manager or Manager, filter by user_id
            $client_list->where('client_rm.user_id', $user_id);
        }

        $client_list = $client_list->groupBy("clients.id")->findAll();
        $branch_list = $this->clientBranchModel->where('client_branch.is_active', 1)->findAll();
        $policy_list = $this->clientPolicyModel
                            ->select('client_policy.*, policy_type.policy_type')
                            ->join('policy_type', 'client_policy.policy_type_id = policy_type.id')
                            ->where('client_policy.is_active', 1)
                            ->findAll();

        $data['client_list'] = $client_list;
        $data['branch_list'] = $branch_list;
        $data['policy_list'] = $policy_list;

        // Get session data if available
        $data['selected_client_id'] = session()->get('client_id');
        $data['selected_branch_id'] = session()->get('branch_id');
        $data['selected_type'] = session()->get('type');

        // dd($data);

        $this->myLogger->logme('error', 'list called');

        $data['page_name'] = "Enrollment";

        return $this->loadLayout('enrollment_list', $data);
    
     }

     public function empby_client_clientbranch($client_id, $branch_id)
     {
        
        $results = $this->clientModel->select('employees.id as employee_id, employees.name as employee_name, 
                                                employees.relationship, employees.emp_code, 
                                                employees.emp_status, auth_history.user_type')
                                    ->join('employees', $client_id .'= employees.client_id AND ' . $branch_id . '= employees.client_branch_id', 'left')
                                    ->join('auth_history', 'employees.id = auth_history.user_id AND "employee" = auth_history.user_type', 'left')
                                    ->where('employees.is_active', 1)
                                    ->where('employees.emp_status !=', 'truncated')
                                    ->groupBy('employees.id')
                                    ->findAll();
        
        $groupedData = [];
        $employeeId = '';

        foreach ($results as $row) {

            if($employeeId != $row['employee_id']){
                $employeeId = $row['employee_id'];
            }else{
                $employeeId = null;
            }
            $employeeName = $row['employee_name'] ;
            $employeeRelationship = $row['relationship'] ;
            $employeeEmpCode =  $row['emp_code'] ;
            $employeeEmpStatus = $row['emp_status'];
            $employeeUserType = $row['user_type'];
    
          
            // if ($employeeId !== null && $employeeRelationship == 'Self') {
            if ($employeeId !== null) {
                // Append employee info to the branch's employees list
                $groupedData[] = [
                    'employee_id' => $employeeId,
                    'employee_name' => $employeeName,
                    'relationship' => $employeeRelationship,
                    'emp_code' => $employeeEmpCode,
                    'emp_status' => $employeeEmpStatus,
                    'user_type' => $employeeUserType
                ];
              
            }
            $employeeId = $row['employee_id'];
        }
                            
        
        return json_encode($groupedData);
     }

     


    /**
     * Beleo function retrieves employee endorsement (emp_endorsement table) data.
     *
     * This method fetches endorsement data based on the provided ID.
     * It determines the type of endorsement action (SI enhancement, deletion, or other),
     * formats the data accordingly, and returns it as a response.
     *
     * @param int|null $id The ID of the endorsement entry to retrieve.
     * @return \CodeIgniter\HTTP\Response Returns a JSON response containing the endorsement entry data.
     */
    public function getEmpEndoresmentEntry($id = null)
    {
        // Create instance of EmpDataServiceController
        $empDataServiceController = new EmpDataServiceController();

        // Check if $id is provided
        if ($id) {
            // Retrieve group key and actions based on $id
            $group_key_actions = $this->empEndorsementModel->select('group_key, actions')->where('id', $id)->first();
            $groupedData = $this->empEndorsementModel->where('group_key', $group_key_actions['group_key'])->findAll();

            // If group key and actions are found
            if ($group_key_actions) {
                // Retrieve endorsement data based on actions
                switch ($group_key_actions['actions']) {
                    case 'si':
                        $data = $this->empEndorsementModel->getDataForEnodrsementListinSIEnhancement($group_key_actions['group_key']);
                        $formatedData = $empDataServiceController->convertRowTColumnForSIEnhancement($data);
                        break;
                    case 'd':
                        $data = $this->empEndorsementModel->getDataForEnodrsementListinDeletion($group_key_actions['group_key']);
                        $formatedData = $empDataServiceController->convertRowTColumnForDeletion($data);
                        break;
                    default:
                        $formatedData = $groupedData;
                        $formatedData[0]['field_name'] = remove_underscore_capitalize_first_letter($formatedData[0]['field_name']);
                        $formatedData[0]['old_value'] = formatDateOrReturn($formatedData[0]['old_value']);
                        $formatedData[0]['new_value'] = formatDateOrReturn($formatedData[0]['new_value']);
                        break;
                }

                // Return response with data
                return $this->respond([
                    'dataStatus' => true,
                    'code' => 200,
                    'data' => $formatedData,
                    'data2' => $groupedData
                ], 200);
            } else {
                // Return response if group key and actions are not found
                return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'no data found'], 200);
            }
        } else {
            // Return response if $id is not provided
            return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'no data found'], 200);
        }
    }


    // @param int $client_policy_id
    // this funciton initiate Inception/adition/DA of employees data only form enrollment app when passing
    // client_policy_id pull draft and enrolled status employees and proceed to calculatin and make entry in DB
    public function initiateManualEmployeesOnboardProcess($client_policy_id)
    {
        $client_data = $this->clientPolicyModel->select('clients.client_name as client_name,client_branch_id')
            ->join('clients', 'clients.id = client_policy.client_id')
            // ->join('policies', 'policies.id = client_policy.policy_id')
            ->where('client_policy.id', $client_policy_id)
            ->first();
        // dd($client_data);
        $empServiceController = new EmployeeServiceController();
        $res = $empServiceController->employeesOnboardPreprocess(['client_policy_id' => $client_policy_id,'client_branch_id' => $client_data['client_branch_id']]);
        // dd($res);

        $count = ($res);
        $message =  $count . ' Employees are Initiate Onboard Process againts Client ' . $client_data['client_name'] . ' and the Policy is ' .$client_policy_id;
        session()->setFlashdata('success1',  $message);
        return redirect()->to(base_url('/employee/upload'));
    }

    public function downloadFileList($file_id = null)
    {
        $file_data = $this->fileModel->where('id', $file_id)->first();
        if (empty($file_data) || empty($file_data['file_name'])) {
            $data['message'] = 'File record not found';
            return view('errors/404', $data);
        }

        $fileName = basename((string) $file_data['file_name']);
        $storage = \Config\Services::getFileStorageService();
        $result = $storage->download(WRITEPATH . 'uploads/excel', $fileName);

        try {
            if ($result['success'] ?? false) {
                $downloadAs = storage_upload_display_name($fileName);
                if (! empty($result['path']) && is_file($result['path'])) {
                    return $this->response->download($result['path'], null)->setFileName($downloadAs);
                }
                if (! empty($result['content'])) {
                    return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs);
                }
            }

            $data['message'] = 'The Physical File Not Found';
            return view('errors/404', $data);
        } catch (\Exception $e) {
            $this->myLogger->logme('error', $e->getMessage());
            echo $e->getMessage();
        }
    }

    public function featchEmpList()
    {
        $client_id = $this->request->getGet('client_id');
        $policy_id = $this->request->getGet('policy_id');

        $emp_data['employees'] = $this->employeePolicyModel->getEmployeePolicyForFileList($client_id, $policy_id);
        $html = view('employee_data_list', $emp_data);

        return $this->respond(['dataStatus' => true, 'code' => 200, 'data' =>  $html], 200);
    }

    public function viewUploadedEmployeeList()
    {

        $empDataServiceController = new EmpDataServiceController();

        $file_id = $this->request->getGet('file_id');
        // $emp_data['employees'] = $this->employeePolicyModel->getViewEmpSuccessList($file_id);
        // $html = view('view_file_upload_emp_list', $emp_data);
        $file_name = $this->fileModel
            ->select(['files.*', 'up.emp_code', 'up.first_name', 'pm.name as policy_name', 'c.short_name', 'cp.id as client_policy_id'])
            ->join('user_profiles up', 'files.created_by = up.id')
            ->join('client_policy cp', 'files.policy_id = cp.id', 'left')
            ->join('policies pm', 'cp.policy_id = pm.id', 'left')
            ->join('clients c', 'files.client_id = c.id and files.client_id = cp.client_id', 'left')
            ->where('files.id', $file_id)->first();

            // dd($file_name);

        try {

            if (!$file_name) {
                return $this->respond([
                    'dataStatus' => false,
                    'code' => 200,
                    'data' => '
No Data Found
', 'file_data' => null ], 200); } $filePath = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $file_name['file_name']); // ✅ File not exists on disk if (empty($filePath) || !file_exists($filePath)) { return $this->respond([ 'dataStatus' => false, 'code' => 200, 'data' => '
No Data Found
', 'file_data' => $file_name ], 200); } $excel_data = $empDataServiceController->readExcelFileToArray($filePath); // ✅ Excel empty or header only if (empty($excel_data) || count($excel_data) <= 1) { return $this->respond([ 'dataStatus' => false, 'code' => 200, 'data' => '
No Data Found
', 'file_data' => $file_name ], 200); } if (file_exists($filePath)) { $excel_data = $empDataServiceController->readExcelFileToArray($filePath); $emp_data['thead'] = $excel_data[0]; unset($excel_data[0]); $emp_data['tbody'] = $excel_data; $emp_data['count'] = count($excel_data); // dd($emp_data); $html = view('view_file_upload_emp_list', $emp_data); } else { $html = '
No Data Found
'; } return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $html, 'file_data' => $file_name, 'excel_data' => $excel_data], 200); } catch (\Throwable $th) { $errorData = [ 'message' => $th->getMessage(), 'file' => $th->getFile(), 'line' => $th->getLine(), 'code' => $th->getCode(), 'trace' => $th->getTraceAsString(), 'trace_array' => $th->getTrace(), // full array version (optional) 'function' => $th->getTrace()[0]['function'] ?? null, 'class' => $th->getTrace()[0]['class'] ?? null, ]; // Handle exception $errorMessage = 'Error occurred:' . PHP_EOL . json_encode($errorData, JSON_PRETTY_PRINT); $this->myLogger->logme('error', $errorMessage); return $this->respond(['dataStatus' => false, 'code' => 500, 'data' => '
Something went wrong
', 'file_data' => $file_name ?? null], 500); } } public function getEmpCount($id = null) { $data = $this->employeePolicyModel->select('employee_polices.id') ->where('employee_polices.is_active', 1) ->where('employee_polices.status', 'active') ->where('employee_polices.client_policy_id', $id) ->findAll(); $emp_count = count($data); $events = ['inception' => 'Inception (Employee + Dependents)', 'addition' => 'Addition (Employee + Dependents)', 'dependent_addition' => 'Dependent Addition (Only Dependents)', 'deletion' => 'Deletion', 'correction' => 'Correction', 'si_enhancement' => 'SI Enhancement']; return $this->respond(['dataStatus' => true, 'code' => 200, 'emp_count' => $emp_count, 'events' => $events, 'client_policy_id' => $id], 200); } public function downloadFullExcelErrorFile($file_id, $rowIndex = 1, $colIndex = 1) { // Get file data from the database $file_data = $this->fileModel->find((int)$file_id); $error = json_decode($file_data['reason']); // echo '
';
        //    print_r($error); die;
        //    dd($error);

        // Check if the file exists
        if (!$file_data) {
            $error_message = "File not found";
            $this->myLogger->logme('error', $error_message . ' for file id ' . $file_id);
            return $error_message;
        }

        $fileName = $file_data['file_name'];
        $filePath = storage_ensure_local_file(WRITEPATH . 'uploads/excel', $fileName);

        // Check if the file exists
        if (empty($filePath) || !file_exists($filePath)) {
            $error_message = "File not found";
            $this->myLogger->logme('error', $error_message . ' for file id ' . $file_id);
            $data['message'] = 'Physical File Not Found';
            return view('errors/404', $data);
        }

        // Load the Excel file
        $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);
        $sheet = $spreadsheet->getActiveSheet();

        //  echo '
';

        foreach ($error->error_data as $index => $error_data) {

            $rowIndex = $index + 1;

            if ($error->error_type == 1) {

                foreach ($error_data as $key => $value) {

                    $colIndex = $value->col_idx + 1;

                    $originalValue = $sheet->getCell([$colIndex, $rowIndex])->getValue();

                    $newValue =  implode(', ', $value->error);
                    $val = $originalValue . ' ( ' . $newValue . ' )';
                    $sheet->setCellValue([$colIndex, $rowIndex],  $val);

                    $style = [
                        'fill' => [
                            'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => 'ffad99'] // Red color
                        ]
                    ];

                    $sheet->getStyle([$colIndex, $rowIndex])->applyFromArray($style);
                }
            } else if ($error->error_type == 2) {


                foreach ($error_data as $key => $value) {


                    $originalValue = $sheet->getCell([1, $rowIndex])->getValue();

                    $newValue =  implode(', ', $value->error);
                    $val = $originalValue . ' ( ' . $newValue . ' )';
                    $sheet->setCellValue([$colIndex, $rowIndex],  $val);

                    $style = [
                        'fill' => [
                            'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => 'ffad99'] // Red color
                        ]
                    ];
                    $sheet->getStyle([$colIndex, $rowIndex])->applyFromArray($style);
                }
            }
        }



        // Create a new filename for the modified Excel file
        $newFileName = 'error_with_highlight_' . $fileName;

        // Save the modified Excel file to a new location
        $newFilePath = WRITEPATH . '/uploads/excel/' . $newFileName;
        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
        $writer->save($newFilePath);

        // Set headers to force download
        $response = service('response');
        $response->setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        $response->setHeader('Content-Disposition', 'attachment;filename="' . $newFileName . '"');
        $response->setHeader('Cache-Control', 'max-age=0');
        $response->setHeader('Content-Length', filesize($newFilePath));
        $response->setBody(file_get_contents($newFilePath));

        // Delete the temporary file
        unlink($newFilePath);

        // Return the response
        return $response;
    }

    // --------------- For E-Card Download -----------------------------------------------------------------------------------------------------

    //E-CARD DOWNLOAD FUNCTION USING HTML PRINT ( Not in use ) do not delete
    public function generateIDCardForEmployeeUsingHtml($rand_string, $people = 0)
    {    
        // dd($rand_string, $people);
        try {
            $this->myLogger->logme('error', 'generateIDCardForEmployee function started.');
        
            // Step 1: Attempt to fetch employee code and client policy ID
            $this->myLogger->logme('error', 'Fetching employee code and client policy ID.');

            $get_emp_code_and_client_policy_id = $this->employeePolicyModel
                ->select('employee_polices.client_policy_id, employees.emp_code, tpa.short_name,employees.client_id')
                ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id')
                ->join('employees', 'employees.id = employee_polices.employee_id')
                ->join('tpa', 'tpa.id = client_policy.tpa_id')
                ->where('employees.emp_status', 'active')
                ->where('employees.is_active', '1')
                ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''")
                ->where('employee_polices.status', 'active')
                ->where('employee_polices.is_active', '1')
                ->where('employee_polices.rand_string', $rand_string)
                ->first();

            // dd($this->employeePolicyModel->getLastQuery());

            // dd($rand_string, $get_emp_code_and_client_policy_id);
        
            if ($get_emp_code_and_client_policy_id == null || $get_emp_code_and_client_policy_id == "") {
                $this->myLogger->logme('error', 'Member not found in this rand_string: ' . $rand_string);
                $data['message'] = 'Record Not Found';
                return view('errors/404', $data);
            }
        
            $this->myLogger->logme('error', 'Member found. Client policy ID: ' . $get_emp_code_and_client_policy_id['client_policy_id']);
        
            $client_policy_id = $get_emp_code_and_client_policy_id['client_policy_id'];
            $emp_code = $get_emp_code_and_client_policy_id['emp_code'];
            $client_id = $get_emp_code_and_client_policy_id['client_id'];
        
            // Step 2: Fetch ECard data
            $this->myLogger->logme('error', 'Fetching ECard data using client_policy_id: ' . $client_policy_id . ' and emp_code: ' . $emp_code);
            $data = $this->employeePolicyModel->getECardDataUsingMd5($client_policy_id, $emp_code,$client_id);
        
            if ($people == 0) {
                $this->myLogger->logme('error', 'Fetching single ECard data using rand_string: ' . $rand_string . ' and emp_code: ' . $emp_code);
                $data = $this->employeePolicyModel->getECardSingleData($rand_string, $emp_code,$client_id);
            }
        
            // Step 3: Prepare template path
            $template_data_path = WRITEPATH . 'e_card_template/';
            // $tpa_short_name = strtolower(str_replace(' ', '_', $get_emp_code_and_client_policy_id['short_name'])) . '.html';
            $tpa_short_name = 'common.html';
            $final_path = $template_data_path . $tpa_short_name;
        
            $this->myLogger->logme('error', 'Checking if template file exists at: ' . $final_path);
        
            if (!file_exists($final_path)) {
                $this->myLogger->logme('error', 'Template file not found: ' . $final_path);
                $data['message'] = 'Template File Not Found';
                return view('errors/404', $data);
            }
        
            $this->myLogger->logme('error', 'Template file found. Reading template data.');
            $tmplt_data = file_get_contents($final_path);
        
            // Step 4: Generate HTML content
            $this->myLogger->logme('error', 'Generating HTML content from template.');
            $html = "";
            foreach ($data as $key => $value) {
                $htmlContent = $tmplt_data;

                $value['front_card'] = "Nhance_Ecard_working_1_front.png";
                $value['back_card'] = "Nhance_Ecard_working_1_Back.png";
        
                $placeholders = [
                    '{CLIENT_NAME}' => $value['client_name'],
                    '{TPA_ID}' => $value['tpa_id'],
                    '{NAME}' => $value['name'],
                    '{UHID}' => $value['uhid'],
                    '{GENDER}' => $value['gender'],
                    '{DOB}' => date('d-M-Y', strtotime($value['dob'])),
                    '{SELF_NAME}' => $value['self'] ?? $value['name'],
                    '{POLICY_DATE}' => date('d-M-Y', strtotime($value['policy_end_date'])),
                    '{POLICY_START_DATE}' => date('d-M-Y', strtotime($value['policy_start_date'])),
                    '{POLICY_NO}' => $value['policy_no'],
                    '{INSURER_NAME}' => strtoupper($value['insurer_name']),
                    '{INSURER_LOGO}' => base_url() . 'public/uploads/logo/' . $value['insurer_logo'],
                    '{FRONT_CARD}' => base_url() . 'public/uploads/template_bg/' . $value['front_card'],
                    '{BACK_CARD}' => base_url() . 'public/uploads/template_bg/' . $value['back_card'],
                    '{EMP_ID}' => $value['emp_code'],
                    '{SI_AMT}' => $value['basic_cover_si'],
                    '{CORPORATE_NAME}' => $value['client_name'],
                    '{AGE}' => $value['emp_age'],
                    '{TPA_NAME}' => $value['tpa_name'],
                    '{INSURER_BRANCH}' => $value['insurer_branch_city'],
                    '{RELATION}' => $value['relationship'],
                    '{TPA_LOGO}' => base_url() . 'public/uploads/logo/' . $value['tpa_logo'],
                    '{MEDI_USER}' => base_url() . 'public/e_card_imgs/medi_uesr.jpg',
                    '{MEDI_INSURER}' => base_url() . 'public/e_card_imgs/Magma.png',
                    '{MEDI_BARCODE}' => base_url() . 'public/e_card_imgs/borcode.jpeg',
                    '{QR_ANDROID}' => base_url() . 'public/e_card_imgs/android.png',
                    '{QR_IOS}' => base_url() . 'public/e_card_imgs/ios.png',
                    '{QR_ANDROID_2}' => base_url() . 'public/e_card_imgs/play_store.png',
                    '{QR_IOS_2}' => base_url() . 'public/e_card_imgs/appstore.png',
                ];

                $placeholders['{LEVELS}'] = $this->generateAcmAndMForEcard($client_id);
        
                foreach ($placeholders as $placeholder => $replaceValue) {
                    $htmlContent = str_replace($placeholder, $replaceValue, $htmlContent);
                }
        
                $html .= $htmlContent;
            }
        
            // Step 5: Output HTML and script for printing
            $this->myLogger->logme('error', 'Generating HTML output with print button.');
            echo '' . $html . '
                  ';
        
            $this->myLogger->logme('error', 'generateIDCardForEmployee function completed successfully.');
        
        } catch (\Exception $e) {
            $this->myLogger->logme('error', 'Exception occurred: ' . $e->getMessage());
            $data['message'] = 'Record Not Found';
            return view('errors/404', $data);
        }
        
    }

    // Preview E-Card Template function
    public function previewTemplate($id = null)
    {
        $value = [
            'tpa_id' => 'TPA12345',
            'name' => 'John Doe',
            'uhid' => 'UHID67890',
            'gender' => 'Male',
            'dob' => '1985-05-15',
            'self' => 'John Doe',
            'policy_end_date' => '2024-12-31',
            'policy_start_date' => '2023-01-01',
            'policy_no' => 'POL1234567890',
            'insurer_name' => 'Example Insurance Company',
            'emp_code' => 'EMP001122',
            'client_name' => 'Corporate Client Inc.',
            'emp_age' => 39,
            'tpa_name' => 'Example TPA',
            'insurer_branch_city' => 'New York',
            'relationship' => 'Self',
            'basic_cover_si' => '5,00,000',
        ];
        
        $tpa_id = $this->TPAModel->where('id', $id)->first();

        $template_data_path =  WRITEPATH . 'e_card_template/';
        $tpa_short_name = strtolower(str_replace(' ', '_', $tpa_id['short_name'])) . '.html';
        $final_path =  $template_data_path . $tpa_short_name;

        if (!file_exists($final_path)) {

            $data['message'] = 'Record Not Found';
            return view('errors/404', $data);
        }

        $tmplt_data = file_get_contents($final_path);

        $placeholders = [
            '{TPA_ID}' => $value['tpa_id'],
            '{NAME}' => $value['name'],
            '{UHID}' => $value['uhid'],
            '{GENDER}' => $value['gender'],
            '{DOB}' => date('d-M-Y', strtotime($value['dob'])),
            '{SELF_NAME}' => $value['self'] ?? $value['name'],
            '{POLICY_DATE}' => date('d-M-Y', strtotime($value['policy_end_date'])),
            '{POLICY_START_DATE}' => date('d-M-Y', strtotime($value['policy_start_date'])),
            '{POLICY_NO}' => $value['policy_no'], 
            '{INSURER_NAME}' => strtoupper($value['insurer_name']),
            '{EMP_ID}' => $value['emp_code'],
            '{SI_AMT}' => $value['basic_cover_si'], 
            '{CORPORATE_NAME}' => $value['client_name'],
            '{AGE}' => $value['emp_age'],
            '{TPA_NAME}' => $value['tpa_name'],
            '{INSURER_BRANCH}' => $value['insurer_branch_city'],
            '{RELATION}' => $value['relationship'],
            '{FRONT_CARD}' => base_url() . 'public/uploads/template_bg/' . $tpa_id['front_card'],
            '{BACK_CARD}' => base_url() . 'public/uploads/template_bg/' . $tpa_id['back_card'],
            '{TPA_LOGO}' => base_url() . 'public/uploads/logo/' . $tpa_id['tpa_logo'],
            '{INSURER_LOGO}' => base_url() . 'public/assets/images/sample_logo_3.png',
            '{MEDI_USER}' => base_url() . 'public/e_card_imgs/medi_uesr.jpg',
            '{MEDI_INSURER}' => base_url() . 'public/e_card_imgs/Magma.png',
            '{MEDI_BARCODE}' => base_url() . 'public/e_card_imgs/borcode.jpeg',
            '{QR_ANDROID}' => base_url() . 'public/e_card_imgs/android.png',
            '{QR_IOS}' => base_url() . 'public/e_card_imgs/ios.png', 
            '{QR_ANDROID_2}' => base_url() . 'public/e_card_imgs/play_store.png',
            '{QR_IOS_2}' => base_url() . 'public/e_card_imgs/appstore.png',

        ];

        $placeholders['{LEVELS}'] = '                   
                    Level 1

1. Gowtham / 8754081806 / gowtham@gmail.com
2. Gowtham / 8754081806 / gowtham@gmail.com

'; // dd($placeholders); // Get the values to replace the placeholders $replaceValues = array_values($placeholders); // Get the placeholders to search for $searchPlaceholders = array_keys($placeholders); // Replace placeholders with values in HTML content $htmlContent = str_replace($searchPlaceholders, $replaceValues, $tmplt_data); echo $htmlContent; } //E-CARD DOWNLOAD FUNCTION USING DOM PDF ( CURRENTLY USING THIS ) Dompdf public function generateIDCardForEmployee($rand_string, $people = 0, $mode = 0) { $mode = (int)$mode; // dd($rand_string, $people,$mode); $this->myLogger->logme('error', 'generateIDCardForEmployee params .' . json_encode(["rand_string" => $rand_string, "people" => $people, "mode" => $mode])); try { $this->myLogger->logme('error', 'generateIDCardForEmployee function started.'); // Step 1: Attempt to fetch employee code and client policy ID $this->myLogger->logme('error', 'Fetching employee code and client policy ID.'); $get_emp_code_and_client_policy_id = $this->employeePolicyModel ->select('employee_polices.client_policy_id, employees.emp_code,employees.name, employee_polices.tpa_id,tpa.short_name,employees.client_id') ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id') ->join('employees', 'employees.id = employee_polices.employee_id') ->join('tpa', 'tpa.id = client_policy.tpa_id') ->where('employees.is_active', '1') ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''") ->whereIn('employee_polices.status', ['active', 'expired']) ->whereIn('employees.emp_status', ['active', 'expired']) ->where('employee_polices.is_active', '1') ->where('employee_polices.rand_string', $rand_string) ->first(); // dd($this->employeePolicyModel->getLastQuery()); // dd($rand_string, $get_emp_code_and_client_policy_id); if ($get_emp_code_and_client_policy_id == null || $get_emp_code_and_client_policy_id == "") { $this->myLogger->logme('error', 'Member not found in this rand_string: ' . $rand_string); $data['message'] = 'Record Not Found'; return view('errors/404', $data); } $this->myLogger->logme('error', 'Member found. Client policy ID: ' . $get_emp_code_and_client_policy_id['client_policy_id']); $client_policy_id = $get_emp_code_and_client_policy_id['client_policy_id']; $emp_code = $get_emp_code_and_client_policy_id['emp_code']; $client_id = $get_emp_code_and_client_policy_id['client_id']; //new step check in S3 if yes then fetch from S3 bucket $s3_key = 'ecard_'.$get_emp_code_and_client_policy_id['name'].'('.$get_emp_code_and_client_policy_id['emp_code'].')'.'_'.$get_emp_code_and_client_policy_id['tpa_id'].'.pdf'; $s3_key = $this->sanitizeFilePart($s3_key); // echo $s3_key;die(); $s3 = \Config\Services::getS3Service(); if($s3->exists($s3_key) && $mode != 2) //2 => for bulk generate so skip s3 check and generate PDF { //get pre signed url & make it download $s3_url = $s3->getPresignedUrl($s3_key ); $pdf = file_get_contents($s3_url['url']); if ($mode == 1) { // Inline view return $this->response ->setHeader('Content-Type', 'application/pdf') ->setHeader('Content-Disposition', 'inline; filename="' . $s3_key . '"') ->setBody($pdf); } else if($mode == 0){ // echo 'Force download';//die(); return $this->response ->setHeader('Content-Type', 'application/pdf') ->setHeader('Content-Disposition', 'attachment; filename="' . $s3_key . '"') ->setBody($pdf); } // exit(); } // else // { // if($mode !== 2) // { // $data['message'] = 'Inprogress... Comeback later! or Contact support'; // return view('errors/404', $data); // } // } //in else generate PDF and upload it in s3 // echo 'else'; // exit(); // Step 2: Fetch ECard data $this->myLogger->logme('error', 'Fetching ECard data using client_policy_id: ' . $client_policy_id . ' and emp_code: ' . $emp_code); $data = $this->employeePolicyModel->getECardDataUsingMd5($client_policy_id, $emp_code,$client_id); if ($people == 0) { $this->myLogger->logme('error', 'Fetching single ECard data using rand_string: ' . $rand_string . ' and emp_code: ' . $emp_code); $data = $this->employeePolicyModel->getECardSingleData($rand_string, $emp_code,$client_id); } // Step 3: Prepare template path $template_data_path = WRITEPATH . 'e_card_template/'; // $tpa_short_name = strtolower(str_replace(' ', '_', $get_emp_code_and_client_policy_id['short_name'])) . '.html'; // $tpa_short_name = 'common.html'; $tpa_short_name = 'new_ecard.html'; $final_path = $template_data_path . $tpa_short_name; $this->myLogger->logme('error', 'Checking if template file exists at: ' . $final_path); if (!file_exists($final_path)) { $this->myLogger->logme('error', 'Template file not found: ' . $final_path); $data['message'] = 'Template File Not Found'; return view('errors/404', $data); } $this->myLogger->logme('error', 'Template file found. Reading template data.'); $tmplt_data = file_get_contents($final_path); // Step 4: Generate HTML content $this->myLogger->logme('error', 'Generating HTML content from template.'); $html = ""; foreach ($data as $key => $value) { $htmlContent = $tmplt_data; $value['front_card'] = "Nhance_Ecard_working_1_front.png"; $value['back_card'] = "Nhance_Ecard_working_1_Back.png"; $placeholders = [ '{CLIENT_NAME}' => $value['client_name'], '{TPA_ID}' => $value['tpa_id'], '{NAME}' => $value['name'], '{UHID}' => $value['uhid'], '{GENDER}' => $value['gender'], '{DOB}' => date('d-M-Y', strtotime($value['dob'])), '{SELF_NAME}' => $value['self'] ?? $value['name'], '{POLICY_DATE}' => date('d-M-Y', strtotime($value['policy_end_date'])), '{POLICY_START_DATE}' => date('d-M-Y', strtotime($value['policy_start_date'])), '{POLICY_NO}' => $value['policy_no'], '{INSURER_NAME}' => strtoupper($value['insurer_name']), '{EMP_ID}' => $value['emp_code'], '{SI_AMT}' => $value['basic_cover_si'], '{CORPORATE_NAME}' => $value['client_name'], '{AGE}' => $value['emp_age'], '{TPA_NAME}' => $value['tpa_name'], '{INSURER_BRANCH}' => $value['insurer_branch_city'], '{RELATION}' => $value['relationship'], '{TPA_LOGO}' => getFileIfExists('uploads/logo/' . $value['tpa_logo']), '{MEDI_USER}' => getFileIfExists('e_card_imgs/medi_uesr.jpg'), '{MEDI_INSURER}' => getFileIfExists('e_card_imgs/Magma.png'), '{MEDI_BARCODE}' => getFileIfExists('e_card_imgs/borcode.jpeg'), '{QR_ANDROID}' => getFileIfExists('e_card_imgs/android.png'), '{QR_IOS}' => getFileIfExists('e_card_imgs/ios.png'), '{QR_ANDROID_2}' => getFileIfExists('e_card_imgs/play_store.png'), '{QR_IOS_2}' => getFileIfExists('e_card_imgs/appstore.png'), '{NHANCE_N_LOGO}' => getFileIfExists('assets/images/Nhance_Favi.png'), '{INSURER_LOGO}' => getFileIfExists('uploads/logo/' . $value['insurer_logo']), '{FRONT_CARD}' => getFileIfExists('uploads/template_bg/' . $value['front_card']), '{BACK_CARD}' => getFileIfExists('uploads/template_bg/' . $value['back_card']), // '{TPA_LOGO}' => base_url() . 'public/uploads/logo/' . $value['tpa_logo'], // '{MEDI_USER}' => base_url() . 'public/e_card_imgs/medi_uesr.jpg', // '{MEDI_INSURER}' => base_url() . 'public/e_card_imgs/Magma.png', // '{MEDI_BARCODE}' => base_url() . 'public/e_card_imgs/borcode.jpeg', // '{QR_ANDROID}' => base_url() . 'public/e_card_imgs/android.png', // '{QR_IOS}' => base_url() . 'public/e_card_imgs/ios.png', // '{QR_ANDROID_2}' => base_url() . 'public/e_card_imgs/play_store.png', // '{QR_IOS_2}' => base_url() . 'public/e_card_imgs/appstore.png', // '{NHANCE_N_LOGO}' => base_url() . 'public/assets/images/Nhance_Favi.png', // '{INSURER_LOGO}' => base_url() . 'public/uploads/logo/' . $value['insurer_logo'], // '{FRONT_CARD}' => base_url() . 'public/uploads/template_bg/' . $value['front_card'], // '{BACK_CARD}' => base_url() . 'public/uploads/template_bg/' . $value['back_card'], ]; $placeholders['{LEVELS}'] = $this->generateAcmAndMForEcard($client_id); $placeholders['{NETWORK_HOSPITAL}'] = $this->generateNetworkHospitalsForEcard($value['network_hospitals']); foreach ($placeholders as $placeholder => $replaceValue) { $htmlContent = str_replace($placeholder, $replaceValue, $htmlContent); } $html .= $htmlContent; } // return $html; // echo $html;die(); // DomPdf $options = new Options(); $options->set('isRemoteEnabled', true); $options->set('isHtml5ParserEnabled', true); $dompdf = new Dompdf($options); // $dompdf->loadHtml('' . $html); // remove the margin $dompdf->loadHtml(' ' . $html ); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); // Set document title $dompdf->addInfo("Title", "E-Card"); $filename = 'ecard_' . date('Y-m-d_H-i-s') . '.pdf'; $temp_local_path = WRITEPATH.'/tmp/'.$s3_key; file_put_contents(($temp_local_path),$dompdf->output()); // if($mode == 1){ // $dompdf->stream($filename, ['Attachment' => false]); // Inline view // }else{ // $dompdf->stream($filename, ['Attachment' => true]); // Force download // } $aws_upload_res = $s3->upload(($temp_local_path)); // print_rr($aws_upload_res); // echo '
PDF generated and uploaded to S3 successfully.
'; unlink($temp_local_path); if($s3->exists($s3_key)) //2 => for bulk generate so skip s3 check and generate PDF { //get pre signed url & make it download $s3_url = $s3->getPresignedUrl($s3_key ); $pdf = file_get_contents($s3_url['url']); if ($mode == 1) { // Inline view return $this->response ->setHeader('Content-Type', 'application/pdf') ->setHeader('Content-Disposition', 'inline; filename="' . $s3_key . '"') ->setBody($pdf); } else if($mode == 0){ // echo 'Force download';//die(); return $this->response ->setHeader('Content-Type', 'application/pdf') ->setHeader('Content-Disposition', 'attachment; filename="' . $s3_key . '"') ->setBody($pdf); } // exit(); } // $this->myLogger->logme('error', 'generateIDCardForEmployee function completed successfully.'); } catch (\Exception $e) { $this->myLogger->logme('error', 'Exception occurred: ' . $e->getMessage()); $data['message'] = 'Record Not Found'; return view('errors/404', $data); } } public function sanitizeFilePart(string $value): string { // Trim spaces $value = trim($value); // Replace ANY unsafe character (including /) with underscore $value = preg_replace('/[^A-Za-z0-9._()-]/', '_', $value); // Collapse multiple underscores $value = preg_replace('/_+/', '_', $value); return $value; } // -------------------------------------------------------------------------------------------------------------------- public function viewECard() { // $this->loadLayout('ecard_template/default_ecard'); $empDataServiceController = new EmpDataServiceController(); $return = $empDataServiceController->importDeletionValidation(['file_id' => 130]); } //truncateFileDataIn DB (de activate rows) NEW FUNCTION public function truncateFileData($file_id, $role_id = null) { $this->myLogger->logme('error', '---- truncateFileData Function called ----'); $file_id = $this->request->uri->getSegment(3); // $file_id = 747; $this->myLogger->logme('error', 'File id for truncate : -- FILE ID : {data} --', ['data' => $file_id]); //get the files data $file = $this->fileModel->find((int)$file_id); $client_id = $file['client_id']; $client_policy_id = $file['policy_id']; $loggedInUserID = get_session_userid(); //get the client policy data $policy_data = $this->clientPolicyModel->where('id', $client_policy_id)->first(); //get the cd transaction data based on the insurer and client $cd_tranction = $this->cashDepositModel ->where('client_id', $client_id) //client ->where('insurer_id', $policy_data['insurer_id']) //insurer ->where('event_name',$file['action']) //event ->where('client_policy_id', $client_policy_id)//policy ->orderBy('id', 'desc') ->first(); // dd($cd_tranction, db_connect()->getLastQuery()); if ($file['action'] == 'inception' || $file['action'] == 'dependent_addition' || $file['action'] == 'addition' || $file['action'] == 'enrollment' || $file['action'] == 'missed_inception') { if($file['action'] == 'enrollment'){ $result = $this->employeeModel->getEmpListByFileId(file_id: $file_id, emp_status: ['draft','enrolled'], policy_status: ['draft','enrolled']); }else{ $result = $this->employeeModel->getEmpListByFileId(file_id: $file_id, emp_status: ['active'], policy_status: ['active']); } // print_r($result); die; if (count($result) && $role_id == null) { if(get_role_id() == 1 || get_role_id() == 5){ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed. Do you want to truncate data from uploaded file?'], 200); }else{ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed'], 200); } } else { $this->myLogger->logme('error', '---- TRUNCATED STARTED WITH ADMIN OR HEAD PERMISSION ----'); $this->myLogger->logme('error', '---- Event Type : -- {data} ----', ['data' => $file['action']]); if($file['action'] != 'enrollment') { $employee_policy_data_with_file_id = $this->employeePolicyModel->where('file_id', $file_id)->findAll(); if(!empty($employee_policy_data_with_file_id) && count($employee_policy_data_with_file_id) > 0){ // GET THE CD TRANSACTION AMOUNT $cd_amount_total = $this->employeePolicyModel->calculateCdTranctionAmount($file_id); $cd_amount = $cd_amount_total['total'] ?? 0; $this->myLogger->logme('error', '---- CD Amount : {data} ----', ['data' => $cd_amount]); //STEP: 1 - Update employee policy table $db = db_connect(); $query = " UPDATE employee_polices SET employee_polices.status = 'truncated', employee_polices.is_active = 0 WHERE employee_polices.file_id = :file_id: "; $binds = ["file_id" => $file_id]; $db->query($query,$binds); $affectedRows = $db->affectedRows(); $this->myLogger->logme('error', '---- employee_polices table update query : {data} ----', ['data' => $query]); $this->myLogger->logme('error', '---- employee_polices table updated - Affected Rows : {data} ----', ['data' => $affectedRows]); // print_r($db->getLastQuery()); die; //STEP:2 - Update emp_endorsement Table if(in_array($file['action'], ['addition', 'dependent_addition'])){ $this->empEndorsementModel->where('file_id', $file_id)->set(['status' => 'truncated','is_active' => 0])->update(); $this->myLogger->logme('error', '---- emp_endorsement table updated ----'); } //STEP:3 - Update files table status $this->fileModel->where('id', $file_id)->set(['status' => 'truncated','updated_by' => $loggedInUserID])->update(); $this->myLogger->logme('error', '---- files table updated ----'); //FINAL STEP - Update reverse entry in cash_deposite table if(!empty($cd_amount)){ $cd_data = [ 'amount' => $cd_amount, 'sub_type_id' => 8, 'endorsement_no' => null, 'insurer_id' =>$policy_data['insurer_id'], 'description' => 'The policy Truncated by Admin or Head', 'transaction_type' => 'Credit', 'updated_by' => 1, 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $policy_data['cd_ac_no'] ?? null, 'cd_ac_pk' => $policy_data['cd_ac_pk'] ?? null, 'event_name' => $file['action'], ]; $response = DepositHelper::saveDeposit($cd_data, $loggedInUserID); $this->myLogger->logme('error', 'cash_deposite table updated -- cd transaction'); } //this job for deactive policy transaction and pt co share table entry for BDS Sync $r = Jobs::addJob(['job_name' => 'removeBDSPolicyTransactionEntryFromTruncate', 'payload' => [ 'client_policy_id' => $client_policy_id ?? null, 'file_id' => $file_id ?? null, 'action_type' => $file['action'] ?? null, ]]); }else{ $this->myLogger->logme('error', '---- There is no data to truncate ----'); return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'There is no data to truncate'], 200); } } else { // echo 'came here...1'; //check all dependents added by self and other dependent policies $emp_codes = $this->employeeModel->select('emp_code') ->where('file_id', $file_id) ->findAll(); $emp_codes = array_column($emp_codes,'emp_code'); // Kint::dump($emp_codes);//die; $dependent_policies = $this->clientPolicyModel->select('id') ->where('base_policy', $client_policy_id) ->findAll(); // $dependent_policies = [ [10],[25],[35] ]; // Kint::dump($dependent_policies); // Kint::dump(array_column($dependent_policies,'id')); if(count($dependent_policies)) { $dependent_policies = array_column($dependent_policies,'id'); // Kint::dump($dependent_policies); $second_level_dependent_policies = $this->clientPolicyModel->select('id') ->whereIn('base_policy', $dependent_policies) ->findAll(); // dd($second_level_dependent_policies); if(count($second_level_dependent_policies)) { $second_level_dependent_policies = array_column($second_level_dependent_policies,'id'); } $dependent_policies = array_merge($dependent_policies,$second_level_dependent_policies); } $dependent_policies = array_merge($dependent_policies,[$client_policy_id]); // Kint::dump($dependent_policies); //update emp and emp plocies $db = db_connect(); $emp_codes = '(' . implode(',', array_map(fn($code) => "'$code'", $emp_codes)) . ')'; $dependent_policies = '(' . implode(',', $dependent_policies) . ')'; $query = " UPDATE employee_polices JOIN employees ON employees.id = employee_polices.employee_id and employees.emp_code in :emp_codes: SET employee_polices.status = 'truncated', employee_polices.is_active = 0 WHERE employee_polices.client_policy_id in :dependent_policies: "; // print_r($query); die; $binds = ["emp_codes" => $emp_codes , "dependent_policies" => $dependent_policies]; $db->query($query,$binds); $affectedRows = $db->affectedRows(); // dd($affectedRows); $affectedRows = $affectedRows * 2; $this->fileModel->where('id', $file_id)->set(['status' => 'truncated','updated_by' => $loggedInUserID])->update(); } $this->myLogger->logme('error', 'SUCCESSFULLY TRUNCATED'); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => round($affectedRows / 2)], 200); } } else if ($file['action'] == 'si_enhancement' || $file['action'] == 'correction' || $file['action'] == 'deletion') { $res = $this->empEndorsementModel->select(['count(id) as count']) ->where('emp_endorsement.file_id', $file_id) ->groupStart() ->where('emp_endorsement.endorsement_id is not null') ->orwhereIn('emp_endorsement.status', ['complete']) ->groupEnd() ->get() ->getResult(); // dd($res); // print_r($this->empEndorsementModel->getLastQuery()); // echo $res[0]->count;die(); if ($res[0]->count == 0 || $role_id == 5 || $role_id == 1) { $this->myLogger->logme('error', 'TRUNCATED STARTED WITH ADMIN OR HEAD PERMISSION'); $this->myLogger->logme('error', 'Event Type : -- {data} --', ['data' => $file['action']]); $transaction_type = 'Credit'; $cd_amount = 0; if($file['action'] == 'deletion' && $res[0]->count > 0){ $transaction_type = 'Debit'; //get cd amount for the particular file id to reverse entry to the cash deposite for only deletion $cd_amount_total = $this->employeePolicyModel->getDeletionDataForTruncated($file['id']); $totalSum = array_sum(array_column($cd_amount_total, 'total')); $cd_amount = $totalSum ?? 0; $this->myLogger->logme('error', 'Deletion CD Amount : {data}', ['data' => $cd_amount]); } $this->myLogger->logme('error', 'Endorsemnt CD Amount : {data}', ['data' => $cd_amount]); //STEP 1: //update truncated status to the Emp_endorsement table $this->empEndorsementModel->where('file_id', $file_id) ->set(['status' => 'truncated','is_active' => 0]) ->update(); $this->myLogger->logme('error', 'emp_endorsement table updated'); //STEP 2: if($file['action'] == 'deletion' && $res[0]->count > 0) { //update the employee policy table reverse the data $this->employeePolicyModel->updateEmployeePolicyTruncateReverse($file_id); $this->myLogger->logme('error', 'employee_polices table updated for deletion'); } if($file['action'] == 'correction'){ } // STEP 3: //update files table status to "truncated" $this->fileModel->where('id', $file_id)->set(['status' => 'truncated','updated_by' => $loggedInUserID])->update(); $this->myLogger->logme('error', 'files table updated'); if(!empty($cd_amount) && $file['action'] != 'correction'){ $cd_data = [ 'amount' => $cd_amount, 'sub_type_id' => 8, 'endorsement_no' => null, 'insurer_id' =>$policy_data['insurer_id'], 'description' => 'The policy Truncated by Admin or Head', 'transaction_type' => $transaction_type, 'updated_by' => 1, 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $policy_data['cd_ac_no'] ?? null, 'cd_ac_pk' => $policy_data['cd_ac_pk'] ?? null, 'event_name' => $file['action'], ]; $response = DepositHelper::saveDeposit($cd_data, $loggedInUserID); $this->myLogger->logme('error', 'cash_deposite table updated -- cd transaction'); } //this job for deactive policy transaction and pt co share table entry for BDS Sync $r = Jobs::addJob(['job_name' => 'removeBDSPolicyTransactionEntryFromTruncate', 'payload' => [ 'client_policy_id' => $client_policy_id ?? null, 'file_id' => $file_id ?? null, 'action_type' => $file['action'] ?? null, ]]); $this->myLogger->logme('error', 'SUCCESSFULLY TRUNCATED'); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'success'], 200); } else { if(get_role_id() == 1 || get_role_id() == 5){ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed. Do you want to truncate data from uploaded file?'], 200); }else{ return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'File data already processed'], 200); } } } } //truncateFileData OLD FUNCTION public function truncateFileDataOld($file_id, $role_id = null) { $file_id = $this->request->uri->getSegment(3); // $file_id = 747; $file = $this->fileModel->find((int)$file_id); $client_id = $file['client_id']; $client_policy_id = $file['policy_id']; $loggedInUserID = get_session_userid(); $policy_data = $this->clientPolicyModel->where('id', $client_policy_id)->first(); $cd_tranction = $this->cashDepositModel ->where('client_id', $client_id) //client ->where('insurer_id', $policy_data['insurer_id']) //insurer ->where('event_name',$file['action']) //event ->where('client_policy_id', $client_policy_id)//policy ->orderBy('id', 'desc') ->first(); // $file['action'] = 'si_enhancement'; // $result = []; // dd($file); if ($file['action'] == 'inception' || $file['action'] == 'dependent_addition' || $file['action'] == 'addition' || $file['action'] == 'enrollment' || $file['action'] == 'missed_inception') { if($file['action'] == 'enrollment'){ $result = $this->employeeModel->getEmpListByFileId(file_id: $file_id, emp_status: ['draft','enrolled'], policy_status: ['draft','enrolled']); }else{ $result = $this->employeeModel->getEmpListByFileId(file_id: $file_id, emp_status: ['active'], policy_status: ['active']); } $result = []; // ~dd($result); if (count($result) && $role_id == null) { if(get_role_id() == 1 || get_role_id() == 5){ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed. Do you want to truncate data from uploaded file?'], 200); }else{ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed'], 200); } } else { $this->myLogger->logme('error', 'TRUNCATED STARTED WITH ADMIN OR HEAD PERMISSION'); $this->myLogger->logme('error', 'Event Type : -- {data} --', ['data' => $file['action']]); // GET THE CD AMOUND //get cd amount for the particular file id to reverse entry to the cash deposite $cd_amount = $cd_tranction['amount']; if(in_array($file['action'], ['addition', 'dependent_addition'])){ $cd_amount_total = $this->employeePolicyModel->getAdditionDataForTruncated($file_id, $file['action']); // dd($cd_amount_total); $cd_amount = $cd_amount_total['total']; $this->myLogger->logme('error', 'Addition or Dependent Addition CD Amount : {data}', ['data' => $cd_amount]); } $this->myLogger->logme('error', 'CD Amount : {data}', ['data' => $cd_amount]); if($file['action'] != 'enrollment') { //STEP: 1 - Update employee policy table //update emp and emp plocies $db = db_connect(); $query = " UPDATE employee_polices SET employee_polices.status = 'truncated', employee_polices.is_active = 0 WHERE employee_polices.file_id = :file_id: "; $binds = ["file_id" => $file_id]; $db->query($query,$binds); $affectedRows = $db->affectedRows(); $this->myLogger->logme('error', 'employee_polices table update query : {data}', ['data' => $query]); $this->myLogger->logme('error', 'employee_polices table updated - Affected Rows : {data}', ['data' => $affectedRows]); // print_r($db->getLastQuery()); die; // $affectedRows = 10; //STEP:2 - Update emp_endorsement Table //update truncated status and is_active 0 to the Emp_endorsement table if(in_array($file['action'], ['addition', 'dependent_addition'])){ $this->empEndorsementModel->where('file_id', $file_id) ->set(['status' => 'truncated','is_active' => 0]) ->update(); $this->myLogger->logme('error', 'emp_endorsement table updated'); } //STEP:3 - Update files table //update file status $this->fileModel->where('id', $file_id)->set(['status' => 'truncated'])->update(); $this->myLogger->logme('error', 'files table updated'); } else { // echo 'came here...1'; //check all dependents added by self and other dependent policies $emp_codes = $this->employeeModel->select('emp_code') ->where('file_id', $file_id) ->findAll(); $emp_codes = array_column($emp_codes,'emp_code'); // Kint::dump($emp_codes);//die; $dependent_policies = $this->clientPolicyModel->select('id') ->where('base_policy', $client_policy_id) ->findAll(); // $dependent_policies = [ [10],[25],[35] ]; // Kint::dump($dependent_policies); // Kint::dump(array_column($dependent_policies,'id')); if(count($dependent_policies)) { $dependent_policies = array_column($dependent_policies,'id'); // Kint::dump($dependent_policies); $second_level_dependent_policies = $this->clientPolicyModel->select('id') ->whereIn('base_policy', $dependent_policies) ->findAll(); // dd($second_level_dependent_policies); if(count($second_level_dependent_policies)) { $second_level_dependent_policies = array_column($second_level_dependent_policies,'id'); } $dependent_policies = array_merge($dependent_policies,$second_level_dependent_policies); } $dependent_policies = array_merge($dependent_policies,[$client_policy_id]); // Kint::dump($dependent_policies); //update emp and emp plocies $db = db_connect(); $emp_codes = '(' . implode(',', array_map(fn($code) => "'$code'", $emp_codes)) . ')'; $dependent_policies = '(' . implode(',', $dependent_policies) . ')'; $query = " UPDATE employee_polices JOIN employees ON employees.id = employee_polices.employee_id and employees.emp_code in :emp_codes: SET employee_polices.status = 'truncated', employee_polices.is_active = 0 WHERE employee_polices.client_policy_id in :dependent_policies: "; $binds = ["emp_codes" => $emp_codes , "dependent_policies" => $dependent_policies]; $db->query($query,$binds); $affectedRows = $db->affectedRows(); // dd($affectedRows); $affectedRows = $affectedRows * 2; $this->fileModel->where('id', $file_id)->set(['status' => 'truncated'])->update(); } //FINAL STEP - Update reverse entry in cash_deposite table if($cd_tranction){ $cd_data = [ 'amount' => $cd_amount, 'sub_type_id' => 8, 'endorsement_no' => null, 'insurer_id' =>$policy_data['insurer_id'], 'description' => 'The policy Truncated by Admin or Head', 'transaction_type' => 'Credit', 'updated_by' => 1, 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $policy_data['cd_ac_no'] ?? null, 'cd_ac_pk' => $policy_data['cd_ac_pk'] ?? null, 'event_name' => $file['action'], ]; $response = DepositHelper::saveDeposit($cd_data, $loggedInUserID); $this->myLogger->logme('error', 'cash_deposite table updated -- cd transaction'); } $this->myLogger->logme('error', 'SUCCESSFULLY TRUNCATED'); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => round($affectedRows / 2)], 200); } } else if ($file['action'] == 'si_enhancement' || $file['action'] == 'correction' || $file['action'] == 'deletion') { $res = $this->empEndorsementModel->select(['count(id) as count']) ->where('emp_endorsement.file_id', $file_id) ->groupStart() ->where('emp_endorsement.endorsement_id is not null') ->orwhereIn('emp_endorsement.status', ['complete']) ->groupEnd() ->get() ->getResult(); // print_r($this->empEndorsementModel->getLastQuery()); // echo $res[0]->count;die(); if ($res[0]->count == 0 || $role_id == 5 || $role_id == 1) { $this->myLogger->logme('error', 'TRUNCATED STARTED WITH ADMIN OR HEAD PERMISSION'); $this->myLogger->logme('error', 'Event Type : -- {data} --', ['data' => $file['action']]); $transaction_type = 'Credit'; $cd_amount = $cd_tranction['amount']; if($file['action'] == 'deletion'){ $transaction_type = 'Debit'; //get cd amount for the particular file id to reverse entry to the cash deposite for only deletion $cd_amount_total = $this->employeePolicyModel->getDeletionDataForTruncated($file['id']); $totalSum = array_sum(array_column($cd_amount_total, 'total')); $cd_amount = $totalSum; $this->myLogger->logme('error', 'Deletion CD Amount : {data}', ['data' => $cd_amount]); } $this->myLogger->logme('error', 'Endorsemnt CD Amount : {data}', ['data' => $cd_amount]); //STEP 1: //update truncated status to the Emp_endorsement table $this->empEndorsementModel->where('file_id', $file_id) ->set(['status' => 'truncated','is_active' => 0]) ->update(); $this->myLogger->logme('error', 'emp_endorsement table updated'); //STEP 2: if($file['action'] == 'deletion') { //update the employee policy table reverse the data $this->employeePolicyModel->updateEmployeePolicyTruncateReverse($file_id); $this->myLogger->logme('error', 'employee_polices table updated for deletion'); } if($file['action'] == 'correction'){ } // STEP 3: //update files table status to "truncated" $this->fileModel->where('id', $file_id)->set(['status' => 'truncated'])->update(); $this->myLogger->logme('error', 'files table updated'); if($cd_tranction && $file['action'] != 'correction'){ $cd_data = [ 'amount' => $cd_amount, 'sub_type_id' => 8, 'endorsement_no' => null, 'insurer_id' =>$policy_data['insurer_id'], 'description' => 'The policy Truncated by Admin or Head', 'transaction_type' => $transaction_type, 'updated_by' => 1, 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $policy_data['cd_ac_no'] ?? null, 'cd_ac_pk' => $policy_data['cd_ac_pk'] ?? null, 'event_name' => $file['action'], ]; $response = DepositHelper::saveDeposit($cd_data, $loggedInUserID); $this->myLogger->logme('error', 'cash_deposite table updated -- cd transaction'); } $this->myLogger->logme('error', 'SUCCESSFULLY TRUNCATED'); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'success'], 200); } else { if(get_role_id() == 1 || get_role_id() == 5){ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed. Do you want to truncate data from uploaded file?'], 200); }else{ return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'File data already processed'], 200); } } } } public function errorListExportImport($file_id) { $empDataServiceController = new EmpDataServiceController(); $file = $this->batchFileModel->where('id', $file_id)->first(); $client_id = $file['client_id']; $client_policy_id = $file['client_policy_id']; $insurer_or_tpa = $file['insurer_or_tpa']; $event_type = $file['event_type']; $error_data = json_decode($file['error_data']); // dd($error_data); $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/import_excel', $file['file_name']); if (!file_exists($file_name_with_path)) { $error_message = "File not found"; $this->myLogger->logme('error', ($error_message . ' for file id ' . $file_id)); $data['message'] = 'Physical File Not Found'; return view('errors/404', $data); } $excel_data = $empDataServiceController->readExcelFileToArray($file_name_with_path); // dd($excel_data); $excelErrorData['excel_header'] = $excel_data[0]; unset($excel_data[0]); // if($event_type == 'inception' || $event_type == 'deletion'){ // array_pop($excel_data); // } // if($event_type == 'deletion'){ // array_pop($excel_data); // } $finalArray = []; foreach ($error_data as $key => $values) { foreach ($values as $key2 => $value) { $row = $value->row; $column = $value->column; if(property_exists($value, 'db_data')){ $error = 'Expected value: ' . ($value->db_data == null || $value->db_data == "" ? 'NULL' : $value->db_data); }else{ if($event_type == 'inception'){ if ($insurer_or_tpa == 'tpa') { $error = 'Expected value : TPA ID'; } else if ($insurer_or_tpa == 'insurer') { $error = 'Expected value : UHID'; } }else{ $error = 'Expected value : ENDORSEMENT ID'; } } $data = ['value' => $excel_data[$row][$column], 'error' => $error,]; $excel_data[$row][$column] = $data; } array_push($finalArray, $excel_data[$key]); } foreach ($finalArray as $fkey => $value) { foreach ($value as $vkey => $arrayData) { if (!is_array($arrayData)) { $data = ['value' => $arrayData]; $finalArray[$fkey][$vkey] = $data; } } } $excelErrorData['excel_data'] = $finalArray; $excelErrorData['file_id'] = $file_id; // dd($excelErrorData); echo view('export_import_error_list', $excelErrorData); } public function hasPolicyConfigCompleted() { $client_policy_id = $this->request->uri->getSegment(3); $policy_details = $this->clientPolicyModel->find((int)$client_policy_id); $insurer_details = $this->insurerModel->where('id', $policy_details['insurer_id'])->first(); $policy_terms = isset($policy_details['policy_terms']) ? true : false; $si_enhancement_true_or_false = 1; if($policy_terms){ $policyTermsData = json_decode($policy_details['policy_terms']); if (isset($policyTermsData->suminsuredenhancement) && $policyTermsData->suminsuredenhancement !== null) { $si_enhancement_true_or_false = $policyTermsData->suminsuredenhancement; } } $employeeRest = new EmployeeRestController(); $tpa_api_service_status = $employeeRest->checkTpaApiEnable($client_policy_id, 'getTPAID', 'internel'); $tpa_push_api_service_status = $employeeRest->checkTpaApiEnable($client_policy_id, 'sendDataToTPA', 'internel'); $slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($client_policy_id,$policy_details['client_id']); $message = null; if (!isset($policy_terms)) { $message .= 'Policy terms'; } if($slab_details['slab_rates'] == null && $slab_details['grid_master'] == null) { $message = isset($message) ? ($message . ' and rack rates ') : ($message . ' Rack rates'); } $message = isset($message) ? ($message . ' not defined for choosed policy') : null; if ($policy_details['cd_ac_pk'] == null) { $message = isset($message) ? ($message . ' The policy does not have a CD account number.') : null; } return $this->respond(['dataStatus' => true, 'code' => 200, 'message' => $message, 'si_enhancement' => $si_enhancement_true_or_false, 'insurer_multi_event' => $insurer_details['is_multi_event'], 'tpa_api_service_status' => $tpa_api_service_status, 'tpa_push_api_service_status' => $tpa_push_api_service_status], 200); } public function testRackRate() { helper('excel_util_helper'); if ($this->request->getMethod() == 'get') { $filterData = $this->request->getGet('client_policy_id'); //just load UI only $this->loadLayout('rack_rate_test'); } if ($this->request->getMethod() == 'post') { $json = $this->request->getJSON(); // return $this->respond(['dataStatus' => false, 'code' => 200, 'data' => $data], 200); // $data = (json_decode(json_encode($data),true)); $client_id = $json->client_id; $policy_id = $json->policy_id; $branch_id = $json->branch_id; $unit_id = $json->unit_id; $action = $json->action; $family_code = $json->emp_code; $tabledata = $json->data; $existing_famility_details = []; if(count($tabledata)) { $family_details = []; foreach($tabledata as $key => $row) { $row = (array)$row; if(!$row['column12']) { $temp[0] = $row['column1'];//sno $temp[1] = $family_code != "" ? $family_code : $row['column2'];//emp code $temp[2] = $row['column3'];//name $temp[3] = $row['column4'];//DOB $temp[4] = strtoupper($row['column5']);//Gender $temp[5] = $row['column6'];//relation $temp[6] = $row['column7'];//SI $temp[7] = $row['column8'];//DOC $temp[8] = '';//DOJ $temp[9] = $row['column9'];//BP $temp[10] = $row['column10'];//band $temp[11] = '';//designation $temp[12] = '';//mobile $temp[13] = '';//EMail $temp[14] = '';//CE $temp[15] = '';//RFE $temp[16] = '';//DOE $temp[17] = '';//Unit $temp[18] = $unit_id;//unit $family_details[] = $temp; } } } if($action == 'dependent_addition') { $existing_famility_details = $this->employeeModel->getEmpFamilybyEmpCode(emp_code: $family_code,client_id: $client_id,client_policy_id: $policy_id,emp_status: ['active'],policy_status:['active'],client_branch_id: [ $branch_id ]); // ~dd($this->employeeModel->getLastQuery()); if(!count($existing_famility_details)) { return $this->respond(['dataStatus' => false, 'code' => 404, 'data' => [],'messgae' => "No Data found for emp code $family_code"], 200); } //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,[]); // Kint::dump($existing_famility_details); $family_details = array_merge($family_details,$existing_famility_details); $family_details = data_group_by_family($family_details)[ $family_code ];// reason to call this again is bring self to first index of the array // dd($family); } //get policy details $policy_details = $this->clientPolicyModel->getPolicyDetails($client_id,$policy_id); $policy_details = (array)$policy_details[0]; // ~dd($policy_details[0]->policy_start_date); //get rack rates $slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($policy_id,$client_id); //get file array or construnct dummy file array here $file = ['id' => null,'client_id' => $client_id,'policy_id' => $policy_id,'action' => 'inception','client_branch_id' => $branch_id,'created_by' => 1]; //get existing units in the current branch $existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $client_id,client_branch_id: $branch_id); //get familiy details in inception file format array from post method $data = calculate_premium_new(family_data: $family_details,policy_terms:$policy_details,slab_details:$slab_details,fileArr: $file,existing_units: $existing_units); // print_rr($data);die(); foreach($data as $key => $member ) { // ~dd($member); if(is_array($member) && isset($member['policy_details']['date_coverage']) && isset($member['policy_details']['policy_end_date']) ) { $data[$key]['policy_details']['no_of_days'] = $member['policy_details']['date_coverage'] ? (calculate_days_bw_dates($member['policy_details']['date_coverage'],$member['policy_details']['policy_end_date'])->days + 1) : ''; } else { $data[$key]['policy_details']['no_of_days'] = '0'; } } return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => ['new' => $data,'old' => $existing_famility_details], 200]); } } public function testCheckDependentConflict() { helper('excel_util_helper'); if ($this->request->getMethod() == 'get') { $filterData = $this->request->getGet('client_policy_id'); //just load UI only $this->loadLayout('rack_rate_test'); } if ($this->request->getMethod() == 'post') { $json = $this->request->getJSON(); // return $this->respond(['dataStatus' => false, 'code' => 200, 'data' => $data], 200); // $data = (json_decode(json_encode($data),true)); $client_id = $json->client_id; $policy_id = $json->policy_id; $branch_id = $json->branch_id; $tabledata = $json->data; if(count($tabledata)) { $family_details = []; foreach($tabledata as $key => $row) { $row = (array)$row; if(!$row['column12']) { $temp[0] = $row['column1'];//sno $temp[1] = $row['column2'];//emp code $temp[2] = $row['column3'];//name $temp[3] = $row['column4'];//DOB $temp[4] = strtoupper($row['column5']);//Gender $temp[5] = $row['column6'];//relation $temp[6] = $row['column7'];//SI $temp[7] = $row['column8'];//DOC $temp[8] = '';//DOJ $temp[9] = $row['column9'];//BP $temp[10] = $row['column10'];//band $temp[11] = '';//designation $temp[12] = '';//mobile $temp[13] = '';//EMail $temp[14] = '';//CE $temp[15] = '';//RFE $temp[16] = '';//DOE $temp[17] = '';//Unit $temp[18] = $row['column11'];//unit $family_details[] = $temp; } } } // print_r($family_details); // return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $family_details], 200); //get policy details $policy_details = $this->clientPolicyModel->getPolicyDetails($client_id,$policy_id); $policy_terms = (array)$policy_details[0]; $is_lgbtq = $policy_terms['is_lgbtq']; // dd($policy_terms); $policy_terms = json_decode($policy_terms['policy_terms']); $policy_terms = (array) $policy_terms;// convert obj to array //get file array or construnct dummy file array here $file = ['id' => null,'client_id' => $client_id,'policy_id' => $policy_id,'action' => 'inception','client_branch_id' => $branch_id,'created_by' => 1]; //get familiy details in inception file format array from post method $result = check_dependent_conflict($family_details, $policy_terms, $file['action'],$is_lgbtq); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => ['policy_terms' => $policy_terms['family_floaters'],'result' => $result] ], 200); } } public function get_client_policy_list_for_remainder($client_id, $client_branch_id) { $policies = $this->clientPolicyModel ->select('client_policy.*, policy_type.policy_type as policy_name') ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') ->where('client_policy.client_id', $client_id) ->where('client_policy.client_branch_id', $client_branch_id) ->where('client_policy.is_active', 1) ->where('client_policy.policy_status', 1) ->whereIn('client_policy.policy_type_id', [2, 3]) ->findAll(); return $this->respond(['status' => true, 'code' => 200, 'data' => $policies], 200); } //-------- Edit individual employee and View & Send E-card ----------------------------------------------------------------------------------------- public function get_emp_master_data_for_update($id) { $employee_data = $this->employeeModel->select("employees.*, DATE_FORMAT(dob, '%d/%m/%Y') AS formatted_dob,")->where('id', $id)->first(); if ($employee_data) { return $this->respond(['status' => true,'code' => 200,'data' => $employee_data,], 200); } else { return $this->respond(['status' => false, 'code' => 404, 'message' => 'No data found.'], 404); } } //UPDATE EMPLOYEE public function update_emp_data() { $rules = [ // 'emp_code' => [ // 'rules' => 'required', // 'errors' => [ // 'required' => 'Employee Code is missing' // ] // ], // 'name' => [ // 'rules' => 'required|min_length[2]|max_length[100]', // 'errors' => [ // 'required' => 'Employee name is required', // 'min_length' => 'Name must be at least 2 characters', // 'max_length' => 'Name cannot exceed 100 characters' // ] // ], // 'gender' => [ // 'rules' => 'permit_empty|in_list[M,F]', // 'errors' => [ // 'in_list' => 'Invalid gender selected' // ] // ], 'email_corporate' => [ 'rules' => 'required|regex_match[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/]', 'errors' => [ 'required' => 'Email address is required.', 'regex_match' => 'Please enter a valid email format (e.g., name@domain.com).' ] ], 'mobile' => [ 'rules' => 'required|numeric|exact_length[10]', 'errors' => [ 'required' => 'Mobile number is required', 'numeric' => 'Mobile number must contain digits only', 'exact_length' => 'Mobile number must be exactly 10 digits' ] ], ]; $request_post_data = $this->request->getPost(); $data = sanitizeInputArrayAdvanced($request_post_data); if (isset($data['relationship'])) { $rules['relationship'] = [ 'rules' => 'required|in_list[Self,Spouse,Child,Father,Mother,Father-in-law,Mother-in-law]', 'errors' => [ 'required' => 'Relationship is required', 'in_list' => 'The selected relationship is invalid.' ] ]; } if (!$this->validate($rules)) { return $this->response->setStatusCode(400)->setJSON([ 'status' => false, 'message' => 'Input validation failed', 'code' => 400, 'errors' => $this->validator->getErrors() ]); } // print_rr($data);die(); // $data['dob'] = date('Y-m-d', strtotime($data['dob'])); $data['dob'] = (!empty($data['dob'])) ? change_date_format($data['dob'], null, 'Y-m-d') : null; // print_rr($data); die; // Fetch current employee data $employee_data = $this->employeeModel->where('id', $data['employee_primary_id'])->first(); if ($employee_data['relationship'] == 'Self') { if(isset($data['gender'])){ if ($employee_data['gender'] != $data['gender']) { $spouse_gender = ($data['gender'] == 'M') ? 'F' : 'M'; $this->employeeModel ->where('emp_code', $employee_data['emp_code']) ->where('relationship', 'Spouse') ->set(['gender' => $spouse_gender]) ->update(); } } } // Update the employee data $result = $this->employeeModel->where('id', $data['employee_primary_id'])->set($data)->update(); if ($result) { return $this->respond(['status' => true, 'code' => 200, 'data' => $data, 'message' => 'Employee updated successfully'], 200); } else { return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to update employee.'], 404); } } public function send_mail_for_individual_employee_ecard($id, $client_policy_id) { $ids[] = $id; $empDataServiceController = new EmpDataServiceController(); $result = $empDataServiceController->sendMailForDownloadingECard(['ids' => $ids, 'client_policy_id' => $client_policy_id], 1); if (isset($result['status']) && $result['status'] == true) { return $this->respond(['status' => true,'code' => 200,'message' => 'Mail sent successfully', 'result' => $result], 200); } else { return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to sent mail.', 'result' => $result], 200); } } public function checkDeletionGetDataFunction() { // $batch_data = [ // 'client_id' => 159, // 'client_policy_id' => 336, // 'client_branch_id' => 126, // ]; // $batch_data['insurer_or_tpa'] = 'insurer'; // $batch_data['insurer_or_tpa'] = 'tpa'; //INCEPTION // $result = $this->employeePolicyModel->getInceptionEmployeeDataForExportExcel($batch_data); // CORRECTION // $result = $this->employeePolicyModel->getCorrectionEmployeesDataForExportExcel($batch_data); //SI-ENHANCEMENT // $result = $this->employeePolicyModel->getSIEnhancementEmployeesDataForExportExcel($batch_data); //DELETION // $result = $this->employeePolicyModel->getDeletionEmployeeDataForExportExcel($batch_data); // print_rr($result); die; //------------------------------------------------------------------------------------------------------------- // $ids = [ // 'employeeIds' => [20252, 20258, 20277, 20282, 20196, 20237, 20314, 20325, 20356], // 'client_id' => 17, // 'client_policy_id' => 30, // 'client_branch_id' => 18, // 'cd_ac_no' => $CD_Account_Number['cd_ac_no'] ?? null, // 'endorsement_no' => $endorsement_id ?? null, // 'count' => 9, // // 'event_name' => $file['event_type'], // // 'policy_name' => $policy_name['policy_name'], // // 'user_id' => $user_id, // ]; // $empDataServiceController = new EmpDataServiceController(); // $result = $empDataServiceController->cashDepositCalculationForDeletion($ids); } // ---------- DOWNLOAD IMPORT BATCH FILE AND SAMPLE FILE ------------------------------------------------------------------------------------------------ public function downloadSampleImportExcelFile($actionType = null) { // $actionType = $this->request->getGet(); $filePath = ''; // Path to your file if ($actionType == 'inception') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_Inception.xlsx'; } else if ($actionType == 'correction') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_correction.xlsx'; } else if ($actionType == 'si_enhancement') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_SI_Enhancement.xlsx'; } else if ($actionType == 'dependent_addition') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_Dependent_Addition.xlsx'; } else if ($actionType == 'addition') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_Addition.xlsx'; } else if ($actionType == 'deletion') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_Deletion.xlsx'; }else if ($actionType == 'missed_inception') { $filePath = ROOTPATH . 'public/sample_import_excel/sample_import_Addition.xlsx'; } // Check if the file exists if (file_exists($filePath)) { // Set the appropriate MIME type $mimeType = mime_content_type($filePath); // Send the file to the client for download return $this->response->download($filePath, null, $mimeType); } else { // File not found, show an error message or redirect echo view('errors/html/production'); } } public function download_import_file($file_id) { $file_data = $this->batchFileModel->where('id', $file_id)->first(); if (empty($file_data) || empty($file_data['file_name'])) { $data['message'] = 'File record not found'; return view('errors/404', $data); } $fileName = basename((string) $file_data['file_name']); $storage = \Config\Services::getFileStorageService(); $result = $storage->download(WRITEPATH . 'uploads/import_excel', $fileName); try { if ($result['success'] ?? false) { $downloadAs = storage_upload_display_name($fileName); if (! empty($result['path']) && is_file($result['path'])) { return $this->response->download($result['path'], null)->setFileName($downloadAs); } if (! empty($result['content'])) { return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs); } } $data['message'] = 'The Physical File Not Found'; return view('errors/404', $data); } catch (\Exception $e) { $this->myLogger->logme('error', $e->getMessage()); echo $e->getMessage(); } } //--------- LOG FILE VIEW AND DOWNLOAD --------------------------------------------------------------------------------------------- public function listLogs() { $logPath = WRITEPATH . 'logs/'; $logs = []; // Check if the log directory exists if (is_dir($logPath)) { $files = array_diff(scandir($logPath), ['.', '..']); // Exclude '.' and '..' $files = array_reverse($files); foreach ($files as $file) { if (is_file($logPath . $file)) { $logs[] = $file; // Add log files to the list } } } $data['logs'] = $logs; $data['server_details'] = get_server_details(); // Pass log files to the view return $this->loadLayout('log_view', $data); } public function downloadLog($fileName) { $logPath = WRITEPATH . 'logs/' . $fileName; // Check if the requested file exists if (file_exists($logPath)) { return $this->response->download($logPath, null)->setFileName($fileName); } // Redirect back with an error if file doesn't exist return redirect()->back()->with('error', 'Log file not found.'); } public function viewLog($fileName) { $logPath = WRITEPATH . 'logs/' . $fileName; if (file_exists($logPath)) { $content = file_get_contents($logPath); $data['fileName'] = $fileName; $data['content'] = $content; $data['server_details'] = get_server_details(); return $this->loadLayout('log_content_view', $data); } return redirect()->back()->with('error', 'Log file not found.'); } public function exportToExceltpadata() { // Create a new Spreadsheet $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); // Header row $headers = [ 'TPA_NAME', 'SHORT_NAME', 'TPA_BRANCH_NAME', 'TPA_BRANCH_CODE', 'TPA_CONTACT_PERSON_NAME', 'TPA_CONTACT_PERSON_EMAIL', 'TPA_CONTACT_PERSON_MOBILE', 'TPA_CONTACT_PERSON_DESIGNATION', 'IS_DELETED' ]; $sheet->fromArray($headers, NULL, 'A1'); // Data rows $data = [ ["ICICI Lombard Health Care", "IL Health care", "Chennai", "997133", "Heena", "dharanisri@jubiliant.in", "9043955294", "General Manager", "YES"], ["ICICI Lombard Health Care", "IL Health care", "Chennai", "997133", "Mahammad shireen", "mahammad.shireen@icicilombard.com", "8655420732", "Claims head", "NO"], ["Medi Assist Insurance TPA Private Limited", "Medi Assist", "Chennai", "YA0000000348", "Ragavi", "dharanisri@jubiliant.in", "9043955294", "Senior Manager", "YES"], ["Medi Assist Insurance TPA Private Limited", "Medi Assist", "Chennai", "YA0000000348", "Vijayalakshmi", "vijayalakshmi.c@mediassist.in", "7795542162", "Senior Executive | Account Management", "NO"], ["Vidal Health Insurance TPA", "Vidal", "Chennai", "YA0000000349", "vijalakshmi", "vijayalakshmi.c@mediassist.in", "7795542162", "Senior Executive", "NO"], ["Vidal Health Insurance TPA", "Vidal", "Chennai", "YA0000000349", "M.Pushparaj", "pushparaj.moorthy@vidalhealth.com", "8939634456", "Executive", "NO"], ["Digit in-House", "Digit in-House", "Go Digit General Insurance Ltd", "1", "sathish", "sathish.n@vidalhealth.com", "7823913800", "Senior Executive", "NO"], ["Digit in-House", "Digit in-House", "Go Digit General Insurance Ltd", "1", "Mr. Pavan", "TK.Pavankumar@godigit.com", "8754490492", "Strategic Partnerships", "NO"], ["Aditya Birla Health Insurance Co. Limited", "ABHI", "Chennai", "O1", "sathish", "sathish.n@vidalhealth.com", "7823913800", "Senior Executive", "NO"], ["Aditya Birla Health Insurance Co. Limited", "ABHI", "Chennai", "O1", "Jhonson Kj", "jhonson.kj@adityabirlacapital.com", "9900729513", "Executive", "NO"], ["Aditya Birla Health Insurance Co. Limited", "ABHI", "Chennai", "01", "Jhonson Kj", "jhonson.kj@adityabirlacapital.com", "9900729513", "Executive", "NO"], ["R Care Health", "R Care", "Chennai", "01", "Jeevanadam", "Jeevanandam.Kumaran@relianceada.com", "8825982053", "Executive", "NO"], ["IFFCO-TOKIO GENERAL INSURANCE CO. LTD", "ITGI", "Chennai", "01", "Anjali", "Anjali.K@ext.iffcotokio.co.in", "6374270165", "Senior Executive", "NO"], ["Star Health and Allied Insurance", "STAR", "Chennai", "110000", "Mr. Vijay Baskar", "vijayabhaskar.m@starhealth.in", "9840905286", "Area Manager", "NO"], ]; $sheet->fromArray($data, NULL, 'A2'); // Save the file $filename = 'TPA_Data.xlsx'; $writer = new Xlsx($spreadsheet); // Set headers for download header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Cache-Control: max-age=0'); $writer->save('php://output'); exit; } //------------------------------------------------------------------------------------------------------ public function test_members_list(){ // $model = new EmployeeModel(); // $list = [ // ['relationship' => 'spouse','emp_code' => 'TEST002', 'name' => 'Lakshmi','email_personal' => 'lakshmi@gmail.com','mobile'=>'6382156701','gender'=>'female','dob'=>'1996-05-19','doj'=>'2022-02-01','basic_pay'=>'100000','emp_status'=>'enrolled'], // ['relationship' => 'Daughter','emp_code' => 'TEST002', 'name' => 'Jayalakshmi','email_personal' => 'jayalakshmi@gmail.com','mobile'=>'6382156701','gender'=>'female','dob'=>'2018-05-19','doj'=>'2022-02-01','basic_pay'=>'100000','emp_status'=>'enrolled'], // ['relationship' => 'Son','emp_code' => 'TEST002', 'name' => 'Jayam Ravi','email_personal' => 'jayamravi@gmail.com','mobile'=>'6382156701','gender'=>'male','dob'=>'1994-05-19','doj'=>'2019-02-01','basic_pay'=>'100000','emp_status'=>'enrolled'], // // ['relationship' => 'self','emp_code' => 'TEST003', 'name' => 'Ravi Shankar','email_personal' => 'srinivassaravanan2002@gmail.com','email_corporate'=>'srinivas.saravanan@venbainfotech.com','mobile'=>'6382156701','gender'=>'male','dob'=>'1994-05-19','doj'=>'2022-02-01','basic_pay'=>'100000','emp_status'=>'enrolled'] // ['relationship' => 'spouse','emp_code' => 'TEST001', 'name' => 'Lakshmi','email_personal' => 'lakshmi@gmail.com','mobile'=>'6382156701','gender'=>'female','dob'=>'1996-05-19','doj'=>'2022-02-01','basic_pay'=>'100000','emp_status'=>'enrolled'], // ]; // foreach($list as $listitem){ // $model->insert($listitem); // } // die(); $employee_data = $this->employeeModel->getTestEmployeeData(); $data['employees'] = $employee_data; $data['clients'] = $this->clientModel->findAll(); // dd($data); $data['tab_name'] = "Employees"; $data['page_name'] = "Employees"; return $this->loadLayout('test_members_list',$data); } public function mapEmployees(){ $request_post_data = $this->request->getPost(); $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data); $client_id = $sanitized_post_data['client_id'] ?? null; $branch_id = $sanitized_post_data['branch_id'] ?? null; $policy_id = $sanitized_post_data['client_policy_id'] ?? null; $selected_employees = (array)$sanitized_post_data['selected'] ?? []; $si_amt = $sanitized_post_data['si_amt'] ?? null; $policy_start_date_unformatted = $sanitized_post_data['policy_start_date'] ?? null; $policy_start_date = change_date_format($policy_start_date_unformatted, 'd/M/Y', 'Y-m-d'); $data1 = [ 'client_id' => $client_id, 'client_branch_id' => $branch_id, ]; $data2 = [ 'client_policy_id' => $policy_id, 'status' => 'draft', 'date_coverage' => $policy_start_date, 'basic_cover_si' => $si_amt, ]; for($i = 0; $i < count($selected_employees); $i++){ $data2['employee_id'] = $selected_employees[$i]; $result1 = $this->employeeModel->set($data1)->where('id',$selected_employees[$i])->update(); $result2 = $this->employeePolicyModel->insert($data2); } if ($result1 && $result2) { return $this->respond(['status' => true, 'code' => 200, 'message' => 'Employees mapped successfully'], 200); } else { return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to map employees.'], 404); } } public function getDataForMapping(){ $policy_id = $this->request->getPost('policy_id');log_message('error',$policy_id); $data['policy_start_date'] = $this->clientPolicyModel->select('policy_start_date')->where('id',$policy_id)->first()['policy_start_date']; $data['si_amt'] = $this->PolicyPremium2Model->select('si')->where('client_policy_id', $policy_id)->groupBy('si')->findAll(); log_message('error',json_encode($data).'policy id '.$policy_id); return $this->respond(['status' => true, 'code' => 200, 'data' => $data], 200); } public function unmapEmployees($actionType){ $request_post_data = $this->request->getPost(); $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data); $selected_employees = (array)$sanitized_post_data['selected'] ?? []; if($actionType == 0){ for($i = 0;$iemployeeModel->set(['client_id' => null, 'client_branch_id' => null])->where('id',$selected_employees[$i])->update();log_message('error',$result1); $result2 = $this->employeePolicyModel->where('employee_id',$selected_employees[$i])->delete();log_message('error',$result2); } } else if ($actionType == 1){ for($i = 0;$iemployeeModel->set(['client_id' => null, 'client_branch_id' => null])->where('id',$selected_employees[$i])->update();log_message('error','result 1 is '.$result1); $result2 = $this->employeePolicyModel->where('employee_id',$selected_employees[$i])->delete();log_message('error', 'result 2 is '.$result2); $emp_code = $this->employeeModel->select('emp_code')->where('id',$selected_employees[$i])->first()['emp_code'];log_message('error','emp_code is '.$emp_code); $result3 = $this->employeeModel->where('emp_code',$emp_code)->whereNotIn('relationship',['self'])->delete();log_message('error','result 3 is '.$result3); } } else{ return $this->respond(['status' => false, 'code' => 404, 'message' => 'Invalid action type.'], 404); } if($actionType == 1){ if($result1 && $result2 && $result3){ return $this->respond(['status' => true, 'code' => 200, 'message' => 'Employees unmapped successfully and Dependencies are Deleted'], 200); } else{ return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to unmap employees.'], 404); } }else{ if($result1 && $result2 ){ return $this->respond(['status' => true, 'code' => 200, 'message' => 'Employees unmapped successfully'], 200); } else{ return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to unmap employees.'], 404); } } } public function cloneWorksheet() { // Define file paths $inputFilePath = 'C:\Users\Venba\Downloads/merge1.xlsx'; // Path to the existing file $outputFilePath = WRITEPATH . '/tmp/cloned_file.xlsx'; // Path to save the new file try { // Load the existing spreadsheet $spreadsheet = IOFactory::load($inputFilePath); // Get the first worksheet (or specify the index of the sheet to clone) $originalWorksheet = $spreadsheet->getSheet(0); // Clone the worksheet $clonedWorksheet = clone $originalWorksheet; // Generate a unique name for the cloned worksheet $baseName = "Cloned Sheet"; $sheetIndex = 1; $uniqueName = $baseName; // Check for duplicate names and generate a unique one while ($spreadsheet->sheetNameExists($uniqueName)) { $uniqueName = $baseName . " " . $sheetIndex; $sheetIndex++; } // Set the unique name for the cloned worksheet $clonedWorksheet->setTitle($uniqueName); // Add the cloned worksheet to the spreadsheet $spreadsheet->addSheet($clonedWorksheet); // Modify the cloned sheet (optional) $clonedWorksheet->setCellValue('A1', 'Hello, Cloned Sheet!'); // Save the modified spreadsheet to a new file $writer = new Xlsx($spreadsheet); $writer->save($outputFilePath); return $this->response->setJSON([ 'status' => 'success', 'message' => 'Spreadsheet with cloned sheet created successfully!', 'file_path' => $outputFilePath, ]); } catch (\Exception $e) { // Handle exceptions return $this->response->setJSON([ 'status' => 'error', 'message' => $e->getMessage(), ]); } } //------------------------------------------------------------------------------------------------------ public function generateAcmAndMForEcard($client_id) { $db = db_connect(); $builder = $db->table('client_rm'); $builder->select('user_profiles.first_name, user_profiles.mobile, user_profiles.email, client_rm.level'); $builder->join('user_profiles', 'client_rm.user_id = user_profiles.id'); $builder->where('client_rm.client_id', $client_id); $builder->whereIn('client_rm.level', [2, 3]); $builder->where('client_rm.is_active', 1); $builder->orderBy('client_rm.level', 'desc'); $query = $builder->get(); $result = $query->getResultArray(); $levels = [ 3 => [], 2 => [] ]; foreach ($result as $value) { $levels[$value['level']][] = $value; } // Generate the HTML content $html = ''; $level_index = 1; foreach ($levels as $level => $contacts) { $displayLevel = $level == 3 ? 1 : 2; // Switch levels for display if($level_index == 1){ $html .= 'Level ' . $displayLevel . '
'; }else{ $html .= '
Level ' . $displayLevel . '
'; } foreach ($contacts as $index => $contact) { $html .= ($index + 1) . '. ' . $contact['first_name'] . ' / ' . $contact['mobile'] . ' / ' . $contact['email'] . '
'; } $level_index++; } $html .= '
'; return $html; } public function generateNetworkHospitalsForEcard($network_hospitals) { $html = ""; if (!empty($network_hospitals)) { $html = '
Network Hospital: ' . $network_hospitals . '
'; } // For debugging // print_r($html); die; return $html; } public function getBatchFileData() { $file_id = $this->request->getGet('file_id'); if(!empty($file_id)){ $batch_file_data = $this->batchFileModel ->where('id', $file_id) ->where('is_active', 1) ->first(); if(!empty($batch_file_data)){ return $this->respond(['status' => true, 'code' => 200, 'batch_file_data' => $batch_file_data], 200); }else{ return $this->respond(['status' => false, 'code' => 200, 'message' => 'No data found.'], 200); } }else{ return $this->respond(['status' => false, 'code' => 404, 'message' => 'No data to found. File ID Not found'], 200); } } public function getEmpHistory(){ $emp_id = $this->request->getPost('emp_id'); $data['emp_history'] = $this->auditHistory->select('field_name,old_value,new_value,created_by,created_at')->where('pk',$emp_id)->where('table_name','employees')->orderBy('created_at', 'DESC')->findAll(); foreach ($data['emp_history'] as &$emp_history) { $emp_history['field_name'] = $this->formatFieldName($emp_history['field_name']); $user = $emp_history['created_by']; if ($user != null && $user != ''){ $userData = $this->userModel->select('first_name, last_name')->where('id', $user)->where('is_active', 1)->first(); $emp_history['created_by'] = ucwords($userData['first_name'] . ' ' . $userData['last_name']); }else{ $emp_history['created_by'] = '-'; } $emp_history['created_at'] = date("d-m-Y H:i:s", strtotime($emp_history['created_at'])); } unset($emp_history); $emp_pol_pk = $this->employeePolicyModel->select('id')->where('employee_id',$emp_id)->first()['id']; $data['emp_pol_history'] = $this->auditHistory->select('field_name,old_value,new_value,created_by,created_at')->where('pk',$emp_pol_pk)->where('table_name','employee_polices')->findAll(); return $this->respond(['status' => true, 'data' => $data],200); } public function formatFieldName($unformattedString){ if (str_contains($unformattedString, '_')) { $data = str_replace('_', ' ', $unformattedString); }else{ $data = $unformattedString; } $format = ucwords($data); return $format; } /** * Below function displays the endorsement list page. * * This method retrieves filter data from the request and fetches the endorsement list * based on the provided filters such as client ID, policy ID, and status. */ public function retailendorsementlist() { $data = []; $data['status'] = ['open' => 'Open', 'inprogress' => 'In-Progress', 'complete' => 'Complete']; $data['client'] = $this->clientModel->select('clients.id,client_name,short_name') ->where('clients.is_active',1) ->where('clients.client_type',2) ->findAll(); $data['insurer'] = $this->insurerModel->select('insurers.id,name,short_name') ->where('insurers.is_active',1) ->findAll(); // if (count($this->request->getGet())) { $filterData = $this->request->getGet(); $data['employees'] = $this->partnerEndorsementRequestModel->getRetailEndorsementList( client_id: $filterData['client_id'] ?? null, insurers_id: $filterData['insurer_id'] ?? null, status: $filterData['status'] ?? null ); $data['getData'] = $filterData; // echo "
";
            // print_r($data); die;
        // }

        $data['tab_name']  = "Retail Endorsement";
        $data['page_name'] = "Retail Endorsement";

        $this->loadLayout('retail_endorsement_list', $data);
    }

    public function retailendorsementsave()
    {
        try {
            $rules = [
            'endorsement_no' => [
                'rules'  => 'required|regex_match[/^[a-zA-Z0-9\/_\-]+$/]',
                'errors' => [
                    'required'    => 'Endorsement Number is missing.',
                    'regex_match' => 'Endorsement Number can only contain letters, numbers, slashes (/), underscores (_), and hyphens (-).'
                ]
            ],
            'status' => [
                'rules'  => 'required',
                'errors' => [
                    'required'   => 'Status is required',
                ]
            ]
        ];
        if (!$this->validate($rules)) {
            return $this->response->setStatusCode(400)->setJSON([
                'status' => false,
                'message' => 'Input validation failed',
                'code' => 400,
                'errors' => $this->validator->getErrors()
            ]);
        }
        $request_post_data   = $this->request->getPost();
        $data = sanitizeInputArrayAdvanced($request_post_data);
        
            if (!empty($data['id'])) {
                $text   = "update";
                $updateID = $data['id'];
                $result = $this->partnerEndorsementRequestModel->where('id', $updateID)->set($data)->update();
            } else {
                $text   = "create";
                $data['created_by'] = get_session_userid();
                $thzMasterModel = new ThzMasterModel();
                $thzMasterModel->insert($data);
                $insertID = $this->partnerEndorsementRequestModel->insertID();
                $result = true;
            }

            $id = isset($insertID) && !empty($insertID) ? $insertID : $updateID;

            return $this->response->setJSON([
                'status' => $result ? 'success' : 'error',
                'message' => $result ? "Partner Endorsement Request {$text}d successfully " : "Unable to {$text} Partner Endorsement Request. Please try again.",
            ])->setStatusCode($result ? 200 : 400);
        } catch (\Throwable $e) {
            $code = ($e->getCode() && $e->getCode() >= 100 && $e->getCode() < 600) ? $e->getCode() : 500;

            $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
                || $e instanceof \mysqli_sql_exception
                || $e instanceof \PDOException;

            $context = ['title'   => get_class($e), 'type'    => get_class($e), 'code'    => $code, 'message' => $e->getMessage(), 'file'    => $e->getFile(), 'line'    => $e->getLine()];

            $this->myLogger->logme('error', "Exception: {message} in {file} on line {line}", $context, 0);

            return $this->response->setJSON([
                'status'  => 'error',
                'message' => $isDbError ? 'Data Access Error' : $e->getMessage(),
                'ref'     => $isDbError ? 'database - ' : 'application - ' . $code . ' - ' . $e->getLine()
            ])->setStatusCode($code);
        }
    }

    // function for skip the Inception and Member data validation
    public function proceedExcelFileDataValidation()
    {
        $file_id = $this->request->getGet('file_id');
        $not_skiped = $this->request->getGet('not_skiped') ?? null;
        $this->myLogger->logme('error', json_encode($this->request->getGet() ?? []));


        if(!empty($not_skiped)){
            $file_model = new FileModel();
            $file_model->where('id', $file_id)->set(['is_comparison_skipped' => 0])->update();
            $message = "Inception and Member data comparision continuted by the user id : " . get_session_userid();
            $this->myLogger->logme('error', $message);
            return $this->respond(['status' => true, 'code' => 200, 'message' => 'Inception and Member data comparision continued'], 200);
        }

        if(!empty($file_id)){

            $r = Jobs::addJob(['job_name' => 'excelFileDataValidation','payload' => ['file_id' => $file_id]]);
            $message = "Inception and Member data comparision skiped successfully by the user id : " . get_session_userid();
            $this->myLogger->logme('error', $message);

            $file_model = new FileModel();
            $file_model->where('id', $file_id)->set(['is_comparison_skipped' => 1])->update();

            $policy_id = $this->request->getGet('policy_id') ?? null;

            if ($policy_id) {

                $client_policy_data = $this->clientPolicyModel->where('id', $policy_id)->first();

                if (!empty($client_policy_data) && isset($client_policy_data['is_from_lead'])) {
                    $lead_id = $client_policy_data['is_from_lead'];

                    if (!empty($lead_id)) {
                        $lead_model = new LeadsModel();
                        $lead_model->where('id', $lead_id)->set(['policy_with_correction' => 1])->update();
                    } else {
                        $this->myLogger->logme('error', 'Lead ID missing for policy ID: ' . $policy_id);
                    }
                } else {
                    $this->myLogger->logme('error', 'No client policy data found for policy ID: ' . $policy_id);
                }
            } else {
                $this->myLogger->logme('error', 'Policy ID not provided in GET request.');
            }

            return $this->respond(['status' => true, 'code' => 200, 'message' => 'Inception and Member data comparision skiped successfully!'], 200);
        }else{
            return $this->respond(['status' => false, 'code' => 500, 'message' => 'Failed to skip the comparison!'], 200);
        }
    }


    public function checkWellnessOnboardStatus($client_policy_id)
    {       


        $fetch_onboarded_employees = $this->request->getGet('fetch_onboarded_employees') ?? false;

        if($fetch_onboarded_employees){
            $data = $this->employeePolicyModel->select('employee_polices.*')
            ->where('employee_polices.is_active', 1)
            ->where('employee_polices.status', 'active')
            ->where('employee_polices.client_policy_id', $client_policy_id)
            ->where('employee_polices.wellness_onboard !=', '0')
            ->findAll();
            return $this->respond(['status' => true, 'code' => 200, 'data' => count($data)], 200);
        }


        // echo $client_policy_id;die();
           $data = $this->employeePolicyModel->select('employee_polices.*,emp.name,emp.relationship,emp.emp_code,emp.name,emp.email_corporate,emp.mobile,emp.dob,cp.policy_no,cp.wellness_plan_id,cp.wellness_vendor_id,cp.policy_start_date as cp_policy_start_date,cp.policy_end_date,cls.short_name')
            ->join('client_policy cp', 'cp.id = employee_polices.client_policy_id')
            ->join('clients cls', "cp.client_id = cls.id")
            ->join('employees emp', "emp.id = employee_polices.employee_id")
            ->where('employee_polices.is_active', 1)
            ->where('employee_polices.status', 'active')
            ->where('employee_polices.client_policy_id', $client_policy_id)
            // ->where('employee_polices.tpa_id is not null')
            ->where('employee_polices.wellness_onboard', '0')
            ->where('emp.emp_status', 'active')
            ->where('emp.is_active', 1)
           ->groupStart()
                ->orwhere('cp.wellness_plan_id IS NOT NULL', null, false)
                ->orWhere('cp.wellness_plan_id !=', '')
                ->orWhere('cp.wellness_plan_id !=', 0)
            ->groupEnd()
            ->groupStart()
                ->orwhere('cp.wellness_vendor_id IS NULL', null, false)
                ->orWhere('cp.wellness_vendor_id =', '')
                ->orWhere('cp.wellness_vendor_id =', 0)
            ->groupEnd()
            ->where('cp.policy_status',1)
            ->where('cp.is_active',1)
            ->findAll();
            // echo count($data);die();
            // if(is_array($data) && count($data))
            // {
                return $this->respond(['status' => true, 'code' => 200, 'data' => count($data)], 200);
            // }
            // return $this->respond(['status' => true, 'code' => 200, 'message' => 'Inception and Member data comparision skiped successfully!'], 200);
    }

    public function initiateWellnessOnboard($client_policy_id, $emp_code = null)
    {
         $r = Jobs::addJob(['job_name' => 'initiateWellnessOnboardJob','payload' => ['client_policy_id' => $client_policy_id, 'emp_code' => $emp_code ?? null   ]]);
        // $this->initiateWellnessOnboardJob(['client_policy_id' => $client_policy_id]);
        return $this->respond(['status' => true, 'code' => 200, 'message' => 'Process started'], 200);
    }

    public function initiateWellnessOnboardJobOLD($arr)
    {

        $client_policy_id = $arr['client_policy_id'];

        $page = max(1, (int)($arr['page'] ?? 1));
        $perPage = max(1, (int)($arr['per_page'] ?? 50));
        $offset = ($page - 1) * $perPage;
        $data = $this->employeePolicyModel->select('employee_polices.*,emp.name,emp.relationship,emp.emp_code,emp.name,emp.email_corporate,emp.mobile,emp.dob,cp.policy_no,cp.wellness_plan_id,cp.wellness_vendor_id,cp.policy_start_date as cp_policy_start_date,cp.policy_end_date,cls.short_name,emp.gender')
            ->join('client_policy cp', 'cp.id = employee_polices.client_policy_id')
            ->join('clients cls', "cp.client_id = cls.id")
            ->join('employees emp', "emp.id = employee_polices.employee_id")
            ->where('employee_polices.is_active', 1)
            ->where('employee_polices.status', 'active')
            ->where('employee_polices.client_policy_id', $client_policy_id)
            // ->where('employee_polices.tpa_id is not null')
            ->where('employee_polices.wellness_onboard', '0')
            ->where('emp.emp_status', 'active')
            ->where('emp.is_active', 1)
            ->groupStart()
                ->where('cp.wellness_plan_id IS NOT NULL', null, false)
                ->orWhere('cp.wellness_plan_id !=', '')
                ->orWhere('cp.wellness_plan_id !=', 0)
            ->groupEnd()
            ->groupStart()
                ->where('cp.wellness_vendor_id IS NULL', null, false)
                ->orWhere('cp.wellness_vendor_id =', '')
                ->orWhere('cp.wellness_vendor_id =', 0)
            ->groupEnd()
            ->where('cp.policy_status',1)
            ->where('cp.is_active',1)
            ->findAll($perPage, $offset);
        // $data = '[{"id":12847,"employee_id":"TEST_EMP_001","client_policy_id":null,"tpa_id":null,"uhid":null,"batch_code":null,"status":"active","pre_existing_alignments":null,"age_band":null,"basic_cover_si":"0","date_coverage":"2025-01-01","policy_end_date":"2025-12-31","days":"0","premium":"0","rata_premimum":"0","gst":"0","si_enhancement_date":null,"date_of_exit":null,"reason_for_exit":null,"claim_status":"0","created_by":null,"created_at":null,"updated_by":null,"updated_at":null,"is_active":"1","rand_string":null,"ecard_sent_status":"0","payable_employee":"0","file_id":null,"wellness_onboard":"0","name":"test name","relationship":"SELF","emp_code":"TEST_EMP_001","email_corporate":"test@gmail.com","mobile":"9797976565","dob":"1975-08-09"},{"id":12846,"employee_id":"TEST_EMP_001","client_policy_id":null,"tpa_id":null,"uhid":null,"batch_code":null,"status":"active","pre_existing_alignments":null,"age_band":null,"basic_cover_si":"0","date_coverage":"2025-01-01","policy_end_date":"2025-12-31","days":"0","premium":"0","rata_premimum":"0","gst":"0","si_enhancement_date":null,"date_of_exit":null,"reason_for_exit":null,"claim_status":"0","created_by":null,"created_at":null,"updated_by":null,"updated_at":null,"is_active":"1","rand_string":null,"ecard_sent_status":"0","payable_employee":"0","file_id":null,"wellness_onboard":"0","name":"dependent 1","relationship":"SON","emp_code":"TEST_EMP_001","email_corporate":"dependent1@gmail.com","mobile":"9898989898","dob":"2001-08-09"}]';
        // $data = (array)json_decode($data,true);
        // print_r(count($data));
        // echo '==============================';die();
        if(is_array($data) && count($data))
        {
            // $data = $input['data'] ?? [];

                // ------------------ GROUP BY FAMILY (emp_code) ------------------
                $families = [];   // [emp_code => [rows...]]

                foreach ($data as $row) {
                    if (empty($row['emp_code'])) {
                        // If emp_code is missing, you can skip or handle separately
                        continue;
                    }

                    $empCode = $row['emp_code'];
                    if (!isset($families[$empCode])) {
                        $families[$empCode] = [];
                    }
                    $families[$empCode][] = $row;
                }

            // print_rr($families);die();

            // ------------------ BUILD PAYLOAD FOR ALL FAMILIES ------------------
            $familiesPayload = [];

            foreach ($families as $empCode => $members) {
                $familiesPayload[$empCode] = $this->buildFamilyPayload($empCode, $members);
            }

            // print_rr($familiesPayload);die();
            $apiResponse = $this->sendFamiliesToWellnessApi($familiesPayload);
            // print_r($apiResponse);
            $updatedData = $this->updateWellnessOnboardResponseToDB($apiResponse);
            // print_r($updatedData);die();
            
            if (count($data) > 0) {
                $delaySeconds = max(1, (int)($arr['recursive_delay_seconds'] ?? 2));
                sleep($delaySeconds);

                $r = Jobs::addJob(['job_name' => 'initiateWellnessOnboardJob','payload' => [
                    'client_policy_id' => $client_policy_id,
                    'page' => $page + 1,
                    'per_page' => $perPage,
                    'recursive_delay_seconds' => $delaySeconds,
                ]]);

                // $this->initiateWellnessOnboardJob([
                //     'client_policy_id' => $client_policy_id,
                //     'page' => $page + 1,
                //     'per_page' => $perPage,
                //     'recursive_delay_seconds' => $delaySeconds,
                // ]);
            }

            return true;




        }
        else
        {
            if ($page > 1) {
                return true;
            }
            return $this->respond(['status' => false, 'code' => 200, 'message' => 'No employees found for wellness onboard!'], 200);

        }

    }


    public function initiateWellnessOnboardJob($arr)
    {
        $client_policy_id = $arr['client_policy_id'] ?? null;
        $emp_code = $arr['emp_code'] ?? null;

        if (!$client_policy_id) {
            log_message('error', '[WellnessOnboard] Missing client_policy_id in payload');
            return true;
        }

        $page    = max(1, (int)($arr['page'] ?? 1));
        $perPage = max(1, (int)($arr['per_page'] ?? 50));
        $offset  = ($page - 1) * $perPage;

        log_message('error', "[WellnessOnboard] Processing page {$page} | perPage {$perPage} | offset {$offset} | client_policy_id {$client_policy_id}");

        // ----------------------------------------------------------------
        // 1. FETCH DATA
        // ----------------------------------------------------------------
        $query = $this->employeePolicyModel
            ->select('employee_polices.*,
                      emp.name, emp.relationship, emp.emp_code, emp.email_corporate,
                      emp.mobile, emp.dob, emp.gender,
                      cp.policy_no, cp.wellness_plan_id, cp.wellness_vendor_id,
                      cp.policy_start_date as cp_policy_start_date, cp.policy_end_date,
                      cls.short_name')
            ->join('client_policy cp', 'cp.id = employee_polices.client_policy_id')
            ->join('clients cls',      'cp.client_id = cls.id')
            ->join('employees emp',    'emp.id = employee_polices.employee_id')
            ->where('employee_polices.is_active', 1)
            ->where('employee_polices.status', 'active')
            ->where('employee_polices.client_policy_id', $client_policy_id)
            // ->where('employee_polices.tpa_id is not null')
            ->where('employee_polices.wellness_onboard', '0')
            ->where('emp.emp_status', 'active')
            ->where('emp.is_active', 1)
            ->groupStart()
                ->where('cp.wellness_plan_id IS NOT NULL', null, false)
                ->orWhere('cp.wellness_plan_id !=', '')
                ->orWhere('cp.wellness_plan_id !=', 0)
            ->groupEnd()
            ->groupStart()
                ->where('cp.wellness_vendor_id IS NULL', null, false)
                ->orWhere('cp.wellness_vendor_id =', '')
                ->orWhere('cp.wellness_vendor_id =', 0)
            ->groupEnd()
            ->where('cp.policy_status', 1)
            ->where('cp.is_active', 1);

            if(!empty($emp_code)){
                $query->where('emp.emp_code', trim($emp_code));
            }

           $data = $query->findAll($perPage, $offset);

        // ----------------------------------------------------------------
        // 2. NO DATA FOUND
        // ----------------------------------------------------------------
        if (empty($data)) {
            log_message('error', "[WellnessOnboard] No data found on page {$page}. Batch complete.");
            return true; // always return true in job context, never $this->respond()
        }

        // ----------------------------------------------------------------
        // 3. GROUP BY FAMILY (emp_code)
        // ----------------------------------------------------------------
        $families = [];
        foreach ($data as $row) {
            if (empty($row['emp_code'])) {
                log_message('warning', '[WellnessOnboard] Skipping row with missing emp_code: ' . json_encode($row));
                continue;
            }
            $families[$row['emp_code']][] = $row;
        }

        if (empty($families)) {
            log_message('warning', "[WellnessOnboard] All rows on page {$page} had missing emp_code. Skipping.");
            return true;
        }

        // ----------------------------------------------------------------
        // 4. BUILD PAYLOAD
        // ----------------------------------------------------------------
        $familiesPayload = [];
        foreach ($families as $empCode => $members) {
            $familiesPayload[$empCode] = $this->buildFamilyPayload($empCode, $members);
        }
        log_message('error', "[WellnessOnboard] Page {$page} API calls done. Families processed: " . json_encode($familiesPayload));
        // ----------------------------------------------------------------
        // 5. SEND TO WELLNESS API
        // ----------------------------------------------------------------
        $apiResponse = $this->sendFamiliesToWellnessApi($familiesPayload);
        log_message('error', "[WellnessOnboard] Page {$page} API calls done. Families processed: " . count($apiResponse));

        // ----------------------------------------------------------------
        // 6. PERSIST RESPONSE TO DB
        // ----------------------------------------------------------------
        $updatedData = $this->updateWellnessOnboardResponseToDB($apiResponse);
        log_message('error', "[WellnessOnboard] Page {$page} DB update done.");

        // ----------------------------------------------------------------
        // 7. SPAWN NEXT PAGE JOB (only if this page was full)
        // ----------------------------------------------------------------
        if (count($data) === $perPage) {
            log_message('error', "[WellnessOnboard] Full page detected. Spawning job for page " . ($page + 1));
            Jobs::addJob([
                'job_name' => 'initiateWellnessOnboardJob',
                'payload'  => [
                    'client_policy_id' => $client_policy_id,
                    'page'             => $page + 1,
                    'per_page'         => $perPage,
                ]
            ]);
        } else {
            log_message('error', "[WellnessOnboard] Partial page ({$page}). This is the last page. Batch complete.");
        }

        return true;
    }

    public function resetWellnessOnboard($client_policy_id, $emp_code = null)
    {   
        if(!empty($emp_code)){

            $employees = db_connect()->table('employees')
                ->select('id')
                ->where('emp_code', trim($emp_code))
                ->get()
                ->getResult(); 

            if (!empty($employees)) {
                $employeeIds = array_column($employees, 'id');

                $this->employeePolicyModel
                    ->where('client_policy_id', $client_policy_id)
                    ->whereIn('employee_id', $employeeIds) 
                    ->set('wellness_onboard', '0')
                    ->update();
            }

        } else {
            $this->employeePolicyModel->where('client_policy_id', $client_policy_id)->set('wellness_onboard', '0')->update();
        }
        
        return $this->respond(['status' => true, 'code' => 200, 'message' => 'Wellness onboard resetted successfully'], 200);
    }



    # ------------------ FUNCTION TO BUILD FAMILY PAYLOAD ------------------
    /**
     * Build the required payload for a single family.
     *
     * @param string $empCode
     * @param array  $members  Array of rows for this emp_code
     * @return array
     */
    private function buildFamilyPayload(string $empCode, array $members): array
    {
        // Use the first member as primary reference for policy level data
        $primary = $members[0];
        // print_rr($primary);die();
        // Map DB fields to your required "policyDetails" structure
        $policyStartDate = $primary['cp_policy_start_date'] ?? null;
        // $policyStartDate = '2025-01-01';
        $policyEndDate   = $primary['policy_end_date'] ?? null;
        // $policyEndDate   = '2025-12-31';

        $payload = [
            "policyDetails" => [
                "policyNumber"    => $primary["policy_no"] ?? null,                              
                "employeeId"      => $empCode,
                "policyName"      => "GMC",              // Static or from DB
                "policyStartDate" => $policyStartDate,
                "policyEndDate"   => $policyEndDate,
                "plan"            => $primary["wellness_plan_id"] ?? null,
                "source"          => 'NHANCE',
                "employer"        => $primary['short_name'] ?? null,
                "employeeCode"    => $empCode,
                "accountNumber"   => "",                  // Fill from DB if available
                "ifsc"            => "",                       // Fill from DB if available
                "accountType"     => ""                          // Fill from DB if available
            ],
            "memberDetails" => []
        ];

        // Build "memberDetails" for each member in this family
        foreach ($members as $index => $row) {

            // You don't have gender in data, so put null or default
            

            $payload["memberDetails"][] = [
                "memberId"         => $row["id"],                       // or custom ID (e.g. employee_id.'-'.$index)
                "name"             => $row["name"],
                "phone"            => $row["mobile"],
                "email"            => $row["email_corporate"],
                "relationshipName" => $this->mapRelationship($row["relationship"],$row["gender"]),
                "gender"           => $row["gender"] == 'M' ? 'Male' : 'Female',
                "dob"              => $row["dob"]
            ];
        }

        return $payload;
    }


    function mapRelationship(string $relationship, ?string $gender = null): string
    {
        // Normalize input
        $key = strtolower(trim($relationship));
        $key = str_replace(['-', '_'], ' ', $key);
        $key = preg_replace('/\s+/', ' ', $key);

        // Base mapping
        $map = [
            'self' => 'self',
            'son' => 'son',
            'daughter' => 'daughter',
            'father' => 'father',
            'mother' => 'mother',
            'father in law' => 'father in law',
            'father-in-law' => 'father in law',
            'mother in law' => 'mother in law',
            'mother-in-law' => 'mother in law',
        ];

        // Special handling for spouse
        if ($key === 'spouse') {
            if ($gender === 'M') {
                return 'husband';
            }
            if ($gender === 'F') {
                return 'wife';
            }

            // fallback if gender missing (better to throw error)
            throw new \Exception("Gender required to map 'Spouse'");
        }

        return $map[$key] ?? '';
    }


    /**
     * Send each family payload to API and attach the response
     *
     * @param array  $familiesPayload  [emp_code => ['policyDetails' => ..., 'memberDetails' => [...]]]
     * @return array  Same array but with ['apiResponse'] added for each family
     */
    public function sendFamiliesToWellnessApi(array $familiesPayload): array
    {
        // CI4 HTTP client
        // print_rr($familiesPayload);die();
        $client =  \Config\Services::curlrequest();//die();
        $endpointUrl = getenv('WELLNESS_ONBOARD_ENDPOINT_URL');
        // Custom headers
        $headers = [
            'Content-Type'  => 'application/json',
            'Authorization'     => 'Basic ' . getenv('WELLNESS_ONBOARD_AUTHORIZATION')
        ];

        foreach ($familiesPayload as $empCode => &$family) {
             // print_rr($family);die();
            try {
                $response = $client->post($endpointUrl, [
                    'headers' => $headers,
                    'body'    => json_encode($family),
                    'http_errors' => false,    // so we can handle non-2xx manually
                    'timeout' => 30,
                ]);

                $statusCode = $response->getStatusCode();
                $body       = (string) $response->getBody();
                $decoded    = json_decode($body, true);

                $family['apiResponse'] = [
                    'statusCode' => $statusCode,
                    'rawBody'    => $body,
                    'data'       => $decoded,
                ];


            } catch (\Throwable $e) {
                // In case of exception, store error info
                $family['apiResponse'] = [
                    'statusCode' => 0,
                    'rawBody'    => null,
                    'data'       => null,
                    'error'      => $e->getMessage(),
                ];
            }

              // print_rr($body );die();
        }

        unset($family); // break reference

        return $familiesPayload;
    }



    /**
     * Batch update wellness_onboard for each family using referenceId from API response.
     *
     * @param array $familiesWithResponse  // output of sendFamiliesToApi()
     * @return void
     */
    public function updateWellnessOnboardResponseToDB(array $familiesWithResponse = []): void
    {
        // echo 'START';
        // Collect all rows to update in a single big batch (optional but efficient)
        $allUpdates = [];

        //  $apiResponse = [
        //     "message" => "success",
        //     "body" => "The policy details are posted successfully",
        //     "policyDetails" => [
        //         [
        //             "memberId"         => "12847",
        //             "name"             => "test name",
        //             "phone"            => 9797976565,
        //             "email"            => "test@gmail.com",
        //             "relationshipName" => "SELF",
        //             "gender"           => "MALE",
        //             "dob"              => "1975-08-09"
        //         ],
        //         [
        //             "memberId"         => "12846",
        //             "name"             => "dependent 1",
        //             "phone"            => 9898989898,
        //             "email"            => "dependent1@gmail.com",
        //             "relationshipName" => "SON",
        //             "gender"           => "MALE",
        //             "dob"              => "2001-08-09"
        //         ]
        //     ],
        //     "referenceId" => "TESTPOL001-client1-1764914537069"
        // ];

        // $familiesWithResponse = [ 

        //         "TEST_EMP_001" => [
        //             "policyDetails" => [
        //                 "policyNumber"    => "TESTPOL001",
        //                 "employeeId"      => "TEST_EMP_001",
        //                 "policyName"      => "Client Policy Name",
        //                 "policyStartDate" => "2025-01-01",
        //                 "policyEndDate"   => "2025-12-31",
        //                 "plan"            => "plan-A",
        //                 "source"          => "client1",
        //                 "employer"        => "employeer1",
        //                 "employeeCode"    => "TEST_EMP_001",
        //                 "accountNumber"   => "",
        //                 "ifsc"            => "",
        //                 "accountType"     => ""
        //             ],
        //             "memberDetails" => [
        //                 [
        //                     "memberId"         => "12847",
        //                     "name"             => "test name",
        //                     "phone"            => 9797976565,
        //                     "email"            => "test@gmail.com",
        //                     "relationshipName" => "SELF",
        //                     "gender"           => "MALE",
        //                     "dob"              => "1975-08-09"
        //                 ],
        //                 [
        //                     "memberId"         => "12846",
        //                     "name"             => "dependent 1",
        //                     "phone"            => 9898989898,
        //                     "email"            => "dependent1@gmail.com",
        //                     "relationshipName" => "SON",
        //                     "gender"           => "MALE",
        //                     "dob"              => "2001-08-09"
        //                 ]
        //             ],

        //             "apiResponse" => [ 'statusCode' => 200 ,"rawBody" => "", "data" => $apiResponse]
        //         ]
        // ];

      

        foreach ($familiesWithResponse as $empCode => $family) {

            $apiResponse = $family['apiResponse'] ?? null;
            if (!$apiResponse || !isset($apiResponse['data'])) {
                // No valid API data for this family
                 $this->myLogger->logme('error', "Wellness Onboard API error for emp_code {$empCode} No apiResponse found:");
                continue;
            }

             // Your endpoint response
            $statusCode = $apiResponse['statusCode'] ?? null;
            if (empty($statusCode) || $statusCode == 400 || $statusCode == 500) {
                $this->myLogger->logme('error', "Wellness Onboard API error for emp_code {$empCode} {}: " . ($apiResponse['rawBody'] ?? 'No response'));
                
                // No referenceId, nothing to update
                continue;
            }

            $data = $apiResponse['data'];

            // Your endpoint response
            $referenceId = $data['referenceId'] ?? null;
            if (empty($referenceId)) {
                // No referenceId, nothing to update
                $this->myLogger->logme('error', "Wellness Onboard API error for emp_code {$empCode} No referenceId found:");
                continue;
            }

            // All members in this family share the same referenceId
            if (empty($family['memberDetails']) || !is_array($family['memberDetails'])) {
                $this->myLogger->logme('error', "Wellness Onboard API error for emp_code {$empCode} No memberDetails found:");
                continue;
            }

            foreach ($family['memberDetails'] as $member) {
                $memberPk = $member['memberId'] ?? null;   // This is employee_policy.id

                if (empty($memberPk)) {
                    continue;
                }

                $allUpdates[] = [
                    'id'               => $memberPk,      // PK column of your table
                    'wellness_onboard' => $referenceId,
                    // uncomment if you have updated_at column
                    // 'updated_at'        => date('Y-m-d H:i:s'),
                ];
            }
        }
        // print_r($allUpdates);die();
        // Do a single batch update for all families/members
        log_message('error','[WellnessOnboard] DB update data - ' . json_encode($allUpdates));
        if (!empty($allUpdates)) {
            // 2nd param is the key to match on; here it's 'id'
            $this->employeePolicyModel->updateBatch($allUpdates, 'id');
        }
    }

    public function getTPADataVariationReport($file_id, $type = 'download')
    {
        // print_rr($this->initializeDeletionProcessForTpaApiData($file_id));
        // die;
        $fileInfo = $this->batchFileModel->find((int) $file_id);
        if (empty($fileInfo)) {
            if ($type === 'view') {
                return [];
            }
            if ($type === 'download') {
                return false;
            }

            return $this->respond(['status' => false, 'code' => 404, 'message' => 'File not found', 'data' => []], 200);
        }

        $client_id = (int) ($fileInfo['client_id'] ?? 0);
        $client_policy_id = (int) ($fileInfo['client_policy_id'] ?? 0);
        // `call_type` controls whether we should force a fresh reconciliation.
        // - job    => always recompute + persist rec_type snapshot
        // - manual => compute only on first call; otherwise use cached rec_type snapshot
        // $callType = strtolower((string) ($this->request->getGet('call_type') ?? 'manual'));
        $isJobCall = $type === 'job';

        $tpaApiDataModel = new TpaApiDataModel();
        // Snapshot existence check:
        // If any active row already has a non-empty rec_type, we consider this file
        // already classified and can safely use cached mode for non-job calls.
        $hasRecTypeSnapshot = $tpaApiDataModel->where('file_id', $file_id)
            ->where('is_active', 1)
            ->where('rec_type IS NOT NULL', null, false)
            ->where('rec_type !=', '')
            ->countAllResults() > 0;

        // Compute mode rules:
        // 1) job calls always recompute and overwrite rec_type for deterministic refresh.
        // 2) first non-job call computes when no snapshot exists.
        // Cached mode is used only for second+ non-job calls.
        $shouldComputeAndPersist = $isJobCall || !$hasRecTypeSnapshot;
        // echo $shouldComputeAndPersist;
        // die;
        $this->myLogger->logme(
            'error',
            'TPA variation report mode selected: ' . json_encode([
                'file_id' => (int) $file_id,
                'call_type' => $isJobCall,
                'mode' => $shouldComputeAndPersist ? 'compute' : 'cached',
            ])
        );
        $emp_data_wo_tpa_id = [];
        $not_in_nhance = [];

        if ($shouldComputeAndPersist) {
            // Load once and index in memory to avoid N+1 queries during reconciliation.
            $allActiveTpaRows = $tpaApiDataModel->select('*')
                ->where('file_id', $file_id)
                ->where('is_active', 1)
                ->findAll();

            $tpaByEmpCode = [];
            foreach ($allActiveTpaRows as $tpaRow) {
                $tpaByEmpCode[$tpaRow['emp_code']][] = $tpaRow;
            }

            $recTypeById = [];
            foreach ($allActiveTpaRows as $tpaRow) {
                // Default classification for active rows.
                // Later loops will overwrite specific rows as `need_to_review` or `not_in_nhance`.
                $recTypeById[$tpaRow['id']] = 'matched';
            }

            $emp_data_wo_tpa_id = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id);

            // Reconcile DB records against TPA records and classify records for rec_type updates.
            $consumedTpaIdsByEmpCode = [];
            foreach ($emp_data_wo_tpa_id as $db_key => $db_row) {
                $empCode = (string) ($db_row['emp_code'] ?? '');
                $empId = (string) ($db_row['id'] ?? '');
                $empName = (string) ($db_row['name'] ?? '');
                $tpa_temp_data = $tpaByEmpCode[$empCode] ?? [];
                $excludeTpaIds = $consumedTpaIdsByEmpCode[$empCode] ?? [];
                $match = $this->reconcileDbWithTpa($db_row, $tpa_temp_data, $excludeTpaIds);
                $emp_data_wo_tpa_id[$db_key]['match'] = $match;

                if (($match['status'] ?? '') === 'matched') {
                    $matchedTpaId = (int) ($match['tpa_record']['id'] ?? 0);
                    // echo 'matched' . $matchedTpaId . ' for emp_code ' . $empCode . PHP_EOL . '
'; if ($matchedTpaId > 0) { $consumedTpaIdsByEmpCode[$empCode][] = $matchedTpaId; // If compare-fields list has differences, the row must be reviewed. // Otherwise keep it as matched. $recTypeById[$matchedTpaId] = empty($match['not_matching']) ? 'matched' : 'need_to_review'; } } else { // echo 'not matched' . ' for emp_code ' . $empCode . PHP_EOL . ' - ' . $empId . ' - ' . $empName . ' - ' . '
'; // No match for this DB member: flag same-relation TPA rows not already paired. $dbRel = strtolower(trim((string) ($db_row['relationship'] ?? ''))); foreach ($tpa_temp_data as $candidate) { if (strtolower(trim((string) ($candidate['relation'] ?? ''))) !== $dbRel) { continue; } $candidateId = (int) ($candidate['id'] ?? 0); if ($candidateId > 0 && !in_array($candidateId, $excludeTpaIds, true)) { $recTypeById[$candidateId] = ''; } } } } $master_emp_codes = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id, [], true); $master_emp_codes = array_column($master_emp_codes, 'emp_code'); $not_in_nhance = []; foreach ($allActiveTpaRows as $tpaRow) { if (!in_array($tpaRow['emp_code'], $master_emp_codes, true)) { // TPA member not found in Nhance master employee list for this client/policy. $not_in_nhance[] = $tpaRow; $recTypeById[(int) $tpaRow['id']] = 'not_in_nhance'; } } if (!empty($recTypeById)) { $updateRows = []; foreach ($recTypeById as $id => $recType) { $updateRows[] = [ 'id' => (int) $id, 'rec_type' => $recType, ]; } // Persist snapshot atomically so subsequent non-job calls can use cached mode. $db = \Config\Database::connect(); $db->transStart(); $tpaApiDataModel->updateBatch($updateRows, 'id'); $db->transComplete(); } // this will match tpa api data with emp/emp policy table and update ref in tpa api data once $this->reconTpaApiDataWithEmployeepolicies(['file_id' => $file_id]); } else { // Cached mode: // `not_in_nhance` stays sourced from persisted rec_type snapshot. // `mismatch_data` must match compute-mode shape: every policy row with // tpa_id NULL gets reconcileDbWithTpa against *all* active TPA rows for // that emp_code (not only rows flagged need_to_review), otherwise second+ // loads drop rows / lose not_matching vs the first compute pass. $not_in_nhance = $tpaApiDataModel->select('*') ->where('is_active', 1) ->where('file_id', $file_id) ->where('rec_type', 'not_in_nhance') ->findAll(); $allActiveTpaRowsCached = $tpaApiDataModel->select('*') ->where('file_id', $file_id) ->where('is_active', 1) ->findAll(); $tpaByEmpCodeCached = []; foreach ($allActiveTpaRowsCached as $tpaRow) { $tpaByEmpCodeCached[$tpaRow['emp_code']][] = $tpaRow; } $emp_data_wo_tpa_id = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id); $consumedTpaIdsByEmpCodeCached = []; foreach ($emp_data_wo_tpa_id as $db_key => $db_row) { $empCode = (string) ($db_row['emp_code'] ?? ''); $tpa_temp_data = $tpaByEmpCodeCached[$empCode] ?? []; $excludeTpaIds = $consumedTpaIdsByEmpCodeCached[$empCode] ?? []; $match = $this->reconcileDbWithTpa($db_row, $tpa_temp_data, $excludeTpaIds); $emp_data_wo_tpa_id[$db_key]['match'] = $match; if (($match['status'] ?? '') === 'matched') { $matchedTpaId = (int) ($match['tpa_record']['id'] ?? 0); if ($matchedTpaId > 0) { $consumedTpaIdsByEmpCodeCached[$empCode][] = $matchedTpaId; } } } } // print_rr($emp_data_wo_tpa_id);die(); // Intentionally keep `not_in_tpa` live from current join/query logic // (as requested) and do not source it from rec_type snapshot. $tpa_emp_codes = $tpaApiDataModel->select('ref') ->where('file_id', $file_id) ->where('is_active', 1) ->groupBy('ref') ->findAll(); // $tpa_emp_codes = array_column($tpa_emp_codes, 'ref'); $tpa_ref = array_column($tpa_emp_codes, 'ref'); $not_in_tpa = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id, $tpa_ref); // Format dates for UI/export (dd/mm/yyyy). Applied after reconciliation so // reconcileDbWithTpa can still compare raw Y-m-d values from the database. $this->formatVariationReportDataForDisplay($not_in_tpa, $not_in_nhance, $emp_data_wo_tpa_id); if (!empty($not_in_tpa) || !empty($not_in_nhance) || !empty($emp_data_wo_tpa_id)) { $not_in_nhance_button_enable_status = false; if (count($not_in_nhance)) { foreach ($not_in_nhance as $nih) { $hasRefKey = array_key_exists('ref', $nih); $ref = $hasRefKey ? $nih['ref'] : null; $refIsEmpty = $ref === null || $ref === ''; if ($refIsEmpty) { $not_in_nhance_button_enable_status = true; break; } } } $not_in_nhance_inception_count = 0; $not_in_nhance_deletion_count = 0; foreach ($not_in_nhance as $nih) { $hasRefKey = array_key_exists('ref', $nih); $ref = $hasRefKey ? $nih['ref'] : null; // Empty/null ref: no key, NULL, '', or whitespace-only string. $refIsEmpty = !$hasRefKey || $ref === null || $ref === '' || (is_string($ref) && trim($ref) === ''); $actionIsDeletion = strtoupper(trim((string) ($nih['action_flag_status'] ?? ''))) === 'D'; // Every empty/null ref row counts as inception; those that also have flag D additionally count as deletion. if ($refIsEmpty) { $not_in_nhance_inception_count++; if ($actionIsDeletion) { $not_in_nhance_deletion_count++; } } } $not_in_nhance_proceed_button_text = sprintf( 'Proceed - Inception(%d) + Deletion(%d)', $not_in_nhance_inception_count, $not_in_nhance_deletion_count ); $not_matched_count = 0; $not_matched_data = []; foreach ($emp_data_wo_tpa_id as $key => $row) { $notMatching = $row['match']['not_matching'] ?? []; if (isset($row['match']) && is_array($notMatching) && $notMatching !== []) { $not_matched_count++; $not_matched_data[] = $row; } } $need_to_review_proceed_button_text = sprintf( 'Proceed - Need to Review ( %d )', $not_matched_count ); $response = [ 'not_in_tpa' => $not_in_tpa, 'not_in_nhance' => $not_in_nhance, 'mismatch_data' => $emp_data_wo_tpa_id, 'not_in_nhance_button_enable_status' => $not_in_nhance_button_enable_status, 'not_in_nhance_inception_count' => $not_in_nhance_inception_count, 'not_in_nhance_deletion_count' => $not_in_nhance_deletion_count, 'not_in_nhance_proceed_button_text' => $not_in_nhance_proceed_button_text, 'not_matched_count' => $not_matched_count, 'not_matched_data' => $not_matched_data, 'need_to_review_proceed_button_text' => $need_to_review_proceed_button_text, ]; if ($type === 'view') { return $this->respond(['status' => true, 'code' => 200, 'message' => '', 'data' => $response], 200); } elseif ($type === 'download') { $this->exportVariationReportExcel($not_in_tpa, $not_in_nhance, $emp_data_wo_tpa_id); } else { return $this->respond(['status' => true, 'code' => 200, 'message' => '', 'data' => $response], 200); } } else { if ($type === 'view') { return []; } if ($type === 'download') { return false; } return $this->respond(['status' => false, 'code' => 202, 'message' => 'No data found', 'data' => []], 200); } } public function proceedTPADataVariationNextStep($file_id) { // echo $file_id;die; try { if (empty($file_id)) { return $this->respond( [ 'status' => false, 'code' => 400, 'message' => 'Invalid file reference', 'data' => [], ], 200 ); } $file = $this->batchFileModel->find($file_id); if (!$file) { return $this->respond( [ 'status' => false, 'code' => 404, 'message' => 'File not found', 'data' => [], ], 200 ); } $tab = $this->request->getGet('tab'); // If the user is proceeding from the "Not in Nhance" tab, // generate an Employee Upload with Events compatible Excel file // and trigger the usual upload pipeline. if ($tab === 'not_in_nhance') { $generationResult = $this->generateEmployeeUploadFromNotInNhance((int) $file_id, $file); if (!$generationResult['status']) { return $this->respond( [ 'status' => false, 'code' => 422, 'message' => $generationResult['message'] ?? 'Unable to generate employee upload file from Not in Nhance data.', 'data' => $generationResult['data'] ?? [], ], 200 ); } if($generationResult['status']) { if($generationResult['data']['file_id']) { // sleep(1); //initiate update references b/w tpa_api_data and employess (pk update) // $this->reconTpaApiDataWithEmployeepolicies(['file_id' => $file_id]); // sleep(1); //initiate deleteion if any // $this->initializeDeletionProcessForTpaApiData(['file_id' => $file_id]); } else { //seems inception file id not there just put a log $this->myLogger->logme( 'error', 'TPA RECON | Inception file id missing after generating employee upload from Not in Nhance data for file_id:' ); } } } elseif ($tab === 'need_to_review') { // For the "Need to Review" tab, generate a Correction Excel // using the same overall pipeline as the Not in Nhance implementation. // $generationResult = $this->generateCorrectionUploadFromNeedToReview((int) $file_id, $file); //once correction file uploaded success fully update ref id b/w employeetable and tpaapi data $generationResult = $this->updateEmployeeDataFromTpa(['batch_file_id' => (int) $file_id]); if (empty($generationResult['success'])) { return $this->respond( [ 'status' => false, 'code' => 422, 'message' => $generationResult['message'] ?? 'Unable to process the data from Need to Review tab.', 'data' => $generationResult['data'] ?? [], ], 200 ); } } $this->myLogger->logme( 'error', 'TPA variation review completed and proceed to next clicked' . json_encode( [ 'file_id' => $file_id, 'user_id' => get_session_userid(), 'tab' => $tab, ] ) ); return $this->respond( [ 'status' => true, 'code' => 200, 'message' => $tab === 'not_in_nhance' ? 'Employee upload file generated from Not in Nhance data and queued for processing.' : ($tab === 'need_to_review' ? 'Review data update successfully.' : 'Proceed to next step recorded successfully.'), 'data' => [], ], 200 ); } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'Error while processing TPA variation proceed to next: ' . $e->getMessage(), ['file_id' => $file_id] ); return $this->respond( [ 'status' => false, 'code' => 500, 'message' => 'Unable to proceed to the next step at the moment.', 'data' => [], ], 200 ); } } /** * Generate an Employee Upload with Events compatible Excel file * from the Not in Nhance TPA variation data and push it into the * existing employee upload pipeline. * * @param int $batchFileId Batch file id used for TPA variation report. * @param array $batchFile Batch file row from DB. * * @return array ['status' => bool, 'message' => string, 'data' => array] */ protected function generateEmployeeUploadFromNotInNhance(int $batchFileId, array $batchFile): array { try { $clientId = (int) ($batchFile['client_id'] ?? 0); $clientPolicyId = (int) ($batchFile['client_policy_id'] ?? 0); $clientBranchId = (int) ($batchFile['client_branch_id'] ?? 0); if (!$clientId || !$clientPolicyId || !$clientBranchId) { return [ 'status' => false, 'message' => 'Incomplete batch file information. Client / policy / branch missing.', 'data' => [], ]; } $TpaApiDataModel = new TpaApiDataModel(); // Get master emp codes from Nhance for this client & policy $masterEmpRows = $this->employeePolicyModel->getTPADataVariationReport($clientId,$clientPolicyId,$batchFileId,[],true); if (!is_array($masterEmpRows)) { $masterEmpRows = []; } $masterEmpCodes = array_column($masterEmpRows, 'emp_code'); // Fetch Not in Nhance rows for this batch file $notInNhance = $TpaApiDataModel->select('*') ->where('is_active', 1) ->where('file_id', $batchFileId) ->whereNotIn('emp_code', $masterEmpCodes) ->findAll(); if (empty($notInNhance)) { return [ 'status' => false, 'message' => 'No "Not in Nhance" records found for this file.', 'data' => [], ]; } $empServiceController = new EmployeeServiceController(); $inceptionColumns = $empServiceController->getInceptionExcelColumns(); if (empty($inceptionColumns)) { return [ 'status' => false, 'message' => 'Unable to load inception Excel column configuration.', 'data' => [], ]; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('Employees'); // Header row from EmployeeServiceController column definitions $colIndex = 1; foreach ($inceptionColumns as $columnDef) { $headerText = $columnDef['col_name'] ?? ''; $columnLetter = Coordinate::stringFromColumnIndex($colIndex); $sheet->setCellValue($columnLetter . '1', $headerText); $colIndex++; } // Helper to safely format dates as d-M-Y when possible $formatDate = static function ($value): string { if (empty($value)) { return ''; } $ts = strtotime($value); if ($ts === false) { return (string) $value; } return date('d-M-Y', $ts); }; // Map Not in Nhance TPA rows into the inception Excel structure $rowIndex = 2; $sno = 1; foreach ($notInNhance as $tpaRow) { $colIndex = 1; foreach ($inceptionColumns as $key => $columnDef) { $value = ''; switch ($key) { case 'sno': $value = $sno; break; case 'emp_id': $value = $tpaRow['emp_code'] ?? ''; break; case 'name_of_emp_dep': $value = $tpaRow['name'] ?? ''; break; case 'dob': $value = $formatDate($tpaRow['dob'] ?? ''); break; case 'gender': $value = $tpaRow['gender'] ?? ''; break; case 'relationship': // Normalize relation text to match allowed values $relation = (string) ($tpaRow['relation'] ?? ''); $relation = trim(strtolower($relation)); $map = [ 'self' => 'Self', 'employee' => 'Self', 'spouse' => 'Spouse', 'wife' => 'Spouse', 'husband' => 'Spouse', 'son' => 'Son', 'daughter' => 'Daughter', 'father' => 'Father', 'mother' => 'Mother', 'father-in-law' => 'Father in Law', 'father in law' => 'Father in Law', 'mother-in-law' => 'Mother in Law', 'mother in law' => 'Mother in Law', ]; $value = $map[$relation] ?? ($tpaRow['relation'] ?? ''); break; case 'basic_cover_si': $value = $tpaRow['si'] ?? ''; break; case 'doc': // Use DOJ from TPA data as Date of Coverage best-effort $value = $formatDate($tpaRow['doj'] ?? ''); break; case 'doj': $value = $formatDate($tpaRow['doj'] ?? ''); break; case 'pre_existing_ailments': // Default to "0" (No) so validation passes for mandatory field $value = '0'; break; case 'change_event': // For addition / dependent_addition, this is mandatory. $value = 'addition'; break; default: // Non-mapped columns (phone, email, etc.) left blank by default. $value = ''; break; } $columnLetter = Coordinate::stringFromColumnIndex($colIndex); $sheet->setCellValue($columnLetter . $rowIndex, $value); $colIndex++; } $rowIndex++; $sno++; } // Auto-size columns $totalColumns = count($inceptionColumns); for ($c = 1; $c <= $totalColumns; $c++) { $columnLetter = Coordinate::stringFromColumnIndex($c); $sheet->getColumnDimension($columnLetter)->setAutoSize(true); } // Persist the Excel file to the same folder used by manual uploads $fileName = sprintf( 'not_in_nhance_employee_upload_%d_%s.xlsx', $batchFileId, date('Ymd_His') ); $filePath = WRITEPATH . 'uploads/excel/' . $fileName; if (! is_dir(WRITEPATH . 'uploads/excel')) { mkdir(WRITEPATH . 'uploads/excel', 0755, true); } $writer = new Xlsx($spreadsheet); $writer->save($filePath); storage_mirror_generated_file($filePath, WRITEPATH . 'uploads/excel', $fileName); // Create a new entry in the files table so that the // existing Employee Upload with Events pipeline can process it. $loggedInUserId = $batchFile['created_by'] ?? get_session_userid(); $action = 'addition'; $newFileId = $this->fileModel->insert([ 'file_name' => $fileName, 'client_id' => $clientId, 'policy_id' => $clientPolicyId, 'created_by' => $loggedInUserId, 'status' => 'inprogress', 'action' => $action, 'client_branch_id'=> $clientBranchId, 'uploaded_by' => 1, 'hr_file_id' => null, 'hr_id' => null, ]); if (!$newFileId || !is_numeric($newFileId)) { $this->myLogger->logme( 'error', 'Failed to insert generated Not in Nhance employee upload file into files table', [ 'batch_file_id' => $batchFileId, 'client_id' => $clientId, 'client_policy_id' => $clientPolicyId, 'client_branch_id' => $clientBranchId, 'file_name' => $fileName, 'insert_result' => $newFileId, ] ); return [ 'status' => false, 'message' => 'Unable to create file record for generated employee upload.', 'data' => [], ]; } // Run the same format validation used for manual uploads. $validationResult = $empServiceController->excelFileFormatValidation(['file_id' => $newFileId, 'batch_file_id' => $batchFileId]); if (isset($validationResult['error_summary']) && count($validationResult['error_summary'])) { return [ 'status' => false, 'message' => 'File upload was successful, but file format validation failed. Please review the error report.', 'data' => ['file_id' => $newFileId], ]; } return [ 'status' => true, 'message' => 'Employee upload file generated from Not in Nhance data and queued for processing.', 'data' => ['file_id' => $newFileId], ]; } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'Error while generating employee upload from Not in Nhance'. json_encode( [ 'batch_file_id' => $batchFileId, 'exception_message' => $e->getMessage(), 'exception_file' => $e->getFile(), 'exception_line' => $e->getLine(), 'exception_trace' => $e->getTraceAsString(), 'client_id' => $batchFile['client_id'] ?? null, 'client_policy_id' => $batchFile['client_policy_id'] ?? null, 'client_branch_id' => $batchFile['client_branch_id'] ?? null, ], JSON_PRETTY_PRINT) ); return [ 'status' => false, 'message' => 'Unexpected error while generating employee upload file.', 'data' => [], ]; } } /** * Generate a Correction Excel file from the Need to Review * TPA variation data and push it into the existing correction * upload pipeline. * * Each mismatched field (name, dob, relationship, email_corporate) * becomes a separate row in the Excel, using the correction * headers defined in EmployeeServiceController::$correction_excel_columns. * * @param int $batchFileId Batch file id used for TPA variation report. * @param array $batchFile Batch file row from DB. * * @return array ['status' => bool, 'message' => string, 'data' => array] */ protected function generateCorrectionUploadFromNeedToReview(int $batchFileId, array $batchFile): array { try { $clientId = (int) ($batchFile['client_id'] ?? 0); $clientPolicyId = (int) ($batchFile['client_policy_id'] ?? 0); $clientBranchId = (int) ($batchFile['client_branch_id'] ?? 0); if (!$clientId || !$clientPolicyId || !$clientBranchId) { return [ 'status' => false, 'message' => 'Incomplete batch file information. Client / policy / branch missing.', 'data' => [], ]; } $TpaApiDataModel = new TpaApiDataModel(); // Reuse the same DB + TPA reconciliation used in getTPADataVariationReport $dbRows = $this->employeePolicyModel->getTPADataVariationReport( $clientId, $clientPolicyId, $batchFileId ); if (!is_array($dbRows) || !count($dbRows)) { return [ 'status' => false, 'message' => 'No employee data found for Need to Review.', 'data' => [], ]; } $mismatchRows = []; $consumedTpaIdsByEmpCode = []; foreach ($dbRows as $dbRow) { $empCode = (string) ($dbRow['emp_code'] ?? ''); $tpaRows = $TpaApiDataModel->select('*') ->where('emp_code', $empCode) ->where('file_id', $batchFileId) ->where('is_active', 1) ->findAll(); if (!count($tpaRows)) { continue; } $excludeTpaIds = $consumedTpaIdsByEmpCode[$empCode] ?? []; $match = $this->reconcileDbWithTpa($dbRow, $tpaRows, $excludeTpaIds); if (($match['status'] ?? '') === 'matched') { $matchedTpaId = (int) ($match['tpa_record']['id'] ?? 0); if ($matchedTpaId > 0) { $consumedTpaIdsByEmpCode[$empCode][] = $matchedTpaId; } } if (($match['status'] ?? '') !== 'matched') { continue; } $tpaRecord = $match['tpa_record'] ?? []; $notMatching = $match['not_matching'] ?? []; if (!is_array($notMatching) || !count($notMatching)) { continue; } // Only consider fields that are supported by the correction Excel headers $allowedFields = ['name', 'dob', 'relationship', 'email_corporate']; foreach ($notMatching as $field) { if (!in_array($field, $allowedFields, true)) { continue; } $mismatchRows[] = [ 'emp_code' => $dbRow['emp_code'] ?? '', 'name' => $dbRow['name'] ?? '', 'field' => $field, // Use TPA value as the corrected value to be applied in Nhance 'value' => $tpaRecord[$field] ?? '', ]; } } if (!count($mismatchRows)) { return [ 'status' => false, 'message' => 'No mismatched records found to generate correction upload.', 'data' => [], ]; } $empServiceController = new EmployeeServiceController(); $correctionColumns = $empServiceController->getCorrectionExcelColumns(); if (empty($correctionColumns)) { return [ 'status' => false, 'message' => 'Unable to load correction Excel column configuration.', 'data' => [], ]; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('Correction'); // Header row from EmployeeServiceController column definitions $colIndex = 1; foreach ($correctionColumns as $columnDef) { $headerText = $columnDef['col_name'] ?? ''; $columnLetter = Coordinate::stringFromColumnIndex($colIndex); $sheet->setCellValue($columnLetter . '1', $headerText); $colIndex++; } $todayDisplay = date('d-M-Y'); $rowIndex = 2; $sno = 1; foreach ($mismatchRows as $row) { $colIndex = 1; $field_name = $row['field'] ?? ''; $field_value = ($field_name == 'dob' ? change_date_format($row['value'] ?? '', 'Y-m-d', 'd-M-Y') : $row['value'] ?? '' ); foreach ($correctionColumns as $key => $columnDef) { $value = ''; switch ($key) { case 'sno': $value = $sno; break; case 'emp_id': $value = $row['emp_code'] ?? ''; break; case 'name_of_emp_dep': $value = $row['name'] ?? ''; break; case 'field': $value = $field_name; break; case 'value': $value = $field_value ?? ''; break; case 'date_of_correction': $value = $todayDisplay; break; case 'change_event': $value = 'correction'; break; case 'remarks': $value = ''; break; default: $value = ''; break; } $columnLetter = Coordinate::stringFromColumnIndex($colIndex); $sheet->setCellValue($columnLetter . $rowIndex, $value); $colIndex++; } $rowIndex++; $sno++; } // Auto-size columns $totalColumns = count($correctionColumns); for ($c = 1; $c <= $totalColumns; $c++) { $columnLetter = Coordinate::stringFromColumnIndex($c); $sheet->getColumnDimension($columnLetter)->setAutoSize(true); } // Persist the Excel file to the same folder used by manual uploads $fileName = sprintf( 'need_to_review_correction_upload_%d_%s.xlsx', $batchFileId, date('Ymd_His') ); $filePath = WRITEPATH . 'uploads/excel/' . $fileName; if (! is_dir(WRITEPATH . 'uploads/excel')) { mkdir(WRITEPATH . 'uploads/excel', 0755, true); } $writer = new Xlsx($spreadsheet); $writer->save($filePath); storage_mirror_generated_file($filePath, WRITEPATH . 'uploads/excel', $fileName); // Insert into files table so the existing correction pipeline can process it. $loggedInUserId = $batchFile['created_by'] ?? get_session_userid(); $newFileId = $this->fileModel->insert([ 'file_name' => $fileName, 'client_id' => $clientId, 'policy_id' => $clientPolicyId, 'created_by' => $loggedInUserId, 'status' => 'inprogress', 'action' => 'correction', 'client_branch_id'=> $clientBranchId, 'uploaded_by' => 1, 'hr_file_id' => null, 'hr_id' => null, ]); if (!$newFileId || !is_numeric($newFileId)) { $this->myLogger->logme( 'error', 'Failed to insert generated Need to Review correction upload file into files table', [ 'batch_file_id' => $batchFileId, 'client_id' => $clientId, 'client_policy_id' => $clientPolicyId, 'client_branch_id' => $clientBranchId, 'file_name' => $fileName, 'insert_result' => $newFileId, ] ); return [ 'status' => false, 'message' => 'Unable to create file record for generated correction upload.', 'data' => [], ]; } // Run the same format validation used for manual uploads so that // the correction file enters the normal processing pipeline. $validationResult = $empServiceController->excelFileFormatValidation(['file_id' => $newFileId]); if (isset($validationResult['error_summary']) && count($validationResult['error_summary'])) { return [ 'status' => false, 'message' => 'File upload was successful, but correction file format validation failed. Please review the error report.', 'data' => ['file_id' => $newFileId], ]; } return [ 'status' => true, 'message' => 'Correction upload file generated from Need to Review data and queued for processing.', 'data' => ['file_id' => $newFileId], ]; } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'Error while generating correction upload from Need to Review'. json_encode( [ 'batch_file_id' => $batchFileId, 'exception_message' => $e->getMessage(), 'exception_file' => $e->getFile(), 'exception_line' => $e->getLine(), 'exception_trace' => $e->getTraceAsString(), 'client_id' => $batchFile['client_id'] ?? null, 'client_policy_id' => $batchFile['client_policy_id'] ?? null, 'client_branch_id' => $batchFile['client_branch_id'] ?? null, ], JSON_PRETTY_PRINT ) ); return [ 'status' => false, 'message' => 'Unexpected error while generating correction upload file.', 'data' => [], ]; } } /** * Apply TPA values to `employees` for rows in the same "Need to Review" set as * {@see generateCorrectionUploadFromNeedToReview}: same `getTPADataVariationReport` slice, * same `reconcileDbWithTpa` matching, then persist mismatched fields from TPA instead of * generating a correction Excel. * * Updatable fields mirror the correction Excel allow-list where they exist on TPA rows: * `name`, `dob`, `gender`, `relationship` (from TPA `relation`), `email_corporate` (if present on TPA). * Note: {@see reconcileDbWithTpa} only pairs rows when DB `relationship` matches TPA `relation`, * so `relationship` rarely appears in `not_matching`; name/dob/gender are the usual diffs. * * @param array $params Expects `batch_file_id` (int, required). * * @return array{success:bool,message:string,data:array} */ public function updateEmployeeDataFromTpa(array $params) { try { $batchFileId = (int) ($params['batch_file_id'] ?? 0); if ($batchFileId <= 0) { return [ 'success' => false, 'message' => 'batch_file_id is required and must be a positive integer.', 'data' => [], ]; } $batchFile = $this->batchFileModel->find($batchFileId); if (!$batchFile) { return [ 'success' => false, 'message' => 'Batch file not found.', 'data' => ['batch_file_id' => $batchFileId], ]; } $clientId = (int) ($batchFile['client_id'] ?? 0); $clientPolicyId = (int) ($batchFile['client_policy_id'] ?? 0); $clientBranchId = (int) ($batchFile['client_branch_id'] ?? 0); if (!$clientId || !$clientPolicyId || !$clientBranchId) { return [ 'success' => false, 'message' => 'Incomplete batch file information. Client / policy / branch missing.', 'data' => [], ]; } $TpaApiDataModel = new TpaApiDataModel(); $dbRows = $this->employeePolicyModel->getTPADataVariationReport( $clientId, $clientPolicyId, $batchFileId ); if (!is_array($dbRows) || $dbRows === []) { return [ 'success' => false, 'message' => 'No employee data found for this TPA variation batch.', 'data' => [], ]; } $allowedFields = ['name', 'dob', 'relationship', 'email_corporate', 'gender']; $employeeModel = new EmployeeModel(); $employeesUpdated = 0; $rowsSkippedNoDiff = 0; $rowsSkippedNoEmployee = 0; $consumedTpaIdsByEmpCode = []; foreach ($dbRows as $dbRow) { $empCode = (string) ($dbRow['emp_code'] ?? ''); $tpaRows = $TpaApiDataModel->select('*') ->where('emp_code', $empCode) ->where('file_id', $batchFileId) ->where('is_active', 1) ->findAll(); if ($tpaRows === []) { continue; } $excludeTpaIds = $consumedTpaIdsByEmpCode[$empCode] ?? []; $match = $this->reconcileDbWithTpa($dbRow, $tpaRows, $excludeTpaIds); if (($match['status'] ?? '') !== 'matched') { continue; } $tpaRecord = $match['tpa_record'] ?? []; $notMatching = $match['not_matching'] ?? []; $matchedTpaId = (int) ($tpaRecord['id'] ?? 0); if ($matchedTpaId > 0) { $consumedTpaIdsByEmpCode[$empCode][] = $matchedTpaId; } if (!is_array($notMatching) || $notMatching === []) { $rowsSkippedNoDiff++; continue; } $employeeId = (int) ($dbRow['employee_id'] ?? 0); if ($employeeId <= 0) { $rowsSkippedNoEmployee++; continue; } $employeeRow = $employeeModel->find($employeeId); if ( !$employeeRow || (int) ($employeeRow['client_id'] ?? 0) !== $clientId ) { $rowsSkippedNoEmployee++; continue; } $updateData = []; foreach ($notMatching as $field) { if (!in_array($field, $allowedFields, true)) { continue; } if ($field === 'relationship') { $val = $tpaRecord['relation'] ?? null; if ($val !== null && $val !== '') { $updateData['relationship'] = $val; } continue; } if ($field === 'email_corporate') { $val = $tpaRecord['email_corporate'] ?? $tpaRecord['email'] ?? null; if ($val !== null && $val !== '') { $updateData['email_corporate'] = $val; } continue; } $val = $tpaRecord[$field] ?? null; if ($val !== null && $val !== '') { $updateData[$field] = $val; } } if ($updateData === []) { continue; } if ($employeeModel->update($employeeId, $updateData)) { $employeesUpdated++; } } if ($employeesUpdated === 0) { $this->myLogger->logme( 'error', 'updateEmployeeDataFromTpa: zero employee rows updated', [ 'batch_file_id' => $batchFileId, 'rows_skipped_no_diff' => $rowsSkippedNoDiff, 'rows_skipped_no_employee' => $rowsSkippedNoEmployee, ] ); } return [ 'success' => true, 'message' => 'TPA-aligned employee updates applied where mismatches were reconciled.', 'data' => [ 'batch_file_id' => $batchFileId, 'employees_updated' => $employeesUpdated, 'rows_skipped_no_diff' => $rowsSkippedNoDiff, 'rows_skipped_no_employee' => $rowsSkippedNoEmployee, ], ]; } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'updateEmployeeDataFromTpa failed: ' . json_encode([ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ], JSON_PRETTY_PRINT) ); return [ 'success' => false, 'message' => 'Unable to process the data from Need to Review tab.', 'data' => [], ]; } } /** * @param array $params batch_file_id (required), file_id (optional, >0 filters employee_polices.file_id) * @param mixed $jobId Optional queue job id when invoked from JobWorker (ignored). * * @return array{success:bool,message:string,data:array} */ public function updateTpaIdForNotInNhance($params, $jobId = null): array { try { if (!is_array($params)) { return [ 'success' => false, 'message' => 'Invalid parameters.', 'data' => [], ]; } $TpaApiDataModel = new TpaApiDataModel(); $fileId = (int) ($params['file_id'] ?? 0); $batchFileId = (int) ($params['batch_file_id'] ?? 0); if ($batchFileId <= 0) { $this->myLogger->logme('error', 'Batch file ID missing in updateTpaIdForNotInNhance', ['params' => $params]); return [ 'success' => false, 'message' => 'Batch file ID is required.', 'data' => [], ]; } $batchFileData = db_connect()->table('batch_files')->where('id', $batchFileId)->get()->getRowArray(); if (empty($batchFileData) || empty($batchFileData['client_policy_id'])) { $this->myLogger->logme('error', 'Batch file not found or missing client_policy_id in updateTpaIdForNotInNhance', ['batch_file_id' => $batchFileId]); return [ 'success' => false, 'message' => 'Batch file not found or missing client policy.', 'data' => [], ]; } $client_policy_data = $this->clientPolicyModel->where('id', $batchFileData['client_policy_id'])->first(); if (empty($client_policy_data)) { $this->myLogger->logme('error', 'Client policy not found in updateTpaIdForNotInNhance', ['client_policy_id' => $batchFileData['client_policy_id']]); return [ 'success' => false, 'message' => 'Client policy not found.', 'data' => [], ]; } // Get master emp codes from Nhance for this client & policy $masterEmpRows = $this->employeePolicyModel->getTPADataVariationReport( $batchFileData['client_id'], $batchFileData['client_policy_id'], $batchFileId, [], true ); if (!is_array($masterEmpRows)) { $masterEmpRows = []; } $masterEmpCodes = array_values(array_filter( array_unique(array_column($masterEmpRows, 'emp_code')), static fn ($code) => $code !== null && $code !== '' )); // Fetch Not in Nhance rows for this batch file $notInNhanceQuery = $TpaApiDataModel->select('*') ->where('is_active', 1) ->where('file_id', $batchFileId); if ($masterEmpCodes !== []) { $notInNhanceQuery->whereNotIn('emp_code', $masterEmpCodes); } $notInNhance = $notInNhanceQuery->findAll(); $uhidValue = $client_policy_data['policy_no'] ?? null; $empPolicyIds = []; foreach ($notInNhance as $tpaRow) { $builder = $this->employeePolicyModel ->select('employee_polices.id') ->join('employees e', 'e.id = employee_polices.employee_id') ->where('e.name', $tpaRow['name'] ?? '') ->where('e.emp_code', $tpaRow['emp_code'] ?? '') ->where('e.dob', $tpaRow['dob'] ?? null) ->where('e.relationship', $tpaRow['relation'] ?? null) ->where('e.gender', $tpaRow['gender'] ?? null) ->where('employee_polices.client_policy_id', (int) $batchFileData['client_policy_id']) ->where('e.client_id', (int) $batchFileData['client_id']); if ($fileId > 0) { $builder->where('employee_polices.file_id', $fileId); } $empPolicyRow = $builder->first(); if (empty($empPolicyRow['id'])) { continue; } $epId = (int) $empPolicyRow['id']; if ($this->employeePolicyModel->update($epId, [ 'tpa_id' => $tpaRow['tpa_id'] ?? null, 'uhid' => $uhidValue, ])) { $empPolicyIds[] = $epId; } } if ($empPolicyIds === []) { $this->myLogger->logme( 'warning', 'updateTpaIdForNotInNhance: zero employee_policy rows updated', [ 'batch_file_id' => $batchFileId, 'not_in_nhance_count' => count($notInNhance), ] ); } return [ 'success' => true, 'message' => 'TPA id / UHID applied on matching employee policies for Not in Nhance rows.', 'data' => [ 'employee_policies_updated' => count($empPolicyIds), 'employee_policy_ids' => $empPolicyIds, ], ]; } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'updateTpaIdForNotInNhance exception: ' . $e->getMessage(), ['params' => $params, 'trace' => $e->getTraceAsString()] ); return [ 'success' => false, 'message' => 'Unexpected error while updating TPA id from Not in Nhance data.', 'data' => [], ]; } } // not in use once all functionality workes well in this funciton then remvoe this function function compareDbWithTpa(array $db, array $tpaRows): array { $partialMatches = []; // Normalize helper $normalizeName = function ($name) { return strtolower( preg_replace('/[.\s_]+/', '', trim($name)) ); }; foreach ($tpaRows as $tpa) { // 0️⃣ emp_code must match if (($db['emp_code'] ?? '') !== ($tpa['emp_code'] ?? '')) { continue; } $relationMatch = strtolower($db['relation'] ?? '') === strtolower($tpa['relation'] ?? ''); $genderMatch = strtoupper($db['gender'] ?? '') === strtoupper($tpa['gender'] ?? ''); $dobMatch = ($db['dob'] ?? '') === ($tpa['dob'] ?? ''); $nameMatch = $normalizeName($db['name'] ?? '') === $normalizeName($tpa['name'] ?? ''); // ✅ FULL MATCH if ($nameMatch && $relationMatch && $genderMatch && $dobMatch) { return [ 'match' => 'full_match', 'record'=> $tpa ]; } // ⚠️ PARTIAL MATCH if ($relationMatch || $genderMatch || $dobMatch) { $partialMatches[] = [ 'record' => $tpa, 'matched_on' => [ 'relation' => $relationMatch, 'gender' => $genderMatch, 'dob' => $dobMatch ] ]; } } // If no full match but partial exists if (!empty($partialMatches)) { return [ 'match' => 'partial_match', 'candidates' => $partialMatches ]; } // Nothing matched return [ 'match' => 'no_match' ]; } /** * Convert a single variation-report date value to dd/mm/yyyy for display. */ private function formatVariationReportDateField($value): string { if ($value === null || $value === '') { return ''; } $formatted = change_date_format((string) $value, null, 'd/m/Y'); return ($formatted !== null && $formatted !== '') ? (string) $formatted : (string) $value; } /** * Format known date columns on one variation-report row (TPA or DB). */ private function formatVariationReportRowDates(array $row, array $dateFields = ['dob', 'doj']): array { foreach ($dateFields as $field) { if (!array_key_exists($field, $row)) { continue; } if ($row[$field] === null || $row[$field] === '') { continue; } $row[$field] = $this->formatVariationReportDateField($row[$field]); } return $row; } /** * Apply dd/mm/yyyy formatting to all variation-report payloads returned to the UI/export. */ private function formatVariationReportDataForDisplay( array &$notInTpa, array &$notInNhance, array &$mismatchData ): void { foreach ($notInTpa as $idx => $row) { $notInTpa[$idx] = $this->formatVariationReportRowDates($row); } foreach ($notInNhance as $idx => $row) { $notInNhance[$idx] = $this->formatVariationReportRowDates($row); } foreach ($mismatchData as $idx => $row) { $row = $this->formatVariationReportRowDates($row); if (isset($row['match']['tpa_record']) && is_array($row['match']['tpa_record'])) { $row['match']['tpa_record'] = $this->formatVariationReportRowDates($row['match']['tpa_record']); } $mismatchData[$idx] = $row; } } /** * Pair one Nhance policy row with a TPA API row for the same emp_code. * * When multiple dependents share a relation (e.g. two Sons), candidates are scored * on name / DOB / gender and the best unique match wins. Already-paired TPA ids * (same emp_code) can be passed via $excludeTpaIds so each TPA row maps once. */ public function reconcileDbWithTpa(array $db, array $tpaRows, array $excludeTpaIds = []): array { $normalizeName = static function ($name) { return strtolower( preg_replace('/[.\s_]+/', '', trim((string) $name)) ); }; $normalizeRelation = static function ($relation) { return strtolower(trim((string) $relation)); }; $dbRel = $normalizeRelation($db['relationship'] ?? ''); $candidates = []; foreach ($tpaRows as $tpa) { if (isset($tpa['match']['status']) && $tpa['match']['status'] === 'matched') { continue; } $tpaId = (int) ($tpa['id'] ?? 0); if ($tpaId > 0 && in_array($tpaId, $excludeTpaIds, true)) { continue; } if ($normalizeRelation($tpa['relation'] ?? '') !== $dbRel) { continue; } $candidates[] = $tpa; } if ($candidates === []) { return ['status' => 'no_match']; } $scoreCandidate = static function (array $tpa) use ($db, $normalizeName) { $score = 0; if ($normalizeName($db['name'] ?? '') === $normalizeName($tpa['name'] ?? '')) { $score += 4; } if ((string) ($db['dob'] ?? '') === (string) ($tpa['dob'] ?? '')) { $score += 2; } if (strtoupper(trim((string) ($db['gender'] ?? ''))) === strtoupper(trim((string) ($tpa['gender'] ?? '')))) { $score += 1; } return $score; }; $bestTpa = null; $bestScore = -1; foreach ($candidates as $tpa) { $score = $scoreCandidate($tpa); if ($score > $bestScore) { $bestScore = $score; $bestTpa = $tpa; } } if ($bestTpa === null) { return ['status' => 'no_match']; } // Multiple Son/Daughter rows: require a unique tie-breaker (name or DOB). if (count($candidates) > 1) { $topCount = 0; foreach ($candidates as $tpa) { if ($scoreCandidate($tpa) === $bestScore) { $topCount++; } } if ($topCount > 1 || $bestScore < 2) { return ['status' => 'no_match']; } } $diff = []; if ($normalizeName($db['name'] ?? '') !== $normalizeName($bestTpa['name'] ?? '')) { $diff[] = 'name'; } if ((string) ($db['dob'] ?? '') !== (string) ($bestTpa['dob'] ?? '')) { $diff[] = 'dob'; } if ( strtoupper(trim((string) ($db['gender'] ?? ''))) !== strtoupper(trim((string) ($bestTpa['gender'] ?? ''))) ) { $diff[] = 'gender'; } return [ 'status' => 'matched', 'tpa_record' => $bestTpa, 'not_matching' => $diff, ]; } public function exportVariationReportExcel(array $notInTPA, array $notInNhance, array $reviewNeeded, string $filename = 'employee_review.xlsx') { function setCell($sheet, int $col, int $row, $value) { $cell = Coordinate::stringFromColumnIndex($col) . $row; $sheet->setCellValue($cell, $value); } $EXPORT_COLUMNS = [ // Sheet 1 — Not in TPA 'not_in_tpa' => [ 'emp_code' => 'Employee Code', 'name' => 'Employee Name', 'relationship' => 'Relation', 'dob' => 'Date of Birth', 'gender' => 'Gender', 'mobile' => 'Mobile No', 'email_corporate' => 'Corporate Email', 'policy_no' => 'Policy No', 'tpa_name' => 'TPA Name', 'change_event' => 'Change Event', ], // Sheet 2 — Not in Nhance 'not_in_nhance' => [ 'emp_code' => 'Employee Code', 'name' => 'Employee Name', 'relation' => 'Relation', 'dob' => 'Date of Birth', 'gender' => 'Gender', 'age' => 'Age', 'tpa_id' => 'TPA Member ID', ], // Sheet 3 — Review Needed (DB side) 'review_main' => [ 'emp_code' => 'Employee Code', 'name' => 'Employee Name', 'relationship' => 'Relation', 'dob' => 'Date of Birth', 'gender' => 'Gender', 'policy_no' => 'Policy No', 'uhid' => 'UHID', 'change_event' => 'Change event' ], // Sheet 3 — Review Needed (TPA side) 'review_tpa' => [ 'emp_code' => 'TPA Employee Code', 'name' => 'TPA Name', 'relation' => 'TPA Relation', 'dob' => 'TPA DOB', 'gender' => 'TPA Gender', 'tpa_id' => 'TPA Member ID', 'age' => 'TPA Age', ], ]; $spreadsheet = new Spreadsheet(); /* ========================================================= * SHEET 1 — NOT IN TPA * ========================================================= */ $sheet1 = $spreadsheet->getActiveSheet(); $sheet1->setTitle('Not in TPA'); $cols = $EXPORT_COLUMNS['not_in_tpa']; $colNo = 1; foreach ($cols as $label) { setCell($sheet1, $colNo++, 1, $label); } $rowNo = 2; foreach ($notInTPA as $row) { $colNo = 1; foreach ($cols as $key => $label) { setCell($sheet1, $colNo++, $rowNo, $row[$key] ?? ''); } $rowNo++; } foreach (range(1, count($cols)) as $c) { $sheet1->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true); } /* ========================================================= * SHEET 2 — NOT IN NHANCE * ========================================================= */ $sheet2 = $spreadsheet->createSheet(); $sheet2->setTitle('Not in Nhance'); $cols = $EXPORT_COLUMNS['not_in_nhance']; $colNo = 1; foreach ($cols as $label) { setCell($sheet2, $colNo++, 1, $label); } $rowNo = 2; foreach ($notInNhance as $row) { $colNo = 1; foreach ($cols as $key => $label) { setCell($sheet2, $colNo++, $rowNo, $row[$key] ?? ''); } $rowNo++; } foreach (range(1, count($cols)) as $c) { $sheet2->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true); } /* ========================================================= * SHEET 3 — REVIEW NEEDED * ========================================================= */ $sheet3 = $spreadsheet->createSheet(); $sheet3->setTitle('Review Needed'); $mainCols = $EXPORT_COLUMNS['review_main']; $tpaCols = $EXPORT_COLUMNS['review_tpa']; // headers $colNo = 1; foreach ($mainCols as $label) { setCell($sheet3, $colNo++, 1, $label); } foreach ($tpaCols as $label) { setCell($sheet3, $colNo++, 1, $label); } // rows $rowNo = 2; foreach ($reviewNeeded as $row) { // main (DB) $colNo = 1; foreach ($mainCols as $key => $label) { setCell($sheet3, $colNo++, $rowNo, $row[$key] ?? ''); } $tpaData = []; $notMatching = []; if (($row['match']['status'] ?? '') === 'matched') { $tpaData = $row['match']['tpa_record'] ?? []; $notMatching = $row['match']['not_matching'] ?? []; } // TPA foreach ($tpaCols as $key => $label) { setCell($sheet3, $colNo++, $rowNo, $tpaData[$key] ?? ''); } // highlight mismatches foreach ($notMatching as $field) { if (isset($mainCols[$field])) { $idx = array_keys($mainCols); $pos = array_search($field, $idx); $cell = Coordinate::stringFromColumnIndex($pos + 1) . $rowNo; $sheet3->getStyle($cell)->getFill() ->setFillType(Fill::FILL_SOLID) ->getStartColor()->setARGB('FFFFFF00'); } if (isset($tpaCols[$field])) { $idx = array_keys($tpaCols); $pos = array_search($field, $idx); $cell = Coordinate::stringFromColumnIndex(count($mainCols) + $pos + 1) . $rowNo; $sheet3->getStyle($cell)->getFill() ->setFillType(Fill::FILL_SOLID) ->getStartColor()->setARGB('FFFFFF00'); } } $rowNo++; } foreach (range(1, count($mainCols) + count($tpaCols)) as $c) { $sheet3->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true); } /* ========================================================= * OUTPUT * ========================================================= */ $writer = new Xlsx($spreadsheet); if (ob_get_length()) ob_end_clean(); header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Cache-Control: max-age=0'); $writer->save('php://output'); exit; } public function bulkGenerateEcardAndStoreinS3(array $params = []) { $request = \Config\Services::request(); $isCli = is_cli(); /* --------------------------------------------------------- * 1. INPUTS (shared for WEB + CLI) * --------------------------------------------------------- */ $client_policy_id = $params['client_policy_id'] ?? (!$isCli ? $request->getGet('client_policy_id') : null); $emp_code = $params['emp_code'] ?? (!$isCli ? $request->getGet('emp_code') : null); $emp_pk = $params['emp_pk'] ?? (!$isCli ? $request->getGet('emp_pk') : null); $batch_size = (int) ($params['batch_size'] ?? (!$isCli ? $request->getGet('batch_size') : 100)); $batch_size = $batch_size > 0 ? $batch_size : 100; $batch_no = isset($params['batch_no']) ? (int) $params['batch_no'] : null; $total_batches = (int) ($params['total_batches'] ?? 0); $execution_mode = $params['execution_mode'] ?? (!$isCli ? $request->getGet('execution_mode') : 'sequential'); $execution_mode = in_array($execution_mode, ['sequential', 'parallel']) ? $execution_mode : 'sequential'; $is_dry_run = $params['is_dry_run'] ?? (!$isCli ? $request->getGet('is_dry_run') : false); $log_search_context = 'ECARD_BULK_TO_S3'; if($is_dry_run) { $log_search_context = 'ECARD_BULK_TO_S3_DRY_RUN'; } // Cursor (KEY FIX: avoids OFFSET issues) $last_emp_id = (int) ($params['last_emp_id'] ?? 0); $this->myLogger->logme('error', "$log_search_context"." INIT - ". json_encode([ 'cli' => $isCli, 'policy' => $client_policy_id, 'batch_no' => $batch_no, 'last_emp_id' => $last_emp_id, 'mode' => $execution_mode, 'is_dry_run' => $is_dry_run ])); /* --------------------------------------------------------- * 2. WEB DISPATCHER (QUEUE CREATOR) * --------------------------------------------------------- */ if (!$isCli && empty($params)) { if (empty($client_policy_id)) { return $this->respond(['status' => false, 'message' => 'client_policy_id required'], 200); } // COUNT QUERY (same filters as worker) $countBuilder = $this->employeePolicyModel->builder() ->join('employees', 'employees.id = employee_polices.employee_id') ->where([ 'employees.emp_status' => 'active', 'employees.is_active' => '1', 'employee_polices.status' => 'active', 'employee_polices.is_active' => '1', 'employee_polices.client_policy_id' => $client_policy_id ]) ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''"); if ($emp_code) $countBuilder->where('employees.emp_code', $emp_code); if ($emp_pk) $countBuilder->where('employees.id', $emp_pk); $total = (int) $countBuilder->countAllResults(); if ($total === 0) { $this->myLogger->logme('error', "$log_search_context". 'No records found. Queue skipped.'); return $this->respond(['status' => 'NO_RECORDS'], 200); } $total_batches = (int) ceil($total / $batch_size); $this->myLogger->logme('error', "$log_search_context".'Queueing jobs - '. json_encode([ 'total' => $total, 'batches' => $total_batches, 'mode' => $execution_mode ])); $basePayload = [ 'client_policy_id' => $client_policy_id, 'batch_size' => $batch_size, 'total_batches' => $total_batches, 'execution_mode' => $execution_mode, 'emp_code' => $emp_code, 'emp_pk' => $emp_pk, 'last_emp_id' => 0, 'is_dry_run' => $is_dry_run ]; if ($execution_mode === 'parallel') { for ($i = 1; $i <= $total_batches; $i++) { Jobs::addJob([ 'job_name' => 'bulkGenerateEcardAndStoreinS3', 'payload' => array_merge($basePayload, ['batch_no' => $i]) ]); } } else { Jobs::addJob([ 'job_name' => 'bulkGenerateEcardAndStoreinS3', 'payload' => array_merge($basePayload, ['batch_no' => 1]) ]); } return $this->respond([ 'status' => 'ECARD_BULK_TO_S3 Job queued', 'message' => 'E-card re-generation process has started successfully.', 'dataStatus' => true, 'total' => $total, 'batches' => $total_batches ], 200); } /* --------------------------------------------------------- * 3. CLI WORKER (ACTUAL PROCESSOR) * --------------------------------------------------------- */ if ($batch_no === null) { $this->myLogger->logme('error', "$log_search_context".'Worker called without batch_no'); return; } $this->myLogger->logme('error', "$log_search_context"."START Batch {$batch_no}"); $builder = $this->employeePolicyModel->builder(); $builder->select(' employee_polices.client_policy_id, employees.emp_code, employees.id as emp_id, tpa.short_name, employees.client_id, employee_polices.rand_string ') ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id') ->join('employees', 'employees.id = employee_polices.employee_id') ->join('tpa', 'tpa.id = client_policy.tpa_id') ->where([ 'employees.emp_status' => 'active', 'employees.is_active' => '1', 'employee_polices.status' => 'active', 'employee_polices.is_active' => '1', 'employee_polices.client_policy_id' => $client_policy_id ]) ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''") ->orderBy('employees.id', 'ASC'); if ($emp_code) $builder->where('employees.emp_code', $emp_code); if ($emp_pk) $builder->where('employees.id', $emp_pk); if ($last_emp_id) $builder->where('employees.id >', $last_emp_id); $rows = $builder->get($batch_size)->getResultArray(); $rowCount = count($rows); $this->myLogger->logme('error', "$log_search_context"." Batch {$batch_no} fetched {$rowCount} rows"); if ($rowCount === 0) { $this->myLogger->logme('error', "$log_search_context"." Batch {$batch_no} empty. STOPPING."); return; } foreach ($rows as $row) { $this->myLogger->logme('error', "$log_search_context".' Processing - '. json_encode([ 'emp_id' => $row['emp_id'], 'emp_code' => $row['emp_code'], 'policy' => $row['client_policy_id'] ])); if(!$is_dry_run) //for tesing skip generate ecard and just log only { $ecard_gen_res = $this->generateIDCardForEmployee($row['rand_string'],0,2); // 2 means skip S3 check } $this->myLogger->logme('error', "$log_search_context".' processed - '. json_encode([ 'emp_id' => $row['emp_id'], 'emp_code' => $row['emp_code'], 'policy' => $row['client_policy_id'], // 'ecard_gen_res' => $ecard_gen_res ]));//check } $new_last_emp_id = end($rows)['emp_id']; /* --------------------------------------------------------- * 4. SEQUENTIAL RE-QUEUE (SAFE) * --------------------------------------------------------- */ if ($execution_mode === 'sequential' && $rowCount === $batch_size) { $this->myLogger->logme('error', "$log_search_context"."Re-queueing next batch - " . json_encode([ 'next_batch' => $batch_no + 1, 'last_emp_id' => $new_last_emp_id ])); Jobs::addJob([ 'job_name' => 'bulkGenerateEcardAndStoreinS3', 'payload' => [ 'client_policy_id' => $client_policy_id, 'batch_size' => $batch_size, 'batch_no' => $batch_no + 1, 'execution_mode' => 'sequential', 'last_emp_id' => $new_last_emp_id, 'emp_code' => $emp_code, 'emp_pk' => $emp_pk, 'is_dry_run' => $is_dry_run ] ]); } $this->myLogger->logme('error', "$log_search_context". "END Batch {$batch_no}"); } public function visitOffBoardCheck() { $params = [ "memberIds" => ["adi_1034292323", "EMPENHANCE-M1", "EMPENHANCE-M3"], // "policyNumber" => "570000/48/2026/290", "policyNumber" => "09823428509239", "source" => "NHANCE" ]; print_rr($this->visitOffBoard($params)); } /** * Executes the Delete Policy API call. * * @param array $params Contains 'memberIds', 'policyNumber', and 'source'. * @return array */ public function visitOffBoard(array $params) { // 1. Load credentials from .env $apiUrl = env('WELLNESS_ONBOARD_ENDPOINT_URL').'delete-policy-with-dependents'; $apiToken = env('WELLNESS_ONBOARD_AUTHORIZATION'); // echo $apiUrl;die(); // 2. Initialize the CI4 CURL service $client = \Config\Services::curlrequest([ 'base_uri' => $apiUrl, 'timeout' => 30, ]); // $client = Services::curlrequest([ // 'base_uri' => $apiUrl, // 'timeout' => 30, // ]); $params['source'] = 'NHANCE'; try { // Log the start of the request for traceability $this->myLogger->logme('error', 'VISIT_OFFBOARD: ' . ($params['policyNumber'] ?? 'N/A')); // 3. Perform the POST request $response = $client->request('POST', '', [ 'headers' => [ 'Authorization' => 'JWT ' . $apiToken, 'Content-Type' => 'application/json', 'Accept' => 'application/json', ], 'json' => [ 'memberIds' => $params['memberIds'] ?? [], 'policyNumber' => $params['policyNumber'] ?? '', 'source' => $params['source'] ?? '', ], 'http_errors' => false, // Prevents throwing exceptions on 4xx/5xx responses ]); $statusCode = $response->getStatusCode(); $rawBody = $response->getBody(); $result = json_decode($rawBody, true); // print_rr($result); // 4. Handle based on HTTP Status Code - BUG FIX: Changed = to == for proper comparison if ($statusCode == 200) { $this->myLogger->logme('error', "VISIT_OFFBOARD API Success (Code $statusCode): Policy deleted."); $return_data = [ 'memberIds' => $params['memberIds'] ?? [], 'api_result' => $result ]; $this->updateVisitoffboardStatus($return_data); return $return_data; } // Log API-level errors (4xx or 5xx) $this->myLogger->logme('error', "VISIT_OFFBOARD API Failure (Code $statusCode): " . json_encode($rawBody)); return [ 'status' => false, 'message' => 'The API returned an error response.', 'code' => $statusCode, 'details' => $result ]; } catch (\Exception $e) { // 5. Catch network or system exceptions $this->myLogger->logme('error', 'VISIT_OFFBOARD API Exception: ' . $e->getMessage()); return [ 'status' => false, 'message' => 'A critical error occurred while contacting the API.', 'error' => $e->getMessage() ]; } } /** * Updates the wellness onboard status in the database for deleted members. * * Marks employee policy records as deleted in the wellness system after * a successful API response from the wellness onboard service. * * @param array $data Contains 'memberIds' array and 'api_result' from API response * @return bool Returns true if update was successful or no action needed, false on error */ public function updateVisitoffboardStatus(array $data): bool { try { // Validate input data structure if (empty($data) || !is_array($data)) { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Invalid data parameter'); return false; } // Check if API result exists if (empty($data['api_result'])) { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: No API result found in data'); return false; } $apiResult = $data['api_result']; // Verify API success status - BUG FIX: Proper key access and validation if (($apiResult['message'] ?? null) !== 'success') { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: API response not successful - ' . json_encode($apiResult)); return false; } // Extract member IDs safely - BUG FIX: Corrected key from memberids to memberIds $memberIds = $data['memberIds'] ?? []; if (empty($memberIds) || !is_array($memberIds)) { $this->myLogger->logme('warn', 'VISIT_OFFBOARD_STATUS_UPDATE: No valid memberIds provided for update'); return true; // Not an error if no members to update } if(!empty($apiResult['missingMemberIds']) && is_array($apiResult['missingMemberIds'])) { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: missing member IDs found - ' . json_encode($apiResult['missingMemberIds'])); } // Update wellness_onboard status for deleted members - Append '_DEL' to existing value $updateResult = $this->employeePolicyModel ->whereIn('id', $memberIds) ->set('wellness_onboard', "CONCAT(wellness_onboard, '_DEL')", false) ->update(); if ($updateResult !== false) { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Updated ' . $updateResult . ' employee policy records with wellness_onboard_DEL status'); return true; } else { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Database update operation failed'); return false; } } catch (\Exception $e) { $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Exception occurred - ' . $e->getMessage() . ' - File: ' . $e->getFile() . ' - Line: ' . $e->getLine()); return false; } } public function insufficientCdBalanceHrMailSend() { $post_data = $this->request->getJson(true); if(empty($post_data) || (!isset($post_data['mails']) && !empty($post_data['mails'])) || (!isset($post_data['client_id']) && !empty($post_data['client_id']))){ return $this->respond(['status' => false, 'code' => 404, 'message' => 'No data send mail'], 200); } $client_data = $this->clientModel->where('is_active', 1)->where('id', $post_data['client_id'])->first(); if(empty($client_data)){ return $this->respond(['status' => false, 'code' => 404, 'message' => 'No client found'], 200); } $notificationModal = new NotificationModel(); $notification_data = $notificationModal ->where('client_id', $post_data['client_id']) ->where('template_name', 'hr_cd_insufficient_balance_mail') ->first(); if(empty($notification_data)){ return $this->respond(['status' => false, 'code' => 404, 'message' => 'No template found'], 200); } if(empty($notification_data['subject']) || empty($notification_data['mail_content'])){ return $this->respond(['status' => false, 'code' => 404, 'message' => 'Template subject or mail content is empty'], 200); } if(empty($notification_data['enabled']) || $notification_data['enabled'] != 1){ return $this->respond(['status' => false, 'code' => 404, 'message' => 'Template is disabled'], 200); } $common['mail_type'] = "hr_cd_insufficient_balance_mail"; $common['client_id'] = $post_data['client_id']; $subject = $notification_data['subject']; $mail_content = $notification_data['mail_content']; foreach ($post_data['mails'] as $hr_id => $hr_data) { $mail_content = str_ireplace('{{hr_name}}', $hr_data['name'], $mail_content); $mail_content = str_ireplace('{{client_name}}', $client_data['client_name'], $mail_content); $res = MailHelper::send_email(['mail' => $hr_data['mail'], 'subject' => $subject, 'message' => $mail_content, 'common' => $common]); } return $this->respond(['status' => true, 'code' => 200, 'message' => 'Mail send successfully'], 200); } public function clearCdSession() { clear_cd_balance_session(); return $this->response->setJSON(['status' => 'cleared']); } public function checkSessionStatus() { // Uses your existing get_cd_balance() helper $data = get_cd_balance(); // Return as JSON so JavaScript can read it return $this->response->setJSON($data); } public function bulkEcardDownloadAsZipFromS3($params) { try { $limit = $params['limit'] ?? 100; $batch_no = $params['batch_no'] ?? 1; $last_id = $params['last_emp_policy_id'] ?? 0; // Fetch batch data $employee_data = $this->employeePolicyModel->getEmployeeDataWithPolicyUsingClientPolicyIdOrEmployeePolicyIds($params, $limit, $last_id); if (empty($employee_data)) { if(!empty($last_id)){ $this->myLogger->logme('error', "bulkEcardDownloadAsZipFromS3 - No more records after last_emp_policy_id: {$last_id}"); $this->myLogger->logme('error', "getEmployeeEcardFromTmpFolderAndZipToS3 - Queuing ZIP creation for folder: " . ($params['folder_name'] ?? 'N/A')); $r = Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]); } return ['status' => true, 'message' => 'Proceeding to Zip']; } // Use a consistent folder name across batches (passed in params) $folderName = $params['folder_name'] ?? 'bulk_ecards_' . $employee_data[0]['policy_no'] . '_' . date('Y-m-d_H-i-s'); $tempPath = FCPATH . 'tmp/' . $folderName . '/'; if (!is_dir($tempPath)) { mkdir($tempPath, 0777, true); } $s3 = \Config\Services::getS3Service(); $pdf_count = 0; $current_last_id = end($employee_data)['emp_policy_id']; foreach ($employee_data as $emp_value) { // Track the last ID in this batch $current_last_id = $emp_value['emp_policy_id']; $s3_key = 'ecard_' . $emp_value['name'] . '(' . $emp_value['emp_code'] . ')' . '_' . $emp_value['tpa_id'] . '.pdf'; $s3_key = $this->sanitizeFilePart($s3_key); if ($s3->exists($s3_key)) { $s3_url = $s3->getPresignedUrl($s3_key); $pdf_content = file_get_contents($s3_url['url']); if ($pdf_content !== false) { file_put_contents($tempPath . $s3_key, $pdf_content); $pdf_count++; } } } $hasMore = count($employee_data) == $limit; $payload = [ 'batch_no' => $batch_no + 1, 'last_emp_policy_id' => $current_last_id, 'folder_name' => $folderName, 'processed_in_this_batch_data_count' => count($employee_data), 'pdf_count' => $pdf_count, 'hr_id' => $params['hr_id'] ?? null ]; if ($hasMore) { $this->myLogger->logme('error', "bulkEcardDownloadAsZipFromS3 - Queuing next batch: " . json_encode($payload)); $r = Jobs::addJob(['job_name' => 'bulkEcardDownloadAsZipFromS3', 'payload' => $payload]); $message = "Queuing next batch"; } else { $this->myLogger->logme('error', "bulkEcardDownloadAsZipFromS3 - No more records after this batch. Next proceeding with getEmployeeEcardFromTmpFolderAndZipToS3"); $r = Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $payload]); $message = "All batch completed. Next proceeding with getEmployeeEcardFromTmpFolderAndZipToS3"; } return ['status' => true, 'message' => $message]; } catch (\Throwable $e) { $mail_response = $this->sendMailToHrWithZipAttachments($params); $context = [ 'error_message' => $e->getMessage(), 'exception_class' => get_class($e), 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString(), 'mail_response' => $mail_response, 'params' => $params, ]; // Log detailed context for debugging $this->myLogger->logme('error', 'bulkEcardDownloadAsZipFromS3 - Exception' . json_encode($context, JSON_PRETTY_PRINT)); // Return a detailed, structured error response return [ 'status' => false, 'message' => 'Exception occurred during bulk e-card download and ZIP creation.', 'error' => $context, ]; } } public function getEmployeeEcardFromTmpFolderAndZipToS3($params) { try { $zipService = new \App\Libraries\ZipService(); $source = FCPATH . 'tmp/' . $params['folder_name']; $destination = '/'; $zipName = $params['folder_name'] . '.zip' ?? ''; $result = $zipService->zipAndUploadS3($source, $destination, $zipName); if($result['status'] === false){ $this->myLogger->logme('error', "getEmployeeEcardFromTmpFolderAndZipToS3 - ZIP creation/upload failed: " . json_encode($result)); $params['url'] = null; // Indicate failure }else{ $params['url'] = $result['presigned_url']['url'] ?? null; } $mail_response = $this->sendMailToHrWithZipAttachments($params); return ['zip_responce' => $result, 'mail_response' => $mail_response]; } catch (\Throwable $e) { $mail_response = $this->sendMailToHrWithZipAttachments($params); $context = [ 'error_message' => $e->getMessage(), 'exception_class' => get_class($e), 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString(), 'mail_response' => $mail_response, 'params' => $params, ]; // Log detailed context for debugging $this->myLogger->logme('error', 'getEmployeeEcardFromTmpFolderAndZipToS3 - Exception' . json_encode($context, JSON_PRETTY_PRINT)); // Return a detailed, structured error response return [ 'status' => false, 'message' => 'Exception occurred during bulk e-card download and ZIP creation.', 'error' => $context, ]; } } public function sendMailToHrWithZipAttachments($params) { $hr_id = $params['hr_id'] ?? null; $url = $params['url'] ?? null; if (empty($hr_id)) { $this->myLogger->logme('error', "sendMailToHrWithZipAttachments - No HR ID provided."); return ['status' => false, 'message' => 'No HR ID provided.']; } $hr_data = $this->LevelContactModel->where('id', $hr_id)->where('is_active', 1)->first(); if (empty($hr_data) || empty($hr_data['email'])) { $this->myLogger->logme('error', "sendMailToHrWithZipAttachments - No valid HR data found for ID: {$hr_id}"); return ['status' => false, 'message' => 'No valid HR data found for ID: ' . $hr_id]; } if(empty($url)){ $subject = "Employee Bulk E-Card Download Failed"; $message = "Dear {$hr_data['name']},

We were unable to generate the bulk e-card ZIP file. Please re-initialize the process or contact support to retry."; }else{ $subject = "Employee Bulk E-Cards Download"; $message = "Dear {$hr_data['name']},

Please find the employee e-cards attached below.

Download Link: Download E-Cards

Note : This link valid for 2 days only."; } $bbc = 'venkateshraman786@gmail.com'; $mail_response = MailHelper::send_email([ 'mail' => $hr_data['email'], 'subject' => $subject, 'message' => $message, 'bcc' => $bbc, 'common' => [ 'mail_type' => 'employee_bulk_ecard_download_by_hr', ] ]); $this->myLogger->logme('error', "sendMailToHrWithZipAttachments - Email sent to HR ID: {$hr_id}, Email Response: " . json_encode($mail_response)); return $mail_response; } public function bulkEcardDownloadAsZipFromS3New($params) { try { $limit = $params['limit'] ?? 100; $last_id = $params['last_id'] ?? 0; $zip_id = $params['zip_id']; $employee_data = $this->employeePolicyModel->getEmployeeDataWithPolicyUsingClientPolicyIdOrEmployeePolicyIds($params, $limit, $last_id); if (empty($employee_data)) { // No more records, move to Zipping phase return Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]); } $tempPath = FCPATH . 'tmp/' . $params['folder_name'] . '/'; if (!is_dir($tempPath)) mkdir($tempPath, 0777, true); $s3 = \Config\Services::getS3Service(); $current_last_id = $last_id; $pdf_count = 0; foreach ($employee_data as $emp) { $current_last_id = $emp['emp_policy_id']; $s3_key = 'ecard_' . $emp['name'] . '(' . $emp['emp_code'] . ')' . '_' . $emp['tpa_id'] . '.pdf'; $s3_key = $this->sanitizeFilePart($s3_key); if ($s3->exists($s3_key)) { $s3_url = $s3->getPresignedUrl($s3_key); $pdf_content = file_get_contents($s3_url['url']); if ($pdf_content !== false) { file_put_contents($tempPath . $s3_key, $pdf_content); $pdf_count++; } } } // Check if we need more batches $params['last_id'] = $current_last_id; $params['pdf_count'] = $pdf_count; $params['batch_no'] = ($params['batch_no'] ?? 1) + 1; if (count($employee_data) == $limit) { return Jobs::addJob(['job_name' => 'bulkEcardDownloadAsZipFromS3', 'payload' => $params]); } else { return Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]); } } catch (\Throwable $e) { $this->logAndNotifyError($e, $params); } } public function getEmployeeEcardFromTmpFolderAndZipToS3New($params) { try { $zipService = new \App\Libraries\ZipService(); $source = FCPATH . 'tmp/' . $params['folder_name']; $zipName = $params['folder_name'] . '.zip'; $s3_dest_key = 'exports/zips/' . $zipName; // 1. Create Zip and Upload $result = $zipService->zipAndUploadS3($source, $s3_dest_key); if ($result['status']) { // 2. IMPORTANT: Update the Activity Record with the S3 Key $history = $this->UserActivityHistoryModel->find($params['zip_id']); $misc = json_decode($history['misc_data'], true); $misc['status'] = 'completed'; $misc['s3_key'] = $s3_dest_key; $this->UserActivityHistoryModel->update($params['zip_id'], [ 'misc_data' => json_encode($misc) ]); $params['url'] = base_url('downloadEmployeeEcardZip/' . md5($params['zip_id'])); } // 3. Cleanup local files $this->recursiveRemoveDir($source); // 4. Email HR return $this->sendMailToHrWithZipAttachments($params); } catch (\Throwable $e) { $this->logAndNotifyError($e, $params); } } public function downloadEmployeeEcardZip($md5Id) { // Search by MD5 of ID $data = $this->UserActivityHistoryModel->where('MD5(CAST(id AS CHAR))', $md5Id)->first(); if (!$data) return "File link expired or invalid."; $misc = json_decode($data['misc_data'], true); $s3Key = $misc['s3_key'] ?? null; if (!$s3Key) return "File is still processing or failed to generate."; $s3 = \Config\Services::getS3Service(); $presigned = $s3->getPresignedUrl($s3Key, 15); // 15 mins expiry return redirect()->to($presigned['url']); } private function logAndNotifyError($e, $params) { $this->myLogger->logme('error', "[ECARD_ZIP]: " . $e->getMessage()); $params['url'] = null; // Forces "Failed" email $this->sendMailToHrWithZipAttachments($params); } private function recursiveRemoveDir($dir) { if (!is_dir($dir)) return; $files = array_diff(scandir($dir), array('.', '..')); foreach ($files as $file) { (is_dir("$dir/$file")) ? $this->recursiveRemoveDir("$dir/$file") : unlink("$dir/$file"); } return rmdir($dir); } /** * Reconcile TPA API rows with Nhance employee + employee policy records. * * Why this function exists: * - TPA ingestion stores raw member rows in `tpa_api_data`. * - Downstream processing may need a stable linkage back to the exact * `employee_polices.id` record that represents that member in Nhance. * - This method resolves that linkage and writes it into `tpa_api_data.ref`. * * Matching strategy: * 1) Resolve candidate Nhance members by `emp_code` scoped to the same file's * client and policy context. * 2) Perform strict exact match on: * - emp_code * - name * - dob * - gender * - relation/relationship * 3) Update `tpa_api_data.ref` only when the exact match is found. * * Important behavior: * - Only active rows are considered on both sides. * - Already linked rows (`ref` present) are skipped to avoid accidental override. * - Updates are done in batch and wrapped in DB transaction for consistency. * * @param int|string $file_id Batch file id whose TPA rows must be reconciled. * * @return array{ * status: bool, * message: string, * data: array{ * file_id:int, * scanned:int, * matched:int, * skipped_already_mapped:int, * unmatched:int * } * } */ public function reconTpaApiDataWithEmployeepolicies($file_id): array { try { $fileId = (int) $file_id['file_id']; if ($fileId <= 0) { return [ 'status' => false, 'message' => 'Invalid file id provided.', 'data' => [], ]; } $fileInfo = $this->batchFileModel->find($fileId); if (empty($fileInfo)) { return [ 'status' => false, 'message' => 'Batch file not found.', 'data' => ['file_id' => $fileId], ]; } $clientId = (int) ($fileInfo['client_id'] ?? 0); $clientPolicyId = (int) ($fileInfo['client_policy_id'] ?? 0); if ($clientId <= 0 || $clientPolicyId <= 0) { return [ 'status' => false, 'message' => 'Client/policy context missing for provided file id.', 'data' => ['file_id' => $fileId], ]; } $db = \Config\Database::connect(); // Pull only active TPA rows for this file. We include `ref` to skip // rows that are already mapped by any previous reconciliation run. $tpaRows = $db->table('tpa_api_data') ->select('id, emp_code, name, dob, relation, gender, ref') ->where('file_id', $fileId) ->where('is_active', 1) ->get() ->getResultArray(); if (empty($tpaRows)) { return [ 'status' => true, 'message' => 'No active TPA rows found for reconciliation.', 'data' => [ 'file_id' => $fileId, 'scanned' => 0, 'matched' => 0, 'skipped_already_mapped' => 0, 'unmatched' => 0, ], ]; } // return $tpaRows; // Build Nhance-side candidate pool once, keyed by emp_code. // Each candidate represents an active employee policy member. $dbMembers = $db->table('employee_polices ep') ->select(' ep.id AS employee_policy_id, emp.emp_code, emp.name, emp.relationship, emp.dob, emp.gender ') ->join('employees emp', 'ep.employee_id = emp.id') ->where('ep.is_active', 1) ->where('ep.status', 'active') ->where('ep.client_policy_id', $clientPolicyId) ->where('emp.client_id', $clientId) ->where('emp.is_active', 1) ->get() ->getResultArray(); // return $dbMembers; $membersByEmpCode = []; foreach ($dbMembers as $member) { $membersByEmpCode[$member['emp_code']][] = $member; } $updates = []; $matched = 0; $skipped = 0; $unmatched = 0; $normalize = static function ($value): string { return strtolower(trim((string) $value)); }; foreach ($tpaRows as $tpaRow) { $existingRef = trim((string) ($tpaRow['ref'] ?? '')); if ($existingRef !== '') { $skipped++; continue; } $empCode = (string) ($tpaRow['emp_code'] ?? ''); $candidates = $membersByEmpCode[$empCode] ?? []; if (empty($candidates)) { $unmatched++; continue; } $tName = $normalize($tpaRow['name'] ?? ''); $tRel = $normalize($tpaRow['relation'] ?? ''); $tDob = (string) ($tpaRow['dob'] ?? ''); $tGender = strtoupper(trim((string) ($tpaRow['gender'] ?? ''))); // Strict exact matching only (no fallback): // emp_code is already scoped via $membersByEmpCode. // Remaining fields must all match together. $picked = null; foreach ($candidates as $candidate) { $nameOk = $normalize($candidate['name'] ?? '') === $tName; $relOk = $normalize($candidate['relationship'] ?? '') === $tRel; $dobOk = (string) ($candidate['dob'] ?? '') === $tDob; $genOk = strtoupper(trim((string) ($candidate['gender'] ?? ''))) === $tGender; if ($nameOk && $relOk && $dobOk && $genOk) { $picked = $candidate; break; } } if ($picked === null) { $unmatched++; continue; } $updates[] = [ 'id' => (int) $tpaRow['id'], 'ref' => (int) $picked['employee_policy_id'], ]; $matched++; } // return $updates; if (!empty($updates)) { $db->transStart(); $db->table('tpa_api_data')->updateBatch($updates, 'id'); $db->transComplete(); } $payload = [ 'file_id' => $fileId, 'scanned' => count($tpaRows), 'matched' => $matched, 'skipped_already_mapped' => $skipped, 'unmatched' => $unmatched, ]; $this->myLogger->logme('error', 'TPA ref reconciliation completed: ' . json_encode($payload)); return [ 'status' => true, 'message' => 'TPA rows reconciled with employee policies successfully.', 'data' => $payload, ]; } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'Error in reconTpaApiDataWithEmployeepolicies: ' . $e->getMessage(), ['file_id' => $file_id] ); return [ 'status' => false, 'message' => 'Unable to reconcile TPA rows with employee policies.', 'data' => [ 'file_id' => (int) $file_id, 'error' => $e->getMessage(), ], ]; } } /** * Build and queue a Deletion import file from TPA reconciled data. * * The logic uses `tpa_api_data.ref` rows with `rec_type = matched` as the * "currently present in TPA" snapshot. Any active Nhance member in the same * client/policy scope not present in that ref set is prepared as a deletion row. * * @param int|string $file_id Source batch_file id of the TPA variation flow. * * @return array{ * status: bool, * message: string, * data: array * } */ public function initializeDeletionProcessForTpaApiData($file_id): array { // echo 'DELETION'; try { $fileId = (int) $file_id['file_id']; if ($fileId <= 0) { return [ 'status' => false, 'message' => 'Invalid file id provided.', 'data' => [], ]; } $fileInfo = $this->batchFileModel->find($fileId); if (empty($fileInfo)) { return [ 'status' => false, 'message' => 'Batch file not found.', 'data' => ['file_id' => $fileId], ]; } $clientId = (int) ($fileInfo['client_id'] ?? 0); $clientPolicyId = (int) ($fileInfo['client_policy_id'] ?? 0); $clientBranchId = (int) ($fileInfo['client_branch_id'] ?? 0); if ($clientId <= 0 || $clientPolicyId <= 0 || $clientBranchId <= 0) { return [ 'status' => false, 'message' => 'Client/policy/branch context missing for provided file id.', 'data' => ['file_id' => $fileId], ]; } $db = \Config\Database::connect(); // Take only mapped rows for this file where reconciliation is stable. $mappedRows = $db->table('tpa_api_data tad') ->select('tad.ref') ->where('tad.file_id', $fileId) ->where('tad.is_active', 1) ->where('tad.action_flag_status', 'D') // ->where('tad.rec_type', 'matched') ->where('tad.ref IS NOT NULL', null, false) ->where('tad.ref !=', '') ->groupBy('tad.ref') ->get() ->getResultArray(); // return $mappedRows; $mappedPolicyIds = array_values(array_filter(array_map( static fn($row) => (int) ($row['ref'] ?? 0), $mappedRows ))); if (empty($mappedPolicyIds)) { return [ 'status' => true, 'message' => 'No reconciled TPA mapped rows found. Deletion initialization skipped.', 'data' => ['file_id' => $fileId, 'candidate_count' => 0], ]; } // Candidate deletions = active Nhance members in scope not present in mapped refs. $candidateBuilder = $db->table('employee_polices ep') ->select(" ep.id AS employee_policy_id, emp.emp_code, emp.name, emp.dob, emp.gender, emp.relationship, ep.basic_cover_si, ep.policy_end_date, ep.premium, ep.claim_status ") ->join('employees emp', 'ep.employee_id = emp.id') ->where('ep.is_active', 1) ->where('ep.status', 'active') ->where('ep.client_policy_id', $clientPolicyId) ->where('emp.client_id', $clientId) ->where('emp.is_active', 1) ->where('emp.emp_status', 'active'); $candidateBuilder->whereIn('ep.id', $mappedPolicyIds); $candidateMembers = $candidateBuilder->get()->getResultArray(); // return $candidateMembers; if (empty($candidateMembers)) { return [ 'status' => true, 'message' => 'No deletion candidates found from TPA reconciliation.', 'data' => ['file_id' => $fileId, 'candidate_count' => 0], ]; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('Deletion'); $headers = [ 'S.No', 'Emp ID', 'Name of Emp/Dep', 'change event ', 'date of exit', 'reason for exit', 'Claim status', ]; foreach ($headers as $idx => $header) { $col = Coordinate::stringFromColumnIndex($idx + 1); $sheet->setCellValue($col . '1', $header); } $rowNo = 2; $serial = 1; $dateOfExit = date('d-M-Y'); foreach ($candidateMembers as $member) { $sheet->setCellValue('A' . $rowNo, $serial); $sheet->setCellValue('B' . $rowNo, (string) ($member['emp_code'] ?? '')); $sheet->setCellValue('C' . $rowNo, (string) ($member['name'] ?? '')); $sheet->setCellValue('D' . $rowNo, 'deletion'); $sheet->setCellValue('E' . $rowNo, $dateOfExit); $sheet->setCellValue('F' . $rowNo, 'tpa deletion'); $sheet->setCellValue('G' . $rowNo, '0'); $rowNo++; $serial++; } for ($c = 1; $c <= count($headers); $c++) { $col = Coordinate::stringFromColumnIndex($c); $sheet->getColumnDimension($col)->setAutoSize(true); } $generatedFileName = sprintf( 'tpa_auto_deletion_%d_%s.xls', $fileId, date('Ymd_His') ); $generatedExcelPath = WRITEPATH . 'uploads/excel/' . $generatedFileName; if (! is_dir(WRITEPATH . 'uploads/excel')) { mkdir(WRITEPATH . 'uploads/excel', 0755, true); } $writer = new Xls($spreadsheet); $writer->save($generatedExcelPath); storage_mirror_generated_file($generatedExcelPath, WRITEPATH . 'uploads/excel', $generatedFileName); // return "HI"; // 1) Create files-table entry for EmployeeServiceController::employeeDisembark. $newFileId = $this->fileModel->insert([ 'file_name' => $generatedFileName, 'client_id' => $clientId, 'policy_id' => $clientPolicyId, 'created_by' => (int) ($fileInfo['created_by'] ?? get_session_userid()), 'status' => 'inprogress', 'action' => 'deletion', 'client_branch_id' => $clientBranchId, 'uploaded_by' => 1, 'hr_file_id' => null, 'hr_id' => null, ]); if (!$newFileId) { return [ 'status' => false, 'message' => 'Unable to create file entry for generated deletion file.', 'data' => ['file_id' => $fileId, 'generated_file_name' => $generatedFileName], ]; } // 2) Trigger existing disembark processing and proceed only on success. $empServiceController = new EmployeeServiceController(); $disembarkResult = $empServiceController->employeeDisembark(['file_id' => (int) $newFileId]); if (!is_array($disembarkResult)) { return [ 'status' => false, 'message' => 'employeeDisembark failed for generated deletion file.', 'data' => [ 'file_id' => $fileId, 'generated_file_id' => (int) $newFileId, 'generated_file_name' => $generatedFileName, ], ]; } //call existing function to get deletion export data $batch_data = [ 'client_id' => $clientId, 'client_policy_id' => $clientPolicyId, 'client_branch_id' => $clientBranchId, 'insurer_or_tpa' => 'tpa', 'event_type' => 'deletion', 'actions' => 'export', 'file_name' => '', ]; $endorsementTs = date('YmdHis'); $objects = $this->employeePolicyModel->getDeletionEmployeeDataForExportExcel($batch_data); // print_rr($objects);die; foreach ($objects as $obj) { $obj->endorsement_id = $endorsementTs; } $excel_header_columns = [ ['column_index' => 0, 'column_name' => 'S.No', 'db_column_name' => 'index'], ['column_index' => 1, 'column_name' => 'EMP ID', 'db_column_name' => 'emp_code'], ['column_index' => 2, 'column_name' => 'EMP NAME', 'db_column_name' => 'emp_name'], ['column_index' => 3, 'column_name' => 'DOB', 'db_column_name' => 'emp_dob'], ['column_index' => 4, 'column_name' => 'GENDER', 'db_column_name' => 'emp_gender'], ['column_index' => 5, 'column_name' => 'RELATIONSHIP', 'db_column_name' => 'emp_relationship'], ['column_index' => 6, 'column_name' => 'SUM INSURED', 'db_column_name' => 'basic_cover_si'], ['column_index' => 7, 'column_name' => 'Date of Leaving', 'db_column_name' => 'dateofexit'], ['column_index' => 8, 'column_name' => 'Policy End Date', 'db_column_name' => 'policy_end_date'], ['column_index' => 9, 'column_name' => 'No Of Days', 'db_column_name' => 'no_of_days'], ['column_index' => 10, 'column_name' => 'Premium', 'db_column_name' => 'premium'], ['column_index' => 11, 'column_name' => 'Pro Rata Premium', 'db_column_name' => 'pro_rata_premium'], ['column_index' => 12, 'column_name' => 'GST', 'db_column_name' => 'gst'], ['column_index' => 13, 'column_name' => 'Total', 'db_column_name' => 'total'], ['column_index' => 14, 'column_name' => 'Claim Status', 'db_column_name' => 'claim_status'], ['column_index' => 15, 'column_name' => 'ENDORSEMENT_ID', 'db_column_name' => 'endorsement_id'] ]; $excel_data_info = generate_insurer_based_excel($excel_header_columns, $objects); // $tempFile = tmpfile(); $generatedImportFileName = sprintf( 'tpa_auto_deletion_import_%d_%s.xlsx', $fileId, date('Ymd_His') ); $generatedImportPath = WRITEPATH . 'uploads/import_excel/' . $generatedImportFileName; if (! is_dir(WRITEPATH . 'uploads/import_excel')) { mkdir(WRITEPATH . 'uploads/import_excel', 0755, true); } $success = generate_excel($excel_data_info['header'], $excel_data_info['data'], $generatedImportPath); if ($success && is_file($generatedImportPath)) { storage_mirror_generated_file($generatedImportPath, WRITEPATH . 'uploads/import_excel', $generatedImportFileName); } // print_rr($success); // die; // 3) Build a separate import-format file from sample_import_Deletion.xlsx // for batch_file import validation pipeline. // $importTemplatePath = ROOTPATH . 'public/sample_import_excel/sample_import_Deletion.xlsx'; // if (!file_exists($importTemplatePath)) { // return [ // 'status' => false, // 'message' => 'Import template file not found for deletion batch file format.', // 'data' => [ // 'file_id' => $fileId, // 'generated_file_id' => (int) $newFileId, // 'template_path' => $importTemplatePath, // ], // ]; // } // $importSpreadsheet = IOFactory::load($importTemplatePath); // $importSheet = $importSpreadsheet->getActiveSheet(); // $importRowNo = 2; // $importSerial = 1; // $endorsementTs = date('YmdHis'); // $formatDate = static function ($value): string { // if (empty($value)) { // return ''; // } // $ts = strtotime((string) $value); // if ($ts === false) { // return (string) $value; // } // return date('d-M-Y', $ts); // }; // foreach ($candidateMembers as $memberKey => $member) { // $policyEndDateRaw = (string) ($member['policy_end_date'] ?? ''); // $policyEndTs = strtotime($policyEndDateRaw); // $exitTs = strtotime($dateOfExit); // $noOfDays = 0; // if ($policyEndTs !== false && $exitTs !== false && $policyEndTs >= $exitTs) { // $noOfDays = (int) floor(($policyEndTs - $exitTs) / 86400); // } // $premium = (float) ($member['premium'] ?? 0); // $proRata = $noOfDays > 0 ? round(($premium * $noOfDays) / 365, 2) : 0.00; // $gst = round($proRata * 0.18, 2); // $total = round($proRata + $gst, 2); // $claimStatus = ((string) ($member['claim_status'] ?? '0') === '1') ? '1' : '0'; // $importSheet->setCellValue('A' . $importRowNo, $importSerial); // $importSheet->setCellValue('B' . $importRowNo, (string) ($member['emp_code'] ?? '')); // $importSheet->setCellValue('C' . $importRowNo, (string) ($member['name'] ?? '')); // $importSheet->setCellValue('D' . $importRowNo, $formatDate($member['dob'] ?? '')); // $importSheet->setCellValue('E' . $importRowNo, (string) ($member['gender'] ?? '')); // $importSheet->setCellValue('F' . $importRowNo, (string) ($member['relationship'] ?? '')); // $importSheet->setCellValue('G' . $importRowNo, (string) ($member['basic_cover_si'] ?? '')); // $importSheet->setCellValue('H' . $importRowNo, $dateOfExit); // $importSheet->setCellValue('I' . $importRowNo, $formatDate($policyEndDateRaw)); // $importSheet->setCellValue('J' . $importRowNo, (string) $noOfDays); // $importSheet->setCellValue('K' . $importRowNo, (string) round($premium, 2)); // $importSheet->setCellValue('L' . $importRowNo, (string) $proRata); // $importSheet->setCellValue('M' . $importRowNo, (string) $gst); // $importSheet->setCellValue('N' . $importRowNo, (string) $total); // $importSheet->setCellValue('O' . $importRowNo, $claimStatus); // $endorsementNo = 'TPA_ENDO_' . $endorsementTs . '_' . $memberKey; // $importSheet->setCellValue('P' . $importRowNo, $endorsementNo); // $importRowNo++; // $importSerial++; // } // $generatedImportFileName = sprintf( // 'tpa_auto_deletion_import_%d_%s.xlsx', // $fileId, // date('Ymd_His') // ); // $generatedImportPath = WRITEPATH . 'uploads/import_excel/' . $generatedImportFileName; // $importWriter = new Xlsx($importSpreadsheet); // $importWriter->save($generatedImportPath); $newBatchData = [ 'client_id' => $clientId, 'client_policy_id' => $clientPolicyId, 'client_branch_id' => $clientBranchId, 'event_type' => 'deletion', 'actions' => 'import', 'insurer_or_tpa' => 'insurer', 'batch_code' => generate_random_string(4), 'created_by' => (int) ($fileInfo['created_by'] ?? get_session_userid()), 'status' => 'pending', 'file_name' => $generatedImportFileName, 'count' => count($candidateMembers), ]; $newBatchFileId = $this->batchFileModel->insert($newBatchData); if (!$newBatchFileId) { return [ 'status' => false, 'message' => 'Unable to create batch file entry for generated deletion file.', 'data' => ['file_id' => $fileId, 'generated_file_name' => $generatedImportFileName], ]; } $empDataServiceController = new EmpDataServiceController(); $importValidationResult = $empDataServiceController->importDeletionValidation(['file_id' => (int) $newBatchFileId]); $resultPayload = [ 'source_file_id' => $fileId, 'generated_file_id' => (int) $newFileId, 'generated_batch_file_id' => (int) $newBatchFileId, 'generated_file_name' => $generatedFileName, 'generated_import_file_name' => $generatedImportFileName, 'candidate_count' => count($candidateMembers), 'endorsement_count' => count($disembarkResult), 'import_validation_result' => $importValidationResult, ]; $this->myLogger->logme('error', 'TPA auto deletion file initialized: ' . json_encode($resultPayload)); return [ 'status' => true, 'message' => 'Deletion file generated and queued for validation.', 'data' => $resultPayload, ]; } catch (\Throwable $e) { $this->myLogger->logme( 'error', 'Error in initializeDeletionProcessForTpaApiData: ' . $e->getMessage(), ['file_id' => (int) $file_id] ); return [ 'status' => false, 'message' => 'Unable to initialize deletion process from TPA data.', 'data' => [ 'file_id' => (int) $file_id, 'error' => $e->getMessage(), ], ]; } } public function tpaReportsDashboard() { $METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY'); $policy_id = $this->request->getGet('client_policy') ?? null; if ($this->request->getGet('api') != 1) { $data = [ 'tab_name' => 'TPA Reports', 'page_name' => 'TPA Reports', 'metabaseUrl' => 'https://nsights.nhanceindia.in', 'dashboardApiUrl' => base_url('/employee/tpaReportsDashboard'), ]; return $this->loadLayout('meta_dashboard_demo_one', $data); } if (empty($policy_id)) { return $this->respond([ 'status' => 'failed', 'message' => 'Client policy is required.', 'data' => [], ]); } $client_policy_data = $this->clientPolicyModel ->select('tpa.dashboard_id') ->join('tpa', 'client_policy.tpa_id = tpa.id') ->where('client_policy.id', $policy_id) ->first(); $database_id = isset($client_policy_data['dashboard_id']) ? (int) $client_policy_data['dashboard_id'] : null; if (empty($database_id)) { if ($this->request->getGet('api') == 1) { return $this->respond([ 'status' => 'failed', 'message' => 'There is no dashboard for this TPA.', 'data' => [] ]); } return view('errors/404', [ 'message' => 'There is no dashboard for this TPA.' ]); } $payload = [ 'resource' => [ 'dashboard' => $database_id ], 'exp' => time() + (10 * 60), // 10 minutes 'params' => (object) ['client_policy' => $policy_id ], // MUST be object for Metabase ]; $token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256'); // dd($token); return $this->respond([ 'status' => 'success', 'message' => 'Form data received successfully!', 'data' => [ 'metabaseToken' => $token, 'metabaseUrl' => 'https://nsights.nhanceindia.in', ], ]); } }