From 9d88aaa2a68235d1a44f2da045acd1066ebeb479 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Sat, 4 Apr 2026 17:26:40 +0530 Subject: [PATCH] Implement ABDM identity storage and align OPD consult/medicine dose masters --- WORKLOG_COPILOT.md | 91 +++++++++++ app/Config/Routes.php | 1 + app/Controllers/Opd.php | 75 ++++++++- app/Controllers/Opd_prescription.php | 86 +++++++++- app/Controllers/Patient.php | 93 +++++++++++ app/Controllers/Setting/Doctor.php | 55 +++++++ app/Controllers/Setting/HospitalProfile.php | 15 ++ ...026-04-04-000036_AddAbdmIdentityFields.php | 97 +++++++++++ ...026-04-04-000037_SyncOpdDoseShedMaster.php | 90 +++++++++++ ...026-04-04-000038_SyncOpdDoseWhenMaster.php | 150 ++++++++++++++++++ app/Views/Setting/Admin/hospital_profile.php | 6 + app/Views/Setting/Doctor/Doctor_V.php | 4 + app/Views/Setting/Doctor/Doctor_profile_V.php | 12 ++ app/Views/billing/Patient_V.php | 8 + app/Views/billing/Person_Edit_V.php | 9 ++ app/Views/billing/Person_profile_V.php | 36 +++++ app/Views/billing/opd_letter_head_pdf.php | 45 +++++- app/Views/billing/opd_medicince_workspace.php | 123 ++++++++++++-- app/Views/billing/opd_prescription_basic.php | 110 ++++++++----- public/assets/img/logo1.png | Bin 0 -> 5389 bytes .../logo_backup_before_attachment_change.png | Bin 0 -> 738 bytes public/favicon.ico | Bin 5430 -> 2306 bytes 22 files changed, 1034 insertions(+), 72 deletions(-) create mode 100644 app/Database/Migrations/2026-04-04-000036_AddAbdmIdentityFields.php create mode 100644 app/Database/Migrations/2026-04-04-000037_SyncOpdDoseShedMaster.php create mode 100644 app/Database/Migrations/2026-04-04-000038_SyncOpdDoseWhenMaster.php create mode 100644 public/assets/img/logo1.png create mode 100644 public/assets/img/logo_backup_before_attachment_change.png diff --git a/WORKLOG_COPILOT.md b/WORKLOG_COPILOT.md index 78e0104..4d28dd0 100644 --- a/WORKLOG_COPILOT.md +++ b/WORKLOG_COPILOT.md @@ -512,6 +512,97 @@ Date: 2026-02-26 - `app/Controllers/Opd_prescription.php` - `app/Config/Routes.php` +--- + +## ABDM Identity Storage — Phase 1 (Paused) + +Date: 2026-04-04 +Status: **PAUSED** — Endpoint server (Gateway) development in progress separately. +Resume after: Gateway API is ready and endpoint URLs are confirmed. + +### Reference Repository +**ABDM Gateway / Endpoint Server:** +> https://github.com/infodevsofttech-admin/HMS-ABDM-Gateway.git + +All ABDM API calls (ABHA creation, HPR lookup, HFR registration, token exchange) will be proxied through this gateway. HMS CI4 will call the gateway's REST endpoints rather than ABDM sandbox/production directly. + +--- + +### What Was Completed (Phase 1 — Local Identity Storage) + +All work below is merged/committed in the HMS CI4 working directory. No gateway calls yet — only local DB storage of ABDM identifiers. + +#### 1. Migration — `app/Database/Migrations/2026-04-04-000036_AddAbdmIdentityFields.php` +- Adds `abha_id VARCHAR(30) NULL` to `patient_master` (safe check; backfills from legacy cols: `abha_no` → `abha` → `abha_address`) +- Adds `hpr_id VARCHAR(40) NULL` to `doctor_master` (safe check) +- Private helpers `tableExists()` / `getColumns()` use raw `SHOW TABLES LIKE` / `SHOW COLUMNS FROM` (CI4 Migration `$db` does not expose `tableExists()` directly) +- **ACTION REQUIRED: Run `php spark migrate` when resuming** + +#### 2. Patient ABHA ID — `app/Controllers/Patient.php` +- `create()` + `update()` capture `input_abha_id` (POST), validate 14 digits, write to detected column +- New endpoint `update_abha()` — AJAX quick-update for patient profile page +- Helper methods: `isValidAbhaId()`, `applyPatientAbhaFieldValues()`, `resolvePatientAbhaIdField()` +- Column resolution priority: `abha_id` → `abha_no` → `abha` → `abha_address` + +#### 3. Patient Views +- `app/Views/billing/Patient_V.php` — ABHA ID input in New Patient tab (14-digit masked) +- `app/Views/billing/Person_profile_V.php` — ABHA ID display + quick-update button with JS handler → POST `billing/patient/update_abha` +- `app/Views/billing/Person_Edit_V.php` — ABHA ID editable field in full edit form + +#### 4. Doctor HPR ID — `app/Controllers/Setting/Doctor.php` +- `store()` + `updateRecord()` capture `input_hpr_id`, validate format, write to detected column +- Helper methods: `resolveDoctorHprField()`, `isValidHprId()` +- Column resolution priority: `hpr_id` → `hpr_no` → `hpr_number` +- Validation regex: `/^[A-Z0-9\/-]{6,40}$/` + +#### 5. Doctor Views +- `app/Views/Setting/Doctor/Doctor_V.php` — HPR ID input in create form +- `app/Views/Setting/Doctor/Doctor_profile_V.php` — HPR ID prefilled input in profile/edit form + +#### 6. Hospital HFR ID — `app/Controllers/Setting/HospitalProfile.php` +- `index()` reads `H_HFR_ID` from `hospital_setting` key-value store +- `save()` validates HFR format, upserts `H_HFR_ID` +- `reset()` deletes `H_HFR_ID` entry +- View: `app/Views/Setting/Admin/hospital_profile.php` — HFR ID input field; wired to save FormData and reset JS + +#### 7. Routes — `app/Config/Routes.php` +- Added: `$routes->post('patient/update_abha', 'Patient::update_abha');` + +--- + +### What Remains — Phase 2 (After Gateway Is Ready) + +These tasks depend on the Gateway API (https://github.com/infodevsofttech-admin/HMS-ABDM-Gateway.git) being operational. + +| # | Task | Notes | +|---|------|-------| +| 1 | **ABHA Creation/Linking flow** | Call gateway to create/link ABHA from Patient form; store returned 14-digit ABHA in `abha_id` | +| 2 | **ABHA OTP Verification flow** | Gateway handles ABDM OTP; HMS shows verify modal; on success update patient record | +| 3 | **HPR Lookup/Verify for Doctors** | Call gateway HPR search by doctor name/reg-no; store verified HPR ID | +| 4 | **HFR Registration status** | Call gateway to check/register hospital in HFR; store `H_HFR_ID` | +| 5 | **Token management** | Gateway handles ABDM access tokens; HMS only sends UID + secret; no token stored in HMS DB | +| 6 | **Surface ABHA/HPR/HFR in Pathlab/Radiology print templates** | Add to diagnosis data arrays from joined master tables; expose as `{{abha_id}}`, `{{hpr_id}}`, `{{hfr_id}}` placeholders | +| 7 | **Patient search by ABHA ID** | Extend `Patient::search()` to include `abha_id` alongside `udai` and `mphone1` | +| 8 | **Snapshot HPR at lab report sign time** | Add `signed_hpr_id` column to lab invoice header; store at signing for immutable audit trail | +| 9 | **ABHA QR Code on OPD/IPD/Billing printouts** | Generate QR from ABHA ID; embed in print views | + +--- + +### Pathlab / Radiology — Confirmed No Separate Storage Needed +- `Diagnosis.php` already JOINs `patient_master` (18+ JOIN references) → inherits `abha_id` +- `Diagnosis.php` reads `hospital_setting` via `readSetting()` → inherits `H_HFR_ID` +- Doctor name on reports traces back to `doctor_master` → inherits `hpr_id` +- **Exception:** Only if immutable audit snapshot is required at sign time (Phase 2, Task 8 above) + +--- + +### Gateway Integration Notes (To Be Confirmed) +- Gateway base URL: to be confirmed from https://github.com/infodevsofttech-admin/HMS-ABDM-Gateway.git +- Expected auth: shared secret / API key between HMS and Gateway (not ABDM tokens directly) +- HMS will POST patient/doctor data to Gateway; Gateway returns ABDM response +- All ABDM sandbox vs. production switching should be configured at Gateway level, not in HMS +- HMS Config key to add when ready: `ABDM_GATEWAY_BASE_URL`, `ABDM_GATEWAY_KEY` in `.env` + ### Validation status - VS Code diagnostics reported no errors in modified files after final patches. diff --git a/app/Config/Routes.php b/app/Config/Routes.php index abfc72d..4d3cace 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -402,6 +402,7 @@ $routes->group('billing', function($routes) { $routes->get('patient/get_name', 'Patient::get_name'); $routes->post('patient/update', 'Patient::update'); $routes->post('patient/update_aadhar', 'Patient::update_aadhar'); + $routes->post('patient/update_abha', 'Patient::update_abha'); $routes->post('patient/update_card', 'Patient::update_card'); $routes->get('case/newcase/(:num)/(:num)', 'Billing\\CaseMaster::newcase/$1/$2'); $routes->get('case/newcase/(:num)/(:num)/(:num)', 'Billing\\CaseMaster::newcase/$1/$2/$3'); diff --git a/app/Controllers/Opd.php b/app/Controllers/Opd.php index 21b96be..f922625 100644 --- a/app/Controllers/Opd.php +++ b/app/Controllers/Opd.php @@ -2990,6 +2990,11 @@ class Opd extends BaseController $mapDose = []; $mapWhen = []; $mapFreq = []; + $mapWhere = []; + $mapDoseLocal = []; + $mapWhenLocal = []; + $mapFreqLocal = []; + $mapWhereLocal = []; $medGenericMap = []; $missingGenericMedIds = []; @@ -2997,14 +3002,23 @@ class Opd extends BaseController $f = $this->db->getFieldNames('opd_dose_shed'); $idF = $this->resolveFirstField($f, ['dose_shed_id', 'id']); $labelF = $this->resolveFirstField($f, ['dose_show_sign', 'dose_sign', 'dose_sign_desc', 'name']); + $localLabelF = $this->resolveFirstField($f, ['dose_show_desc', 'dose_sign_hindi', 'dose_sign_desc']); if ($idF !== null && $labelF !== null) { - $rows = $this->db->table('opd_dose_shed')->select($idF . ' as id,' . $labelF . ' as label')->where($labelF . ' !=', '')->get()->getResultArray(); + $select = [$idF . ' as id', $labelF . ' as label']; + if ($localLabelF !== null && $localLabelF !== $labelF) { + $select[] = $localLabelF . ' as local_label'; + } + $rows = $this->db->table('opd_dose_shed')->select(implode(',', $select))->where($labelF . ' !=', '')->get()->getResultArray(); foreach ($rows as $r) { $id = trim((string) ($r['id'] ?? '')); $label = trim((string) ($r['label'] ?? '')); if ($id !== '' && $label !== '') { $mapDose[$id] = $label; } + $localLabel = trim((string) ($r['local_label'] ?? '')); + if ($id !== '' && $localLabel !== '') { + $mapDoseLocal[$id] = $localLabel; + } } } } @@ -3013,14 +3027,23 @@ class Opd extends BaseController $f = $this->db->getFieldNames('opd_dose_when'); $idF = $this->resolveFirstField($f, ['dose_when_id', 'id']); $labelF = $this->resolveFirstField($f, ['dose_sign', 'dose_sign_desc', 'name']); + $localLabelF = $this->resolveFirstField($f, ['dose_sign_hindi', 'dose_sign_desc']); if ($idF !== null && $labelF !== null) { - $rows = $this->db->table('opd_dose_when')->select($idF . ' as id,' . $labelF . ' as label')->where($labelF . ' !=', '')->get()->getResultArray(); + $select = [$idF . ' as id', $labelF . ' as label']; + if ($localLabelF !== null && $localLabelF !== $labelF) { + $select[] = $localLabelF . ' as local_label'; + } + $rows = $this->db->table('opd_dose_when')->select(implode(',', $select))->where($labelF . ' !=', '')->get()->getResultArray(); foreach ($rows as $r) { $id = trim((string) ($r['id'] ?? '')); $label = trim((string) ($r['label'] ?? '')); if ($id !== '' && $label !== '') { $mapWhen[$id] = $label; } + $localLabel = trim((string) ($r['local_label'] ?? '')); + if ($id !== '' && $localLabel !== '') { + $mapWhenLocal[$id] = $localLabel; + } } } } @@ -3029,14 +3052,48 @@ class Opd extends BaseController $f = $this->db->getFieldNames('opd_dose_frequency'); $idF = $this->resolveFirstField($f, ['dose_freq_id', 'id']); $labelF = $this->resolveFirstField($f, ['dose_sign', 'dose_sign_desc', 'name']); + $localLabelF = $this->resolveFirstField($f, ['dose_sign_hindi', 'dose_sign_desc']); if ($idF !== null && $labelF !== null) { - $rows = $this->db->table('opd_dose_frequency')->select($idF . ' as id,' . $labelF . ' as label')->where($labelF . ' !=', '')->get()->getResultArray(); + $select = [$idF . ' as id', $labelF . ' as label']; + if ($localLabelF !== null && $localLabelF !== $labelF) { + $select[] = $localLabelF . ' as local_label'; + } + $rows = $this->db->table('opd_dose_frequency')->select(implode(',', $select))->where($labelF . ' !=', '')->get()->getResultArray(); foreach ($rows as $r) { $id = trim((string) ($r['id'] ?? '')); $label = trim((string) ($r['label'] ?? '')); if ($id !== '' && $label !== '') { $mapFreq[$id] = $label; } + $localLabel = trim((string) ($r['local_label'] ?? '')); + if ($id !== '' && $localLabel !== '') { + $mapFreqLocal[$id] = $localLabel; + } + } + } + } + + if ($this->db->tableExists('opd_dose_where')) { + $f = $this->db->getFieldNames('opd_dose_where'); + $idF = $this->resolveFirstField($f, ['dose_where_id', 'id']); + $labelF = $this->resolveFirstField($f, ['dose_sign', 'dose_sign_desc', 'name']); + $localLabelF = $this->resolveFirstField($f, ['dose_sign_hindi', 'dose_sign_desc']); + if ($idF !== null && $labelF !== null) { + $select = [$idF . ' as id', $labelF . ' as label']; + if ($localLabelF !== null && $localLabelF !== $labelF) { + $select[] = $localLabelF . ' as local_label'; + } + $rows = $this->db->table('opd_dose_where')->select(implode(',', $select))->where($labelF . ' !=', '')->get()->getResultArray(); + foreach ($rows as $r) { + $id = trim((string) ($r['id'] ?? '')); + $label = trim((string) ($r['label'] ?? '')); + if ($id !== '' && $label !== '') { + $mapWhere[$id] = $label; + } + $localLabel = trim((string) ($r['local_label'] ?? '')); + if ($id !== '' && $localLabel !== '') { + $mapWhereLocal[$id] = $localLabel; + } } } } @@ -3045,9 +3102,15 @@ class Opd extends BaseController $doseRaw = trim((string) ($medRow['dosage'] ?? '')); $whenRaw = trim((string) ($medRow['dosage_when'] ?? '')); $freqRaw = trim((string) ($medRow['dosage_freq'] ?? '')); - $medRow['dosage_label'] = ($doseRaw !== '' && isset($mapDose[$doseRaw])) ? $mapDose[$doseRaw] : $doseRaw; - $medRow['dosage_when_label'] = ($whenRaw !== '' && isset($mapWhen[$whenRaw])) ? $mapWhen[$whenRaw] : $whenRaw; - $medRow['dosage_freq_label'] = ($freqRaw !== '' && isset($mapFreq[$freqRaw])) ? $mapFreq[$freqRaw] : $freqRaw; + $whereRaw = trim((string) ($medRow['dosage_where'] ?? '')); + $medRow['dosage_label'] = ($doseRaw !== '' && $doseRaw !== '0' && isset($mapDose[$doseRaw])) ? $mapDose[$doseRaw] : ($doseRaw === '0' ? '' : $doseRaw); + $medRow['dosage_when_label'] = ($whenRaw !== '' && $whenRaw !== '0' && isset($mapWhen[$whenRaw])) ? $mapWhen[$whenRaw] : ($whenRaw === '0' ? '' : $whenRaw); + $medRow['dosage_freq_label'] = ($freqRaw !== '' && $freqRaw !== '0' && isset($mapFreq[$freqRaw])) ? $mapFreq[$freqRaw] : ($freqRaw === '0' ? '' : $freqRaw); + $medRow['dosage_where_label'] = ($whereRaw !== '' && $whereRaw !== '0' && isset($mapWhere[$whereRaw])) ? $mapWhere[$whereRaw] : ($whereRaw === '0' ? '' : $whereRaw); + $medRow['dosage_local_label'] = ($doseRaw !== '' && $doseRaw !== '0' && isset($mapDoseLocal[$doseRaw])) ? $mapDoseLocal[$doseRaw] : ''; + $medRow['dosage_when_local_label'] = ($whenRaw !== '' && $whenRaw !== '0' && isset($mapWhenLocal[$whenRaw])) ? $mapWhenLocal[$whenRaw] : ''; + $medRow['dosage_freq_local_label'] = ($freqRaw !== '' && $freqRaw !== '0' && isset($mapFreqLocal[$freqRaw])) ? $mapFreqLocal[$freqRaw] : ''; + $medRow['dosage_where_local_label'] = ($whereRaw !== '' && $whereRaw !== '0' && isset($mapWhereLocal[$whereRaw])) ? $mapWhereLocal[$whereRaw] : ''; $genericInline = trim((string) ($medRow['genericname'] ?? ($medRow['salt_name'] ?? ''))); if ($genericInline === '') { diff --git a/app/Controllers/Opd_prescription.php b/app/Controllers/Opd_prescription.php index 790f885..a34a0ca 100644 --- a/app/Controllers/Opd_prescription.php +++ b/app/Controllers/Opd_prescription.php @@ -4733,6 +4733,8 @@ class Opd_prescription extends BaseController $insert['remark'] = strtoupper(trim((string) $this->request->getPost('remark'))); } + $this->applyDoseMasterStringFields($insert, $fields); + $user = auth()->user(); if (in_array('update_by', $fields, true)) { $userLabel = $user ? ($user->username ?? $user->email ?? 'User') : 'User'; @@ -4991,6 +4993,8 @@ class Opd_prescription extends BaseController } } + $this->applyDoseMasterStringFields($update, $fields); + if (empty($update)) { return $this->response->setJSON(['update' => 0, 'error_text' => 'No editable fields found']); } @@ -5372,15 +5376,43 @@ class Opd_prescription extends BaseController $fields = $this->db->getFieldNames($table); $idField = $this->resolveFirstField($fields, $idCandidates); - $labelField = $this->resolveFirstField($fields, $labelCandidates); - if ($idField === null || $labelField === null) { + if ($idField === null) { return []; } + $labelField = null; + $secondaryLabelField = null; + $localLabelField = null; + + if ($table === 'opd_dose_shed') { + $labelField = $this->resolveFirstField($fields, ['dose_show_sign', 'dose_sign', 'dose_sign_desc', 'name']); + $localLabelField = $this->resolveFirstField($fields, ['dose_show_desc', 'dose_sign_hindi', 'dose_sign_desc']); + } else { + $labelField = $this->resolveFirstField($fields, ['dose_sign', 'dose_sign_desc', 'name']); + $secondaryLabelField = $this->resolveFirstField($fields, ['dose_sign_desc', 'name']); + $localLabelField = $this->resolveFirstField($fields, ['dose_sign_hindi', 'dose_sign_desc']); + } + + if ($labelField === null) { + $labelField = $this->resolveFirstField($fields, $labelCandidates); + } + + if ($labelField === null) { + return []; + } + + $select = [$idField . ' as id', $labelField . ' as label']; + if ($secondaryLabelField !== null && $secondaryLabelField !== $labelField) { + $select[] = $secondaryLabelField . ' as secondary_label'; + } + if ($localLabelField !== null && $localLabelField !== $labelField) { + $select[] = $localLabelField . ' as local_label'; + } + return $this->db->table($table) - ->select($idField . ' as id,' . $labelField . ' as label') + ->select(implode(',', $select)) ->where($labelField . ' !=', '') - ->orderBy($labelField, 'ASC') + ->orderBy($idField, 'ASC') ->get() ->getResultArray(); } @@ -5396,7 +5428,27 @@ class Opd_prescription extends BaseController foreach ($rows as $row) { $id = trim((string) ($row['id'] ?? '')); $label = trim((string) ($row['label'] ?? '')); - if ($id === '' || $label === '') { + if ($id === '' || $id === '0' || $label === '') { + continue; + } + $map[$id] = $label; + } + + return $map; + } + + private function getDoseMasterLocalLabelMap(string $table, array $idCandidates, array $labelCandidates): array + { + $rows = $this->getDoseMasterRows($table, $idCandidates, $labelCandidates); + if (empty($rows)) { + return []; + } + + $map = []; + foreach ($rows as $row) { + $id = trim((string) ($row['id'] ?? '')); + $label = trim((string) ($row['local_label'] ?? ($row['secondary_label'] ?? ''))); + if ($id === '' || $id === '0' || $label === '') { continue; } $map[$id] = $label; @@ -5408,13 +5460,35 @@ class Opd_prescription extends BaseController private function resolveDoseMasterLabel($value, array $map): string { $raw = trim((string) $value); - if ($raw === '') { + if ($raw === '' || $raw === '0') { return ''; } return $map[$raw] ?? $raw; } + private function applyDoseMasterStringFields(array &$payload, array $fields): void + { + $doseMap = $this->getDoseMasterLabelMap('opd_dose_shed', ['dose_shed_id', 'id'], ['dose_show_sign', 'dose_sign', 'dose_sign_desc', 'name']); + $whenMap = $this->getDoseMasterLabelMap('opd_dose_when', ['dose_when_id', 'id'], ['dose_sign', 'dose_sign_desc', 'name']); + $freqMap = $this->getDoseMasterLabelMap('opd_dose_frequency', ['dose_freq_id', 'id'], ['dose_sign', 'dose_sign_desc', 'name']); + $whereMap = $this->getDoseMasterLabelMap('opd_dose_where', ['dose_where_id', 'id'], ['dose_sign', 'dose_sign_desc', 'name']); + + $stringFields = [ + 'dosage_str' => $this->resolveDoseMasterLabel($payload['dosage'] ?? '', $doseMap), + 'dosage_when_str' => $this->resolveDoseMasterLabel($payload['dosage_when'] ?? '', $whenMap), + 'dosage_freq_str' => $this->resolveDoseMasterLabel($payload['dosage_freq'] ?? '', $freqMap), + 'dosage_where_str' => $this->resolveDoseMasterLabel($payload['dosage_where'] ?? '', $whereMap), + ]; + + foreach ($stringFields as $field => $value) { + if ($value === '' || ! in_array($field, $fields, true)) { + continue; + } + $payload[$field] = $value; + } + } + private function hydrateNabhPrescriptionFields(array $row, string $remarks): array { $pick = function (array $candidates) use ($row): string { diff --git a/app/Controllers/Patient.php b/app/Controllers/Patient.php index 4ed0051..4a145e4 100644 --- a/app/Controllers/Patient.php +++ b/app/Controllers/Patient.php @@ -38,6 +38,7 @@ class Patient extends BaseController public function create() { $isAjax = $this->request->isAJAX(); + $abhaId = trim((string) $this->request->getPost('input_abha_id')); $chk_age = $this->request->getPost('chk_age'); $age_month = (string) $this->request->getPost('input_age_month'); @@ -75,6 +76,19 @@ class Patient extends BaseController ->with('error', $errorText); } + if ($abhaId !== '' && ! $this->isValidAbhaId($abhaId)) { + if ($isAjax) { + return $this->response->setJSON([ + 'insertid' => 0, + 'error_text' => 'ABHA ID must be a 14-digit number.', + ]); + } + + return redirect()->to(base_url('billing/patient')) + ->withInput() + ->with('error', 'ABHA ID must be a 14-digit number.'); + } + $bloodGroup = trim((string) $this->request->getPost('input_blood_group')); if ($bloodGroup === '') { $bloodGroup = 'Not Define'; @@ -96,6 +110,7 @@ class Patient extends BaseController 'udai' => strtoupper((string) $this->request->getPost('input_udai')), 'estimate_dob' => $estimate_dob, ]; + $this->applyPatientAbhaFieldValues($data, $abhaId); if ($chk_age === 'on') { $data['age'] = $age_year; @@ -383,6 +398,7 @@ class Patient extends BaseController } $chk_age = $this->request->getPost('chk_age'); + $abhaId = trim((string) $this->request->getPost('input_abha_id')); $age_month = (string) $this->request->getPost('input_age_month'); $age_year = (string) $this->request->getPost('input_age_year'); @@ -410,6 +426,13 @@ class Patient extends BaseController ]); } + if ($abhaId !== '' && ! $this->isValidAbhaId($abhaId)) { + return $this->response->setJSON([ + 'update' => 0, + 'error_text' => 'ABHA ID must be a 14-digit number.', + ]); + } + $data = [ 'mphone1' => $this->request->getPost('input_mphone1'), 'p_fname' => strtoupper((string) $this->request->getPost('input_name')), @@ -427,6 +450,7 @@ class Patient extends BaseController 'estimate_dob' => $estimate_dob, 'blood_group' => $this->request->getPost('input_blood_group'), ]; + $this->applyPatientAbhaFieldValues($data, $abhaId); if ($chk_age === 'on') { $data['age'] = $age_year; @@ -469,6 +493,42 @@ class Patient extends BaseController ]); } + public function update_abha() + { + if (!$this->request->isAJAX()) { + return $this->response + ->setStatusCode(400) + ->setJSON(['update' => 0, 'error_text' => 'Invalid request']); + } + + $pid = (int) $this->request->getPost('p_id'); + $abhaId = trim((string) $this->request->getPost('abha_id')); + + if ($abhaId !== '' && ! $this->isValidAbhaId($abhaId)) { + return $this->response->setJSON([ + 'update' => 0, + 'error_text' => 'ABHA ID must be a 14-digit number.', + ]); + } + + $data = []; + $this->applyPatientAbhaFieldValues($data, $abhaId); + if ($data === []) { + return $this->response->setJSON([ + 'update' => 0, + 'error_text' => 'ABHA field not found in patient master.', + ]); + } + + $patientModel = new PatientModel(); + $patientModel->updatePatient($data, $pid); + + return $this->response->setJSON([ + 'update' => 1, + 'showcontent' => 'Data Saved successfully', + ]); + } + public function update_card() { if (!$this->request->isAJAX()) { @@ -970,5 +1030,38 @@ class Patient extends BaseController } } + private function applyPatientAbhaFieldValues(array &$data, string $abhaId): void + { + $targetField = $this->resolvePatientAbhaIdField(); + if ($targetField !== null) { + $data[$targetField] = $abhaId; + } + } + + private function resolvePatientAbhaIdField(): ?string + { + if (! $this->db->tableExists('patient_master')) { + return null; + } + + $fields = $this->db->getFieldNames('patient_master') ?? []; + foreach (['abha_id', 'abha_no', 'abha'] as $field) { + if (in_array($field, $fields, true)) { + return $field; + } + } + + if (in_array('abha_address', $fields, true)) { + return 'abha_address'; + } + + return null; + } + + private function isValidAbhaId(string $value): bool + { + return preg_match('/^\d{14}$/', $value) === 1; + } + } diff --git a/app/Controllers/Setting/Doctor.php b/app/Controllers/Setting/Doctor.php index 3f24e74..3e5d5ef 100644 --- a/app/Controllers/Setting/Doctor.php +++ b/app/Controllers/Setting/Doctor.php @@ -55,12 +55,30 @@ class Doctor extends BaseController $doctorModel = new DoctorModel(); $regField = $this->resolveDoctorRegField(); + $hprField = $this->resolveDoctorHprField(); $shortDescription = trim((string) $this->request->getPost('txt_doc_sign')); $regInput = trim((string) $this->request->getPost('input_doc_reg_no')); + $hprInput = strtoupper(trim((string) $this->request->getPost('input_hpr_id'))); if ($regInput === '' && $shortDescription !== '') { $regInput = $this->extractRegNoFromText($shortDescription); } + if ($hprInput !== '' && ! $this->isValidHprId($hprInput)) { + $errors = ['HPR ID format is invalid. Use alphanumeric characters with / or -']; + if ($this->request->isAJAX()) { + $templateContext = $this->getDoctorTemplateContext(); + return view('Setting/Doctor/Doctor_V', [ + 'errors' => $errors, + 'formData' => $this->request->getPost(), + 'template_options' => $templateContext['options'], + 'opd_print_template_options' => $templateContext['opd_print_options'], + 'template_fields' => $templateContext['fields'], + ]); + } + + return redirect()->back()->withInput()->with('errors', $errors); + } + $data = [ 'p_title' => $this->request->getPost('select_title'), 'mphone1' => $this->request->getPost('input_mphone1'), @@ -91,6 +109,9 @@ class Doctor extends BaseController if ($regField !== null) { $data[$regField] = $regInput; } + if ($hprField !== null) { + $data[$hprField] = $hprInput; + } $insertId = $doctorModel->insert($data); @@ -141,12 +162,22 @@ class Doctor extends BaseController $doctorModel = new DoctorModel(); $docId = (int) $this->request->getPost('doc_id'); $regField = $this->resolveDoctorRegField(); + $hprField = $this->resolveDoctorHprField(); $shortDescription = trim((string) $this->request->getPost('txt_doc_sign')); $regInput = trim((string) $this->request->getPost('input_doc_reg_no')); + $hprInput = strtoupper(trim((string) $this->request->getPost('input_hpr_id'))); if ($regInput === '' && $shortDescription !== '') { $regInput = $this->extractRegNoFromText($shortDescription); } + if ($hprInput !== '' && ! $this->isValidHprId($hprInput)) { + return $this->response->setJSON([ + 'update' => 0, + 'showcontent' => '', + 'error_text' => 'HPR ID format is invalid. Use alphanumeric characters with / or -', + ]); + } + $data = [ 'p_title' => $this->request->getPost('select_title'), 'mphone1' => $this->request->getPost('input_mphone1'), @@ -177,6 +208,9 @@ class Doctor extends BaseController if ($regField !== null) { $data[$regField] = $regInput; } + if ($hprField !== null) { + $data[$hprField] = $hprInput; + } $updated = $doctorModel->updateDoctor($data, $docId); @@ -542,6 +576,27 @@ class Doctor extends BaseController return null; } + private function resolveDoctorHprField(): ?string + { + if (! $this->db->tableExists('doctor_master')) { + return null; + } + + $fields = $this->db->getFieldNames('doctor_master'); + foreach (['hpr_id', 'hpr_no', 'hpr_number'] as $field) { + if (in_array($field, $fields, true)) { + return $field; + } + } + + return null; + } + + private function isValidHprId(string $value): bool + { + return preg_match('/^[A-Z0-9\/-]{6,40}$/', $value) === 1; + } + private function extractRegNoFromText(string $text): string { $normalized = preg_replace('/\s+/', ' ', trim($text)); diff --git a/app/Controllers/Setting/HospitalProfile.php b/app/Controllers/Setting/HospitalProfile.php index 1bc0011..62d6109 100644 --- a/app/Controllers/Setting/HospitalProfile.php +++ b/app/Controllers/Setting/HospitalProfile.php @@ -23,6 +23,7 @@ class HospitalProfile extends BaseController 'hospital_address_2' => $this->readSettingValue('H_address_2'), 'hospital_phone' => $this->readSettingValue('H_phone_No'), 'hospital_email' => $this->readSettingValue('H_Email'), + 'hospital_hfr_id' => $this->readSettingValue('H_HFR_ID'), 'footer_version' => $this->readSettingValue('HMS_UPDATE_ID') !== '' ? $this->readSettingValue('HMS_UPDATE_ID') : hms_default_version_id(), @@ -56,6 +57,7 @@ class HospitalProfile extends BaseController $address2 = trim((string) $this->request->getPost('hospital_address_2')); $phone = trim((string) $this->request->getPost('hospital_phone')); $email = trim((string) $this->request->getPost('hospital_email')); + $hfrId = strtoupper(trim((string) $this->request->getPost('hospital_hfr_id'))); $footerVersion = trim((string) $this->request->getPost('footer_version')); $pharmacyName = trim((string) $this->request->getPost('pharmacy_name')); @@ -72,6 +74,15 @@ class HospitalProfile extends BaseController ]); } + if ($hfrId !== '' && preg_match('/^[A-Z0-9\/-]{6,40}$/', $hfrId) !== 1) { + return $this->response->setJSON([ + 'update' => 0, + 'error_text' => 'HFR ID format is invalid. Use alphanumeric characters with / or -', + 'csrfName' => csrf_token(), + 'csrfHash' => csrf_hash(), + ]); + } + $savedCount = 0; if ($this->upsertSettingValue('H_Name', $name)) { $savedCount++; @@ -88,6 +99,9 @@ class HospitalProfile extends BaseController if ($this->upsertSettingValue('H_Email', $email)) { $savedCount++; } + if ($this->upsertSettingValue('H_HFR_ID', $hfrId)) { + $savedCount++; + } if ($this->upsertSettingValue('HMS_UPDATE_ID', $footerVersion)) { $savedCount++; } @@ -204,6 +218,7 @@ class HospitalProfile extends BaseController 'H_address_2', 'H_phone_No', 'H_Email', + 'H_HFR_ID', 'HMS_UPDATE_ID', 'H_logo', 'H_Med_Name', diff --git a/app/Database/Migrations/2026-04-04-000036_AddAbdmIdentityFields.php b/app/Database/Migrations/2026-04-04-000036_AddAbdmIdentityFields.php new file mode 100644 index 0000000..bcd5a51 --- /dev/null +++ b/app/Database/Migrations/2026-04-04-000036_AddAbdmIdentityFields.php @@ -0,0 +1,97 @@ +addPatientAbhaId(); + $this->addDoctorHprId(); + } + + public function down() + { + if ($this->tableExists('patient_master') && in_array('abha_id', $this->getColumns('patient_master'), true)) { + $this->forge->dropColumn('patient_master', 'abha_id'); + } + + if ($this->tableExists('doctor_master') && in_array('hpr_id', $this->getColumns('doctor_master'), true)) { + $this->forge->dropColumn('doctor_master', 'hpr_id'); + } + } + + private function addPatientAbhaId(): void + { + if (! $this->tableExists('patient_master')) { + return; + } + + $columns = $this->getColumns('patient_master'); + if (! in_array('abha_id', $columns, true)) { + $this->forge->addColumn('patient_master', [ + 'abha_id' => [ + 'type' => 'VARCHAR', + 'constraint' => 30, + 'null' => true, + ], + ]); + $columns[] = 'abha_id'; + } + + if (in_array('abha_id', $columns, true) && in_array('abha_no', $columns, true)) { + $this->db->query("UPDATE patient_master SET abha_id = IFNULL(NULLIF(abha_id,''), NULLIF(abha_no,''))"); + } + + if (in_array('abha_id', $columns, true) && in_array('abha', $columns, true)) { + $this->db->query("UPDATE patient_master SET abha_id = IFNULL(NULLIF(abha_id,''), NULLIF(abha,''))"); + } + + if (in_array('abha_id', $columns, true) && in_array('abha_address', $columns, true)) { + $this->db->query("UPDATE patient_master SET abha_id = IFNULL(NULLIF(abha_id,''), NULLIF(abha_address,''))"); + } + } + + private function addDoctorHprId(): void + { + if (! $this->tableExists('doctor_master')) { + return; + } + + if (! in_array('hpr_id', $this->getColumns('doctor_master'), true)) { + $this->forge->addColumn('doctor_master', [ + 'hpr_id' => [ + 'type' => 'VARCHAR', + 'constraint' => 40, + 'null' => true, + ], + ]); + } + } + + /** + * @return string[] + */ + private function getColumns(string $table): array + { + if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) { + return []; + } + + $result = $this->db->query('SHOW COLUMNS FROM `' . $table . '`')->getResultArray(); + + return array_map(static fn (array $row): string => (string) ($row['Field'] ?? ''), $result); + } + + private function tableExists(string $table): bool + { + if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) { + return false; + } + + $row = $this->db->query("SHOW TABLES LIKE '" . $table . "'")->getRowArray(); + return ! empty($row); + } +} diff --git a/app/Database/Migrations/2026-04-04-000037_SyncOpdDoseShedMaster.php b/app/Database/Migrations/2026-04-04-000037_SyncOpdDoseShedMaster.php new file mode 100644 index 0000000..4349558 --- /dev/null +++ b/app/Database/Migrations/2026-04-04-000037_SyncOpdDoseShedMaster.php @@ -0,0 +1,90 @@ +tableExists('opd_dose_shed')) { + return; + } + + $this->db->table('opd_dose_shed')->truncate(); + + $rows = [ + [ + 'dose_shed_id' => 1, + 'dose_show_sign' => '1 - 0 - 0', + 'dose_show_desc' => 'सुबह', + ], + [ + 'dose_shed_id' => 2, + 'dose_show_sign' => '0 - 0 - 1', + 'dose_show_desc' => 'रात को', + ], + [ + 'dose_shed_id' => 3, + 'dose_show_sign' => '1 - 0 - 1', + 'dose_show_desc' => 'सुबह - शाम', + ], + [ + 'dose_shed_id' => 4, + 'dose_show_sign' => '1 - 1 - 1', + 'dose_show_desc' => 'सुबह - दोपहर - शाम', + ], + [ + 'dose_shed_id' => 5, + 'dose_show_sign' => '1 - 1 - 0', + 'dose_show_desc' => 'सुबह - दोपहर', + ], + [ + 'dose_shed_id' => 6, + 'dose_show_sign' => '0 - 1 - 0', + 'dose_show_desc' => 'दोपहर', + ], + [ + 'dose_shed_id' => 7, + 'dose_show_sign' => '0 - 1 - 1', + 'dose_show_desc' => 'दोपहर - शाम', + ], + [ + 'dose_shed_id' => 8, + 'dose_show_sign' => '0 - 0 - 0', + 'dose_show_desc' => '', + ], + ]; + + $this->db->table('opd_dose_shed')->insertBatch($rows); + + $this->resetAutoIncrement('opd_dose_shed', 9); + + } + + public function down() + { + // Intentionally left as no-op because previous master seed values are environment-specific. + } + + private function tableExists(string $table): bool + { + if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) { + return false; + } + + $row = $this->db->query("SHOW TABLES LIKE '" . $table . "'")->getRowArray(); + return ! empty($row); + } + + private function resetAutoIncrement(string $table, int $nextId): void + { + if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) { + return; + } + + $nextId = max(1, $nextId); + $this->db->query('ALTER TABLE `' . $table . '` AUTO_INCREMENT = ' . $nextId); + } +} \ No newline at end of file diff --git a/app/Database/Migrations/2026-04-04-000038_SyncOpdDoseWhenMaster.php b/app/Database/Migrations/2026-04-04-000038_SyncOpdDoseWhenMaster.php new file mode 100644 index 0000000..eca5084 --- /dev/null +++ b/app/Database/Migrations/2026-04-04-000038_SyncOpdDoseWhenMaster.php @@ -0,0 +1,150 @@ +tableExists('opd_dose_when')) { + return; + } + + $this->db->table('opd_dose_when')->truncate(); + + $rows = [ + [ + 'dose_when_id' => 1, + 'dose_sign' => 'BF', + 'dose_sign_desc' => 'Before Food', + 'dose_sign_hindi' => 'भोजन से पहले', + ], + [ + 'dose_when_id' => 2, + 'dose_sign' => 'AF', + 'dose_sign_desc' => 'After Food', + 'dose_sign_hindi' => 'भोजन के बाद', + ], + [ + 'dose_when_id' => 3, + 'dose_sign' => 'BB', + 'dose_sign_desc' => 'Before Breakfast', + 'dose_sign_hindi' => 'नाश्ते से पहले', + ], + [ + 'dose_when_id' => 4, + 'dose_sign' => 'AB', + 'dose_sign_desc' => 'After Breakfast', + 'dose_sign_hindi' => 'नाश्ते के बाद', + ], + [ + 'dose_when_id' => 5, + 'dose_sign' => 'BL', + 'dose_sign_desc' => 'Before Lunch', + 'dose_sign_hindi' => 'दोपहर के भोजन से पहले', + ], + [ + 'dose_when_id' => 6, + 'dose_sign' => 'AL', + 'dose_sign_desc' => 'After Lunch', + 'dose_sign_hindi' => 'दोपहर के भोजन के बाद', + ], + [ + 'dose_when_id' => 7, + 'dose_sign' => 'BD', + 'dose_sign_desc' => 'Before Dinner', + 'dose_sign_hindi' => 'रात के खाने से पहले', + ], + [ + 'dose_when_id' => 8, + 'dose_sign' => 'AD', + 'dose_sign_desc' => 'After Dinner', + 'dose_sign_hindi' => 'रात के खाने के बाद', + ], + [ + 'dose_when_id' => 9, + 'dose_sign' => 'WF', + 'dose_sign_desc' => 'With Food', + 'dose_sign_hindi' => 'खाने के साथ', + ], + [ + 'dose_when_id' => 10, + 'dose_sign' => 'WT', + 'dose_sign_desc' => 'With Tea', + 'dose_sign_hindi' => 'चाय के साथ', + ], + [ + 'dose_when_id' => 11, + 'dose_sign' => 'ES', + 'dose_sign_desc' => 'Empty Stomach', + 'dose_sign_hindi' => 'खाली पेट', + ], + [ + 'dose_when_id' => 12, + 'dose_sign' => 'BT', + 'dose_sign_desc' => 'Bed Time', + 'dose_sign_hindi' => 'सोने का समय', + ], + [ + 'dose_when_id' => 13, + 'dose_sign' => 'BBATH', + 'dose_sign_desc' => 'Before Bath', + 'dose_sign_hindi' => 'स्नान से पहले', + ], + [ + 'dose_when_id' => 14, + 'dose_sign' => 'ABATH', + 'dose_sign_desc' => 'After Bath', + 'dose_sign_hindi' => 'नहाने के बाद', + ], + [ + 'dose_when_id' => 15, + 'dose_sign' => 'BS', + 'dose_sign_desc' => 'Before Sun', + 'dose_sign_hindi' => 'सूर्य से पहले', + ], + [ + 'dose_when_id' => 16, + 'dose_sign' => 'AS', + 'dose_sign_desc' => 'After Sun', + 'dose_sign_hindi' => 'दोपहर के बाद', + ], + [ + 'dose_when_id' => 17, + 'dose_sign' => 'SoS', + 'dose_sign_desc' => 'SoS', + 'dose_sign_hindi' => 'आपात स्थिति में', + ], + ]; + + $this->db->table('opd_dose_when')->insertBatch($rows); + $this->resetAutoIncrement('opd_dose_when', 18); + } + + public function down() + { + // No-op: prior dose_when master rows vary by installation. + } + + private function tableExists(string $table): bool + { + if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) { + return false; + } + + $row = $this->db->query("SHOW TABLES LIKE '" . $table . "'")->getRowArray(); + return ! empty($row); + } + + private function resetAutoIncrement(string $table, int $nextId): void + { + if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) { + return; + } + + $nextId = max(1, $nextId); + $this->db->query('ALTER TABLE `' . $table . '` AUTO_INCREMENT = ' . $nextId); + } +} diff --git a/app/Views/Setting/Admin/hospital_profile.php b/app/Views/Setting/Admin/hospital_profile.php index a78e5f9..57d2741 100644 --- a/app/Views/Setting/Admin/hospital_profile.php +++ b/app/Views/Setting/Admin/hospital_profile.php @@ -27,6 +27,10 @@ +
+ + +
@@ -147,6 +151,7 @@ fd.append('hospital_address_2', ($('#hospital_address_2').val() || '').trim()); fd.append('hospital_phone', ($('#hospital_phone').val() || '').trim()); fd.append('hospital_email', ($('#hospital_email').val() || '').trim()); + fd.append('hospital_hfr_id', ($('#hospital_hfr_id').val() || '').trim()); fd.append('footer_version', ($('#footer_version').val() || '').trim()); fd.append('pharmacy_name', ($('#pharmacy_name').val() || '').trim()); fd.append('pharmacy_address', ($('#pharmacy_address').val() || '').trim()); @@ -261,6 +266,7 @@ $('#hospital_address_2').val(''); $('#hospital_phone').val(''); $('#hospital_email').val(''); + $('#hospital_hfr_id').val(''); $('#footer_version').val(''); $('#pharmacy_name').val(''); $('#pharmacy_address').val(''); diff --git a/app/Views/Setting/Doctor/Doctor_V.php b/app/Views/Setting/Doctor/Doctor_V.php index f311024..a3b4967 100644 --- a/app/Views/Setting/Doctor/Doctor_V.php +++ b/app/Views/Setting/Doctor/Doctor_V.php @@ -66,6 +66,10 @@
+
+ + +
diff --git a/app/Views/Setting/Doctor/Doctor_profile_V.php b/app/Views/Setting/Doctor/Doctor_profile_V.php index 7cc1a5f..ca87155 100644 --- a/app/Views/Setting/Doctor/Doctor_profile_V.php +++ b/app/Views/Setting/Doctor/Doctor_profile_V.php @@ -1,5 +1,6 @@ {$regField}) && trim((string) $data[0]->{$regField}) !== '') { @@ -19,6 +20,13 @@ if (!empty($data) && !empty($data[0])) { } } } + + foreach (['hpr_id', 'hpr_no', 'hpr_number'] as $hprField) { + if (isset($data[0]->{$hprField}) && trim((string) $data[0]->{$hprField}) !== '') { + $doctorHprId = trim((string) $data[0]->{$hprField}); + break; + } + } } ?> dob)) {
+
+ + +
diff --git a/app/Views/billing/Patient_V.php b/app/Views/billing/Patient_V.php index a15a82c..d41b7d0 100644 --- a/app/Views/billing/Patient_V.php +++ b/app/Views/billing/Patient_V.php @@ -39,6 +39,14 @@ onchange="onchange_aadhar()">
+
+
+ + +
+
diff --git a/app/Views/billing/Person_Edit_V.php b/app/Views/billing/Person_Edit_V.php index 310d9de..1032bac 100644 --- a/app/Views/billing/Person_Edit_V.php +++ b/app/Views/billing/Person_Edit_V.php @@ -10,6 +10,7 @@
user(); + $patientAbhaId = (string) ($data[0]->abha_id ?? $data[0]->abha_no ?? $data[0]->abha ?? $data[0]->abha_address ?? ''); $isAdmin = is_object($user) && method_exists($user, 'inGroup') ? $user->inGroup('admin') : false; if ($data[0]->p_edit == 1 || $isAdmin) { $readonly = ''; @@ -82,6 +83,14 @@ autocomplete="off">
+
+
+ + +
+
diff --git a/app/Views/billing/Person_profile_V.php b/app/Views/billing/Person_profile_V.php index a924c1b..7492ab2 100644 --- a/app/Views/billing/Person_profile_V.php +++ b/app/Views/billing/Person_profile_V.php @@ -13,6 +13,9 @@
+ abha_id ?? $data[0]->abha_no ?? $data[0]->abha ?? $data[0]->abha_address ?? ''); + ?> user(); $canEditOpd = is_object($user) && method_exists($user, 'can') ? $user->can('billing.opd.edit') : false; @@ -104,6 +107,10 @@
Aadhar No.
udai?>
+
+
ABHA ID
+
+
Phone
mphone1?>
@@ -130,6 +137,13 @@
+
+ +
+ + +
+
@@ -283,6 +297,28 @@ $(document).ready(function() { } }); + $('#btn_update_abha').click(function() { + var p_id = $('#p_id').val(); + var abha_id = ($('#input_abha_id').val() || '').trim(); + var csrf_name = ''; + var csrf_value = $('input[name=""]').first().val() || ''; + + if (abha_id !== '' && !/^\d{14}$/.test(abha_id)) { + alert('ABHA ID must be a 14-digit number.'); + return; + } + + if (confirm("Are you sure Update ABHA ID.")) { + $.post('', { + "p_id": p_id, + "abha_id": abha_id, + [csrf_name]: csrf_value + }, function(data) { + load_form('/' + p_id); + }); + } + }); + $('#btn_inc_opd').click(function() { var p_id = $('#p_id').val(); load_form('/' + p_id); diff --git a/app/Views/billing/opd_letter_head_pdf.php b/app/Views/billing/opd_letter_head_pdf.php index d0f10ae..3797ef7 100644 --- a/app/Views/billing/opd_letter_head_pdf.php +++ b/app/Views/billing/opd_letter_head_pdf.php @@ -330,13 +330,52 @@ $toLocalText = static function (string $input): string { $med) : ?> diff --git a/app/Views/billing/opd_medicince_workspace.php b/app/Views/billing/opd_medicince_workspace.php index a104a59..dfa61f5 100644 --- a/app/Views/billing/opd_medicince_workspace.php +++ b/app/Views/billing/opd_medicince_workspace.php @@ -105,19 +105,27 @@
- +
- +
- +
- +
@@ -151,6 +159,7 @@ var activeListFilter = 'all'; var companySuggestTimer = null; var medMasterDataTable = null; + var defaultDoseMasterCache = { dose: [], when: [], freq: [], where: [] }; function showToast(message, type) { var toastId = 'med_toast_' + Date.now(); @@ -257,7 +266,93 @@ function clearForm() { $('#med_id').val('0'); $('#med_item_name,#med_formulation,#med_genericname,#med_salt_name,#med_dosage_restriction,#med_company_name').val(''); - $('#med_default_dosage,#med_default_when,#med_default_freq,#med_default_where,#med_default_days,#med_default_qty,#med_default_remark').val(''); + $('#med_default_days,#med_default_qty,#med_default_remark').val(''); + $('#med_default_dosage,#med_default_when,#med_default_freq,#med_default_where').val(''); + } + + function renderDefaultMasterSelect($select, rows, placeholder) { + var html = '