From c26b5bf01ef13432cbbdd8ec18700b8ee1e39aa4 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Tue, 27 Oct 2026 00:32:25 +0530 Subject: [PATCH] fix(pharmacy): resolve internal doctor linking and auto-matching for mobile draft invoices --- app/Controllers/Medical.php | 65 ++++++++++++++++++++++- app/Views/medical/invoice_edit.php | 16 ++++++ app/Views/medical/invoice_master_edit.php | 16 ++++++ app/Views/medical/mobile_store.php | 1 + 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/app/Controllers/Medical.php b/app/Controllers/Medical.php index 2c25b7b..a07ea29 100644 --- a/app/Controllers/Medical.php +++ b/app/Controllers/Medical.php @@ -4167,6 +4167,24 @@ class Medical extends BaseController $docList[] = $docRow; } } + } elseif (!empty($invoice->doc_name)) { + $cleanName = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', trim((string)$invoice->doc_name))); + foreach ($docList as $d) { + $dName = trim((string) ($d->p_fname ?? '')); + $cleanDName = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $dName)); + if (strcasecmp($dName, $invoice->doc_name) === 0 || strcasecmp($cleanDName, $cleanName) === 0) { + $matchedId = (int) ($d->id ?? 0); + if ($matchedId > 0) { + $invoice->doc_id = $matchedId; + $invoice->doc_name = $dName; + $this->db->table('invoice_med_master')->where('id', $invoice->id)->update([ + 'doc_id' => $matchedId, + 'doc_name' => $dName + ]); + break; + } + } + } } } @@ -15531,18 +15549,20 @@ class Medical extends BaseController ipd.id AS ipd_id, ipd.ipd_code, ipd.bed_no, + ipd.r_doc_id AS ipd_doc_id, ipd.r_doc_name AS ipd_doc_name, ipd.ipd_status, opd.opd_id, opd.opd_code, + opd.doc_id AS opd_doc_id, opd.doc_name AS opd_doc_name ', false); // Join active or recent IPD - $builder->join('(SELECT id, ipd_code, p_id, bed_no, r_doc_name, ipd_status FROM ipd_master ORDER BY id DESC LIMIT 500) ipd', 'ipd.p_id = p.id', 'left'); + $builder->join('(SELECT id, ipd_code, p_id, bed_no, r_doc_id, r_doc_name, ipd_status FROM ipd_master ORDER BY id DESC LIMIT 500) ipd', 'ipd.p_id = p.id', 'left'); // Join active or recent OPD - $builder->join('(SELECT opd_id, opd_code, p_id, doc_name FROM opd_master ORDER BY opd_id DESC LIMIT 500) opd', 'opd.p_id = p.id', 'left'); + $builder->join('(SELECT opd_id, opd_code, p_id, doc_id, doc_name FROM opd_master ORDER BY opd_id DESC LIMIT 500) opd', 'opd.p_id = p.id', 'left'); $builder->groupStart(); $builder->like('p.p_code', $term); @@ -15566,7 +15586,27 @@ class Medical extends BaseController foreach ($results as $r) { $isIpd = !empty($r['ipd_id']) && ((int)($r['ipd_status'] ?? 1) === 1 || empty($r['opd_id'])); + $docId = $isIpd ? ((int)($r['ipd_doc_id'] ?? 0) ?: (int)($r['opd_doc_id'] ?? 0)) : ((int)($r['opd_doc_id'] ?? 0) ?: (int)($r['ipd_doc_id'] ?? 0)); $docName = $isIpd ? ($r['ipd_doc_name'] ?: ($r['opd_doc_name'] ?: 'Doctor')) : ($r['opd_doc_name'] ?: ($r['ipd_doc_name'] ?: 'Doctor')); + + if ($docId <= 0 && !empty($docName) && $docName !== 'Doctor' && $this->db->tableExists('doctor_master')) { + $cleanDoc = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $docName)); + $matchedDoc = $this->db->table('doctor_master') + ->select('id, p_fname') + ->groupStart() + ->where('p_fname', $docName) + ->orWhere('p_fname', $cleanDoc) + ->orLike('p_fname', $cleanDoc) + ->groupEnd() + ->where('active', 1) + ->get() + ->getRowArray(); + if ($matchedDoc) { + $docId = (int)$matchedDoc['id']; + $docName = trim((string)($matchedDoc['p_fname'] ?? $docName)); + } + } + $genderStr = ((int)($r['gender'] ?? 0) === 1) ? 'Male' : (((int)($r['gender'] ?? 0) === 2) ? 'Female' : 'Other'); $patients[] = [ @@ -15582,6 +15622,7 @@ class Medical extends BaseController 'bed_no' => (string)($r['bed_no'] ?? ''), 'opd_id' => (int)($r['opd_id'] ?? 0), 'opd_code' => (string)($r['opd_code'] ?? ''), + 'doc_id' => $docId, 'doc_name' => (string)$docName, 'badge' => $isIpd ? ('IPD #' . ($r['ipd_id'] ?: $r['ipd_code']) . (!empty($r['bed_no']) ? ' [Bed: ' . $r['bed_no'] . ']' : '')) : ('OPD #' . ($r['opd_code'] ?: $r['opd_id'])) ]; @@ -15721,9 +15762,28 @@ class Medical extends BaseController $bedNo = trim((string)($json['bed_no'] ?? '')); $opdId = (int)($json['opd_id'] ?? 0); $opdCode = trim((string)($json['opd_code'] ?? '')); + $docId = (int)($json['doc_id'] ?? 0); $docName = trim((string)($json['doc_name'] ?? '')); $pickerName = trim((string)($json['picker_name'] ?? (session('name') ?: 'Mobile Picker'))); + if ($docId <= 0 && $docName !== '' && $docName !== 'Doctor' && $this->db->tableExists('doctor_master')) { + $cleanDoc = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $docName)); + $matchedDoc = $this->db->table('doctor_master') + ->select('id, p_fname') + ->groupStart() + ->where('p_fname', $docName) + ->orWhere('p_fname', $cleanDoc) + ->orLike('p_fname', $cleanDoc) + ->groupEnd() + ->where('active', 1) + ->get() + ->getRowArray(); + if ($matchedDoc) { + $docId = (int)$matchedDoc['id']; + $docName = trim((string)($matchedDoc['p_fname'] ?? $docName)); + } + } + $invFields = $this->db->getFieldNames('invoice_med_master') ?? []; $setIfExists = static function (array &$arr, array $fields, string $col, $val): void { if (in_array($col, $fields, true)) { @@ -15743,6 +15803,7 @@ class Medical extends BaseController $setIfExists($header, $invFields, 'ipd_id', $ipdId); $setIfExists($header, $invFields, 'ipd_code', $ipdCode); $setIfExists($header, $invFields, 'bed_no', $bedNo); + $setIfExists($header, $invFields, 'doc_id', $docId); $setIfExists($header, $invFields, 'doc_name', $docName); $setIfExists($header, $invFields, 'draft_source', 'mobile_picker'); $setIfExists($header, $invFields, 'picker_name', $pickerName); diff --git a/app/Views/medical/invoice_edit.php b/app/Views/medical/invoice_edit.php index 2e9c4b3..9a3622d 100644 --- a/app/Views/medical/invoice_edit.php +++ b/app/Views/medical/invoice_edit.php @@ -49,6 +49,22 @@ } } } + + // Auto-match doctor by name if doc_id is 0 or unassigned + if (!$docFound && !empty($docList) && $currentDocName !== '') { + $cleanCurrentDoc = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $currentDocName)); + foreach ($docList as $d) { + $dName = trim((string) ($d->p_fname ?? '')); + $cleanDName = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $dName)); + if (strcasecmp($dName, $currentDocName) === 0 || strcasecmp($cleanDName, $cleanCurrentDoc) === 0) { + $currentDocId = (int) ($d->id ?? 0); + $currentDocName = $dName; + $docFound = true; + break; + } + } + } + // If not found in hospital doctors list but doctor name exists, treat as outside doctor $isOtherDoc = (!$docFound && ($currentDocId === 0 || $currentDocId === 999999) && $currentDocName !== ''); ?> diff --git a/app/Views/medical/invoice_master_edit.php b/app/Views/medical/invoice_master_edit.php index b372397..73f2ab8 100644 --- a/app/Views/medical/invoice_master_edit.php +++ b/app/Views/medical/invoice_master_edit.php @@ -177,6 +177,22 @@ } } } + + // Auto-match doctor by name if masterDocId is 0 or unassigned + if (!$masterDocFound && !empty($docList) && $masterDocName !== '') { + $cleanMasterDoc = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $masterDocName)); + foreach ($docList as $d) { + $dName = trim((string) ($d->p_fname ?? '')); + $cleanDName = trim(preg_replace('/^(dr\.?|doctor)\s+/i', '', $dName)); + if (strcasecmp($dName, $masterDocName) === 0 || strcasecmp($cleanDName, $cleanMasterDoc) === 0) { + $masterDocId = (int) ($d->id ?? 0); + $masterDocName = $dName; + $masterDocFound = true; + break; + } + } + } + $masterIsOtherDoc = (!$masterDocFound && ($masterDocId === 0 || $masterDocId === 999999) && $masterDocName !== ''); ?>
diff --git a/app/Views/medical/mobile_store.php b/app/Views/medical/mobile_store.php index af32e08..417963e 100644 --- a/app/Views/medical/mobile_store.php +++ b/app/Views/medical/mobile_store.php @@ -824,6 +824,7 @@ bed_no: selectedPatient ? selectedPatient.bed_no : '', opd_id: selectedPatient ? selectedPatient.opd_id : 0, opd_code: selectedPatient ? selectedPatient.opd_code : '', + doc_id: selectedPatient ? (selectedPatient.doc_id || 0) : 0, doc_name: selectedPatient ? selectedPatient.doc_name : '', picker_name: operatorName, items: cartItems