nhance/app/Controllers/EmployeeController.php
2026-08-07 10:19:31 +05:30

7562 lines
326 KiB
PHP
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Controllers;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
use App\Helpers\DepositHelper;
use App\Helpers\MailHelper;
use App\Models\EmployeeModel;
use App\Models\EmployeePolicyModel;
use App\Models\ClientModel;
use App\Models\ClientBranchModel;
use App\Models\PolicesModel;
use App\Models\FileModel;
use App\Models\BatchListModel;
use App\Models\BatchFileModel;
use App\Models\EmpEndorsementModel;
use App\Models\ClientPolicyModel;
use App\Models\TPAModel;
use App\Models\InsurerExcelExportTemplateModel;
use App\Models\InsurerModel;
use App\Models\ClientDepositModel;
use App\Models\PolicyPremium2Model;
use App\Models\AuditHistoryModel;
use App\Models\UserModel;
use App\Models\PartnerEndorsementRequestModel;
use App\Models\TpaApiDataModel;
use App\Models\LevelContactModel;
use App\Models\NotificationModel;
use App\Controllers\Jobs;
use App\Controllers\JobWorker;
use App\Controllers\Jobs\SubJob;
use App\Controllers\EmployeeServiceController;
use App\Controllers\EmpDataServiceController;
use App\Models\LeadsModel;
use App\Models\ThzMasterModel;
use App\Models\UserActivityHistoryModel;
use CodeIgniter\API\ResponseTrait;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Writer\Xls;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use Dompdf\Dompdf;
use Dompdf\Options;
use Kint;
use Firebase\JWT\JWT;
class EmployeeController extends AdminController
{
use ResponseTrait;
protected $myLogger;
protected $employeeModel;
protected $employeePolicyModel;
protected $clientModel;
protected $clientBranchModel;
protected $fileModel;
protected $batchListModel;
protected $batchFileModel;
protected $empEndorsementModel;
protected $clientPolicyModel;
protected $TPAModel;
protected $policiesModel;
protected $excelExportTemplateModel;
protected $insurerModel;
protected $cashDepositModel;
protected $PolicyPremium2Model;
protected $auditHistory;
protected $userModel;
protected $partnerEndorsementRequestModel;
protected $LevelContactModel;
protected $UserActivityHistoryModel;
public function __construct()
{
// helper('utility');
set_session_context('Employee');
$this->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 pendingApprovalsList()
{
$data = [];
$filterData = $this->request->getGet() ?: [];
$client_id = $filterData['client_id'] ?? null;
$policy_id = $filterData['policy_id'] ?? null;
$branch_id = $filterData['branch_id'] ?? null;
$employees = $this->employeePolicyModel->getPendingApprovalDependents(
client_id: $client_id,
policy_id: $policy_id,
branch_id: $branch_id,
);
// Default: only pending_approval. When ACM filters client + branch + policy → show all statuses.
$hasFullFilter = ! empty($client_id) && $client_id != '0'
&& ! empty($branch_id) && $branch_id != '0'
&& ! empty($policy_id) && $policy_id != '0';
if (! $hasFullFilter && ! empty($employees)) {
$employees = array_values(array_filter($employees, static function ($row) {
return strtolower((string) ($row['status'] ?? '')) === 'pending_approval';
}));
}
$data['employees'] = $employees;
$data['getData'] = [
'client_id' => $client_id ?? '0',
'policy_id' => $policy_id ?? '0',
'branch_id' => $branch_id ?? '0',
'emp_code' => '',
'emp_name' => '',
'status' => $hasFullFilter
? ['pending_approval', 'active', 'rejected']
: ['pending_approval'],
];
// AJAX filter submit → return table HTML only
if (count($this->request->getGet())) {
$html = view('employee_pending_approvals_data_list', $data);
return $this->respond(['status' => true, 'html' => $html], 200);
}
// Default page load → list pending dependents only
$data['tab_name'] = 'Approvals';
$data['page_name'] = 'Approvals';
$data['default_table_html'] = view('employee_pending_approvals_data_list', $data);
$this->loadLayout('employee_pending_approvals_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 "<pre>";
}
$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' => '<div class="text-center">No Data Found</div>',
'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' => '<div class="text-center">No Data Found</div>',
'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' => '<div class="text-center">No Data Found</div>',
'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 = '<div class="text-center">No Data Found</div>';
}
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' => '<div class="text-center">Something went wrong</div>', '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 '<pre>';
// 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 '<pre>';
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 '<button id="downloadBtn" style="display: block;margin: 30px;position: relative;left: 220px;">Print</button>' . $html . '</button>
<script>
document.getElementById("downloadBtn").addEventListener("click", function() {
this.style.display = "none";
window.print();
this.style.display = "block";
});
</script>';
$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}'] = '
<span style="font-family: sans-serif;">Level 1</span><br><br>
<span style="font-family: sans-serif;">1. Gowtham / 8754081806 / gowtham@gmail.com</span><br>
<span style="font-family: sans-serif;">2. Gowtham / 8754081806 / gowtham@gmail.com</span><br><br>';
// 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('<style>@page { margin: 0; }</style>' . $html); // remove the margin
$dompdf->loadHtml('
<style>
@page { margin: 0; }
@import url("https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap");
body { font-family: "Lato", sans-serif !important; }
</style>
' . $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 '<br>PDF generated and uploaded to S3 successfully.<br>';
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 = [
'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()
]);
}
$employeeId = (int) ($data['employee_primary_id'] ?? 0);
if ($employeeId <= 0) {
return $this->respond(['status' => false, 'code' => 400, 'message' => 'Employee ID is required'], 400);
}
// Fetch current employee data
$employee_data = $this->employeeModel->where('id', $employeeId)->first();
if (!$employee_data) {
return $this->respond(['status' => false, 'code' => 404, 'message' => 'Employee not found'], 404);
}
// Whitelist only editable fields from this form.
// name / gender / dob are disabled for active employees and may be absent from POST —
// only update them when the client actually sent a value (do not force null).
$updateData = [
'email_corporate' => $data['email_corporate'],
'mobile' => $data['mobile'],
];
if (!empty($data['name'])) {
$updateData['name'] = $data['name'];
}
if (isset($data['gender']) && $data['gender'] !== '') {
$updateData['gender'] = $data['gender'];
}
if (!empty($data['dob'])) {
$updateData['dob'] = change_date_format($data['dob'], null, 'Y-m-d');
}
if (isset($data['relationship'])) {
$updateData['relationship'] = $data['relationship'];
}
if ($employee_data['relationship'] == 'Self' && isset($updateData['gender'])) {
if ($employee_data['gender'] != $updateData['gender']) {
$spouse_gender = ($updateData['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', $employeeId)->set($updateData)->update();
if ($result) {
return $this->respond(['status' => true, 'code' => 200, 'data' => $updateData, '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;$i<count($selected_employees);$i++){log_message('error',$selected_employees[$i]);
$result1 = $this->employeeModel->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;$i<count($selected_employees);$i++){
log_message('error','Emp id is '.$selected_employees[$i]);
$result1 = $this->employeeModel->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 . '<br>';
}else{
$html .= '<br> Level ' . $displayLevel . '<br>';
}
foreach ($contacts as $index => $contact) {
$html .= ($index + 1) . '. ' . $contact['first_name'] . ' / ' . $contact['mobile'] . ' / ' . $contact['email'] . '<br>';
}
$level_index++;
}
$html .= '<br>';
return $html;
}
public function generateNetworkHospitalsForEcard($network_hospitals)
{
$html = "";
if (!empty($network_hospitals)) {
$html = '<div style="margin-top: 6px;">
<span style="font-weight: 500;">Network Hospital:</span>
<a href="' . $network_hospitals . '" target="_blank" style="color: #0066cc; text-decoration: none; display: inline-block; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom;">' . $network_hospitals . '</a>
</div>';
}
// 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 "<pre>";
// 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 . '<br>';
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 . ' - ' . '<br>';
// 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']},<br><br>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']},<br><br>Please find the employee e-cards attached below.<br><br>Download Link: <a href='{$url}'>Download E-Cards</a><br><br>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(),
],
];
}
}
/**
* TPA Reports dashboard page — native MIS only (ABHI / ICICI / Medi Assist / Vidal).
*/
public function tpaReportsDashboard()
{
$data = [
'tab_name' => 'TPA Reports',
'page_name' => 'TPA Reports',
'misApiUrl' => base_url('/util/tpa-reports/mis'),
];
return $this->loadLayout('tpa_mis_reports_dashboard', $data);
}
/**
* Metabase signed-embed token for a client policy.
* GET /util/tpa-reports/metabase?client_policy=
* GET /employeeRest/tpa-reports/metabase?client_policy=
*/
public function tpaReportsMetabase()
{
$METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
$policy_id = $this->request->getGet('client_policy')
?? $this->request->getGet('client_policy_id')
?? null;
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)) {
return $this->respond([
'status' => 'failed',
'message' => 'There is no dashboard for this TPA.',
'data' => [],
]);
}
$payload = [
'resource' => [
'dashboard' => $database_id,
],
'exp' => time() + (10 * 60),
'params' => (object) ['client_policy' => $policy_id],
];
$token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256');
return $this->respond([
'status' => 'success',
'message' => 'Form data received successfully!',
'data' => [
'metabaseToken' => $token,
'metabaseUrl' => 'https://nsights.nhanceindia.in',
],
]);
}
/**
* Native TPA MIS report embed info for the frontend (preview + PDF URLs).
* GET /util/tpa-reports/mis?client_policy=
* GET /employeeRest/tpa-reports/mis?client_policy=
*/
public function tpaMisReport()
{
$policyId = (int) (
$this->request->getGet('client_policy')
?? $this->request->getGet('client_policy_id')
?? 0
);
if ($policyId <= 0) {
return $this->respond([
'status' => 'failed',
'message' => 'Client policy is required.',
'data' => [],
]);
}
$policy = $this->clientPolicyModel
->select('id, tpa_id')
->where('id', $policyId)
->first();
if (!$policy) {
return $this->respond([
'status' => 'failed',
'message' => 'Policy not found.',
'data' => [],
]);
}
$tpaId = (int) ($policy['tpa_id'] ?? 0);
$map = [
(int) env('ABHI_PRIMARY_KEY_CONSTANT') => 'abhi',
(int) env('ICICI_PRIMARY_KEY_CONSTANT') => 'icici',
(int) env('MEDI_ASSIST_PRIMARY_KEY_CONSTANT') => 'medi_assist',
(int) env('VIDAL_PRIMARY_KEY_CONSTANT') => 'vidal',
];
$kind = $map[$tpaId] ?? null;
if ($kind === null) {
return $this->respond([
'status' => 'failed',
'message' => 'MIS report is not available for this policy TPA. Supported: ABHI, ICICI, Medi Assist, Vidal.',
'data' => [
'supported' => false,
'tpa_id' => $tpaId,
],
]);
}
$path = $this->request->getUri()->getPath();
$isJwt = stripos($path, 'employeeRest') !== false;
$prefix = $isJwt ? 'employeeRest/claims-collection-report' : 'util/claims-collection-report';
$labels = [
'abhi' => 'ABHI MIS Report',
'icici' => 'ICICI Portfolio Analysis',
'medi_assist' => 'Medi Assist Portfolio Analysis',
'vidal' => 'Vidal Corporate Analysis',
];
return $this->respond([
'status' => 'success',
'message' => 'MIS report available.',
'data' => [
'supported' => true,
'kind' => $kind,
'tpa_id' => $tpaId,
'title' => $labels[$kind] ?? 'TPA MIS Report',
'preview_url' => base_url($prefix . '/mis?client_policy_id=' . $policyId),
'pdf_url' => base_url($prefix . '/mis-pdf?client_policy_id=' . $policyId),
],
]);
}
}