devsofttech_hms_ci4/app/Libraries/Abdm/DreamsoftConnector.php
DevSoftTech Server 0628f8f813 feat: ABDM OPD Queue + ABHA Register flow + patient ABHA search fix
ABDM OPD Queue (today):
- New EAtriaBridgeConnector: opdQueueFetch/opdTokenCreate/opdTokenUpdateStatus + patch() helper
- New AbdmOpdQueue controller: index/list/fetchQueue/createToken/updateTokenStatus/processScannedToken
  - fetchQueue syncs gateway tokens into abdm_opd_tokens (local DB) and enriches with HMS patient data
  - processScannedToken auto-finds/creates patient_master record from ABHA scan data, marks token CALLED
- New migration: abdm_opd_tokens table (gateway_token_id, source, status, patient_id, opd_id, processed_at)
- New view: abdm/opd_queue.php - reception screen with auto-refresh 30s, HMS Patient column (green row when OPD registered)
- Sidebar: ABDM OPD Queue nav link added
- Routes: AbdmOpdQueue with abdmPermFilter

ABHA Register tab (earlier this session):
- New Abha controller: initiate/verifyOtp/communication/verifyCommOtp/validateAbha/card + autoCreateOrFindPatient
- New views: abha/card.php, partials/abha_create_panel.php, partials/abha_otp_modal.php
- Patient_V.php: ABHA Register tab with 4-method wizard (ABHA number, QR scan, facility QR, mobile OTP)

Patient ABHA search fix:
- Patient::search() now detects ABHA column (abha_id/abha_no/abha/abha_address) and searches by it

ABDM Bridge infrastructure:
- EAtriaBridgeConnector: new connector for e-atria.in ABDM bridge gateway
- AbdmConnectorFactory/Interface updated
- AbdmGatewaySettings controller + view
- SNOMED/CSNOTK terminology service skeleton
- Finance payout OPD consult views
- Migration: AddAbdmPushFieldsToOpdAndPatient, CreateSnomedCoreTables
- Docs: abdm/ API specs, architecture, gateway guides
2026-05-16 04:21:31 +05:30

206 lines
7.0 KiB
PHP

<?php
namespace App\Libraries\Abdm;
use App\Libraries\BridgeSyncService;
/**
* DreamsoftConnector
*
* Routes all ABDM operations through the Dreamsoft bridge middleware
* by enqueuing events to bridge_sync_queue via BridgeSyncService.
*
* This is the default (and currently only production) adapter.
* Switch to 'direct_abdm' in Config\AbdmConnector when DirectAbdmConnector is ready.
*/
class DreamsoftConnector implements AbdmConnectorInterface
{
private BridgeSyncService $bridge;
public function __construct()
{
$this->bridge = new BridgeSyncService();
}
public function getConnectorName(): string
{
return 'dreamsoft';
}
// -------------------------------------------------------------------------
// ABHA
// -------------------------------------------------------------------------
public function validateAbha(string $abhaId, array $fullPayload = []): array
{
$payload = $fullPayload !== [] ? $fullPayload : [
'abha_id' => $abhaId,
'requested_at' => date('Y-m-d H:i:s'),
];
$queueId = $this->bridge->enqueue('abdm.abha.validate', $payload, 'abha', $abhaId);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
// -------------------------------------------------------------------------
// Consent
// -------------------------------------------------------------------------
public function requestConsent(
int $patientId,
string $abhaId,
string $purposeCode,
string $expiresAt,
string $consentHandle,
array $rawPayload = []
): array {
$payload = $rawPayload !== [] ? $rawPayload : [
'patient_id' => $patientId,
'abha_id' => $abhaId,
'purpose_code' => $purposeCode,
'expires_at' => $expiresAt,
'consent_handle' => $consentHandle,
];
$queueId = $this->bridge->enqueue('abdm.consent.requested', $payload, 'consent', $consentHandle);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
// -------------------------------------------------------------------------
// Health Record Sharing
// -------------------------------------------------------------------------
public function sharePrescriptionBundle(array $payload, string $entityId = ''): array
{
$queueId = $this->bridge->enqueue(
'abdm.fhir.share.requested',
$payload,
'opd_fhir_document',
$entityId
);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
public function shareIpdDischargeBundle(array $payload, string $entityId = ''): array
{
$queueId = $this->bridge->enqueue(
'abdm.ipd.discharge.share.requested',
$payload,
'ipd_discharge',
$entityId
);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
public function shareDiagnosisReportBundle(array $payload, string $entityId = ''): array
{
$queueId = $this->bridge->enqueue(
'abdm.diagnosis.report.share.requested',
$payload,
'lab_request',
$entityId
);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
// -------------------------------------------------------------------------
// Scan & Share
// -------------------------------------------------------------------------
public function scanShareLookup(string $qrPayload, string $abhaIdHint = '', array $fullPayload = []): array
{
$payload = $fullPayload !== [] ? $fullPayload : [
'qr_payload' => $qrPayload,
'abha_id_hint' => $abhaIdHint,
'requested_at' => date('Y-m-d H:i:s'),
];
$queueId = $this->bridge->enqueue(
'abdm.scan_share.lookup',
$payload,
'abha_scan',
$abhaIdHint !== '' ? $abhaIdHint : null
);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
// -------------------------------------------------------------------------
// M1 ABHA OTP Flows — not queue-able; throw so callers fall back to sync connector
// -------------------------------------------------------------------------
public function abhaAadhaarGenerateOtp(array $payload): array
{
throw new \RuntimeException(
'DreamsoftConnector does not support synchronous M1 OTP flows. '
. 'Set abdm.connector = eatria_bridge in .env to use M1 endpoints.'
);
}
public function abhaAadhaarVerifyOtp(array $payload): array
{
throw new \RuntimeException(
'DreamsoftConnector does not support synchronous M1 OTP flows. '
. 'Set abdm.connector = eatria_bridge in .env to use M1 endpoints.'
);
}
public function abhaMobileGenerateOtp(array $payload): array
{
throw new \RuntimeException(
'DreamsoftConnector does not support synchronous M1 OTP flows. '
. 'Set abdm.connector = eatria_bridge in .env to use M1 endpoints.'
);
}
public function abhaMobileVerifyOtp(array $payload): array
{
throw new \RuntimeException(
'DreamsoftConnector does not support synchronous M1 OTP flows. '
. 'Set abdm.connector = eatria_bridge in .env to use M1 endpoints.'
);
}
// -------------------------------------------------------------------------
// NHCX Claims
// -------------------------------------------------------------------------
public function nhcxClaimCreate(
array $bundle,
int $documentId,
int $patientId,
int $encounterId
): array {
$payload = [
'nhcx_claim_document_id' => $documentId,
'patient_id' => $patientId,
'encounter_id' => $encounterId,
'bundle' => $bundle,
];
$queueId = $this->bridge->enqueue(
'nhcx.claim.created',
$payload,
'nhcx_claim_document',
(string) $documentId
);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
public function nhcxClaimStatusRequest(
int $documentId,
string $externalRef,
string $currentStatus,
array $fullPayload = []
): array {
$payload = $fullPayload !== [] ? $fullPayload : [
'nhcx_claim_document_id' => $documentId,
'external_ref' => $externalRef,
'claim_status' => $currentStatus,
'requested_at' => date('Y-m-d H:i:s'),
];
$queueId = $this->bridge->enqueue(
'nhcx.claim.status.requested',
$payload,
'nhcx_claim_document',
(string) $documentId
);
return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued'];
}
}