diff --git a/app/Controllers/Patient.php b/app/Controllers/Patient.php index e1873a1..1135a20 100644 --- a/app/Controllers/Patient.php +++ b/app/Controllers/Patient.php @@ -2070,6 +2070,39 @@ class Patient extends BaseController $documentsPersisted = (int) ($fetchResult['documents_persisted'] ?? 0); $documentsUpdated = (int) ($fetchResult['documents_updated'] ?? 0); + // The consent-artifact-scoped fetch above (bridge "Method 2") may resolve + // to a stale/different session sharing the same consent artifact id. Per + // the bridge gateway team, GET /v1/hiu/data/fetch?request_id=... ("Method + // 1") targets the ONE specific consent request instead -- this is the + // "self"/current session's own data. Try it before falling back to the + // broader by-ABHA-address historical lookup (Method 3). + if ($documentsPersisted + $documentsUpdated === 0 && $consentRequestRef !== '') { + try { + $requestIdFetchResult = $service->runOperation('data_fetch', [ + 'abha_address' => $abhaContext['abha_address'], + 'consentRequestId' => $consentRequestRef, + 'fetch_by_request_id' => 1, + ]); + } catch (\Throwable $e) { + $requestIdFetchResult = null; + } + + if (is_array($requestIdFetchResult) && (int) ($requestIdFetchResult['ok'] ?? 0) === 1) { + $reqDocumentsPersisted = (int) ($requestIdFetchResult['documents_persisted'] ?? 0); + $reqDocumentsUpdated = (int) ($requestIdFetchResult['documents_updated'] ?? 0); + if ($reqDocumentsPersisted + $reqDocumentsUpdated > 0) { + return $this->response->setJSON([ + 'ok' => 1, + 'phase' => 'COMPLETED', + 'message' => 'Records fetched successfully using existing granted consent.', + 'documents_persisted' => $reqDocumentsPersisted, + 'documents_updated' => $reqDocumentsUpdated, + 'data' => ['data_fetch' => $fetchResult, 'data_fetch_by_request_id' => $requestIdFetchResult], + ]); + } + } + } + // The consent-artifact-scoped fetch above (bridge "Method 1/2") only // returns data for the ONE consent/request we targeted. Per the bridge // gateway team, GET /v1/hiu/data/fetch?abha_address=... ("Method 3") @@ -3552,7 +3585,16 @@ class Patient extends BaseController $phase = 'REQUESTED'; $priority = 120; - if (($operation === 'DATA_FETCH' || $operation === 'HI_DATA_PUSH_CALLBACK') && $status === 'SUCCESS') { + // NOTE: `status` only reflects whether the bridge API call itself + // succeeded (no HTTP/transport error) -- it does NOT mean the HIP + // actually sent any health records (see M3HiuWorkflowService:: + // resolveState()/runOperation(), which always set status=success for + // any error-free response, even one reporting decrypted_data=[]). + // Whether data truly arrived is tracked separately via workflow_state + // (DATA_PENDING vs DATA_RECEIVED); require that here too, otherwise a + // broad/historical data_fetch attempt with empty decrypted_data can + // wrongly hijack "latest consent" resolution with a stale consent_id. + if (($operation === 'DATA_FETCH' || $operation === 'HI_DATA_PUSH_CALLBACK') && $status === 'SUCCESS' && $state === 'DATA_RECEIVED') { $phase = 'COMPLETED'; $priority = 500; } elseif (in_array($rawConsentStatus, ['GRANTED', 'APPROVED', 'ACTIVE'], true)) { diff --git a/app/Libraries/Abdm/M3HiuWorkflowService.php b/app/Libraries/Abdm/M3HiuWorkflowService.php index 5604e28..ebf2116 100644 --- a/app/Libraries/Abdm/M3HiuWorkflowService.php +++ b/app/Libraries/Abdm/M3HiuWorkflowService.php @@ -998,6 +998,35 @@ class M3HiuWorkflowService ]; } + // Method 1 (per bridge gateway team, 2026-07-29): GET /v1/hiu/data/fetch + // ?request_id=... fetches data for the ONE specific consent request that + // request_id belongs to -- this is the "self"/current session's own data, + // distinct from Method 2 (consent_id, which can resolve to a different/ + // stale session sharing the same consent artifact) and Method 3 (abha_address, + // which returns unrelated historical sessions across every past consent). + // Callers opt in explicitly via fetch_by_request_id=1. + $fetchByRequestId = (int) ($clean['fetch_by_request_id'] ?? 0) === 1; + if ($fetchByRequestId) { + $requestIdOnly = trim((string) ( + $clean['abdm_consent_request_id'] + ?? $clean['consentRequestId'] + ?? $clean['consent_request_id'] + ?? '' + )); + if ($requestIdOnly === '') { + return [ + 'ok' => 0, + 'http_code' => 422, + 'error_text' => 'consent_request_id is required to fetch data by request_id (Method 1).', + ]; + } + + return [ + 'ok' => 1, + 'payload' => ['request_id' => $requestIdOnly], + ]; + } + $requestFallback = ''; if (! $requestIdGenerated) { $requestFallback = trim((string) (