diff --git a/ABDM_CARD_DOWNLOAD_IMPLEMENTATION.md b/ABDM_CARD_DOWNLOAD_IMPLEMENTATION.md new file mode 100644 index 0000000..eb87ae5 --- /dev/null +++ b/ABDM_CARD_DOWNLOAD_IMPLEMENTATION.md @@ -0,0 +1,450 @@ +# HMS ABHA Card Download Implementation - Per ABDM Bridge v3 Spec + +## Overview +HMS implements the ABDM Bridge v3 Gateway endpoint for downloading official ABHA cards. This is fully documented and operational. + +--- + +## ๐ฏ Implementation Checklist + +### โ Gateway Endpoint Call +**File**: `app/Libraries/Abdm/EAtriaBridgeConnector.php` (Lines 740-764) + +**Endpoint**: `GET /api/v3/abha/card` + +**Implementation**: +```php +$cardResult = $this->get( + '/v3/abha/card', + array_filter([ + 'abha_number' => $abhaNumber, + 'abha_address' => $abhaAddress, + ], static fn($value): bool => trim((string) $value) !== ''), + $patientToken !== '' ? ['X-Token' => 'Bearer ' . $patientToken] : [] +); +``` + +**Parameters Sent**: +- `abha_number`: ABHA ID (e.g., "91-5101-6530-5101") +- `abha_address`: ABHA Address (e.g., "singhdevender0328@sbx") +- `X-Token` Header: Patient authentication token (when available) + +**Response Handling** (Lines 751-762): +```php +if (! empty($cardResult['ok']) && (int) $cardResult['ok'] === 1) { + $cardData = is_array($cardResult['data'] ?? null) + ? $cardResult['data'] + : $cardResult; + + // Extract card from any field name + $card = $this->extractOfficialCard($cardResult) + ?: $this->extractOfficialCard($cardData); + + if ($card !== '') { + $result['card_base64'] = $card; + $result['card_content_type'] = $this->resolveCardContentType($cardData); + $result['card_source'] = $this->extractCardSource($cardResult); + } +} +``` + +--- + +## ๐ Card Download Data Flow + +``` +1. ABHA Verification Complete + โ +2. HMS Controller: Abha::verifyOtp() or verifyCommOtp() + โ +3. Card already in response? + โโ YES โ Use it (from verify-otp/verify-comm-otp response) + โโ NO โ Call Gateway... + โ +4. Bridge Connector: Call /v3/abha/card + โโ Pass: abha_number, abha_address + โโ Auth: X-Token header (patient-specific) + โโ To: https://abdm-bridge.e-atria.in/api/v3/abha/card + โ +5. Gateway Response + { + "ok": 1, + "card_format": "png", + "official_card": "data:image/png;base64,...", + "card_source": "abdm", + "source": "abdm_official" + } + โ +6. Extract Card Data + โโ official_card field + โโ card_data_uri field (if present) + โโ multiple fallback options + โ +7. Return to Client + { + "ok": 1, + "card_base64": "data:image/png;base64,...", + "card_content_type": "image/png", + "card_source": "abdm" + } + โ +8. Browser Display + โโ +``` + +--- + +## ๐ Card Field Extraction + +**File**: `app/Libraries/Abdm/EAtriaBridgeConnector.php` (Lines 810-823) + +**Supported Card Field Names** (in priority order): +1. `official_card` โ +2. `card_data_uri` โ +3. `card_base64` โ +4. `card_data` โ +5. `abhaCard` โ +6. `abha_card` โ +7. `cardData` โ +8. `card` โ + +**Nested Structure Support**: +```php +foreach (['official_card', 'card_data_uri', 'card_base64', ...] as $key) { + $value = $source[$key] ?? ''; + if (is_string($value) && trim($value) !== '') { + return trim($value); // Found at top level + } + if (is_array($value)) { + foreach (['base64', 'data', 'card_base64', 'card_data'] as $nestedKey) { + if (is_string($value[$nestedKey] ?? null)) { + return trim($value[$nestedKey]); // Found nested + } + } + } +} +``` + +--- + +## ๐ผ๏ธ Card Display Views + +### 1. HTML Card View +**Route**: `GET abha/card/{abha_number}` +**File**: `app/Controllers/Abha.php` (Lines 509-600) +**Returns**: HTML page for display/printing + +```php +public function card(string $abhaNumber = '') +{ + // Validate ABHA format + $abhaNumClean = preg_replace('/\D/', '', $abhaNumber); + + if (strlen($abhaNumClean) !== 14) { + return $this->response->setStatusCode(400) + ->setBody('
' . htmlspecialchars($address) . '
Phone: ' . htmlspecialchars($phone) . ' | Email: ' . htmlspecialchars($email) . '
Fit to resume work