fix(abdm): resolve 500 internal server error on ABHA patient request list

This commit is contained in:
DevSoftTech Server 2026-09-09 18:46:28 +05:30
parent 9176877d07
commit b89bace2c9
3 changed files with 389 additions and 201 deletions

View File

@ -28,17 +28,27 @@ class AbdmHiu extends BaseController
public function patientRequestListData() public function patientRequestListData()
{ {
$q = trim((string) ($this->request->getGet('q') ?? '')); try {
$status = trim((string) ($this->request->getGet('status') ?? '')); $q = trim((string) ($this->request->getGet('q') ?? ''));
$limit = (int) ($this->request->getGet('limit') ?? 300); $status = trim((string) ($this->request->getGet('status') ?? ''));
if ($limit <= 0 || $limit > 1000) { $limit = (int) ($this->request->getGet('limit') ?? 300);
$limit = 300; if ($limit <= 0 || $limit > 1000) {
$limit = 300;
}
$service = new \App\Libraries\Abdm\ConsentSessionListService();
$result = $service->getGlobalConsentRequestsList(['q' => $q, 'status' => $status], $limit);
return $this->response->setJSON($result);
} catch (\Throwable $e) {
log_message('error', 'AbdmHiu::patientRequestListData failure: ' . $e->getMessage() . "\n" . $e->getTraceAsString());
return $this->response->setJSON([
'ok' => 0,
'error' => 'Unable to load consent requests: ' . $e->getMessage(),
'requests' => [],
]);
} }
$service = new \App\Libraries\Abdm\ConsentSessionListService();
$result = $service->getGlobalConsentRequestsList(['q' => $q, 'status' => $status], $limit);
return $this->response->setJSON($result);
} }
public function documents() public function documents()

View File

