fix(abdm): capture patient-modified consent dates, fix premature expiry, and update consent UI labels

- Extract and contrast both requested and patient-granted date ranges and eraseAt timestamps from ABDM consent artefacts
- Fix premature session expiration when patient grants longer consent validity than initially requested by HIU
- Update UI labels from Valid From / Valid To to Request From / Request To and Consent Valid Upto
- Show original requested dates struck-through and granted dates highlighted with Updated badges in consent detail modals
- Add visual indicators for patient-modified dates in consent requests tables
This commit is contained in:
DevSoftTech Server 2026-10-25 06:39:25 +05:30
parent 43d52163ab
commit 6cc34057b5
4 changed files with 369 additions and 102 deletions

View File

@ -6327,9 +6327,9 @@ class Patient extends BaseController
$requestedHiTypes = [];
$requestedOn = '';
$purpose = '';
$validFrom = '';
$validTo = '';
$eraseAt = '';
$requestedFrom = '';
$requestedTo = '';
$requestedEraseAt = '';
$requestedBy = '';
$hfrId = trim((string) ($best['hfr_id'] ?? ''));
@ -6342,40 +6342,31 @@ class Patient extends BaseController
$requestedHiTypes = $this->normalizeHiTypesList($consentBlock['hiTypes'] ?? $consentBlock['hi_types'] ?? []);
$requestedOn = trim((string) ($consentRequestRow['created_at'] ?? ''));
$purpose = trim((string) ($consentBlock['purpose']['text'] ?? $consentBlock['purpose']['code'] ?? ''));
$validFrom = trim((string) ($consentBlock['permission']['dateRange']['from'] ?? $consentBlock['permission']['date_range']['from'] ?? ''));
$validTo = trim((string) ($consentBlock['permission']['dateRange']['to'] ?? $consentBlock['permission']['date_range']['to'] ?? ''));
$eraseAt = trim((string) ($consentBlock['permission']['dataEraseAt'] ?? $consentBlock['permission']['data_erase_at'] ?? ''));
$requestedFrom = trim((string) ($consentBlock['permission']['dateRange']['from'] ?? $consentBlock['permission']['date_range']['from'] ?? ''));
$requestedTo = trim((string) ($consentBlock['permission']['dateRange']['to'] ?? $consentBlock['permission']['date_range']['to'] ?? ''));
$requestedEraseAt = trim((string) ($consentBlock['permission']['dataEraseAt'] ?? $consentBlock['permission']['data_erase_at'] ?? ''));
$requestedBy = trim((string) ($consentBlock['requester']['name'] ?? ''));
if ($hfrId === '') {
$hfrId = trim((string) ($consentRequestRow['hfr_id'] ?? ''));
}
}
// Fallback scanning across all session rows for missing metadata (dates, purpose, requestedBy)
// Fallback scanning across session rows for missing requested metadata
foreach ($rows as $row) {
$rowReq = json_decode((string) ($row['request_json'] ?? ''), true);
$rowResp = json_decode((string) ($row['response_json'] ?? ''), true);
$containers = [
is_array($rowReq) ? ($rowReq['consent'] ?? null) : null,
is_array($rowReq) ? ($rowReq['consentDetail'] ?? null) : null,
is_array($rowReq) ? ($rowReq['data']['consent'] ?? null) : null,
is_array($rowReq) ? ($rowReq['data']['consentDetail'] ?? null) : null,
is_array($rowReq) ? ($rowReq['data'] ?? null) : null,
is_array($rowReq) ? $rowReq : null,
is_array($rowResp) ? ($rowResp['consent'] ?? null) : null,
is_array($rowResp) ? ($rowResp['consentDetail'] ?? null) : null,
is_array($rowResp) ? ($rowResp['data']['consent'] ?? null) : null,
is_array($rowResp) ? ($rowResp['data']['consentDetail'] ?? null) : null,
is_array($rowResp) ? ($rowResp['data'] ?? null) : null,
is_array($rowResp) ? $rowResp : null,
];
foreach ($containers as $c) {
if (! is_array($c)) {
continue;
}
if ($validFrom === '') {
$validFrom = trim((string) (
if ($requestedFrom === '') {
$requestedFrom = trim((string) (
$c['permission']['dateRange']['from']
?? $c['permission']['date_range']['from']
?? $c['date_range']['from']
@ -6387,8 +6378,8 @@ class Patient extends BaseController
?? ''
));
}
if ($validTo === '') {
$validTo = trim((string) (
if ($requestedTo === '') {
$requestedTo = trim((string) (
$c['permission']['dateRange']['to']
?? $c['permission']['date_range']['to']
?? $c['date_range']['to']
@ -6400,8 +6391,8 @@ class Patient extends BaseController
?? ''
));
}
if ($eraseAt === '') {
$eraseAt = trim((string) (
if ($requestedEraseAt === '') {
$requestedEraseAt = trim((string) (
$c['permission']['dataEraseAt']
?? $c['permission']['data_erase_at']
?? $c['expiry']
@ -6416,7 +6407,6 @@ class Patient extends BaseController
$purpose = trim((string) (
$c['purpose']['text']
?? $c['purpose']['code']
?? $c['purpose']
?? ''
));
}
@ -6427,66 +6417,167 @@ class Patient extends BaseController
?? ''
));
}
if ($requestedOn === '') {
$requestedOn = trim((string) ($row['created_at'] ?? ''));
}
}
if ($requestedOn === '') {
$requestedOn = trim((string) ($row['created_at'] ?? ''));
}
}
// Bridge flattens consent.hi_types -> top-level hi_types on consent_status /
// consent_reconcile / consent_callback responses (see M3HiuGatewayClient
// flatten logic). The "best" row for overall phase can be a data_fetch /
// hi_data_push_callback row (once records are COMPLETED) whose response is
// a FHIR data bundle with no hi_types field at all — so look separately for
// the most recent row (within this session) that actually carries the
// granted hi_types payload.
// Scan for GRANTED / UPDATED metadata from ABDM callback & response payloads
$grantedHiTypes = [];
$grantedOn = '';
$grantedFrom = '';
$grantedTo = '';
$grantedEraseAt = '';
foreach ($rows as $row) {
$decoded = json_decode((string) ($row['response_json'] ?? ''), true);
if (! is_array($decoded)) {
continue;
}
$rowHiTypes = $this->normalizeHiTypesList($decoded['hi_types'] ?? $decoded['consent']['hi_types'] ?? []);
if ($rowHiTypes !== []) {
$grantedHiTypes = $rowHiTypes;
$grantedOn = trim((string) ($decoded['granted_at'] ?? $row['updated_at'] ?? ''));
break;
$containers = [
$decoded['consent'] ?? null,
$decoded['consentDetail'] ?? null,
$decoded['data']['consent'] ?? null,
$decoded['data']['consentDetail'] ?? null,
$decoded['data'] ?? null,
$decoded,
];
foreach ($containers as $c) {
if (! is_array($c)) {
continue;
}
$rowHiTypes = $this->normalizeHiTypesList($c['hi_types'] ?? $c['hiTypes'] ?? []);
if ($rowHiTypes !== []) {
$grantedHiTypes = $rowHiTypes;
}
$candGrantedOn = trim((string) (
$c['granted_at']
?? $c['grantedAt']
?? $c['permission']['granted_at']
?? $c['permission']['grantedAt']
?? ''
));
if ($candGrantedOn !== '') {
$grantedOn = $candGrantedOn;
}
$candFrom = trim((string) (
$c['date_range']['from']
?? $c['dateRange']['from']
?? $c['permission']['dateRange']['from']
?? $c['permission']['date_range']['from']
?? $c['valid_from']
?? $c['validFrom']
?? ''
));
if ($candFrom !== '') {
$grantedFrom = $candFrom;
}
$candTo = trim((string) (
$c['date_range']['to']
?? $c['dateRange']['to']
?? $c['permission']['dateRange']['to']
?? $c['permission']['date_range']['to']
?? $c['valid_to']
?? $c['validTo']
?? ''
));
if ($candTo !== '') {
$grantedTo = $candTo;
}
$candErase = trim((string) (
(is_array($c['expiry'] ?? null) ? ($c['expiry']['date'] ?? null) : ($c['expiry'] ?? null))
?? $c['permission']['dataEraseAt']
?? $c['permission']['data_erase_at']
?? $c['dataEraseAt']
?? $c['data_erase_at']
?? $c['erase_at']
?? $c['eraseAt']
?? ''
));
if ($candErase !== '') {
$grantedEraseAt = $candErase;
}
}
}
// If this session's overall phase is GRANTED/COMPLETED but no row ever
// recorded WHICH hi_types were granted (e.g. data arrived via an async
// hi_data_push_callback before any consent_reconcile/consent_status poll
// ran and stored a hi_types-bearing response), do not mark every
// requested type as DENIED for lack of evidence — a COMPLETED/GRANTED
// phase is itself proof the consent covers at least the requested
// types, so fall back to treating the full requested set as granted.
// recorded WHICH hi_types were granted, fall back to requested types.
if ($grantedHiTypes === [] && $requestedHiTypes !== [] && in_array($phase, ['GRANTED', 'COMPLETED'], true)) {
$grantedHiTypes = $requestedHiTypes;
}
// Effective values: if granted values exist from ABDM, they represent the official patient-approved values
$validFrom = $grantedFrom !== '' ? $grantedFrom : $requestedFrom;
$validTo = $grantedTo !== '' ? $grantedTo : $requestedTo;
$eraseAt = $grantedEraseAt !== '' ? $grantedEraseAt : $requestedEraseAt;
// Detect if patient modified the date range or expiry in the PHR app
$isDateFromModified = false;
if ($requestedFrom !== '' && $grantedFrom !== '') {
$tsReqFrom = strtotime($requestedFrom);
$tsGntFrom = strtotime($grantedFrom);
if ($tsReqFrom !== false && $tsGntFrom !== false && date('Y-m-d', $tsReqFrom) !== date('Y-m-d', $tsGntFrom)) {
$isDateFromModified = true;
}
}
$isDateToModified = false;
if ($requestedTo !== '' && $grantedTo !== '') {
$tsReqTo = strtotime($requestedTo);
$tsGntTo = strtotime($grantedTo);
if ($tsReqTo !== false && $tsGntTo !== false && date('Y-m-d', $tsReqTo) !== date('Y-m-d', $tsGntTo)) {
$isDateToModified = true;
}
}
$isEraseAtModified = false;
if ($requestedEraseAt !== '' && $grantedEraseAt !== '') {
$tsReqErase = strtotime($requestedEraseAt);
$tsGntErase = strtotime($grantedEraseAt);
if ($tsReqErase !== false && $tsGntErase !== false && abs($tsReqErase - $tsGntErase) > 60) {
$isEraseAtModified = true;
}
}
$revokedOn = trim((string) ($best['revoked_at'] ?? ''));
$expiredOn = trim((string) ($best['expired_at'] ?? ''));
if (in_array($phase, ['GRANTED', 'COMPLETED'], true) && $grantedOn === '') {
$grantedOn = trim((string) ($bestDecoded['granted_at'] ?? $best['updated_at'] ?? ''));
}
// ABDM M3 HIU compliance: evaluate consent expiration against erase_at (dataEraseAt)
// ABDM M3 HIU compliance: evaluate consent expiration against effective erase_at (dataEraseAt)
$isConsentExpired = false;
if ($phase === 'EXPIRED') {
$isConsentExpired = true;
} elseif ($eraseAt !== '') {
$eraseTimestamp = strtotime($eraseAt);
if ($eraseTimestamp !== false && $eraseTimestamp <= time()) {
$effectiveEraseTimestamp = ($eraseAt !== '') ? strtotime($eraseAt) : false;
if ($effectiveEraseTimestamp !== false) {
if ($effectiveEraseTimestamp <= time()) {
$isConsentExpired = true;
}
}
if (! $isConsentExpired && $expiredOn !== '') {
} elseif ($expiredOn !== '') {
$expTime = strtotime($expiredOn);
if ($expTime !== false && $expTime <= time()) {
$isConsentExpired = true;
}
} elseif ($phase === 'EXPIRED') {
$isConsentExpired = true;
}
// If effective eraseAt is in the future, the consent is NOT expired!
// (Revive from any premature EXPIRED state stamped by legacy code)
if (! $isConsentExpired && $phase === 'EXPIRED') {
$expiredOn = '';
if ($status === 'SUCCESS' && ($state === 'DATA_RECEIVED' || in_array($bestPriority, [480, 490, 500], true))) {
$phase = 'COMPLETED';
} elseif ($grantedOn !== '' || in_array($rawConsentStatus, ['GRANTED', 'APPROVED', 'ACTIVE'], true) || in_array($state, ['GRANTED', 'APPROVED', 'ACTIVE'], true)) {
$phase = 'GRANTED';
}
}
if ($isConsentExpired) {
@ -6575,6 +6666,16 @@ class Patient extends BaseController
'valid_from' => $validFrom,
'valid_to' => $validTo,
'erase_at' => $eraseAt,
'requested_from' => $requestedFrom,
'requested_to' => $requestedTo,
'requested_erase_at' => $requestedEraseAt,
'granted_from' => $grantedFrom,
'granted_to' => $grantedTo,
'granted_erase_at' => $grantedEraseAt,
'is_date_from_modified' => $isDateFromModified,
'is_date_to_modified' => $isDateToModified,
'is_date_range_modified' => ($isDateFromModified || $isDateToModified),
'is_erase_at_modified' => $isEraseAtModified,
'requested_on' => $requestedOn,
'granted_on' => $grantedOn,
'revoked_on' => $revokedOn,

View File

@ -573,9 +573,9 @@ class ConsentSessionListService
$requestedHiTypes = [];
$requestedOn = '';
$purpose = '';
$validFrom = '';
$validTo = '';
$eraseAt = '';
$requestedFrom = '';
$requestedTo = '';
$requestedEraseAt = '';
$requestedBy = '';
$hfrId = trim((string) ($best['hfr_id'] ?? ''));
@ -588,17 +588,17 @@ class ConsentSessionListService
$requestedHiTypes = $this->normalizeHiTypesList($consentBlock['hiTypes'] ?? $consentBlock['hi_types'] ?? []);
$requestedOn = trim((string) ($consentRequestRow['created_at'] ?? ''));
$purpose = $this->extractScalarString($consentBlock['purpose']['text'] ?? $consentBlock['purpose']['code'] ?? null);
$validFrom = $this->extractScalarString(
$requestedFrom = $this->extractScalarString(
$consentBlock['permission']['dateRange']['from']
?? $consentBlock['permission']['date_range']['from']
?? null
);
$validTo = $this->extractScalarString(
$requestedTo = $this->extractScalarString(
$consentBlock['permission']['dateRange']['to']
?? $consentBlock['permission']['date_range']['to']
?? null
);
$eraseAt = $this->extractScalarString(
$requestedEraseAt = $this->extractScalarString(
$consentBlock['permission']['dataEraseAt']
?? $consentBlock['permission']['data_erase_at']
?? null
@ -609,48 +609,55 @@ class ConsentSessionListService
}
}
// Fallback scanning across all session rows for missing metadata (dates, purpose, requestedBy)
// Fallback scanning across session rows for missing requested metadata
foreach ($rows as $row) {
$rowReq = json_decode((string) ($row['request_json'] ?? ''), true);
$rowResp = json_decode((string) ($row['response_json'] ?? ''), true);
$containers = [
is_array($rowReq) ? ($rowReq['consent'] ?? null) : null,
is_array($rowReq) ? ($rowReq['consentDetail'] ?? null) : null,
is_array($rowReq) ? ($rowReq['data']['consent'] ?? null) : null,
is_array($rowReq) ? $rowReq : null,
is_array($rowResp) ? ($rowResp['consent'] ?? null) : null,
is_array($rowResp) ? ($rowResp['consentDetail'] ?? null) : null,
is_array($rowResp) ? $rowResp : null,
];
foreach ($containers as $c) {
if (! is_array($c)) {
continue;
}
if ($validFrom === '') {
$validFrom = $this->extractScalarString(
if ($requestedFrom === '') {
$requestedFrom = $this->extractScalarString(
$c['permission']['dateRange']['from']
?? $c['permission']['date_range']['from']
?? $c['date_range']['from']
?? $c['dateRange']['from']
?? $c['valid_from']
?? $c['validFrom']
?? $c['date_from']
?? $c['dateFrom']
?? null
);
}
if ($validTo === '') {
$validTo = $this->extractScalarString(
if ($requestedTo === '') {
$requestedTo = $this->extractScalarString(
$c['permission']['dateRange']['to']
?? $c['permission']['date_range']['to']
?? $c['date_range']['to']
?? $c['dateRange']['to']
?? $c['valid_to']
?? $c['validTo']
?? $c['date_to']
?? $c['dateTo']
?? null
);
}
if ($eraseAt === '') {
$eraseAt = $this->extractScalarString(
if ($requestedEraseAt === '') {
$requestedEraseAt = $this->extractScalarString(
$c['permission']['dataEraseAt']
?? $c['permission']['data_erase_at']
?? (is_array($c['expiry'] ?? null) ? ($c['expiry']['date'] ?? null) : ($c['expiry'] ?? null))
?? $c['dataEraseAt']
?? $c['data_erase_at']
?? $c['erase_at']
?? $c['eraseAt']
?? null
);
}
@ -658,7 +665,6 @@ class ConsentSessionListService
$purpose = $this->extractScalarString(
$c['purpose']['text']
?? $c['purpose']['code']
?? $c['purpose']
?? null
);
}
@ -669,27 +675,133 @@ class ConsentSessionListService
?? null
);
}
if ($requestedOn === '') {
$requestedOn = trim((string) ($row['created_at'] ?? ''));
}
}
if ($requestedOn === '') {
$requestedOn = trim((string) ($row['created_at'] ?? ''));
}
}
// Scan for GRANTED / UPDATED metadata from ABDM callback & response payloads
$grantedHiTypes = [];
$grantedOn = '';
$grantedFrom = '';
$grantedTo = '';
$grantedEraseAt = '';
foreach ($rows as $row) {
$decoded = json_decode((string) ($row['response_json'] ?? ''), true);
if (! is_array($decoded)) {
continue;
}
$rowHiTypes = $this->normalizeHiTypesList($decoded['hi_types'] ?? $decoded['consent']['hi_types'] ?? []);
if ($rowHiTypes !== []) {
$grantedHiTypes = $rowHiTypes;
$grantedOn = trim((string) (
$this->extractScalarString($decoded['granted_at'] ?? null)
?: ($row['updated_at'] ?? '')
$containers = [
$decoded['consent'] ?? null,
$decoded['consentDetail'] ?? null,
$decoded['data']['consent'] ?? null,
$decoded['data']['consentDetail'] ?? null,
$decoded['data'] ?? null,
$decoded,
];
foreach ($containers as $c) {
if (! is_array($c)) {
continue;
}
$rowHiTypes = $this->normalizeHiTypesList($c['hi_types'] ?? $c['hiTypes'] ?? []);
if ($rowHiTypes !== []) {
$grantedHiTypes = $rowHiTypes;
}
$candGrantedOn = trim((string) (
$this->extractScalarString($c['granted_at'] ?? null)
?: $this->extractScalarString($c['grantedAt'] ?? null)
?: $this->extractScalarString($c['permission']['granted_at'] ?? null)
?: $this->extractScalarString($c['permission']['grantedAt'] ?? null)
?: ''
));
break;
if ($candGrantedOn !== '') {
$grantedOn = $candGrantedOn;
}
$candFrom = trim((string) (
$this->extractScalarString($c['date_range']['from'] ?? null)
?: $this->extractScalarString($c['dateRange']['from'] ?? null)
?: $this->extractScalarString($c['permission']['dateRange']['from'] ?? null)
?: $this->extractScalarString($c['permission']['date_range']['from'] ?? null)
?: $this->extractScalarString($c['valid_from'] ?? null)
?: $this->extractScalarString($c['validFrom'] ?? null)
?: ''
));
if ($candFrom !== '') {
$grantedFrom = $candFrom;
}
$candTo = trim((string) (
$this->extractScalarString($c['date_range']['to'] ?? null)
?: $this->extractScalarString($c['dateRange']['to'] ?? null)
?: $this->extractScalarString($c['permission']['dateRange']['to'] ?? null)
?: $this->extractScalarString($c['permission']['date_range']['to'] ?? null)
?: $this->extractScalarString($c['valid_to'] ?? null)
?: $this->extractScalarString($c['validTo'] ?? null)
?: ''
));
if ($candTo !== '') {
$grantedTo = $candTo;
}
$candErase = trim((string) (
$this->extractScalarString(is_array($c['expiry'] ?? null) ? ($c['expiry']['date'] ?? null) : ($c['expiry'] ?? null))
?: $this->extractScalarString($c['permission']['dataEraseAt'] ?? null)
?: $this->extractScalarString($c['permission']['data_erase_at'] ?? null)
?: $this->extractScalarString($c['dataEraseAt'] ?? null)
?: $this->extractScalarString($c['data_erase_at'] ?? null)
?: $this->extractScalarString($c['erase_at'] ?? null)
?: $this->extractScalarString($c['eraseAt'] ?? null)
?: ''
));
if ($candErase !== '') {
$grantedEraseAt = $candErase;
}
}
}
// If this session's overall phase is GRANTED/COMPLETED but no row ever
// recorded WHICH hi_types were granted, fall back to requested types.
if ($grantedHiTypes === [] && $requestedHiTypes !== [] && in_array($phase, ['GRANTED', 'COMPLETED'], true)) {
$grantedHiTypes = $requestedHiTypes;
}
// Effective values: if granted values exist from ABDM, they represent the official patient-approved values
$validFrom = $grantedFrom !== '' ? $grantedFrom : $requestedFrom;
$validTo = $grantedTo !== '' ? $grantedTo : $requestedTo;
$eraseAt = $grantedEraseAt !== '' ? $grantedEraseAt : $requestedEraseAt;
// Detect if patient modified the date range or expiry in the PHR app
$isDateFromModified = false;
if ($requestedFrom !== '' && $grantedFrom !== '') {
$tsReqFrom = strtotime($requestedFrom);
$tsGntFrom = strtotime($grantedFrom);
if ($tsReqFrom !== false && $tsGntFrom !== false && date('Y-m-d', $tsReqFrom) !== date('Y-m-d', $tsGntFrom)) {
$isDateFromModified = true;
}
}
$isDateToModified = false;
if ($requestedTo !== '' && $grantedTo !== '') {
$tsReqTo = strtotime($requestedTo);
$tsGntTo = strtotime($grantedTo);
if ($tsReqTo !== false && $tsGntTo !== false && date('Y-m-d', $tsReqTo) !== date('Y-m-d', $tsGntTo)) {
$isDateToModified = true;
}
}
$isEraseAtModified = false;
if ($requestedEraseAt !== '' && $grantedEraseAt !== '') {
$tsReqErase = strtotime($requestedEraseAt);
$tsGntErase = strtotime($grantedEraseAt);
if ($tsReqErase !== false && $tsGntErase !== false && abs($tsReqErase - $tsGntErase) > 60) {
$isEraseAtModified = true;
}
}
@ -702,21 +814,31 @@ class ConsentSessionListService
));
}
// ABDM M3 HIU compliance: evaluate consent expiration against erase_at (dataEraseAt)
// ABDM M3 HIU compliance: evaluate consent expiration against effective erase_at (dataEraseAt)
$isConsentExpired = false;
if ($phase === 'EXPIRED') {
$isConsentExpired = true;
} elseif ($eraseAt !== '') {
$eraseTimestamp = strtotime($eraseAt);
if ($eraseTimestamp !== false && $eraseTimestamp <= time()) {
$effectiveEraseTimestamp = ($eraseAt !== '') ? strtotime($eraseAt) : false;
if ($effectiveEraseTimestamp !== false) {
if ($effectiveEraseTimestamp <= time()) {
$isConsentExpired = true;
}
}
if (! $isConsentExpired && $expiredOn !== '') {
} elseif ($expiredOn !== '') {
$expTime = strtotime($expiredOn);
if ($expTime !== false && $expTime <= time()) {
$isConsentExpired = true;
}
} elseif ($phase === 'EXPIRED') {
$isConsentExpired = true;
}
// If effective eraseAt is in the future, the consent is NOT expired!
// (Revive from any premature EXPIRED state stamped by legacy code)
if (! $isConsentExpired && $phase === 'EXPIRED') {
$expiredOn = '';
if ($status === 'SUCCESS' && ($state === 'DATA_RECEIVED' || in_array($bestPriority, [480, 490, 500], true))) {
$phase = 'COMPLETED';
} elseif ($grantedOn !== '' || in_array($rawConsentStatus, ['GRANTED', 'APPROVED', 'ACTIVE'], true) || in_array($state, ['GRANTED', 'APPROVED', 'ACTIVE'], true)) {
$phase = 'GRANTED';
}
}
if ($isConsentExpired) {
@ -797,6 +919,16 @@ class ConsentSessionListService
'valid_from' => $validFrom,
'valid_to' => $validTo,
'erase_at' => $eraseAt,
'requested_from' => $requestedFrom,
'requested_to' => $requestedTo,
'requested_erase_at' => $requestedEraseAt,
'granted_from' => $grantedFrom,
'granted_to' => $grantedTo,
'granted_erase_at' => $grantedEraseAt,
'is_date_from_modified' => $isDateFromModified,
'is_date_to_modified' => $isDateToModified,
'is_date_range_modified' => ($isDateFromModified || $isDateToModified),
'is_erase_at_modified' => $isEraseAtModified,
'requested_on' => $requestedOn,
'granted_on' => $grantedOn,
'revoked_on' => $revokedOn,

View File

@ -144,17 +144,34 @@
if (!consent) {
return '<div class="text-danger small">No consent details available.</div>';
}
var metaHtml = '<div class="row small text-muted mb-3">'
function renderDateField(label, reqVal, gntVal, isMod, effectiveVal) {
if (!reqVal && !gntVal && !effectiveVal) {
return '<div class="col-md-6">' + label + ': <strong>-</strong></div>';
}
if (isMod && reqVal && gntVal) {
return '<div class="col-md-6">' + label + ': '
+ '<span class="text-decoration-line-through text-muted small" title="Original Requested">' + fmtTs(reqVal) + '</span> '
+ '&rarr; <strong class="text-primary" title="Patient Updated in PHR">' + fmtTs(gntVal) + '</strong> '
+ '<span class="badge bg-warning-subtle text-warning border border-warning-subtle py-0 px-1 ms-1" style="font-size:0.75rem;" title="Updated by Patient in PHR App">Updated</span>'
+ '</div>';
}
var displayVal = gntVal || effectiveVal || reqVal;
return '<div class="col-md-6">' + label + ': <strong>' + fmtTs(displayVal) + '</strong></div>';
}
var metaHtml = '<div class="row small text-muted mb-3 g-2">'
+ '<div class="col-md-6">Patient: <strong>' + escHtml(consent.patient_name || '-') + '</strong></div>'
+ '<div class="col-md-6">UHID: <strong>' + escHtml(consent.patient_code || '-') + '</strong></div>'
+ '<div class="col-md-6">Consent ID: <strong>' + escHtml(consent.consent_id || consent.abdm_consent_artifact_id || consent.consent_request_id || consent.request_id || '-') + '</strong></div>'
+ '<div class="col-md-6">ABHA: <strong>' + escHtml(consent.abha_address || '-') + '</strong></div>'
+ '<div class="col-md-6">Purpose: <strong>' + escHtml(consent.purpose || '-') + '</strong></div>'
+ '<div class="col-md-6">Status: <strong>' + escHtml(consent.status || '-') + '</strong></div>'
+ '<div class="col-md-6">Valid From: <strong>' + fmtTs(consent.valid_from) + '</strong></div>'
+ '<div class="col-md-6">Valid To: <strong>' + fmtTs(consent.valid_to) + '</strong></div>'
+ renderDateField('Request From', consent.requested_from, consent.granted_from, consent.is_date_from_modified, consent.valid_from)
+ renderDateField('Request To', consent.requested_to, consent.granted_to, consent.is_date_to_modified, consent.valid_to)
+ '<div class="col-md-6">Requested On: <strong>' + fmtTs(consent.requested_on) + '</strong></div>'
+ '<div class="col-md-6">Erase Date: <strong>' + fmtTs(consent.erase_at) + '</strong></div>'
+ renderDateField('Consent Valid Upto', consent.requested_erase_at, consent.granted_erase_at, consent.is_erase_at_modified, consent.erase_at)
+ (consent.granted_on ? '<div class="col-md-6">Granted On: <strong>' + fmtTs(consent.granted_on) + '</strong></div>' : '')
+ (consent.requested_by ? '<div class="col-md-6">Requested By: <strong>' + escHtml(consent.requested_by) + '</strong></div>' : '')
+ '</div>';
var rowsHtml = '';

View File

@ -390,9 +390,9 @@ if ($patientPhotoPath === '') {
<tr>
<th>ID</th>
<th>Status</th>
<th>Expiry Date</th>
<th>Date From</th>
<th>Date To</th>
<th>Consent Valid Upto</th>
<th>Request From</th>
<th>Request To</th>
<th>View</th>
<th class="text-end">Show Data / Print</th>
</tr>
@ -1241,15 +1241,32 @@ $(function() {
});
stepperHtml += '</div>';
var metaHtml = '<div class="row small text-muted mb-3">'
function renderDateField(label, reqVal, gntVal, isMod, effectiveVal) {
if (!reqVal && !gntVal && !effectiveVal) {
return '<div class="col-md-6">' + label + ': <strong>-</strong></div>';
}
if (isMod && reqVal && gntVal) {
return '<div class="col-md-6">' + label + ': '
+ '<span class="text-decoration-line-through text-muted small" title="Original Requested">' + fmtConsentTs(reqVal) + '</span> '
+ '&rarr; <strong class="text-primary" title="Patient Updated in PHR">' + fmtConsentTs(gntVal) + '</strong> '
+ '<span class="badge bg-warning-subtle text-warning border border-warning-subtle py-0 px-1 ms-1" style="font-size:0.75rem;" title="Updated by Patient in PHR App">Updated</span>'
+ '</div>';
}
var displayVal = gntVal || effectiveVal || reqVal;
return '<div class="col-md-6">' + label + ': <strong>' + fmtConsentTs(displayVal) + '</strong></div>';
}
var metaHtml = '<div class="row small text-muted mb-3 g-2">'
+ '<div class="col-md-6">Consent ID: <strong>' + escHtml(consent.consent_id || consent.abdm_consent_artifact_id || consent.consent_request_id || consent.request_id || '-') + '</strong></div>'
+ '<div class="col-md-6">ABHA: <strong>' + escHtml(consent.abha_address || '-') + '</strong></div>'
+ '<div class="col-md-6">Purpose: <strong>' + escHtml(consent.purpose || '-') + '</strong></div>'
+ '<div class="col-md-6">Status: <strong>' + escHtml(statusUpper || '-') + '</strong></div>'
+ '<div class="col-md-6">Valid From: <strong>' + fmtConsentTs(consent.valid_from) + '</strong></div>'
+ '<div class="col-md-6">Valid To: <strong>' + fmtConsentTs(consent.valid_to) + '</strong></div>'
+ renderDateField('Request From', consent.requested_from, consent.granted_from, consent.is_date_from_modified, consent.valid_from)
+ renderDateField('Request To', consent.requested_to, consent.granted_to, consent.is_date_to_modified, consent.valid_to)
+ '<div class="col-md-6">Requested On: <strong>' + fmtConsentTs(consent.requested_on) + '</strong></div>'
+ '<div class="col-md-6">Erase Date: <strong>' + fmtConsentTs(consent.erase_at) + '</strong></div>'
+ renderDateField('Consent Valid Upto', consent.requested_erase_at, consent.granted_erase_at, consent.is_erase_at_modified, consent.erase_at)
+ (consent.granted_on ? '<div class="col-md-6">Granted On: <strong>' + fmtConsentTs(consent.granted_on) + '</strong></div>' : '')
+ (consent.requested_by ? '<div class="col-md-6">Requested By: <strong>' + escHtml(consent.requested_by) + '</strong></div>' : '')
+ '</div>';
var rowsHtml = '';
@ -1328,9 +1345,9 @@ $(function() {
html += '<tr>'
+ '<td class="small">' + escHtml(rowId) + '</td>'
+ '<td><span class="badge ' + consentStatusBadgeClass(status) + '">' + escHtml(status || 'UNKNOWN') + '</span></td>'
+ '<td class="small">' + fmtConsentTs(consent.erase_at) + '</td>'
+ '<td class="small">' + fmtConsentTs(consent.valid_from) + '</td>'
+ '<td class="small">' + fmtConsentTs(consent.valid_to) + '</td>'
+ '<td class="small">' + (consent.is_erase_at_modified ? '<span class="text-primary fw-semibold" title="Original Requested: ' + fmtConsentTs(consent.requested_erase_at) + '">' + fmtConsentTs(consent.erase_at) + ' <i class="fa fa-info-circle text-info ms-1" title="Edited by Patient in PHR"></i></span>' : fmtConsentTs(consent.erase_at)) + '</td>'
+ '<td class="small">' + (consent.is_date_from_modified ? '<span class="text-primary fw-semibold" title="Original Requested: ' + fmtConsentTs(consent.requested_from) + '">' + fmtConsentTs(consent.valid_from) + ' <i class="fa fa-info-circle text-info ms-1" title="Edited by Patient in PHR"></i></span>' : fmtConsentTs(consent.valid_from)) + '</td>'
+ '<td class="small">' + (consent.is_date_to_modified ? '<span class="text-primary fw-semibold" title="Original Requested: ' + fmtConsentTs(consent.requested_to) + '">' + fmtConsentTs(consent.valid_to) + ' <i class="fa fa-info-circle text-info ms-1" title="Edited by Patient in PHR"></i></span>' : fmtConsentTs(consent.valid_to)) + '</td>'
+ '<td><button type="button" class="btn btn-link btn-sm p-0 abdm-view-request-btn" data-idx="' + idx + '">View</button></td>'
+ '<td class="text-end">'
+ (canFetch ? actionHtml : '<span class="text-muted small">-</span>')