diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php index 2c28bb6c..133d6ad1 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -476,6 +476,7 @@ class ApiServiceController extends BaseController ->where('ep.status', 'active') ->where('e.is_active', 1) ->where('ep.is_active', 1) + ->where('ep.wellness_onboard != 0') ->get() ->getResultArray(); diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index ff208769..812e6f28 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -47,6 +47,7 @@ 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; @@ -657,7 +658,7 @@ class EmployeeController extends AdminController if ($actionType == 'inception') { $filePath = ROOTPATH . 'public/sample_excel/sample_inception.xls'; } else if ($actionType == 'correction') { - $filePath = ROOTPATH . 'public/sample_excel/sample_correction .xls'; + $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') { @@ -3629,17 +3630,17 @@ class EmployeeController extends AdminController ->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.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 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 IS NULL', null, false) ->orWhere('cp.wellness_vendor_id =', '') ->orWhere('cp.wellness_vendor_id =', 0) ->groupEnd() @@ -3661,31 +3662,38 @@ class EmployeeController extends AdminController return $this->respond(['status' => true, 'code' => 200, 'message' => 'Process started'], 200); } - public function initiateWellnessOnboardJob($arr) + public function initiateWellnessOnboardJobOLD($arr) { $client_policy_id = $arr['client_policy_id']; - // $this->updateWellnessOnboardResponseToDB();die(); - // echo $client_policy_id;die(); - $data = $this->employeePolicyModel->select('employee_polices.*,emp.name,emp.relationship,emp.emp_code,emp.name,emp.gender,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') + + $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.tpa_id is not null') ->where('employee_polices.wellness_onboard', '0') ->where('emp.emp_status', 'active') ->where('emp.is_active', 1) - ->where('cp.wellness_plan_id is not null') - ->where('cp.wellness_vendor_id is null') - // ->where('cp.policy_status',1) - // ->where('cp.is_active',1) - ->findAll(); - // print_r($this->employeePolicyModel->getLastQuery()); - // print_r($data); - // echo '==============================';die(); + ->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)); @@ -3710,6 +3718,8 @@ class EmployeeController extends AdminController $families[$empCode][] = $row; } + // print_rr($families);die(); + // ------------------ BUILD PAYLOAD FOR ALL FAMILIES ------------------ $familiesPayload = []; @@ -3722,6 +3732,26 @@ class EmployeeController extends AdminController // 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; @@ -3730,6 +3760,9 @@ class EmployeeController extends AdminController } else { + if ($page > 1) { + return true; + } return $this->respond(['status' => false, 'code' => 200, 'message' => 'No employees found for wellness onboard!'], 200); } @@ -3737,6 +3770,121 @@ class EmployeeController extends AdminController } + public function initiateWellnessOnboardJob($arr) + { + $client_policy_id = $arr['client_policy_id'] ?? 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 + // ---------------------------------------------------------------- + $data = $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) + ->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); + } + + // ---------------------------------------------------------------- + // 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; + } + + # ------------------ FUNCTION TO BUILD FAMILY PAYLOAD ------------------ /** @@ -4033,6 +4181,8 @@ class EmployeeController extends AdminController 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') { @@ -4153,6 +4303,9 @@ class EmployeeController extends AdminController $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); } else { // echo 'else';die; // Cached mode: @@ -4294,8 +4447,13 @@ class EmployeeController extends AdminController { if($generationResult['data']['file_id']) { - //initiate update references b/w tpa_api_data and employess + sleep(1); + //initiate update references b/w tpa_api_data and employess (pk update) + $this->reconTpaApiDataWithEmployeepolicies($file_id); + sleep(1); //initiate deleteion if any + $this->initializeDeletionProcessForTpaApiData($file_id); + } else { @@ -4311,6 +4469,8 @@ class EmployeeController extends AdminController // 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([$file_id]); if (!$generationResult['status']) { @@ -6416,6 +6576,7 @@ class EmployeeController extends AdminController ]; } + // 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') @@ -6435,7 +6596,8 @@ class EmployeeController extends AdminController ->where('emp.is_active', 1) ->get() ->getResultArray(); - + + // return $dbMembers; $membersByEmpCode = []; foreach ($dbMembers as $member) { $membersByEmpCode[$member['emp_code']][] = $member; @@ -6495,7 +6657,7 @@ class EmployeeController extends AdminController ]; $matched++; } - + // return $updates; if (!empty($updates)) { $db->transStart(); $db->table('tpa_api_data')->updateBatch($updates, 'id'); @@ -6535,4 +6697,393 @@ class EmployeeController extends AdminController } } + /** + * 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; + 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; + + $writer = new Xls($spreadsheet); + $writer->save($generatedExcelPath); + // 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; + $success = generate_excel($excel_data_info['header'], $excel_data_info['data'], $generatedImportPath); + // 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(), + ], + ]; + } + } + } diff --git a/app/Filters/AuthApiRateLimitFilter.php b/app/Filters/AuthApiRateLimitFilter.php index 944af97f..74c2b4fb 100644 --- a/app/Filters/AuthApiRateLimitFilter.php +++ b/app/Filters/AuthApiRateLimitFilter.php @@ -7,6 +7,7 @@ use CodeIgniter\Filters\FilterInterface; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; +use App\Filters\Cors; /** * AuthApiFilter * @@ -26,10 +27,12 @@ use CodeIgniter\HTTP\ResponseInterface; class AuthApiRateLimitFilter implements FilterInterface { protected RateLimiterService $limiter; + protected Cors $corsFilter; public function __construct() { $this->limiter = new RateLimiterService(); + $this->corsFilter = new Cors(); } // ------------------------------------------------------------------------- @@ -138,6 +141,7 @@ class AuthApiRateLimitFilter implements FilterInterface 'type' => $result['type'] ?? 'request', ], ])); + $this->corsFilter->after($request, $response); return $response; } } diff --git a/app/Views/client_branch.php b/app/Views/client_branch.php index fd00a267..61f5ec37 100755 --- a/app/Views/client_branch.php +++ b/app/Views/client_branch.php @@ -172,7 +172,7 @@ input:checked + .slider-branch-contact:before {
@@ -180,7 +180,9 @@ input:checked + .slider-branch-contact:before { + data-parsley-pattern-message="Branch Code can contain letters, numbers, underscore (_) and hyphen (-)." + oninput="this.value = this.value.replace(/[^A-Za-z0-9_-]/g, '')" + onblur="this.value = this.value.trim();">
@@ -209,14 +211,14 @@ input:checked + .slider-branch-contact:before {
@@ -771,7 +773,7 @@ function appendContactHtml(contact = false, reset = false) {
@@ -1364,7 +1366,8 @@ function setDefaultUnitValue() { var client_id = $('#client_id_branch').val(); - var branch_code = $('#branch_code').val(); + var branch_code = ($('#branch_code').val() || '').trim(); + $('#branch_code').val(branch_code); var units = $('#selected').val(); console.log('client_id', client_id) diff --git a/app/Views/insurer_branch.php b/app/Views/insurer_branch.php index 6ea9b4ae..92494a03 100755 --- a/app/Views/insurer_branch.php +++ b/app/Views/insurer_branch.php @@ -108,15 +108,17 @@
+ data-parsley-pattern="^[a-zA-Z0-9\s_-]+$" + data-parsley-pattern-message="Branch Code can contain letters, numbers, spaces, underscore (_) and hyphen (-)." + oninput="this.value = this.value.replace(/[^A-Za-z0-9_\- ]/g, '')" + onblur="this.value = this.value.trim();">
@@ -147,7 +149,7 @@ @@ -158,7 +160,7 @@
@@ -197,8 +199,8 @@
+ data-parsley-pattern="^[a-zA-Z0-9\s_-]+$" + data-parsley-pattern-message="Contact name can contain letters, numbers, spaces, underscore (_) and hyphen (-).">
@@ -213,7 +215,7 @@
@@ -456,7 +458,7 @@ if (!/^[a-zA-Z0-9\s_-]+$/.test(v)) return 'Branch Name can contain letters, numbers, spaces, underscore (_) and hyphen (-).'; return ''; case 'branch_code': - if (!/^[a-zA-Z0-9_-]+$/.test(v)) return 'Branch Code can contain letters, numbers, underscore (_) and hyphen (-).'; + if (!/^[a-zA-Z0-9\s_-]+$/.test(v)) return 'Branch Code can contain letters, numbers, spaces, underscore (_) and hyphen (-).'; return ''; case 'address1': return ''; @@ -968,8 +970,8 @@
+ data-parsley-pattern="^[a-zA-Z0-9\s_-]+$" + data-parsley-pattern-message="Contact name can contain letters, numbers, spaces, underscore (_) and hyphen (-).">
@@ -984,7 +986,7 @@
diff --git a/app/Views/layout/footer.php b/app/Views/layout/footer.php index 3851bb0e..9463619c 100755 --- a/app/Views/layout/footer.php +++ b/app/Views/layout/footer.php @@ -277,6 +277,7 @@