Fix ABDM live fetch and discovery for PrescriptionRecord and WellnessRecord

This commit is contained in:
DevSoftTech Server 2026-10-06 09:38:40 +05:30
parent da61637c56
commit 686513cf27
5 changed files with 490 additions and 28 deletions

View File

@ -4983,10 +4983,11 @@ class AbdmGateway extends BaseController
continue;
}
// Strategy 0: Live On-Demand Fresh Generation for OPD Consult Record
if (preg_match('/(?:OPD|PRESCRIPTION)-(\d+)(?:-S(\d+))?/i', $ref, $m)) {
$targetPatientId = (int) $m[1];
$targetSessionId = (int) ($m[2] ?? 0);
// Strategy 0: Live On-Demand Fresh Generation for OPD Consult & Prescription Records
if (preg_match('/^(OPD|PRESCRIPTION|PRESC)-(\d+)(?:-S(\d+))?/i', $ref, $m)) {
$refPrefix = strtoupper($m[1]);
$targetPatientId = (int) $m[2];
$targetSessionId = (int) ($m[3] ?? 0);
$targetOpdId = 0;
if ($targetSessionId > 0 && $db->tableExists('opd_prescription')) {
@ -5005,14 +5006,21 @@ class AbdmGateway extends BaseController
if ($targetOpdId > 0) {
try {
$isPrescriptionReq = in_array($refPrefix, ['PRESC', 'PRESCRIPTION'], true);
$targetBundleType = $isPrescriptionReq ? 'PrescriptionRecord' : 'OPConsultRecord';
$targetHiType = $isPrescriptionReq ? 'PrescriptionRecord' : 'OPConsultRecord';
$targetDisplay = $isPrescriptionReq
? ('Prescription - ' . date('d M Y'))
: ('Consultation Record - ' . date('d M Y'));
$opdCtrl = new \App\Controllers\Opd_prescription();
$opdCtrl->initController($this->request, $this->response, service('logger'));
$regen = $opdCtrl->regenerateFhirBundleInternal($targetOpdId, $targetSessionId);
$regen = $opdCtrl->regenerateFhirBundleInternal($targetOpdId, $targetSessionId, $targetBundleType);
if (!empty($regen['ok']) && !empty($regen['bundle'])) {
$records[] = [
'careContextReference' => $ref,
'hiType' => 'OPConsultRecord',
'display' => 'Consultation Record - ' . date('d M Y'),
'hiType' => $targetHiType,
'display' => $targetDisplay,
'bundle' => $regen['bundle'],
];
continue;
@ -5047,6 +5055,82 @@ class AbdmGateway extends BaseController
}
}
// Strategy 0c: Live On-Demand Fresh Generation for Wellness Record
if (preg_match('/^WELLNESS-(?:(\d+)-)?(?:S)?(\d+)/i', $ref, $wMatch)) {
$wPart1 = (int) ($wMatch[1] ?? 0);
$wPart2 = (int) ($wMatch[2] ?? 0);
$targetPatientId = 0;
$targetSessionId = 0;
// Check if part2 is a date (e.g. 20261006)
$isDatePart2 = ($wPart2 >= 19700101 && $wPart2 <= 21001231);
$candidateEntityId = $isDatePart2 ? $wPart1 : $wPart2;
$candidatePatientId = $isDatePart2 ? 0 : $wPart1;
if ($db->tableExists('opd_prescription')) {
// Try finding by prescription id
if ($candidateEntityId > 0) {
$pRow = $db->table('opd_prescription')
->select('id, p_id, opd_id')
->where('id', $candidateEntityId)
->get(1)
->getRowArray();
if ($pRow) {
$targetSessionId = (int) $pRow['id'];
$targetPatientId = (int) $pRow['p_id'];
}
}
// If not found, check by session_id or opd_id
if ($targetPatientId <= 0 && $candidateEntityId > 0) {
$pRow = $db->table('opd_prescription')
->select('id, p_id, opd_id')
->where('session_id', $candidateEntityId)
->orWhere('opd_id', $candidateEntityId)
->orderBy('id', 'DESC')
->get(1)
->getRowArray();
if ($pRow) {
$targetSessionId = (int) $pRow['id'];
$targetPatientId = (int) $pRow['p_id'];
}
}
// If candidatePatientId is set, or if candidateEntityId was patient_id
if ($targetPatientId <= 0) {
$testPid = $candidatePatientId > 0 ? $candidatePatientId : $candidateEntityId;
if ($testPid > 0) {
$pRow = $db->table('opd_prescription')
->select('id, p_id, opd_id')
->where('p_id', $testPid)
->orderBy('id', 'DESC')
->get(1)
->getRowArray();
if ($pRow) {
$targetPatientId = (int) $pRow['p_id'];
$targetSessionId = (int) $pRow['id'];
}
}
}
}
if ($targetPatientId > 0) {
try {
$wellnessPayload = $this->buildWellnessRecordPayload($targetPatientId, $targetSessionId, '');
if ($wellnessPayload !== null && !empty($wellnessPayload['bundle'])) {
$records[] = [
'careContextReference' => $ref,
'hiType' => 'WellnessRecord',
'display' => $wellnessPayload['care_context_display'] ?? ('Wellness Record - ' . date('d M Y')),
'bundle' => $wellnessPayload['bundle'],
];
continue;
}
} catch (\Throwable $ex) {
log_message('warning', 'Live Wellness FHIR generation in recordsFetch failed: ' . $ex->getMessage());
}
}
}
// Strategy A: Check if health_records already has stored FHIR record_data
$hrRow = null;
if ($db->tableExists('health_records')) {
@ -5100,13 +5184,14 @@ class AbdmGateway extends BaseController
// Strategy B: Build compliant FHIR Document Bundle from patient_master & OPD
// STRICTLY restricted to OPD/consultation care contexts.
// NEVER synthesize dummy consultation records for invoices, discharge, labs, radiology, etc.
if (preg_match('/^(?:OPD|PRESCRIPTION|CONSULT)/i', $ref)) {
if (preg_match('/^(?:OPD|PRESCRIPTION|PRESC|CONSULT)/i', $ref)) {
$bundle = $this->assembleFhirBundleForCareContext($ref);
if ($bundle !== null) {
$isPresc = (bool) preg_match('/^(?:PRESC|PRESCRIPTION)/i', $ref);
$records[] = [
'careContextReference' => $ref,
'hiType' => 'OPConsultRecord',
'display' => 'OPConsultRecord - ' . date('d M Y'),
'hiType' => $isPresc ? 'PrescriptionRecord' : 'OPConsultRecord',
'display' => ($isPresc ? 'PrescriptionRecord - ' : 'OPConsultRecord - ') . date('d M Y'),
'bundle' => $bundle,
];
}
@ -6292,7 +6377,9 @@ class AbdmGateway extends BaseController
if (! empty($wopd)) {
$vDate = ! empty($wopd['date_opd_visit']) ? $wopd['date_opd_visit'] : date('Y-m-d');
$dateStr = date('d M Y', strtotime((string) $vDate));
$ccRef = 'WELLNESS-' . $patientId . '-S' . $taskEntityId . '-' . date('Ymd', strtotime((string) $vDate));
$cleanDate = date('Ymd', strtotime((string) $vDate));
// Reference format matching task board (e.g. WELLNESS-33723-20261006)
$ccRef = 'WELLNESS-' . $taskEntityId . '-' . $cleanDate;
$display = 'WellnessRecord - ' . $dateStr;
$addContext([
'careContextId' => $ccRef,
@ -6386,10 +6473,9 @@ class AbdmGateway extends BaseController
}
}
// 4. Query opd_prescription (OPD consultations & prescriptions)
// 4. Query opd_prescription (OPD consultations, prescriptions & wellness records)
if ($this->db->tableExists('opd_prescription')) {
$prescRows = $this->db->table('opd_prescription')
->select('id, p_id, date_opd_visit, session_id, p_datetime')
->where('p_id', $patientId)
->orderBy('id', 'DESC')
->limit(30)
@ -6401,10 +6487,12 @@ class AbdmGateway extends BaseController
? $pr['date_opd_visit']
: date('Y-m-d', strtotime((string) ($pr['p_datetime'] ?? 'now')));
$dateStr = date('d M Y', strtotime($visitDate));
$cleanDate = str_replace('-', '', $visitDate);
$sessionId = ! empty($pr['session_id']) ? $pr['session_id'] : $pr['id'];
$ccRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . str_replace('-', '', $visitDate);
$display = 'OPConsultRecord - ' . $dateStr;
// 4a. Consultation Record
$ccRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . $cleanDate;
$display = 'OPConsultRecord - ' . $dateStr;
$addContext([
'careContextId' => $ccRef,
'referenceNumber' => $ccRef,
@ -6414,6 +6502,44 @@ class AbdmGateway extends BaseController
'is_fhir_ready' => true,
'is_primary' => false,
]);
// 4b. Prescription Record (if prescribed medicines exist)
$hasMeds = false;
if ($this->db->tableExists('opd_prescrption_prescribed')) {
$hasMeds = ($this->db->table('opd_prescrption_prescribed')->where('prescription_id', (int) $pr['id'])->countAllResults() > 0);
}
if (! $hasMeds && $this->db->tableExists('opd_prescription_prescribed')) {
$hasMeds = ($this->db->table('opd_prescription_prescribed')->where('opd_pre_id', (int) $pr['id'])->countAllResults() > 0);
}
if ($hasMeds) {
$prescCcRef = 'PRESC-' . $patientId . '-S' . $sessionId . '-' . $cleanDate;
$prescDisplay = 'Prescription - ' . $dateStr;
$addContext([
'careContextId' => $prescCcRef,
'referenceNumber' => $prescCcRef,
'display' => $prescDisplay,
'record_type' => 'PrescriptionRecord',
'patient_id' => $patientId,
'is_fhir_ready' => true,
'is_primary' => false,
]);
}
// 4c. Wellness Record (if vitals exist)
$hasVitals = ! empty($pr['bp']) || ! empty($pr['pulse']) || ! empty($pr['temp']) || ! empty($pr['spo2']) || ! empty($pr['weight']) || ! empty($pr['height']);
if ($hasVitals) {
$wellCcRef = 'WELLNESS-' . $sessionId . '-' . $cleanDate;
$wellDisplay = 'Wellness Record - ' . $dateStr;
$addContext([
'careContextId' => $wellCcRef,
'referenceNumber' => $wellCcRef,
'display' => $wellDisplay,
'record_type' => 'WellnessRecord',
'patient_id' => $patientId,
'is_fhir_ready' => true,
'is_primary' => false,
]);
}
}
}

View File

@ -4844,7 +4844,7 @@ class Opd_prescription extends BaseController
*
* @return array<string, mixed>
*/
public function regenerateFhirBundleInternal(int $opdId, int $sessionId): array
public function regenerateFhirBundleInternal(int $opdId, int $sessionId, string $bundleType = 'OPConsultRecord'): array
{
if ($opdId <= 0) {
@ -4932,7 +4932,8 @@ class Opd_prescription extends BaseController
if ($prescriptionPdf !== null) {
$clinicalContext['attachments'][] = $prescriptionPdf;
}
$clinicalContext['bundle_type'] = 'OPConsultRecord';
$normalizedBundleType = in_array($bundleType, ['Prescription', 'PrescriptionRecord'], true) ? 'PrescriptionRecord' : 'OPConsultRecord';
$clinicalContext['bundle_type'] = $normalizedBundleType;
$bundle = $this->fhirR4Builder->buildOpConsultBundle($patient, $encounter, $medications, $conditions, $clinicalContext);
$bundleJson = (string) json_encode($bundle, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
@ -4947,10 +4948,10 @@ class Opd_prescription extends BaseController
}
$generatedAt = Time::now('Asia/Kolkata')->toDateTimeString();
// Overwrite the latest stored bundle for this opd_id / session
// Overwrite the latest stored bundle for this opd_id / session and bundle_type
$existingBuilder = $this->db->table('opd_fhir_documents')
->where('opd_id', $opdId)
->whereIn('bundle_type', ['OPConsultRecord', 'MedicationRequestBundle', 'PrescriptionRecord']);
->where('bundle_type', $normalizedBundleType);
if ($sessionId > 0) {
$existingBuilder->where('opd_session_id', $sessionId);
}
@ -4960,7 +4961,7 @@ class Opd_prescription extends BaseController
$this->db->table('opd_fhir_documents')
->where('id', (int) $existing['id'])
->update([
'bundle_type' => 'OPConsultRecord',
'bundle_type' => $normalizedBundleType,
'bundle_json' => $bundleJson,
'generated_by' => $generatedBy,
'generated_at' => $generatedAt,
@ -4970,7 +4971,7 @@ class Opd_prescription extends BaseController
$this->db->table('opd_fhir_documents')->insert([
'opd_id' => $opdId,
'opd_session_id' => $sessionId,
'bundle_type' => 'OPConsultRecord',
'bundle_type' => $normalizedBundleType,
'bundle_json' => $bundleJson,
'generated_by' => $generatedBy,
'generated_at' => $generatedAt,
@ -4982,7 +4983,9 @@ class Opd_prescription extends BaseController
'ok' => 1,
'message' => 'FHIR bundle regenerated successfully',
'document_id' => $documentId,
'bundle_type' => $normalizedBundleType,
'bundle' => $bundle,
'medications' => $medications,
'generated_at' => $generatedAt,
'entry_count' => isset($bundle['entry']) ? count($bundle['entry']) : 0,
];
@ -11830,6 +11833,45 @@ class Opd_prescription extends BaseController
]);
}
// Also generate and store PrescriptionRecord FHIR bundle if medicines were prescribed
$prescBundleJson = null;
if (! empty($medications)) {
$prescContext = $clinicalContext;
$prescContext['bundle_type'] = 'PrescriptionRecord';
$prescBundle = $this->fhirR4Builder->buildOpConsultBundle($patient, $encounter, $medications, $conditions, $prescContext);
$prescBundleJson = (string) json_encode($prescBundle, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$existingPrescDoc = $this->db->table('opd_fhir_documents')
->where('opd_id', $opdId)
->where('opd_session_id', $sessionId)
->where('bundle_type', 'PrescriptionRecord')
->orderBy('id', 'DESC')
->get(1)
->getRowArray();
if (! empty($existingPrescDoc['id'])) {
$this->db->table('opd_fhir_documents')
->where('id', (int) $existingPrescDoc['id'])
->update([
'bundle_json' => $prescBundleJson,
'generated_by' => $generatedBy,
'generated_at' => $now,
'updated_at' => $now,
]);
} else {
$this->db->table('opd_fhir_documents')->insert([
'opd_id' => $opdId,
'opd_session_id' => $sessionId,
'bundle_type' => 'PrescriptionRecord',
'bundle_json' => $prescBundleJson,
'generated_by' => $generatedBy,
'generated_at' => $now,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
if (! $inserted) {
return false;
}
@ -11839,8 +11881,10 @@ class Opd_prescription extends BaseController
$patientId = (int) ($patientRow['id'] ?? ($opdRow['p_id'] ?? 0));
$visitDateRaw = trim((string) ($opdRow['date_opd_visit'] ?? $opdRow['apointment_date'] ?? ''));
$visitDate = $visitDateRaw !== '' ? date('Y-m-d', strtotime($visitDateRaw)) : date('Y-m-d');
$careContextRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . str_replace('-', '', $visitDate);
$cleanDate = str_replace('-', '', $visitDate);
$careContextRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . $cleanDate;
// 1. Upsert OPConsultRecord
$existingHr = $this->db->table('health_records')
->select('id')
->where('care_context_reference', $careContextRef)
@ -11865,6 +11909,74 @@ class Opd_prescription extends BaseController
$hrPayload['created_at'] = Time::now('Asia/Kolkata')->toDateTimeString();
$this->db->table('health_records')->insert($hrPayload);
}
// 2. Upsert PrescriptionRecord (if medications exist)
if (! empty($medications) && ! empty($prescBundleJson)) {
$prescCcRef = 'PRESC-' . $patientId . '-S' . $sessionId . '-' . $cleanDate;
$existingPrescHr = $this->db->table('health_records')
->select('id')
->where('care_context_reference', $prescCcRef)
->get(1)
->getRowArray();
$prescHrPayload = [
'patient_id' => $patientId > 0 ? $patientId : null,
'abha_id' => $abhaAddress !== '' ? $abhaAddress : null,
'hi_type' => 'PrescriptionRecord',
'entity_type' => 'opd_prescription',
'entity_id' => (string) $sessionId,
'record_data' => $prescBundleJson,
'care_context_reference' => $prescCcRef,
'push_status' => 'local_discovery_ready',
'updated_at' => Time::now('Asia/Kolkata')->toDateTimeString(),
];
if (! empty($existingPrescHr)) {
$this->db->table('health_records')->where('id', (int) $existingPrescHr['id'])->update($prescHrPayload);
} else {
$prescHrPayload['created_at'] = Time::now('Asia/Kolkata')->toDateTimeString();
$this->db->table('health_records')->insert($prescHrPayload);
}
}
// 3. Upsert WellnessRecord (if vitals exist)
$hasVitals = ! empty($clinicalContext['observations']);
if ($hasVitals && class_exists('\App\Controllers\DoctorDocument')) {
try {
$docCtrl = new \App\Controllers\DoctorDocument();
$wSource = $docCtrl->buildWellnessRecordSource($patientId, $sessionId);
if (! empty($wSource) && ! empty($wSource['vitals'])) {
$wFactory = new \App\Libraries\Abdm\Fhir\FhirGeneratorFactory();
$wGen = $wFactory->wellness()->generate($wSource);
if (! empty($wGen['bundle'])) {
$wellBundleJson = json_encode($wGen['bundle'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$wellCcRef = 'WELLNESS-' . $sessionId . '-' . $cleanDate;
$existingWellHr = $this->db->table('health_records')
->select('id')
->where('care_context_reference', $wellCcRef)
->get(1)
->getRowArray();
$wellHrPayload = [
'patient_id' => $patientId > 0 ? $patientId : null,
'abha_id' => $abhaAddress !== '' ? $abhaAddress : null,
'hi_type' => 'WellnessRecord',
'entity_type' => 'opd_vitals',
'entity_id' => (string) $sessionId,
'record_data' => $wellBundleJson,
'care_context_reference' => $wellCcRef,
'push_status' => 'local_discovery_ready',
'updated_at' => Time::now('Asia/Kolkata')->toDateTimeString(),
];
if (! empty($existingWellHr)) {
$this->db->table('health_records')->where('id', (int) $existingWellHr['id'])->update($wellHrPayload);
} else {
$wellHrPayload['created_at'] = Time::now('Asia/Kolkata')->toDateTimeString();
$this->db->table('health_records')->insert($wellHrPayload);
}
}
}
} catch (\Throwable $we) {
log_message('warning', '[storePrescriptionFhirBundle] auto wellness error: ' . $we->getMessage());
}
}
} catch (\Throwable $e) {
log_message('warning', '[storePrescriptionFhirBundle] auto health_records insert error: ' . $e->getMessage());
}

View File

@ -517,6 +517,115 @@ class AbdmTaskBoardSyncService
}
}
// 5b. If medications exist and we linked OPConsultRecord, also link PrescriptionRecord care context to bridge
$sessionId = (int) ($docRow['opd_session_id'] ?? 0);
if ($isSuccess && $sessionId > 0) {
$hasMeds = false;
if ($this->db->tableExists('opd_prescrption_prescribed')) {
$hasMeds = ($this->db->table('opd_prescrption_prescribed')->where('prescription_id', $sessionId)->countAllResults() > 0);
}
if (! $hasMeds && $this->db->tableExists('opd_prescription_prescribed')) {
$hasMeds = ($this->db->table('opd_prescription_prescribed')->where('opd_pre_id', $sessionId)->countAllResults() > 0);
}
if ($hasMeds) {
$cleanDate = str_replace('-', '', $visitDate);
$prescCcRef = 'PRESC-' . $patientId . '-S' . $sessionId . '-' . $cleanDate;
$prescDisplay = 'Prescription - ' . $visitDate;
try {
$opdCtrl = new \App\Controllers\Opd_prescription();
$opdCtrl->initController(\Config\Services::request(), \Config\Services::response(), service('logger'));
$prescRegen = $opdCtrl->regenerateFhirBundleInternal($opdId, $sessionId, 'PrescriptionRecord');
$prescBundleJson = ! empty($prescRegen['bundle']) ? json_encode($prescRegen['bundle'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null;
$prescPushData = [
'patient_id' => (string) $patientId,
'patient_name' => $patientName !== '' ? $patientName : ('PATIENT-' . $patientId),
'abha_id' => $abhaNumber,
'abha_address' => $abhaAddress,
'year_of_birth' => $yearOfBirth,
'gender' => $gender,
'hi_type' => 'PrescriptionRecord',
'record_type' => 'PrescriptionRecord',
'visit_date' => $visitDate,
'care_context_reference' => $prescCcRef,
'care_context_display' => $prescDisplay,
'notes' => $prescDisplay,
'queue_id' => $prescCcRef,
];
if (! empty($prescRegen['bundle'])) {
$prescPushData['bundle'] = $prescRegen['bundle'];
$prescPushData['fhir_bundle'] = $prescRegen['bundle'];
}
$prescRes = $this->connector->pushRecord($prescPushData);
$this->recordLinkedState(
$patientId,
$effectiveAbha,
'PrescriptionRecord',
'opd_prescription',
(string) $sessionId,
$prescCcRef,
(string) ($prescRes['queue_id'] ?? $prescCcRef),
(int) ($prescRes['record_id'] ?? 0),
$prescBundleJson
);
} catch (\Throwable $pe) {
log_message('warning', '[linkAndPushOpdRecord] Prescription care context push error: ' . $pe->getMessage());
}
}
// 5c. If vitals exist, also link WellnessRecord care context to bridge
try {
$pRow = $this->db->table('opd_prescription')->where('id', $sessionId)->get(1)->getRowArray();
$hasVitals = ! empty($pRow['bp']) || ! empty($pRow['pulse']) || ! empty($pRow['temp']) || ! empty($pRow['spo2']) || ! empty($pRow['weight']);
if ($hasVitals && class_exists('\App\Controllers\DoctorDocument')) {
$cleanDate = str_replace('-', '', $visitDate);
$wellCcRef = 'WELLNESS-' . $sessionId . '-' . $cleanDate;
$docCtrl = new \App\Controllers\DoctorDocument();
$wSource = $docCtrl->buildWellnessRecordSource($patientId, $sessionId);
if (! empty($wSource) && ! empty($wSource['vitals'])) {
$wFactory = new \App\Libraries\Abdm\Fhir\FhirGeneratorFactory();
$wGen = $wFactory->wellness()->generate($wSource);
$wellBundleJson = ! empty($wGen['bundle']) ? json_encode($wGen['bundle'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null;
$wellDisplay = 'Wellness Record - ' . $visitDate;
$wellPushData = [
'patient_id' => (string) $patientId,
'patient_name' => $patientName !== '' ? $patientName : ('PATIENT-' . $patientId),
'abha_id' => $abhaNumber,
'abha_address' => $abhaAddress,
'year_of_birth' => $yearOfBirth,
'gender' => $gender,
'hi_type' => 'WellnessRecord',
'record_type' => 'WellnessRecord',
'visit_date' => $visitDate,
'care_context_reference' => $wellCcRef,
'care_context_display' => $wellDisplay,
'notes' => $wellDisplay,
'queue_id' => $wellCcRef,
];
if (! empty($wGen['bundle'])) {
$wellPushData['bundle'] = $wGen['bundle'];
$wellPushData['fhir_bundle'] = $wGen['bundle'];
}
$wellRes = $this->connector->pushRecord($wellPushData);
$this->recordLinkedState(
$patientId,
$effectiveAbha,
'WellnessRecord',
'opd_vitals',
(string) $sessionId,
$wellCcRef,
(string) ($wellRes['queue_id'] ?? $wellCcRef),
(int) ($wellRes['record_id'] ?? 0),
$wellBundleJson
);
}
}
} catch (\Throwable $we) {
log_message('warning', '[linkAndPushOpdRecord] Wellness care context push error: ' . $we->getMessage());
}
}
if ($isSuccess) {
return [
'ok' => 1,
@ -794,6 +903,25 @@ class AbdmTaskBoardSyncService
'queue_id' => $careContextRef,
];
$bundleJson = null;
if ($taskType === 'wellness_record_publish' && class_exists('\App\Controllers\DoctorDocument')) {
try {
$docCtrl = new \App\Controllers\DoctorDocument();
$wSource = $docCtrl->buildWellnessRecordSource($patientId, $entityId);
if (! empty($wSource)) {
$wFactory = new \App\Libraries\Abdm\Fhir\FhirGeneratorFactory();
$wGen = $wFactory->wellness()->generate($wSource);
if (! empty($wGen['bundle'])) {
$pushData['bundle'] = $wGen['bundle'];
$pushData['fhir_bundle'] = $wGen['bundle'];
$bundleJson = (string) json_encode($wGen['bundle'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
}
} catch (\Throwable $we) {
log_message('warning', '[processIndividualWorkTask] Wellness bundle generation error: ' . $we->getMessage());
}
}
try {
$result = $this->connector->pushRecord($pushData);
$ok = (int) ($result['ok'] ?? 0);
@ -812,7 +940,8 @@ class AbdmTaskBoardSyncService
(string) $entityId,
$careContextRef,
$queueId,
(int) ($result['record_id'] ?? 0)
(int) ($result['record_id'] ?? 0),
$bundleJson
);
return ['ok' => 1, 'queue_id' => $queueId];
@ -832,7 +961,8 @@ class AbdmTaskBoardSyncService
string $entityId,
string $careContextRef,
string $queueId,
int $bridgeRecordId
int $bridgeRecordId,
?string $recordData = null
): void {
$now = Time::now('Asia/Kolkata')->toDateTimeString();
@ -854,6 +984,9 @@ class AbdmTaskBoardSyncService
'abdm_txn_id' => $queueId,
'updated_at' => $now,
];
if ($recordData !== null && $recordData !== '') {
$hrData['record_data'] = $recordData;
}
if ($bridgeRecordId > 0 && in_array('bridge_record_id', $this->db->getFieldNames('health_records') ?? [], true)) {
$hrData['bridge_record_id'] = $bridgeRecordId;
}

View File

@ -718,10 +718,10 @@ class FhirR4Builder
'type' => [
'coding' => [[
'system' => 'http://snomed.info/sct',
'code' => '371530004',
'display' => 'Clinical consultation report',
'code' => $isOpConsult ? '371530004' : '440545006',
'display' => $isOpConsult ? 'Clinical consultation report' : 'Prescription record',
]],
'text' => 'Clinical Consultation report',
'text' => $isOpConsult ? 'Clinical Consultation report' : 'Prescription record',
],
'subject' => ['reference' => $patientRef, 'display' => 'Patient'],
'encounter' => ['reference' => $encounterRef, 'display' => 'Encounter'],

View File

@ -41,9 +41,23 @@ final class CareContextDiscoveryTest extends CIUnitTestCase
$db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('opd_prescription') . " (
id INTEGER PRIMARY KEY,
p_id INTEGER,
opd_id INTEGER,
date_opd_visit TEXT,
session_id INTEGER,
p_datetime TEXT
p_datetime TEXT,
bp TEXT,
pulse TEXT,
temp TEXT,
spo2 TEXT,
weight TEXT,
height TEXT
)");
$db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('opd_prescrption_prescribed') . " (
id INTEGER PRIMARY KEY,
prescription_id INTEGER,
medicine_name TEXT,
dosage_summary TEXT
)");
$db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('opd_master') . " (
@ -442,5 +456,82 @@ final class CareContextDiscoveryTest extends CIUnitTestCase
$this->assertTrue($invoiceCtx['is_primary']);
$this->assertTrue($invoiceCtx['is_fhir_ready']);
}
public function testDiscoversPrescriptionAndWellnessCareContextsWhenPresent(): void
{
$db = \Config\Database::connect();
$db->table('opd_prescription')->insert([
'id' => 901,
'p_id' => 15350,
'opd_id' => 15350,
'session_id' => 901,
'date_opd_visit' => '2026-10-06',
'bp' => '120/80',
'pulse' => '72',
'temp' => '98.4',
'spo2' => '98',
'weight' => '70',
'height' => '175',
]);
$db->table('opd_prescrption_prescribed')->insert([
'id' => 101,
'prescription_id' => 901,
'medicine_name' => 'CAP PANTOP DSR',
'dosage_summary' => '1 Tab | OD | 5 days',
]);
$refGateway = new ReflectionClass($this->gateway);
$method = $refGateway->getMethod('findCareContextsForPatient');
$method->setAccessible(true);
[$v3, $full] = $method->invoke($this->gateway, 15350, 'P-15350', 'DEVENDER SINGH');
$refs = array_column($v3, 'referenceNumber');
$this->assertContains('OPD-15350-S901-20261006', $refs);
$this->assertContains('PRESC-15350-S901-20261006', $refs);
$this->assertContains('WELLNESS-901-20261006', $refs);
$types = array_column($full, 'record_type');
$this->assertContains('OPConsultRecord', $types);
$this->assertContains('PrescriptionRecord', $types);
$this->assertContains('WellnessRecord', $types);
}
public function testDiscoversWellnessTaskBoardCareContext(): void
{
$db = \Config\Database::connect();
$db->table('opd_prescription')->insert([
'id' => 33723,
'p_id' => 15350,
'opd_id' => 15350,
'session_id' => 33723,
'date_opd_visit' => '2026-10-06',
'bp' => '130/85',
'pulse' => '75',
]);
$refGateway = new ReflectionClass($this->gateway);
$method = $refGateway->getMethod('findCareContextsForPatient');
$method->setAccessible(true);
[$v3, $full] = $method->invoke(
$this->gateway,
15350,
'P-15350',
'DEVENDER SINGH',
'wellness_record_publish',
'33723'
);
$refs = array_column($v3, 'referenceNumber');
$this->assertContains('WELLNESS-33723-20261006', $refs);
$primary = $full[0];
$this->assertSame('WELLNESS-33723-20261006', $primary['careContextId']);
$this->assertSame('WellnessRecord', $primary['record_type']);
$this->assertTrue($primary['is_primary']);
}
}