@ -25,99 +25,141 @@ class ConsentSessionListService
*/ */
public function getGlobalConsentRequestsList(array $filters = [], int $limit = 300): array public function getGlobalConsentRequestsList(array $filters = [], int $limit = 300): array
{ {
if (! $this->db->tableExists('abdm_hiu_workflows') || ! $this->db->tableExists('patient_master')) { @ini_set('memory_limit', '256M');
return ['ok' => 1, 'requests' => []];
}
$fields = $this->db->getFieldNames('abdm_hiu_workflows') ?? []; try {
$select = ['id', 'operation', 'workflow_state', 'status', 'request_id', 'consent_id', 'hfr_id', 'abha_address', 'created_at', 'updated_at', 'completed_at', 'expired_at', 'revoked_at', 'last_error', 'http_code', 'request_json', 'response_json']; if (! $this->db->tableExists('abdm_hiu_workflows') || ! $this->db->tableExists('patient_master')) {
foreach (['abdm_consent_request_id', 'abdm_consent_artifact_id', 'gateway_request_id'] as $optionalField) { return ['ok' => 1, 'requests' => []];
if (in_array($optionalField, $fields, true)) {
$select[] = $optionalField;
} }
}
$rows = $this->db->table('abdm_hiu_workflows') $fields = $this->db->getFieldNames('abdm_hiu_workflows') ?? [];
->select(implode(', ', $select)) if ($fields === []) {
->whereIn('operation', [ return ['ok' => 1, 'requests' => []];
'consent_request',
'consent_status',
'consent_reconcile',
'data_fetch',
'consent_callback',
'hi_on_request_callback',
'hi_data_push_callback',
])
->orderBy('id', 'DESC')
->get(2000)
->getResultArray();
if ($rows === []) {
return ['ok' => 1, 'requests' => []];
}
// Group rows by abha_address, preserving the DESC-by-id order within each group.
$byAddress = [];
foreach ($rows as $row) {
$addr = trim((string) ($row['abha_address'] ?? ''));
if ($addr === '') {
continue;
} }
$byAddress[$addr][] = $row;
}
if ($byAddress === []) { $candidateColumns = [
return ['ok' => 1, 'requests' => []]; 'id', 'operation', 'workflow_state', 'status', 'request_id', 'consent_id',
} 'hfr_id', 'abha_address', 'created_at', 'updated_at', 'completed_at',
'expired_at', 'revoked_at', 'last_error', 'http_code',
$patientsByAddress = $this->lookupPatientsByAbhaAddress(array_keys($byAddress)); 'abdm_consent_request_id', 'abdm_consent_artifact_id', 'gateway_request_id',
$statusFilter = strtoupper(trim((string) ($filters['status'] ?? '')));
$q = strtolower(trim((string) ($filters['q'] ?? '')));
$out = [];
foreach ($byAddress as $addr => $addrRows) {
$patientInfo = $patientsByAddress[$addr] ?? [
'patient_id' => 0,
'patient_code' => '',
'patient_name' => '',
'mobile' => '',
]; ];
$select = [];
foreach ($candidateColumns as $col) {
if (in_array($col, $fields, true)) {
$select[] = $col;
}
}
if ($select === []) {
$select[] = 'id';
}
$sessions = $this->groupWorkflowRowsIntoSessions($addrRows); // Exclude huge FHIR bundles and decrypted base64 document attachments
foreach ($sessions as $sessionRows) { // in data_fetch and hi_data_push_callback rows from being buffered into PHP memory.
$detail = $this->computeConsentSessionDetail($sessionRows, $addr); if (in_array('request_json', $fields, true)) {
if ((int) ($detail['ok'] ?? 0) !== 1) { $select[] = "(CASE WHEN operation IN ('data_fetch', 'hi_data_push_callback', 'DATA_FETCH', 'HI_DATA_PUSH_CALLBACK') THEN NULL ELSE request_json END) AS request_json";
}
if (in_array('response_json', $fields, true)) {
$select[] = "(CASE WHEN operation IN ('data_fetch', 'hi_data_push_callback', 'DATA_FETCH', 'HI_DATA_PUSH_CALLBACK') THEN NULL ELSE response_json END) AS response_json";
}
$selectSql = implode(', ', $select);
$rows = $this->db->table('abdm_hiu_workflows')
->select($selectSql)
->whereIn('operation', [
'consent_request',
'consent_status',
'consent_reconcile',
'data_fetch',
'consent_callback',
'hi_on_request_callback',
'hi_data_push_callback',
'CONSENT_REQUEST',
'CONSENT_STATUS',
'CONSENT_RECONCILE',
'DATA_FETCH',
'CONSENT_CALLBACK',
'HI_ON_REQUEST_CALLBACK',
'HI_DATA_PUSH_CALLBACK',
])
->orderBy('id', 'DESC')
->get(2000)
->getResultArray();
if ($rows === []) {
return ['ok' => 1, 'requests' => []];
}
// Group rows by abha_address, preserving the DESC-by-id order within each group.
$byAddress = [];
foreach ($rows as $row) {
$addr = trim((string) ($row['abha_address'] ?? ''));
if ($addr === '') {
continue; continue;
} }
$consent = $detail['consent']; $byAddress[$addr][] = $row;
}
if ($statusFilter !== '' && strtoupper((string) $consent['status']) !== $statusFilter) { if ($byAddress === []) {
continue; return ['ok' => 1, 'requests' => []];
} }
if ($q !== '') {
$haystack = strtolower( $patientsByAddress = $this->lookupPatientsByAbhaAddress(array_keys($byAddress));
$patientInfo['patient_name'] . ' ' . $patientInfo['patient_code'] . ' '
. $patientInfo['mobile'] . ' ' . $addr $statusFilter = strtoupper(trim((string) ($filters['status'] ?? '')));
); $q = strtolower(trim((string) ($filters['q'] ?? '')));
if (strpos($haystack, $q) === false) {
$out = [];
foreach ($byAddress as $addr => $addrRows) {
$patientInfo = $patientsByAddress[$addr] ?? [
'patient_id' => 0,
'patient_code' => '',
'patient_name' => '',
'mobile' => '',
];
$sessions = $this->groupWorkflowRowsIntoSessions($addrRows);
foreach ($sessions as $sessionRows) {
$detail = $this->computeConsentSessionDetail($sessionRows, $addr);
if ((int) ($detail['ok'] ?? 0) !== 1) {
continue; continue;
} }
$consent = $detail['consent'];
if ($statusFilter !== '' && strtoupper((string) ($consent['status'] ?? '')) !== $statusFilter) {
continue;
}
if ($q !== '') {
$haystack = strtolower(
($patientInfo['patient_name'] ?? '') . ' ' . ($patientInfo['patient_code'] ?? '') . ' '
. ($patientInfo['mobile'] ?? '') . ' ' . $addr
);
if (strpos($haystack, $q) === false) {
continue;
}
}
$out[] = array_merge($patientInfo, $consent);
} }
$out[] = array_merge($patientInfo, $consent);
} }
usort($out, function ($a, $b) {
return strcmp((string) ($b['requested_on'] ?? ''), (string) ($a['requested_on'] ?? ''));
});
if ($limit > 0 && count($out) > $limit) {
$out = array_slice($out, 0, $limit);
}
return ['ok' => 1, 'requests' => $out];
} catch (\Throwable $e) {
log_message('error', 'ConsentSessionListService::getGlobalConsentRequestsList failure: ' . $e->getMessage() . "\n" . $e->getTraceAsString());
return [
'ok' => 0,
'error' => 'Failed to load consent requests: ' . $e->getMessage(),
'requests' => [],
];
} }
usort($out, function ($a, $b) {
return strcmp((string) ($b['requested_on'] ?? ''), (string) ($a['requested_on'] ?? ''));
});
if ($limit > 0 && count($out) > $limit) {
$out = array_slice($out, 0, $limit);
}
return ['ok' => 1, 'requests' => $out];
} }
/** /**
@ -126,45 +168,68 @@ class ConsentSessionListService
*/ */
private function lookupPatientsByAbhaAddress(array $abhaAddresses): array private function lookupPatientsByAbhaAddress(array $abhaAddresses): array
{ {
$fields = $this->db->getFieldNames('patient_master') ?? []; try {
$idCol = $this->resolveExistingColumn($fields, ['id']); if ($abhaAddresses === [] || ! $this->db->tableExists('patient_master')) {
$uhidCol = $this->resolveExistingColumn($fields, ['p_code', 'uhid', 'uhid_no', 'patient_code', 'patient_id']); return [];
$nameCol = $this->resolveExistingColumn($fields, ['p_fname', 'patient_name', 'name']); }
$mobileCol = $this->resolveExistingColumn($fields, ['p_mobile', 'mobile', 'phone', 'contact_no']);
$abhaAddressCol = $this->resolveExistingColumn($fields, ['abha_address', 'abha_addr']);
if ($idCol === null || $abhaAddressCol === null || $abhaAddresses === []) { $fields = $this->db->getFieldNames('patient_master') ?? [];
$idCol = $this->resolveExistingColumn($fields, ['id']);
$uhidCol = $this->resolveExistingColumn($fields, ['p_code', 'uhid', 'uhid_no', 'patient_code', 'patient_id']);
$nameCol = $this->resolveExistingColumn($fields, ['p_fname', 'patient_name', 'name']);
$lastNameCol = $this->resolveExistingColumn($fields, ['p_lname', 'last_name']);
$mobileCol = $this->resolveExistingColumn($fields, ['mphone1', 'mphone2', 'p_mobile', 'mobile', 'phone', 'contact_no', 'phone1']);
$abhaAddressCol = $this->resolveExistingColumn($fields, ['abha_address', 'abha_addr']);
if ($idCol === null || $abhaAddressCol === null) {
return [];
}
$selectParts = [$idCol . ' AS id', $abhaAddressCol . ' AS abha_address'];
if ($uhidCol !== null) {
$selectParts[] = $uhidCol . ' AS uhid';
}
if ($nameCol !== null) {
$selectParts[] = $nameCol . ' AS name';
}
if ($lastNameCol !== null) {
$selectParts[] = $lastNameCol . ' AS last_name';
}
if ($mobileCol !== null) {
$selectParts[] = $mobileCol . ' AS mobile';
}
$rows = $this->db->table('patient_master')
->select(implode(', ', $selectParts), false)
->whereIn($abhaAddressCol, $abhaAddresses)
->get()
->getResultArray();
$out = [];
foreach ($rows as $p) {
$addr = trim((string) ($p['abha_address'] ?? ''));
if ($addr === '') {
continue;
}
$firstName = trim((string) ($p['name'] ?? ''));
$lastName = trim((string) ($p['last_name'] ?? ''));
if ($lastName === '0') {
$lastName = '';
}
$fullName = trim($firstName . ' ' . $lastName);
$out[$addr] = [
'patient_id' => (int) ($p['id'] ?? 0),
'patient_code' => trim((string) ($p['uhid'] ?? '')),
'patient_name' => $fullName !== '' ? $fullName : $firstName,
'mobile' => trim((string) ($p['mobile'] ?? '')),
];
}
return $out;
} catch (\Throwable $e) {
log_message('warning', 'ConsentSessionListService::lookupPatientsByAbhaAddress error: ' . $e->getMessage());
return []; return [];
} }
$builder = $this->db->table('patient_master')
->select('' . $idCol . ' AS id, ' . $abhaAddressCol . ' AS abha_address', false);
if ($uhidCol !== null) {
$builder->select($uhidCol . ' AS uhid', false);
}
if ($nameCol !== null) {
$builder->select($nameCol . ' AS name', false);
}
if ($mobileCol !== null) {
$builder->select($mobileCol . ' AS mobile', false);
}
$builder->whereIn($abhaAddressCol, $abhaAddresses);
$out = [];
foreach ($builder->get()->getResultArray() as $p) {
$addr = trim((string) ($p['abha_address'] ?? ''));
if ($addr === '') {
continue;
}
$out[$addr] = [
'patient_id' => (int) ($p['id'] ?? 0),
'patient_code' => trim((string) ($p['uhid'] ?? '')),
'patient_name' => trim((string) ($p['name'] ?? '')),
'mobile' => trim((string) ($p['mobile'] ?? '')),
];
}
return $out;
} }
private function resolveExistingColumn(array $fields, array $candidates): ?string private function resolveExistingColumn(array $fields, array $candidates): ?string
@ -179,11 +244,9 @@ class ConsentSessionListService
} }
/** /**
* Splits a DESC-by-id set of workflow rows (all belonging to one ABHA * Splits a DESC-by-id set of workflow rows into distinct consent request
* address) into distinct consent request "sessions" — each * "sessions", correlating rows by their stable identifiers (request_id /
* CONSENT_REQUEST row starts a new session, and every subsequent row * abdm_consent_request_id / consent_id) rather than simple chronological proximity.
* belongs to that session until the next CONSENT_REQUEST row appears.
* Returns sessions in chronological order (oldest session first).
* *
* @param array<int, array<string, mixed>> $rows rows ordered DESC by id * @param array<int, array<string, mixed>> $rows rows ordered DESC by id
* @return array<int, array<int, array<string, mixed>>> * @return array<int, array<int, array<string, mixed>>>
@ -193,20 +256,94 @@ class ConsentSessionListService
$chronological = array_reverse($rows); $chronological = array_reverse($rows);
$sessions = []; $sessions = [];
$current = []; $order = [];
$abdmIdToAnchor = [];
$requestIdToAnchor = [];
$anchorHasAbdmId = [];
$openAnchor = null;
foreach ($chronological as $row) { foreach ($chronological as $row) {
$operation = strtoupper(trim((string) ($row['operation'] ?? ''))); $operation = strtoupper(trim((string) ($row['operation'] ?? '')));
if ($operation === 'CONSENT_REQUEST' && $current !== []) { $rowRequestId = trim((string) ($row['request_id'] ?? ''));
$sessions[] = $current; $rowAbdmConsentRequestId = trim((string) ($row['abdm_consent_request_id'] ?? ''));
$current = []; $rowConsentId = trim((string) ($row['consent_id'] ?? ''));
if ($operation === 'CONSENT_REQUEST') {
$anchorKey = 'anchor_' . count($order);
$order[] = $anchorKey;
$sessions[$anchorKey] = [$row];
if ($rowRequestId !== '') {
$requestIdToAnchor[$rowRequestId] = $anchorKey;
}
if ($rowAbdmConsentRequestId !== '') {
$abdmIdToAnchor[$rowAbdmConsentRequestId] = $anchorKey;
$requestIdToAnchor[$rowAbdmConsentRequestId] = $anchorKey;
$anchorHasAbdmId[$anchorKey] = true;
}
if ($rowConsentId !== '') {
$abdmIdToAnchor[$rowConsentId] = $anchorKey;
$requestIdToAnchor[$rowConsentId] = $anchorKey;
}
$openAnchor = $anchorKey;
continue;
}
$anchorKey = null;
if ($rowAbdmConsentRequestId !== '' && isset($abdmIdToAnchor[$rowAbdmConsentRequestId])) {
$anchorKey = $abdmIdToAnchor[$rowAbdmConsentRequestId];
} elseif ($rowRequestId !== '' && isset($requestIdToAnchor[$rowRequestId])) {
$anchorKey = $requestIdToAnchor[$rowRequestId];
} elseif ($rowConsentId !== '' && isset($requestIdToAnchor[$rowConsentId])) {
$anchorKey = $requestIdToAnchor[$rowConsentId];
} elseif ($openAnchor !== null && ($rowAbdmConsentRequestId === '' || empty($anchorHasAbdmId[$openAnchor]))) {
$anchorKey = $openAnchor;
}
if ($anchorKey === null) {
$anchorKey = 'orphan_' . count($order);
$order[] = $anchorKey;
$sessions[$anchorKey] = [];
}
$sessions[$anchorKey][] = $row;
if ($anchorKey === $openAnchor) {
$openAnchor = null;
}
if ($rowAbdmConsentRequestId !== '') {
$abdmIdToAnchor[$rowAbdmConsentRequestId] = $anchorKey;
$anchorHasAbdmId[$anchorKey] = true;
}
if ($rowRequestId !== '') {
$requestIdToAnchor[$rowRequestId] = $anchorKey;
}
if ($rowConsentId !== '') {
$requestIdToAnchor[$rowConsentId] = $anchorKey;
} }
$current[] = $row;
}
if ($current !== []) {
$sessions[] = $current;
} }
return $sessions; $result = [];
foreach ($order as $anchorKey) {
if (! empty($sessions[$anchorKey])) {
$result[] = $sessions[$anchorKey];
}
}
return $result;
}
/**
* Extracts a clean scalar string from mixed input (preventing Array-to-string conversion notices).
*
* @param mixed $val
*/
private function extractScalarString($val): string
{
if (is_scalar($val)) {
return trim((string) $val);
}
return '';
} }
/** /**
@ -234,25 +371,27 @@ class ConsentSessionListService
$rawConsentStatus = ''; $rawConsentStatus = '';
if (isset($decoded['consent']) && is_array($decoded['consent'])) { if (isset($decoded['consent']) && is_array($decoded['consent'])) {
$rawConsentStatus = trim((string) ( $rawConsentStatus = $this->extractScalarString(
$decoded['consent']['status'] $decoded['consent']['status']
?? $decoded['consent']['consent_status'] ?? $decoded['consent']['consent_status']
?? $decoded['consent']['consentStatus'] ?? $decoded['consent']['consentStatus']
?? '' ?? null
)); );
} }
if ($rawConsentStatus === '' && isset($decoded['consentDetail']) && is_array($decoded['consentDetail'])) { if ($rawConsentStatus === '' && isset($decoded['consentDetail']) && is_array($decoded['consentDetail'])) {
$rawConsentStatus = trim((string) ($decoded['consentDetail']['status'] ?? '')); $rawConsentStatus = $this->extractScalarString($decoded['consentDetail']['status'] ?? null);
} }
if ($rawConsentStatus === '' && isset($decoded['data']['consent']) && is_array($decoded['data']['consent'])) { if ($rawConsentStatus === '' && isset($decoded['data']['consent']) && is_array($decoded['data']['consent'])) {
$rawConsentStatus = trim((string) ($decoded['data']['consent']['status'] ?? '')); $rawConsentStatus = $this->extractScalarString($decoded['data']['consent']['status'] ?? null);
} }
if ($rawConsentStatus === '') { if ($rawConsentStatus === '') {
$rawConsentStatus = trim((string) ($decoded['consent_status'] ?? $decoded['consentStatus'] ?? '')); $rawConsentStatus = $this->extractScalarString(
$decoded['consent_status'] ?? $decoded['consentStatus'] ?? null
);
} }
if ($rawConsentStatus === '' || in_array(strtolower($rawConsentStatus), ['success', 'ok', 'failed', 'error', 'status_checked'], true)) { if ($rawConsentStatus === '' || in_array(strtolower($rawConsentStatus), ['success', 'ok', 'failed', 'error', 'status_checked'], true)) {
$topStatus = trim((string) ($decoded['status'] ?? '')); $topStatus = $this->extractScalarString($decoded['status'] ?? null);
if (! in_array(strtolower($topStatus), ['success', 'ok', 'failed', 'error', 'status_checked', '1', '0'], true)) { if (! in_array(strtolower($topStatus), ['success', 'ok', 'failed', 'error', 'status_checked', '1', '0', ''], true)) {
$rawConsentStatus = $topStatus; $rawConsentStatus = $topStatus;
} }
} }
@ -264,9 +403,12 @@ class ConsentSessionListService
$phase = 'REQUESTED'; $phase = 'REQUESTED';
$priority = 120; $priority = 120;
if (($operation === 'DATA_FETCH' || $operation === 'HI_DATA_PUSH_CALLBACK') && $status === 'SUCCESS') { if (($operation === 'DATA_FETCH' || $operation === 'HI_DATA_PUSH_CALLBACK') && $status === 'SUCCESS' && $state === 'DATA_RECEIVED') {
$phase = 'COMPLETED'; $phase = 'COMPLETED';
$priority = 500; $priority = 500;
} elseif (($operation === 'DATA_FETCH' || $operation === 'HI_DATA_PUSH_CALLBACK') && $status === 'SUCCESS') {
$phase = 'COMPLETED';
$priority = 490;
} elseif (in_array($rawConsentStatus, ['GRANTED', 'APPROVED', 'ACTIVE'], true)) { } elseif (in_array($rawConsentStatus, ['GRANTED', 'APPROVED', 'ACTIVE'], true)) {
$phase = 'GRANTED'; $phase = 'GRANTED';
$priority = 430; $priority = 430;
@ -325,20 +467,22 @@ class ConsentSessionListService
} }
$rowStatus = ''; $rowStatus = '';
if (isset($rowDecoded['consent']) && is_array($rowDecoded['consent'])) { if (isset($rowDecoded['consent']) && is_array($rowDecoded['consent'])) {
$rowStatus = trim((string) ( $rowStatus = $this->extractScalarString(
$rowDecoded['consent']['status'] $rowDecoded['consent']['status']
?? $rowDecoded['consent']['consent_status'] ?? $rowDecoded['consent']['consent_status']
?? '' ?? null
)); );
} }
if ($rowStatus === '' && isset($rowDecoded['consentDetail']) && is_array($rowDecoded['consentDetail'])) { if ($rowStatus === '' && isset($rowDecoded['consentDetail']) && is_array($rowDecoded['consentDetail'])) {
$rowStatus = trim((string) ($rowDecoded['consentDetail']['status'] ?? '')); $rowStatus = $this->extractScalarString($rowDecoded['consentDetail']['status'] ?? null);
} }
if ($rowStatus === '' && isset($rowDecoded['data']['consent']) && is_array($rowDecoded['data']['consent'])) { if ($rowStatus === '' && isset($rowDecoded['data']['consent']) && is_array($rowDecoded['data']['consent'])) {
$rowStatus = trim((string) ($rowDecoded['data']['consent']['status'] ?? '')); $rowStatus = $this->extractScalarString($rowDecoded['data']['consent']['status'] ?? null);
} }
if ($rowStatus === '') { if ($rowStatus === '') {
$rowStatus = trim((string) ($rowDecoded['consent_status'] ?? $rowDecoded['consentStatus'] ?? '')); $rowStatus = $this->extractScalarString(
$rowDecoded['consent_status'] ?? $rowDecoded['consentStatus'] ?? null
);
} }
if ($rowStatus === '' || in_array(strtolower($rowStatus), ['success', 'ok', 'failed', 'error', 'status_checked'], true)) { if ($rowStatus === '' || in_array(strtolower($rowStatus), ['success', 'ok', 'failed', 'error', 'status_checked'], true)) {
$rowState = strtoupper(trim((string) ($row['workflow_state'] ?? ''))); $rowState = strtoupper(trim((string) ($row['workflow_state'] ?? '')));
@ -359,6 +503,7 @@ class ConsentSessionListService
if ($terminalPhase !== '') { if ($terminalPhase !== '') {
$phase = $terminalPhase; $phase = $terminalPhase;
} }
$consentId = ''; $consentId = '';
$consentRequestId = ''; $consentRequestId = '';
foreach ($rows as $row) { foreach ($rows as $row) {
@ -370,19 +515,19 @@ class ConsentSessionListService
$rowConsentId = trim((string) ( $rowConsentId = trim((string) (
$row['abdm_consent_artifact_id'] $row['abdm_consent_artifact_id']
?? $row['consent_id'] ?? $row['consent_id']
?? $rowDecoded['consent_id'] ?? $this->extractScalarString($rowDecoded['consent_id'] ?? null)
?? $rowDecoded['consentId'] ?? $this->extractScalarString($rowDecoded['consentId'] ?? null)
?? $rowDecoded['consent']['id'] ?? $this->extractScalarString($rowDecoded['consent']['id'] ?? null)
?? $rowDecoded['consent']['consent_id'] ?? $this->extractScalarString($rowDecoded['consent']['consent_id'] ?? null)
?? $rowDecoded['consent']['consentId'] ?? $this->extractScalarString($rowDecoded['consent']['consentId'] ?? null)
?? $rowDecoded['consentDetail']['id'] ?? $this->extractScalarString($rowDecoded['consentDetail']['id'] ?? null)
?? $rowDecoded['consentDetail']['consentId'] ?? $this->extractScalarString($rowDecoded['consentDetail']['consentId'] ?? null)
?? $rowDecoded['consent_artifact_id'] ?? $this->extractScalarString($rowDecoded['consent_artifact_id'] ?? null)
?? $rowDecoded['consent_artefact_id'] ?? $this->extractScalarString($rowDecoded['consent_artefact_id'] ?? null)
?? $rowDecoded['consentArtifactId'] ?? $this->extractScalarString($rowDecoded['consentArtifactId'] ?? null)
?? $rowDecoded['consentArtefactId'] ?? $this->extractScalarString($rowDecoded['consentArtefactId'] ?? null)
?? $rowDecoded['data']['consent']['id'] ?? $this->extractScalarString($rowDecoded['data']['consent']['id'] ?? null)
?? $rowDecoded['data']['consent_id'] ?? $this->extractScalarString($rowDecoded['data']['consent_id'] ?? null)
?? '' ?? ''
)); ));
if ($rowConsentId !== '' && ! preg_match('/^REQ-/i', $rowConsentId)) { if ($rowConsentId !== '' && ! preg_match('/^REQ-/i', $rowConsentId)) {
@ -391,14 +536,14 @@ class ConsentSessionListService
$rowConsentRequestId = trim((string) ( $rowConsentRequestId = trim((string) (
$row['abdm_consent_request_id'] $row['abdm_consent_request_id']
?? $rowDecoded['abdm_consent_request_id'] ?? $this->extractScalarString($rowDecoded['abdm_consent_request_id'] ?? null)
?? $rowDecoded['consent_request_id'] ?? $this->extractScalarString($rowDecoded['consent_request_id'] ?? null)
?? $rowDecoded['consentRequestId'] ?? $this->extractScalarString($rowDecoded['consentRequestId'] ?? null)
?? $rowDecoded['consent']['consent_request_id'] ?? $this->extractScalarString($rowDecoded['consent']['consent_request_id'] ?? null)
?? $rowDecoded['consent']['consentRequestId'] ?? $this->extractScalarString($rowDecoded['consent']['consentRequestId'] ?? null)
?? $rowDecoded['consentDetail']['consent_request_id'] ?? $this->extractScalarString($rowDecoded['consentDetail']['consent_request_id'] ?? null)
?? $rowDecoded['consentDetail']['consentRequestId'] ?? $this->extractScalarString($rowDecoded['consentDetail']['consentRequestId'] ?? null)
?? $rowDecoded['data']['consent_request_id'] ?? $this->extractScalarString($rowDecoded['data']['consent_request_id'] ?? null)
?? '' ?? ''
)); ));
if ($rowConsentRequestId !== '' && ! preg_match('/^REQ-/i', $rowConsentRequestId)) { if ($rowConsentRequestId !== '' && ! preg_match('/^REQ-/i', $rowConsentRequestId)) {
@ -418,6 +563,11 @@ class ConsentSessionListService
} }
} }
$anchorState = strtoupper(trim((string) (is_array($consentRequestRow) ? ($consentRequestRow['workflow_state'] ?? '') : '')));
if (in_array($anchorState, ['EXPIRED', 'DENIED', 'REVOKED'], true)) {
$phase = $anchorState;
}
$requestedHiTypes = []; $requestedHiTypes = [];
$requestedOn = ''; $requestedOn = '';
$purpose = ''; $purpose = '';
@ -435,11 +585,23 @@ class ConsentSessionListService
$consentBlock = (array) ($reqPayload['consent'] ?? []); $consentBlock = (array) ($reqPayload['consent'] ?? []);
$requestedHiTypes = $this->normalizeHiTypesList($consentBlock['hiTypes'] ?? $consentBlock['hi_types'] ?? []); $requestedHiTypes = $this->normalizeHiTypesList($consentBlock['hiTypes'] ?? $consentBlock['hi_types'] ?? []);
$requestedOn = trim((string) ($consentRequestRow['created_at'] ?? '')); $requestedOn = trim((string) ($consentRequestRow['created_at'] ?? ''));
$purpose = trim((string) ($consentBlock['purpose']['text'] ?? $consentBlock['purpose']['code'] ?? '')); $purpose = $this->extractScalarString($consentBlock['purpose']['text'] ?? $consentBlock['purpose']['code'] ?? null);
$validFrom = trim((string) ($consentBlock['permission']['dateRange']['from'] ?? $consentBlock['permission']['date_range']['from'] ?? '')); $validFrom = $this->extractScalarString(
$validTo = trim((string) ($consentBlock['permission']['dateRange']['to'] ?? $consentBlock['permission']['date_range']['to'] ?? '')); $consentBlock['permission']['dateRange']['from']
$eraseAt = trim((string) ($consentBlock['permission']['dataEraseAt'] ?? $consentBlock['permission']['data_erase_at'] ?? '')); ?? $consentBlock['permission']['date_range']['from']
$requestedBy = trim((string) ($consentBlock['requester']['name'] ?? '')); ?? null
);
$validTo = $this->extractScalarString(
$consentBlock['permission']['dateRange']['to']
?? $consentBlock['permission']['date_range']['to']
?? null
);
$eraseAt = $this->extractScalarString(
$consentBlock['permission']['dataEraseAt']
?? $consentBlock['permission']['data_erase_at']
?? null
);
$requestedBy = $this->extractScalarString($consentBlock['requester']['name'] ?? null);
if ($hfrId === '') { if ($hfrId === '') {
$hfrId = trim((string) ($consentRequestRow['hfr_id'] ?? '')); $hfrId = trim((string) ($consentRequestRow['hfr_id'] ?? ''));
} }
@ -463,47 +625,47 @@ class ConsentSessionListService
continue; continue;
} }
if ($validFrom === '') { if ($validFrom === '') {
$validFrom = trim((string) ( $validFrom = $this->extractScalarString(
$c['permission']['dateRange']['from'] $c['permission']['dateRange']['from']
?? $c['permission']['date_range']['from'] ?? $c['permission']['date_range']['from']
?? $c['date_range']['from'] ?? $c['date_range']['from']
?? $c['dateRange']['from'] ?? $c['dateRange']['from']
?? '' ?? null
)); );
} }
if ($validTo === '') { if ($validTo === '') {
$validTo = trim((string) ( $validTo = $this->extractScalarString(
$c['permission']['dateRange']['to'] $c['permission']['dateRange']['to']
?? $c['permission']['date_range']['to'] ?? $c['permission']['date_range']['to']
?? $c['date_range']['to'] ?? $c['date_range']['to']
?? $c['dateRange']['to'] ?? $c['dateRange']['to']
?? '' ?? null
)); );
} }
if ($eraseAt === '') { if ($eraseAt === '') {
$eraseAt = trim((string) ( $eraseAt = $this->extractScalarString(
$c['permission']['dataEraseAt'] $c['permission']['dataEraseAt']
?? $c['permission']['data_erase_at'] ?? $c['permission']['data_erase_at']
?? $c['expiry'] ?? (is_array($c['expiry'] ?? null) ? ($c['expiry']['date'] ?? null) : ($c['expiry'] ?? null))
?? $c['dataEraseAt'] ?? $c['dataEraseAt']
?? $c['data_erase_at'] ?? $c['data_erase_at']
?? '' ?? null
)); );
} }
if ($purpose === '') { if ($purpose === '') {
$purpose = trim((string) ( $purpose = $this->extractScalarString(
$c['purpose']['text'] $c['purpose']['text']
?? $c['purpose']['code'] ?? $c['purpose']['code']
?? $c['purpose'] ?? $c['purpose']
?? '' ?? null
)); );
} }
if ($requestedBy === '') { if ($requestedBy === '') {
$requestedBy = trim((string) ( $requestedBy = $this->extractScalarString(
$c['requester']['name'] $c['requester']['name']
?? $c['requester'] ?? $c['requester']
?? '' ?? null
)); );
} }
if ($requestedOn === '') { if ($requestedOn === '') {
$requestedOn = trim((string) ($row['created_at'] ?? '')); $requestedOn = trim((string) ($row['created_at'] ?? ''));
@ -521,7 +683,10 @@ class ConsentSessionListService
$rowHiTypes = $this->normalizeHiTypesList($decoded['hi_types'] ?? $decoded['consent']['hi_types'] ?? []); $rowHiTypes = $this->normalizeHiTypesList($decoded['hi_types'] ?? $decoded['consent']['hi_types'] ?? []);
if ($rowHiTypes !== []) { if ($rowHiTypes !== []) {
$grantedHiTypes = $rowHiTypes; $grantedHiTypes = $rowHiTypes;
$grantedOn = trim((string) ($decoded['granted_at'] ?? $row['updated_at'] ?? '')); $grantedOn = trim((string) (
$this->extractScalarString($decoded['granted_at'] ?? null)
?: ($row['updated_at'] ?? '')
));
break; break;
} }
} }
@ -529,7 +694,10 @@ class ConsentSessionListService
$revokedOn = trim((string) ($best['revoked_at'] ?? '')); $revokedOn = trim((string) ($best['revoked_at'] ?? ''));
$expiredOn = trim((string) ($best['expired_at'] ?? '')); $expiredOn = trim((string) ($best['expired_at'] ?? ''));
if (in_array($phase, ['GRANTED', 'COMPLETED'], true) && $grantedOn === '') { if (in_array($phase, ['GRANTED', 'COMPLETED'], true) && $grantedOn === '') {
$grantedOn = trim((string) ($bestDecoded['granted_at'] ?? $best['updated_at'] ?? '')); $grantedOn = trim((string) (
$this->extractScalarString($bestDecoded['granted_at'] ?? null)
?: ($best['updated_at'] ?? '')
));
} }
$items = []; $items = [];
@ -607,9 +775,15 @@ class ConsentSessionListService
$out = []; $out = [];
foreach ($value as $v) { foreach ($value as $v) {
$v = trim((string) $v); if (is_array($v)) {
if ($v !== '' && ! in_array($v, $out, true)) { $v = $v['type'] ?? $v['hiType'] ?? $v['name'] ?? $v['code'] ?? null;
$out[] = $v; }
if (! is_scalar($v)) {
continue;
}
$s = trim((string) $v);
if ($s !== '' && ! in_array($s, $out, true)) {
$out[] = $s;
} }
} }

View File

@ -202,7 +202,11 @@
$('#prlCountBox').text('Loading...'); $('#prlCountBox').text('Loading...');
var url = listUrl + '?q=' + encodeURIComponent($('#prlSearch').val() || '') + '&status=' + encodeURIComponent($('#prlStatus').val() || ''); var url = listUrl + '?q=' + encodeURIComponent($('#prlSearch').val() || '') + '&status=' + encodeURIComponent($('#prlStatus').val() || '');
fetch(url, { credentials: 'same-origin' }) fetch(url, { credentials: 'same-origin' })
.then(function(resp) { return resp.json(); }) .then(function(resp) {
return resp.json().catch(function() {
return { ok: 0, error: 'Server returned HTTP ' + resp.status + (resp.statusText ? (' (' + resp.statusText + ')') : '') };
});
})
.then(function(data) { .then(function(data) {
if (!data || data.ok !== 1) { if (!data || data.ok !== 1) {
throw new Error((data && data.error) || 'Unable to load consent requests.'); throw new Error((data && data.error) || 'Unable to load consent requests.');