systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; require_once SYSTEMPATH . 'Config/DotEnv.php'; (new CodeIgniter\Config\DotEnv(ROOTPATH))->load(); defined('ENVIRONMENT') || define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development')); $boot = APPPATH . 'Config/Boot/' . ENVIRONMENT . '.php'; if (is_file($boot)) { require_once $boot; } if (empty(env('JWT_SECRET'))) { $smokeJwtSecret = 'smoke-verified-hr-claims-submenu-jwt-secret'; putenv('JWT_SECRET=' . $smokeJwtSecret); $_ENV['JWT_SECRET'] = $smokeJwtSecret; $_SERVER['JWT_SECRET'] = $smokeJwtSecret; } use App\Controllers\RestAuthenticationController; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; use Config\Services; $pass = 0; $fail = 0; $skip = 0; $results = []; function ok(string $label, bool $cond, string $detail = ''): void { global $pass, $fail, $results; if ($cond) { $pass++; $results[] = '[PASS] ' . $label . ($detail !== '' ? " — {$detail}" : ''); } else { $fail++; $results[] = '[FAIL] ' . $label . ($detail !== '' ? " — {$detail}" : ''); } } function skip(string $label, string $detail = ''): void { global $skip, $results; $skip++; $results[] = '[SKIP] ' . $label . ($detail !== '' ? " — {$detail}" : ''); } /** * @return array{http:int,body:array,raw:string,error:?string} */ function invokeGetVerifiedHrData(array $payload): array { try { $uri = new URI('http://localhost/nhance_v2/employeeRest/getVerifiedHrData'); $bodyString = json_encode($payload, JSON_THROW_ON_ERROR); $request = new IncomingRequest( config('App'), $uri, $bodyString, new UserAgent() ); $request->setMethod('post'); $request->setHeader('Content-Type', 'application/json'); $request->setHeader('User-Agent', 'SmokeTest/1.0'); $request->setGlobal('post', []); Services::injectMock('request', $request); $controller = new RestAuthenticationController(); $response = Services::response(); $logger = Services::logger(); $controller->initController($request, $response, $logger); // Local DB user may lack INSERT on auth_history; stub so smoke can focus on claims logic. $authHistoryStub = new class { public function insert($data = null, bool $returnID = true) { return true; } }; $ref = new ReflectionProperty(RestAuthenticationController::class, 'authHistoryModel'); $ref->setAccessible(true); $ref->setValue($controller, $authHistoryStub); $resp = $controller->getVerifiedHrData(); $raw = $resp->getBody(); $body = json_decode($raw, true); return [ 'http' => $resp->getStatusCode(), 'body' => is_array($body) ? $body : [], 'raw' => (string) $raw, 'error' => null, ]; } catch (Throwable $e) { return [ 'http' => 500, 'body' => [], 'raw' => '', 'error' => $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine(), ]; } } function findHrRowForClient(array $dataRows, int $clientId, int $hrId): ?array { foreach ($dataRows as $row) { if ((int) ($row['client_id'] ?? 0) === $clientId && (int) ($row['id'] ?? 0) === $hrId) { return $row; } } return $dataRows[0] ?? null; } function postModulesContainClaims(?array $allowedModules): bool { if (!is_array($allowedModules)) { return false; } if (isset($allowedModules['post']) && is_array($allowedModules['post'])) { return in_array(4, array_map('intval', $allowedModules['post']), true); } if (!isset($allowedModules['pre']) && !isset($allowedModules['post'])) { return in_array(4, array_map('intval', $allowedModules), true); } return false; } $db = db_connect(); $fixture = $db->query( "SELECT hac.id AS hac_id, hac.post_hr_id, hac.post_client_id, hac.post_branch_id, hac.allowed_modules, hac.allowed_active_policies, lc.mobile, lc.email, lc.otp AS original_otp FROM hr_access_control hac INNER JOIN level_contacts lc ON lc.id = hac.post_hr_id WHERE hac.is_active = 1 AND lc.is_active = 1 AND lc.contact_type = 'client' AND lc.mobile IS NOT NULL AND lc.mobile <> '' AND hac.allowed_modules LIKE '%4%' AND hac.allowed_active_policies IS NOT NULL AND hac.allowed_active_policies <> '[]' AND hac.allowed_active_policies <> '' ORDER BY hac.id DESC LIMIT 1" )->getRowArray(); $nonEbPolicy = $db->query( "SELECT cp.id, pt.allocg FROM client_policy cp JOIN policy_type pt ON pt.id = cp.policy_type_id WHERE pt.allocg <> 'EB' AND cp.is_active = 1 ORDER BY cp.id DESC LIMIT 1" )->getRowArray(); if (!$fixture) { skip('Fixture HR with claims + policies', 'none found'); foreach ($results as $line) { echo $line . PHP_EOL; } echo PHP_EOL . "PASS={$pass} FAIL={$fail} SKIP={$skip}" . PHP_EOL; exit($fail > 0 ? 1 : 0); } ok('Fixture HR with claims module', true, "hac_id={$fixture['hac_id']} hr={$fixture['post_hr_id']} mobile={$fixture['mobile']}"); $otp = '999111'; $originalPolicies = $fixture['allowed_active_policies']; $originalModules = $fixture['allowed_modules']; $originalOtp = $fixture['original_otp']; $hrId = (int) $fixture['post_hr_id']; $clientId = (int) $fixture['post_client_id']; $hacId = (int) $fixture['hac_id']; $mobile = $fixture['mobile']; $restore = static function () use ($db, $hacId, $hrId, $originalPolicies, $originalModules, $originalOtp): void { $db->table('hr_access_control')->where('id', $hacId)->update([ 'allowed_active_policies' => $originalPolicies, 'allowed_modules' => $originalModules, ]); $db->table('level_contacts')->where('id', $hrId)->update([ 'otp' => $originalOtp, ]); }; register_shutdown_function($restore); // ── Case 1: EB-only policies → claims_sub_menu = ["EB"] ────────────────────── $db->table('level_contacts')->where('id', $hrId)->update(['otp' => $otp]); $case1 = invokeGetVerifiedHrData([ 'mobile_no' => $mobile, 'otp' => $otp, ]); ok('Case1 HTTP/error free', $case1['error'] === null, (string) ($case1['error'] ?? 'ok')); ok('Case1 status success', ($case1['body']['status'] ?? '') === 'success', json_encode($case1['body']['message'] ?? $case1['body']['status'] ?? null)); $case1Rows = $case1['body']['data'] ?? []; $case1Row = is_array($case1Rows) ? findHrRowForClient($case1Rows, $clientId, $hrId) : null; ok('Case1 row found', is_array($case1Row), 'client_id=' . $clientId); ok( 'Case1 claims still present', postModulesContainClaims($case1Row['allowed_modules'] ?? null), json_encode($case1Row['allowed_modules'] ?? null) ); ok( 'Case1 claims_sub_menu is EB only', ($case1Row['claims_sub_menu'] ?? null) === ['EB'], json_encode($case1Row['claims_sub_menu'] ?? null) ); // ── Case 2: include Non-EB policy → claims_sub_menu = ["EB","Non-EB"] ───────── if (!$nonEbPolicy) { skip('Case2 Non-EB policy fixture', 'no non-EB client_policy found'); } else { $mixedPolicies = json_decode($originalPolicies, true) ?: []; $mixedPolicies[] = (int) $nonEbPolicy['id']; $mixedPolicies = array_values(array_unique(array_map('intval', $mixedPolicies))); $db->table('hr_access_control')->where('id', $hacId)->update([ 'allowed_active_policies' => json_encode($mixedPolicies), ]); $db->table('level_contacts')->where('id', $hrId)->update(['otp' => $otp]); $case2 = invokeGetVerifiedHrData([ 'mobile_no' => $mobile, 'otp' => $otp, ]); ok('Case2 HTTP/error free', $case2['error'] === null, (string) ($case2['error'] ?? 'ok')); ok('Case2 status success', ($case2['body']['status'] ?? '') === 'success', json_encode($case2['body']['status'] ?? null)); $case2Rows = $case2['body']['data'] ?? []; $case2Row = is_array($case2Rows) ? findHrRowForClient($case2Rows, $clientId, $hrId) : null; ok( 'Case2 claims_sub_menu has EB + Non-EB', ($case2Row['claims_sub_menu'] ?? null) === ['EB', 'Non-EB'], json_encode($case2Row['claims_sub_menu'] ?? null) . ' nonEbPolicy=' . $nonEbPolicy['id'] . '/' . $nonEbPolicy['allocg'] ); } // ── Case 3: empty policies → claims stripped, claims_sub_menu = [] ──────────── $db->table('hr_access_control')->where('id', $hacId)->update([ 'allowed_active_policies' => '[]', ]); $db->table('level_contacts')->where('id', $hrId)->update(['otp' => $otp]); $case3 = invokeGetVerifiedHrData([ 'mobile_no' => $mobile, 'otp' => $otp, ]); ok('Case3 HTTP/error free', $case3['error'] === null, (string) ($case3['error'] ?? 'ok')); ok('Case3 status success', ($case3['body']['status'] ?? '') === 'success', json_encode($case3['body']['status'] ?? null)); $case3Rows = $case3['body']['data'] ?? []; $case3Row = is_array($case3Rows) ? findHrRowForClient($case3Rows, $clientId, $hrId) : null; ok( 'Case3 claims module removed', !postModulesContainClaims($case3Row['allowed_modules'] ?? null), json_encode($case3Row['allowed_modules'] ?? null) ); ok( 'Case3 claims_sub_menu empty', ($case3Row['claims_sub_menu'] ?? null) === [], json_encode($case3Row['claims_sub_menu'] ?? null) ); $restore(); ob_end_clean(); foreach ($results as $line) { echo $line . PHP_EOL; } echo PHP_EOL . "PASS={$pass} FAIL={$fail} SKIP={$skip}" . PHP_EOL; exit($fail > 0 ? 1 : 0);