From 38b96a1003369dfbb01e82bc46d78fb953de5d04 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Thu, 1 Oct 2026 12:59:45 +0530 Subject: [PATCH] Fix radiology editor DICOM gallery context, match related templates, and remove manual ABDM panel --- app/Controllers/Diagnosis.php | 254 +++++++++++++----- .../diagnosis/imaging_upload_gallery.php | 16 +- .../diagnosis/lab_final_report_editor.php | 144 ++-------- .../diagnosis/lab_final_report_show_xray.php | 12 +- 4 files changed, 227 insertions(+), 199 deletions(-) diff --git a/app/Controllers/Diagnosis.php b/app/Controllers/Diagnosis.php index 9a7a26e..39ae7e4 100644 --- a/app/Controllers/Diagnosis.php +++ b/app/Controllers/Diagnosis.php @@ -1046,27 +1046,7 @@ class Diagnosis extends BaseController return '
Report not found
'; } - $invoiceItem = $this->db->table('invoice_item') - ->select('item_id') - ->where('id', (int) ($reportRow->charge_item_id ?? 0)) - ->get() - ->getRow(); - - $templateBuilder = $this->db->table('radiology_ultrasound_template') - ->select('id, template_name, title, keywords, impression_cat') - ->where('Modality', (int) ($reportRow->lab_type ?? 0)); - - if (! empty($invoiceItem->item_id)) { - $templateBuilder->groupStart() - ->where('charge_id', (int) $invoiceItem->item_id) - ->orWhere('charge_id', 0) - ->groupEnd(); - } - - $templates = $templateBuilder - ->orderBy('template_name', 'ASC') - ->get() - ->getResult(); + $templates = $this->getRadiologyTemplatesForReport($reportRow); return view('diagnosis/lab_final_report_show_xray', [ 'report_format' => [$reportRow], @@ -1126,27 +1106,7 @@ class Diagnosis extends BaseController } } - $invoiceItem = $this->db->table('invoice_item') - ->select('item_id') - ->where('id', (int) ($reportRow->charge_item_id ?? 0)) - ->get() - ->getRow(); - - $templateBuilder = $this->db->table('radiology_ultrasound_template') - ->select('id, template_name, title, keywords, impression_cat') - ->where('Modality', (int) ($reportRow->lab_type ?? 0)); - - if (! empty($invoiceItem->item_id)) { - $templateBuilder->groupStart() - ->where('charge_id', (int) $invoiceItem->item_id) - ->orWhere('charge_id', 0) - ->groupEnd(); - } - - $templates = $templateBuilder - ->orderBy('template_name', 'ASC') - ->get() - ->getResult(); + $templates = $this->getRadiologyTemplatesForReport($reportRow); return view('diagnosis/lab_final_report_editor', [ 'report_format' => [$reportRow], @@ -1155,6 +1115,138 @@ class Diagnosis extends BaseController ]); } + /** + * Fetch and rank radiology templates matching a given report. + * + * @param object|array $reportRow + * @return array + */ + private function getRadiologyTemplatesForReport($reportRow): array + { + $reportObj = is_array($reportRow) ? (object) $reportRow : $reportRow; + $labType = (int) ($reportObj->lab_type ?? 0); + if ($labType <= 0 || ! $this->db->tableExists('radiology_ultrasound_template')) { + return []; + } + + $builder = $this->db->table('radiology_ultrasound_template') + ->select('id, template_name, title, keywords, impression_cat, charge_id, Modality'); + + if ($labType === 2) { + $builder->groupStart() + ->where('Modality', 2) + ->orWhere('Modality IS NULL') + ->groupEnd(); + } else { + $builder->where('Modality', $labType); + } + + $allTemplates = $builder->orderBy('template_name', 'ASC')->get()->getResult(); + if (empty($allTemplates)) { + return []; + } + + $chargeItemId = (int) ($reportObj->charge_item_id ?? 0); + $reportName = trim((string) ($reportObj->report_name ?? '')); + + $invoiceItem = null; + if ($chargeItemId > 0 && $this->db->tableExists('invoice_item')) { + $invoiceItem = $this->db->table('invoice_item') + ->select('item_id, item_name') + ->where('id', $chargeItemId) + ->get() + ->getRow(); + } + + $itemId = (int) ($invoiceItem->item_id ?? 0); + $itemName = trim((string) ($invoiceItem->item_name ?? '')); + + // Normalizer helper for clinical test names + $normalizeTest = static function (string $text): string { + $s = strtolower(trim($text)); + $s = preg_replace('/\b(x[- ]?ray|xray|mri|ct|scan|usg|ultrasound|view|views|plain|contrast)\b/i', ' ', $s); + $s = preg_replace('/[^a-z0-9]+/i', ' ', $s); + return trim((string) preg_replace('/\s+/', ' ', $s)); + }; + + $normalizedReportName = $normalizeTest($reportName); + $normalizedItemName = $normalizeTest($itemName); + $primaryTarget = $normalizedReportName !== '' ? $normalizedReportName : $normalizedItemName; + + // Collect related charge IDs from hc_items + $matchedChargeIds = []; + if ($itemId > 0) { + $matchedChargeIds[] = $itemId; + } + + if ($primaryTarget !== '' && $this->db->tableExists('hc_items')) { + $hcRows = $this->db->table('hc_items') + ->select('id, idesc') + ->where('itype', $labType) + ->get() + ->getResult(); + + foreach ($hcRows as $hc) { + $hcClean = $normalizeTest((string) ($hc->idesc ?? '')); + if ($hcClean !== '' && ($hcClean === $primaryTarget || str_contains($hcClean, $primaryTarget) || str_contains($primaryTarget, $hcClean))) { + $matchedChargeIds[] = (int) $hc->id; + } + } + $matchedChargeIds = array_values(array_unique($matchedChargeIds)); + } + + $targetTokens = array_values(array_filter(explode(' ', $primaryTarget), static fn($t) => strlen($t) >= 3)); + + foreach ($allTemplates as $tpl) { + $score = 0; + $tplChargeId = (int) ($tpl->charge_id ?? 0); + $tplCleanTitle = $normalizeTest((string) ($tpl->title ?? '')); + $tplCleanName = $normalizeTest((string) ($tpl->template_name ?? '')); + $tplKeywords = strtolower((string) ($tpl->keywords ?? '')); + + if ($tplChargeId > 0 && in_array($tplChargeId, $matchedChargeIds, true)) { + $score = max($score, 100); + } + + if ($primaryTarget !== '') { + if ($tplCleanTitle === $primaryTarget || $tplCleanName === $primaryTarget) { + $score = max($score, 90); + } elseif (str_contains($tplCleanTitle, $primaryTarget) || str_contains($tplCleanName, $primaryTarget) || str_contains($primaryTarget, $tplCleanTitle)) { + $score = max($score, 75); + } + } + + if (! empty($targetTokens)) { + $tokenHits = 0; + $searchCorpus = $tplCleanName . ' ' . $tplCleanTitle . ' ' . $tplKeywords; + foreach ($targetTokens as $token) { + if (str_contains($searchCorpus, $token)) { + $tokenHits++; + } + } + if ($tokenHits === count($targetTokens)) { + $score = max($score, 60); + } elseif ($tokenHits > 0) { + $score = max($score, 30 + ($tokenHits * 10)); + } + } + + $tpl->match_score = $score; + $tpl->is_related = $score >= 50; + } + + usort($allTemplates, static function ($a, $b) { + $scoreA = (int) ($a->match_score ?? 0); + $scoreB = (int) ($b->match_score ?? 0); + if ($scoreA !== $scoreB) { + return $scoreB <=> $scoreA; + } + return strcasecmp((string) ($a->template_name ?? ''), (string) ($b->template_name ?? '')); + }); + + return $allTemplates; + } + public function getTemplateXray($templateId) { $templateId = (int) $templateId; @@ -2994,31 +3086,52 @@ class Diagnosis extends BaseController $labType = (int) $labType; $labReqId = (int) $labReqId; - if ($invoiceId <= 0 || $labType <= 0 || ! $this->db->tableExists('file_upload_data')) { + $studyName = ''; + if ($labReqId > 0 && $this->db->tableExists('lab_request')) { + $requestRow = $this->db->table('lab_request') + ->select('id, charge_id, lab_type, report_name') + ->where('id', $labReqId) + ->get(1) + ->getRowArray(); + if ($requestRow) { + $studyName = trim((string) ($requestRow['report_name'] ?? '')); + if ($invoiceId <= 0 || $invoiceId === $labReqId) { + $invoiceId = (int) ($requestRow['charge_id'] ?? $invoiceId); + } + if ($labType <= 0) { + $labType = (int) ($requestRow['lab_type'] ?? $labType); + } + } + } + + if (($invoiceId <= 0 && $labReqId <= 0) || ! $this->db->tableExists('file_upload_data')) { return view('diagnosis/imaging_upload_gallery', [ 'files' => [], 'study_name' => '', ]); } - $studyName = ''; - if ($labReqId > 0) { - $requestRow = $this->db->table('lab_request') - ->select('id, report_name') - ->where('id', $labReqId) - ->get(1) - ->getRowArray(); - $studyName = trim((string) ($requestRow['report_name'] ?? '')); - } + $fields = $this->db->getFieldNames('file_upload_data'); + $hasRepoId = in_array('repo_id', $fields, true); $builder = $this->db->table('file_upload_data') - ->where('isdelete', 0) - ->where('charge_id', $invoiceId) - ->where('charge_type', $labType); + ->where('isdelete', 0); - $fields = $this->db->getFieldNames('file_upload_data'); - if ($labReqId > 0 && in_array('repo_id', $fields, true)) { + if ($labReqId > 0 && $hasRepoId && $invoiceId > 0) { + $builder->groupStart() + ->where('repo_id', $labReqId) + ->orGroupStart() + ->where('charge_id', $invoiceId) + ->where('charge_type', $labType) + ->groupEnd() + ->groupEnd(); + } elseif ($labReqId > 0 && $hasRepoId) { $builder->where('repo_id', $labReqId); + } elseif ($invoiceId > 0) { + $builder->where('charge_id', $invoiceId); + if ($labType > 0) { + $builder->where('charge_type', $labType); + } } $rows = $builder->orderBy('id', 'DESC')->get()->getResultArray(); @@ -3677,18 +3790,31 @@ class Diagnosis extends BaseController */ private function findImagingFilesForRequest(int $invoiceId, int $labType, int $labReqId): array { - if ($invoiceId <= 0 || $labType <= 0 || ! $this->db->tableExists('file_upload_data')) { + if (($invoiceId <= 0 && $labReqId <= 0) || ! $this->db->tableExists('file_upload_data')) { return []; } - $builder = $this->db->table('file_upload_data') - ->where('isdelete', 0) - ->where('charge_id', $invoiceId) - ->where('charge_type', $labType); - $fields = $this->db->getFieldNames('file_upload_data'); - if ($labReqId > 0 && in_array('repo_id', $fields, true)) { + $hasRepoId = in_array('repo_id', $fields, true); + + $builder = $this->db->table('file_upload_data') + ->where('isdelete', 0); + + if ($labReqId > 0 && $hasRepoId && $invoiceId > 0) { + $builder->groupStart() + ->where('repo_id', $labReqId) + ->orGroupStart() + ->where('charge_id', $invoiceId) + ->where('charge_type', $labType) + ->groupEnd() + ->groupEnd(); + } elseif ($labReqId > 0 && $hasRepoId) { $builder->where('repo_id', $labReqId); + } elseif ($invoiceId > 0) { + $builder->where('charge_id', $invoiceId); + if ($labType > 0) { + $builder->where('charge_type', $labType); + } } return $builder->orderBy('id', 'DESC')->get()->getResultArray(); diff --git a/app/Views/diagnosis/imaging_upload_gallery.php b/app/Views/diagnosis/imaging_upload_gallery.php index e2c38ac..6a670f3 100644 --- a/app/Views/diagnosis/imaging_upload_gallery.php +++ b/app/Views/diagnosis/imaging_upload_gallery.php @@ -41,13 +41,21 @@ $studyName = trim((string) ($study_name ?? '')); Uploaded image - +
- DICOM preview + + DICOM preview + +
+
+
DICOM Imaging File
+
- DICOM Preview + DICOM - Open DICOM + + Download / View +
diff --git a/app/Views/diagnosis/lab_final_report_editor.php b/app/Views/diagnosis/lab_final_report_editor.php index 340073f..9fe5c76 100644 --- a/app/Views/diagnosis/lab_final_report_editor.php +++ b/app/Views/diagnosis/lab_final_report_editor.php @@ -154,11 +154,17 @@ $editReason = trim((string) ($edit_reason ?? '')); $tplTitle = trim((string) ($tpl->title ?? '')); $tplKeywords = trim((string) ($tpl->keywords ?? '')); $tplCategory = trim((string) ($tpl->impression_cat ?? '')); - $searchBlob = strtolower(trim($tplName . ' ' . $tplTitle . ' ' . $tplKeywords . ' ' . $tplCategory)); + $isRelated = !empty($tpl->is_related); + $searchBlob = strtolower(trim($tplName . ' ' . $tplTitle . ' ' . $tplKeywords . ' ' . $tplCategory . ($isRelated ? ' related' : ''))); ?> - -
- -
-
ABDM – Share Report
-
-
- - -
-
-
- -
-
- -
-
-
- - -
-
- - -
- -
Ready
-
-
@@ -321,15 +297,17 @@ $editReason = trim((string) ($edit_reason ?? '')); // Show imaging uploads (gallery) function showImagingUploadsFromEditor() { - const reqId = document.getElementById('hid_value_req_id').value; - const testName = document.getElementById('hid_value_report_name').value; + const reqId = document.getElementById('hid_value_req_id') ? document.getElementById('hid_value_req_id').value : ''; + const testName = document.getElementById('hid_value_report_name') ? document.getElementById('hid_value_report_name').value : ''; if (!reqId) { alert('Request ID not found'); return; } showImagingUploads(reqId, testName); } function showImagingUploads(reqId, testName) { - const labType = document.getElementById('lab_type').value; - fetch(baseUrl + 'diagnosis/imaging-upload-gallery/' + reqId + '/' + labType + '/' + reqId, { + const invoiceId = document.getElementById('invoice_id') ? document.getElementById('invoice_id').value : ''; + const labType = document.getElementById('lab_type') ? document.getElementById('lab_type').value : ''; + const targetInvoice = invoiceId || reqId; + fetch(baseUrl + 'diagnosis/imaging-upload-gallery/' + targetInvoice + '/' + (labType || '0') + '/' + reqId, { headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(r => r.text()) @@ -534,97 +512,7 @@ $editReason = trim((string) ($edit_reason ?? '')); } } - // ─── ABDM Lab/Radiology Report Share ────────────────────────────── - (function initDiagAbdmActions() { - var csrfName = ''; - var csrfHash = ''; - var labReqId = id ?? 0) ?>; - var patientId = patient_id ?? 0) ?>; - - function setStatus(msg, isError) { - var el = document.getElementById('diag_abdm_action_status'); - if (!el) { return; } - el.textContent = msg; - el.style.color = isError ? '#dc3545' : '#6c757d'; - } - - function abdmPost(url, payload, onSuccess) { - setStatus('Sending…'); - var data = Object.assign({}, payload); - data[csrfName] = csrfHash; - fetch(url, { - method: 'POST', - headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' }, - body: new URLSearchParams(data).toString() - }) - .then(function(r) { return r.json(); }) - .then(function(resp) { - if (resp && resp.csrf_hash) { csrfHash = resp.csrf_hash; } - if (resp && resp.csrf_token) { csrfName = resp.csrf_token; } - onSuccess(resp); - }) - .catch(function(e) { setStatus('Request failed: ' + e.message, true); }); - } - - var btnValidate = document.getElementById('btn_diag_abdm_validate_abha'); - if (btnValidate) { - btnValidate.addEventListener('click', function() { - var abha = (document.getElementById('diag_abha_address') || {}).value || ''; - if (!abha.trim()) { setStatus('Enter ABHA Address first.', true); return; } - abdmPost(baseUrl + 'AbdmGateway/abha_validate', { abha_address: abha, patient_id: patientId }, function(resp) { - setStatus(resp && resp.message ? resp.message : (resp && resp.ok ? 'ABHA valid.' : 'Validation failed.'), !(resp && resp.ok)); - }); - }); - } - - var btnConsent = document.getElementById('btn_diag_abdm_consent_request'); - if (btnConsent) { - btnConsent.addEventListener('click', function() { - var abha = (document.getElementById('diag_abha_address') || {}).value || ''; - var purpose = (document.getElementById('diag_abdm_purpose_code') || {}).value || 'CAREMGT'; - var expires = (document.getElementById('diag_abdm_consent_expires_at') || {}).value || ''; - if (!abha.trim()) { setStatus('Enter ABHA Address first.', true); return; } - abdmPost(baseUrl + 'AbdmGateway/consent_request', { - abha_address: abha, patient_id: patientId, purpose_code: purpose, expires_at: expires - }, function(resp) { - if (resp && resp.consent_handle) { - var ch = document.getElementById('diag_abdm_consent_handle'); - if (ch) { ch.value = resp.consent_handle; } - } - setStatus(resp && resp.message ? resp.message : (resp && resp.ok ? 'Consent requested.' : 'Consent request failed.'), !(resp && resp.ok)); - }); - }); - } - - var btnShare = document.getElementById('btn_diag_abdm_share_report'); - if (btnShare) { - btnShare.addEventListener('click', function() { - var abha = (document.getElementById('diag_abha_address') || {}).value || ''; - var ch = (document.getElementById('diag_abdm_consent_handle') || {}).value || ''; - if (!abha.trim()) { setStatus('Enter ABHA Address first.', true); return; } - abdmPost(baseUrl + 'AbdmGateway/share_diagnosis_report_bundle', { - lab_req_id: labReqId, patient_id: patientId, abha_id: abha, consent_handle: ch - }, function(resp) { - if (resp && resp.consent_handle) { - var chEl = document.getElementById('diag_abdm_consent_handle'); - if (chEl && !chEl.value) { chEl.value = resp.consent_handle; } - } - var msg = resp && resp.status ? ('Queued: ' + resp.status) : (resp && resp.message ? resp.message : 'Share request sent.'); - if (resp && resp.warning) { msg += ' Warning: ' + resp.warning; } - setStatus(msg, !(resp && (resp.ok || resp.queue_id))); - }); - }); - } - - // Default consent expiry +30 days - (function() { - var el = document.getElementById('diag_abdm_consent_expires_at'); - if (!el || el.value) { return; } - var d = new Date(); d.setDate(d.getDate() + 30); - el.value = d.toISOString().slice(0, 16); - })(); - })(); - // ─── end ABDM ───────────────────────────────────────────────────── + // ABDM report sharing panel removed per user requirement diff --git a/app/Views/diagnosis/lab_final_report_show_xray.php b/app/Views/diagnosis/lab_final_report_show_xray.php index 8c3c1ce..489f36f 100644 --- a/app/Views/diagnosis/lab_final_report_show_xray.php +++ b/app/Views/diagnosis/lab_final_report_show_xray.php @@ -94,11 +94,17 @@ $templates = $radiology_ultrasound_template ?? []; $tplTitle = trim((string) ($tpl->title ?? '')); $tplKeywords = trim((string) ($tpl->keywords ?? '')); $tplCategory = trim((string) ($tpl->impression_cat ?? '')); - $searchBlob = strtolower(trim($tplName . ' ' . $tplTitle . ' ' . $tplKeywords . ' ' . $tplCategory)); + $isRelated = !empty($tpl->is_related); + $searchBlob = strtolower(trim($tplName . ' ' . $tplTitle . ' ' . $tplKeywords . ' ' . $tplCategory . ($isRelated ? ' related' : ''))); ?>