From 92a954a4cda7e2a87a1049647ecaecf8b216ac83 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Mon, 27 Jul 2026 14:12:56 +0530 Subject: [PATCH] Fix ABDM HIU auto-flow duplicate consent handling --- app/Controllers/Patient.php | 101 +++++++++++++++++--- app/Libraries/Abdm/M3HiuWorkflowService.php | 24 ++++- 2 files changed, 106 insertions(+), 19 deletions(-) diff --git a/app/Controllers/Patient.php b/app/Controllers/Patient.php index aac6cfe..8c3633a 100644 --- a/app/Controllers/Patient.php +++ b/app/Controllers/Patient.php @@ -1375,18 +1375,36 @@ class Patient extends BaseController } if ((int) ($consentResult['ok'] ?? 0) !== 1) { - $httpCode = (int) ($consentResult['http_code'] ?? 422); - if ($httpCode < 100 || $httpCode > 599) { - $httpCode = 422; + $errorText = trim((string) ($consentResult['error_text'] ?? 'Consent request failed.')); + $isDuplicateConsent = stripos($errorText, 'ABDM-1070') !== false + || stripos($errorText, 'Duplicate consent request') !== false; + + if ($isDuplicateConsent) { + $existingRequestId = $this->findLatestAbdmGatewayRequestId($abhaContext['abha_address']); + if ($existingRequestId !== '') { + $consentResult['ok'] = 1; + $consentResult['http_code'] = 200; + $consentResult['request_id'] = $existingRequestId; + $consentResult['workflow_state'] = 'REQUESTED'; + $consentResult['reused_existing_request'] = 1; + $consentResult['message'] = 'Duplicate consent detected. Reusing latest request for reconciliation.'; + } } - return $this->response->setStatusCode($httpCode)->setJSON([ - 'ok' => 0, - 'phase' => 'REQUEST_FAILED', - 'error' => (string) ($consentResult['error_text'] ?? 'Consent request failed.'), - 'request_id' => (string) ($consentResult['request_id'] ?? ''), - 'data' => $consentResult, - ]); + if ((int) ($consentResult['ok'] ?? 0) !== 1) { + $httpCode = (int) ($consentResult['http_code'] ?? 422); + if ($httpCode < 100 || $httpCode > 599) { + $httpCode = 422; + } + + return $this->response->setStatusCode($httpCode)->setJSON([ + 'ok' => 0, + 'phase' => 'REQUEST_FAILED', + 'error' => (string) ($consentResult['error_text'] ?? 'Consent request failed.'), + 'request_id' => (string) ($consentResult['request_id'] ?? ''), + 'data' => $consentResult, + ]); + } } $flowRefId = trim((string) ( @@ -1401,9 +1419,6 @@ class Patient extends BaseController ?? $consentResult['abdm_consent_request_id'] ?? '' )); - if ($consentRequestRef === '') { - $consentRequestRef = $flowRefId; - } $consentArtifactRef = trim((string) ( $consentResult['consent_id'] ?? $consentResult['abdm_consent_artifact_id'] @@ -1422,13 +1437,21 @@ class Patient extends BaseController ]); } + if ($consentRequestRef === '' && preg_match('/^REQ-HIU-/i', $flowRefId) === 1) { + $resolvedRequestId = $this->findLatestAbdmGatewayRequestId($abhaContext['abha_address']); + if ($resolvedRequestId !== '') { + $flowRefId = $resolvedRequestId; + } + } + $reconcilePayload = [ 'abha_address' => $abhaContext['abha_address'], ]; + if ($flowRefId !== '') { + $reconcilePayload['request_id'] = $flowRefId; + } if ($consentRequestRef !== '') { $reconcilePayload['consentRequestId'] = $consentRequestRef; - } else { - $reconcilePayload['request_id'] = $flowRefId; } try { @@ -2729,5 +2752,53 @@ class Patient extends BaseController return 'REQUESTED'; } + private function findLatestAbdmGatewayRequestId(string $abhaAddress): string + { + $abhaAddress = trim($abhaAddress); + if ($abhaAddress === '' || ! $this->db->tableExists('abdm_hiu_workflows')) { + return ''; + } + + $fields = $this->db->getFieldNames('abdm_hiu_workflows') ?? []; + $select = ['request_id', 'response_json']; + if (in_array('gateway_request_id', $fields, true)) { + $select[] = 'gateway_request_id'; + } + if (in_array('hms_request_id', $fields, true)) { + $select[] = 'hms_request_id'; + } + + $rows = $this->db->table('abdm_hiu_workflows') + ->select(implode(', ', $select)) + ->where('operation', 'consent_request') + ->where('abha_address', $abhaAddress) + ->where('status', 'success') + ->orderBy('id', 'DESC') + ->get(20) + ->getResultArray(); + + foreach ($rows as $row) { + $candidates = [ + trim((string) ($row['gateway_request_id'] ?? '')), + trim((string) ($row['request_id'] ?? '')), + ]; + + $decoded = json_decode((string) ($row['response_json'] ?? ''), true); + if (is_array($decoded)) { + $candidates[] = trim((string) ($decoded['gateway_request_id'] ?? '')); + $candidates[] = trim((string) ($decoded['request_id'] ?? '')); + $candidates[] = trim((string) ($decoded['requestId'] ?? '')); + } + + foreach ($candidates as $candidate) { + if ($candidate !== '' && preg_match('/^REQ-/i', $candidate) === 1) { + return $candidate; + } + } + } + + return ''; + } + } diff --git a/app/Libraries/Abdm/M3HiuWorkflowService.php b/app/Libraries/Abdm/M3HiuWorkflowService.php index db2661a..721ee5e 100644 --- a/app/Libraries/Abdm/M3HiuWorkflowService.php +++ b/app/Libraries/Abdm/M3HiuWorkflowService.php @@ -602,6 +602,7 @@ class M3HiuWorkflowService private function normalizePayload(array $payload): array { $normalized = $payload; + $generatedRequestId = false; // Accept both legacy snake_case and guide-defined camelCase keys. if (! isset($normalized['request_id']) && isset($normalized['requestId'])) { @@ -641,6 +642,7 @@ class M3HiuWorkflowService if ($normalized['request_id'] === '') { $normalized['request_id'] = 'REQ-HIU-' . date('YmdHis') . '-' . strtoupper(bin2hex(random_bytes(3))); + $generatedRequestId = true; } if (! isset($normalized['requestId']) || trim((string) $normalized['requestId']) === '') { @@ -656,11 +658,14 @@ class M3HiuWorkflowService $normalized['consentId'] = $normalized['consent_id']; } + $normalized['__generated_request_id'] = $generatedRequestId ? 1 : 0; + return $normalized; } private function preparePayloadForOperation(string $operation, array $normalized): array { + $requestIdGenerated = (int) ($normalized['__generated_request_id'] ?? 0) === 1; $clean = $this->stripInternalNoise($normalized); $requestId = trim((string) ($clean['requestId'] ?? $clean['request_id'] ?? '')); if ($requestId === '') { @@ -794,6 +799,9 @@ class M3HiuWorkflowService if ($operation === 'consent_reconcile') { $requestIdRef = trim((string) ($clean['request_id'] ?? $clean['requestId'] ?? '')); + if ($requestIdGenerated) { + $requestIdRef = ''; + } $consentRequestId = trim((string) ($clean['abdm_consent_request_id'] ?? $clean['consentRequestId'] ?? '')); $consentId = trim((string) ($clean['abdm_consent_artifact_id'] ?? $clean['consentId'] ?? $clean['consent_id'] ?? '')); @@ -823,6 +831,15 @@ class M3HiuWorkflowService } if ($operation === 'data_fetch') { + $requestFallback = ''; + if (! $requestIdGenerated) { + $requestFallback = trim((string) ( + $clean['request_id'] + ?? $clean['requestId'] + ?? '' + )); + } + $consentId = trim((string) ( $clean['abdm_consent_artifact_id'] ?? $clean['consentId'] @@ -830,9 +847,7 @@ class M3HiuWorkflowService ?? $clean['abdm_consent_request_id'] ?? $clean['consentRequestId'] ?? $clean['consent_request_id'] - ?? $clean['request_id'] - ?? $clean['requestId'] - ?? '' + ?? $requestFallback )); if ($consentId === '') { $consentId = $this->resolveAbdmConsentArtifactIdFromWorkflow($clean); @@ -871,7 +886,8 @@ class M3HiuWorkflowService $payload['csrf_test_name'], $payload['patient_id'], $payload['abha_id'], - $payload['abhaId'] + $payload['abhaId'], + $payload['__generated_request_id'] ); if (isset($payload['requestId'])) {