db = \Config\Database::connect(); $this->baseUrl = rtrim((string) (getenv('EATRIA_BRIDGE_URL') ?: 'https://abdm-bridge.e-atria.in/api'), '/'); } public function consentRequest(array $payload): array { return $this->call('/v3/hiu/consent/request', $payload, 'consent.request'); } public function consentRequestStatus(array $payload): array { return $this->call('/v3/hiu/consent/request/status', $payload, 'consent.request.status'); } public function consentRequestFetch(array $payload): array { return $this->call('/v3/hiu/consent/request/fetch', $payload, 'consent.request.fetch'); } public function healthInformationRequest(array $payload): array { return $this->call('/v3/hiu/health-information/request', $payload, 'health-information.request'); } private function call(string $path, array $payload, string $eventKey): array { $settings = $this->resolveRuntimeSettings(); if (($settings['ok'] ?? 0) !== 1) { return $settings; } $token = (string) ($settings['token'] ?? ''); $hfrId = (string) ($settings['hfr_id'] ?? ''); $hospitalId = (string) ($settings['hospital_id'] ?? ''); $payloadHfrId = trim((string) ($payload['hfr_id'] ?? '')); if ($payloadHfrId !== '' && strcasecmp($payloadHfrId, $hfrId) !== 0) { return [ 'ok' => 0, 'http_code' => 400, 'error_text' => 'hfr_id mismatch: payload hfr_id does not match hospital_setting.ABDM_HFR_ID', 'retryable' => 0, ]; } $payload['hfr_id'] = $hfrId; $url = $this->baseUrl . $path; $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'Authorization: Bearer ' . $token, ]; if ($hospitalId !== '') { $headers[] = 'X-Hospital-Id: ' . $hospitalId; } $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $this->timeoutSec, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ]); $raw = curl_exec($ch); $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlErr = curl_error($ch); curl_close($ch); $decoded = json_decode((string) $raw, true); $isJson = is_array($decoded); $ok = $isJson ? (int) ($decoded['ok'] ?? ($httpCode >= 200 && $httpCode < 300 ? 1 : 0)) : (int) ($httpCode >= 200 && $httpCode < 300); $errorText = ''; if ($curlErr !== '') { $errorText = $curlErr; } elseif ($ok !== 1) { $errorText = $isJson ? (string) ($decoded['message'] ?? $decoded['error_text'] ?? $decoded['error'] ?? ('HTTP ' . $httpCode)) : ('HTTP ' . $httpCode . ' non-JSON response'); } $retryable = 0; if ($curlErr !== '' || $httpCode >= 500 || $httpCode === 0 || str_contains(strtolower($errorText), 'timed out')) { $retryable = 1; } $response = $isJson ? $decoded : ['raw' => (string) $raw]; $response['ok'] = $ok; $response['http_code'] = $httpCode; $response['error_text'] = $errorText; $response['retryable'] = $retryable; $gatewayRequestId = trim((string) ($response['request_id'] ?? $response['requestId'] ?? '')); if ($gatewayRequestId === '') { $gatewayRequestId = trim((string) ($payload['requestId'] ?? $payload['request_id'] ?? '')); } $response['gateway_request_id'] = $gatewayRequestId; $abdmConsentRequestId = $this->findFirstValueByKeys($response, [ 'consentRequestId', 'consent_request_id', 'abdm_consent_request_id', ]); if ($abdmConsentRequestId === '') { $abdmConsentRequestId = trim((string) ($payload['consentRequestId'] ?? '')); } if ($abdmConsentRequestId !== '') { $response['abdm_consent_request_id'] = $abdmConsentRequestId; $response['consent_request_id'] = $abdmConsentRequestId; } $abdmConsentId = $this->findFirstValueByKeys($response, [ 'consentId', 'consent_id', ]); if ($abdmConsentId === '') { $abdmConsentId = trim((string) ($payload['consentId'] ?? $payload['consent_id'] ?? '')); } if ($abdmConsentId !== '') { $response['consent_id'] = $abdmConsentId; $response['abdm_consent_artifact_id'] = $abdmConsentId; } if (! isset($response['request_id'])) { $response['request_id'] = $gatewayRequestId; } if (! isset($response['transaction_id'])) { $response['transaction_id'] = (string) ($response['transactionId'] ?? $payload['transactionId'] ?? $payload['transaction_id'] ?? ''); } $this->writeApiLog($eventKey, $path, $payload, $response, $httpCode, $ok, $errorText, $hospitalId); return $response; } private function resolveRuntimeSettings(): array { if (! $this->db->tableExists('hospital_setting')) { return ['ok' => 0, 'http_code' => 500, 'error_text' => 'hospital_setting table not found', 'retryable' => 0]; } $rows = $this->db->table('hospital_setting') ->select('s_name, s_value') ->whereIn('s_name', ['EATRIA_BRIDGE_TOKEN', 'ABDM_HFR_ID', 'ABDM_HOSPITAL_ID']) ->get() ->getResultArray(); $kv = []; foreach ($rows as $row) { $key = trim((string) ($row['s_name'] ?? '')); if ($key === '') { continue; } $kv[$key] = trim((string) ($row['s_value'] ?? '')); } $token = (string) ($kv['EATRIA_BRIDGE_TOKEN'] ?? ''); $hfrId = (string) ($kv['ABDM_HFR_ID'] ?? ''); $hospitalId = (string) ($kv['ABDM_HOSPITAL_ID'] ?? ''); if ($token === '') { return [ 'ok' => 0, 'http_code' => 401, 'error_text' => 'Missing token: set hospital_setting.EATRIA_BRIDGE_TOKEN', 'retryable' => 0, ]; } if ($hfrId === '') { return [ 'ok' => 0, 'http_code' => 400, 'error_text' => 'Missing hfr_id: set hospital_setting.ABDM_HFR_ID', 'retryable' => 0, ]; } return [ 'ok' => 1, 'token' => $token, 'hfr_id' => $hfrId, 'hospital_id' => $hospitalId, ]; } private function writeApiLog( string $eventKey, string $path, array $request, array $response, int $httpCode, int $ok, string $errorText, string $hospitalId ): void { if (! $this->db->tableExists('abdm_api_logs')) { return; } $status = $ok === 1 ? 'success' : 'error'; $entityId = trim((string) ( $request['consent_id'] ?? $request['consentId'] ?? $request['consentRequestId'] ?? $request['request_id'] ?? $request['requestId'] ?? $request['transaction_id'] ?? $request['transactionId'] ?? '' )); $this->db->table('abdm_api_logs')->insert([ 'channel' => 'eatria_bridge', 'event_type' => 'abdm.m3.hiu.' . $eventKey, 'endpoint' => $this->baseUrl . $path, 'http_method' => 'POST', 'entity_type' => 'abdm_hiu', 'entity_id' => $entityId, 'request_json' => (string) json_encode($request, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 'response_code' => $httpCode, 'response_json' => (string) json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 'status' => $status, 'error_message' => $errorText !== '' ? mb_substr($errorText, 0, 1000) : null, 'created_at' => date('Y-m-d H:i:s'), ]); } private function findFirstValueByKeys(array $root, array $keys): string { $queue = [$root]; while (! empty($queue)) { $node = array_shift($queue); if (! is_array($node)) { continue; } foreach ($keys as $key) { if (isset($node[$key])) { $value = trim((string) $node[$key]); if ($value !== '') { return $value; } } } foreach ($node as $child) { if (is_array($child)) { $queue[] = $child; } } } return ''; } }