Implement ABDM identity storage and align OPD consult/medicine dose masters
This commit is contained in:
parent
bd5601c131
commit
9d88aaa2a6
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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 === '') {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddAbdmIdentityFields extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class SyncOpdDoseShedMaster extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class SyncOpdDoseWhenMaster extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->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);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,10 @@
|
|||
<label class="form-label">Hospital Email</label>
|
||||
<input type="text" class="form-control" id="hospital_email" value="<?= esc($hospital_email ?? '') ?>" placeholder="hospital@example.com">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Hospital HFR ID</label>
|
||||
<input type="text" class="form-control" id="hospital_hfr_id" value="<?= esc($hospital_hfr_id ?? '') ?>" placeholder="ABDM HFR ID">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Version / Update ID</label>
|
||||
<input type="text" class="form-control" id="footer_version" value="<?= esc($footer_version ?? '') ?>" placeholder="e.g. 2026.03.27.01">
|
||||
|
|
@ -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('');
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@
|
|||
<label class="form-label">Doctor Registration No.</label>
|
||||
<input class="form-control" name="input_doc_reg_no" placeholder="NMC/MCI Registration No." type="text" value="<?= esc($formData['input_doc_reg_no'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">HPR ID</label>
|
||||
<input class="form-control" name="input_hpr_id" placeholder="ABDM HPR ID" type="text" value="<?= esc($formData['input_hpr_id'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Date of Birth</label>
|
||||
<input class="form-control" name="datepicker_dob" type="date" value="<?= esc($doctorDobValue) ?>">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
$doctorRegNo = '';
|
||||
$doctorHprId = '';
|
||||
if (!empty($data) && !empty($data[0])) {
|
||||
foreach (['nmc_reg_no', 'mci_reg_no', 'registration_no', 'reg_no', 'doctor_reg_no', 'doc_reg_no', 'council_reg_no'] as $regField) {
|
||||
if (isset($data[0]->{$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
|
|
@ -81,6 +89,10 @@ if (!empty($data) && !empty($data[0]) && !empty($data[0]->dob)) {
|
|||
<label class="form-label">Doctor Registration No.</label>
|
||||
<input class="form-control" name="input_doc_reg_no" placeholder="NMC/MCI Registration No." type="text" value="<?= esc($doctorRegNo) ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">HPR ID</label>
|
||||
<input class="form-control" name="input_hpr_id" placeholder="ABDM HPR ID" type="text" value="<?= esc($doctorHprId) ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Date of Birth</label>
|
||||
<input class="form-control" name="datepicker_dob" value="<?= esc($doctorDobValue) ?>" type="date" />
|
||||
|
|
|
|||
|
|
@ -39,6 +39,14 @@
|
|||
onchange="onchange_aadhar()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="form-label">ABHA ID</label>
|
||||
<input class="form-control" name="input_abha_id" id="input_abha_id"
|
||||
placeholder="14-digit ABHA ID" type="text" autocomplete="off"
|
||||
maxlength="14" data-inputmask='"mask": "99999999999999"' data-mask>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Phone Number</label>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
</div>
|
||||
<?php
|
||||
$user = auth()->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">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label>ABHA ID</label>
|
||||
<input class="form-control input-sm" name="input_abha_id" id="input_abha_id"
|
||||
value="<?= esc($patientAbhaId) ?>" placeholder="14-digit ABHA ID" type="text"
|
||||
autocomplete="off" maxlength="14">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label>Phone Number</label>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
<div class="jsError"></div>
|
||||
<form role="form" class="form1">
|
||||
<?= csrf_field() ?>
|
||||
<?php
|
||||
$patientAbhaId = (string) ($data[0]->abha_id ?? $data[0]->abha_no ?? $data[0]->abha ?? $data[0]->abha_address ?? '');
|
||||
?>
|
||||
<?php
|
||||
$user = auth()->user();
|
||||
$canEditOpd = is_object($user) && method_exists($user, 'can') ? $user->can('billing.opd.edit') : false;
|
||||
|
|
@ -104,6 +107,10 @@
|
|||
<div class="col-lg-3 col-md-4 label">Aadhar No.</div>
|
||||
<div class="col-lg-9 col-md-8"><?=$data[0]->udai?></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">ABHA ID</div>
|
||||
<div class="col-lg-9 col-md-8"><?= esc($patientAbhaId) ?></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Phone</div>
|
||||
<div class="col-lg-9 col-md-8"><?=$data[0]->mphone1?></div>
|
||||
|
|
@ -130,6 +137,13 @@
|
|||
<button type="button" id="btn_update_aadhar" class="btn btn-info">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<label class="form-label">ABHA ID</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input class="form-control" type="text" name="input_abha_id" id="input_abha_id" value="<?= esc($patientAbhaId) ?>" maxlength="14">
|
||||
<button type="button" id="btn_update_abha" class="btn btn-info">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<button type="button" class="btn btn-warning btn-sm mt-4" onclick="load_form('<?= base_url('billing/patient/show_cards') ?>/<?=$data[0]->id?>/1');">Insurance Update</button>
|
||||
</div>
|
||||
|
|
@ -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 = '<?= csrf_token() ?>';
|
||||
var csrf_value = $('input[name="<?= csrf_token() ?>"]').first().val() || '<?= csrf_hash() ?>';
|
||||
|
||||
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('<?= base_url('billing/patient/update_abha') ?>', {
|
||||
"p_id": p_id,
|
||||
"abha_id": abha_id,
|
||||
[csrf_name]: csrf_value
|
||||
}, function(data) {
|
||||
load_form('<?= base_url('billing/patient/person_record') ?>/' + p_id);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#btn_inc_opd').click(function() {
|
||||
var p_id = $('#p_id').val();
|
||||
load_form('<?= base_url('Opdcase/addopd') ?>/' + p_id);
|
||||
|
|
|
|||
|
|
@ -330,13 +330,52 @@ $toLocalText = static function (string $input): string {
|
|||
<?php foreach (($rx_medicines ?? []) as $idx => $med) : ?>
|
||||
<?php
|
||||
$dosage = trim((string) ($med['dosage'] ?? ''));
|
||||
if ($dosage === '0') {
|
||||
$dosage = '';
|
||||
}
|
||||
$when = trim((string) ($med['dosage_when'] ?? ''));
|
||||
if ($when === '0') {
|
||||
$when = '';
|
||||
}
|
||||
$freq = trim((string) ($med['dosage_freq'] ?? ''));
|
||||
if ($freq === '0') {
|
||||
$freq = '';
|
||||
}
|
||||
$where = trim((string) ($med['dosage_where_label'] ?? ($med['dosage_where_str'] ?? ($med['dosage_where'] ?? ''))));
|
||||
if ($where === '0') {
|
||||
$where = '';
|
||||
}
|
||||
$doseText = trim($dosage . ($freq !== '' ? ' / ' . $freq : ''));
|
||||
$genericText = trim((string) ($med['genericname'] ?? ($med['generic_name'] ?? ($med['salt_name'] ?? ''))));
|
||||
$instruction = trim(($when !== '' ? $when : '') . ((trim((string) ($med['remark'] ?? '')) !== '') ? (' | ' . trim((string) ($med['remark'] ?? ''))) : ''));
|
||||
$doseLocal = $toLocalText(trim($doseText . ($when !== '' ? ' ' . $when : '')));
|
||||
$instructionLocal = $toLocalText($instruction);
|
||||
$instructionParts = [];
|
||||
if ($when !== '') {
|
||||
$instructionParts[] = $when;
|
||||
}
|
||||
if ($where !== '') {
|
||||
$instructionParts[] = 'Where: ' . $where;
|
||||
}
|
||||
if (trim((string) ($med['remark'] ?? '')) !== '') {
|
||||
$instructionParts[] = trim((string) ($med['remark'] ?? ''));
|
||||
}
|
||||
$instruction = trim(implode(' | ', $instructionParts));
|
||||
$doseLocalParts = array_filter([
|
||||
trim((string) ($med['dosage_local_label'] ?? '')),
|
||||
trim((string) ($med['dosage_when_local_label'] ?? '')),
|
||||
trim((string) ($med['dosage_freq_local_label'] ?? '')),
|
||||
]);
|
||||
$instructionLocalParts = [];
|
||||
$whereLocal = trim((string) ($med['dosage_where_local_label'] ?? ''));
|
||||
if ($whereLocal !== '') {
|
||||
$instructionLocalParts[] = $whereLocal;
|
||||
}
|
||||
if ($instruction !== '') {
|
||||
$translatedInstruction = $toLocalText($instruction);
|
||||
if ($translatedInstruction !== '' && strtolower($translatedInstruction) !== strtolower($instruction)) {
|
||||
$instructionLocalParts[] = $translatedInstruction;
|
||||
}
|
||||
}
|
||||
$doseLocal = !empty($doseLocalParts) ? implode(' ', $doseLocalParts) : $toLocalText(trim($doseText . ($when !== '' ? ' ' . $when : '')));
|
||||
$instructionLocal = !empty($instructionLocalParts) ? implode(' | ', array_values(array_unique($instructionLocalParts))) : $toLocalText($instruction);
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc((string) ($idx + 1)) ?></td>
|
||||
|
|
|
|||
|
|
@ -105,19 +105,27 @@
|
|||
<div class="row g-1 mb-2">
|
||||
<div class="col-6">
|
||||
<label class="form-label form-label-sm mb-0">Dose</label>
|
||||
<input type="text" id="med_default_dosage" class="form-control form-control-sm" placeholder="e.g. 1-0-1">
|
||||
<select id="med_default_dosage" class="form-select form-select-sm">
|
||||
<option value="">Select dose</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label form-label-sm mb-0">When</label>
|
||||
<input type="text" id="med_default_when" class="form-control form-control-sm" placeholder="e.g. AC">
|
||||
<select id="med_default_when" class="form-select form-select-sm">
|
||||
<option value="">Select when</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label form-label-sm mb-0">Frequency</label>
|
||||
<input type="text" id="med_default_freq" class="form-control form-control-sm" placeholder="e.g. TDS">
|
||||
<select id="med_default_freq" class="form-select form-select-sm">
|
||||
<option value="">Select frequency</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label form-label-sm mb-0">Route</label>
|
||||
<input type="text" id="med_default_where" class="form-control form-control-sm" placeholder="e.g. ORAL">
|
||||
<select id="med_default_where" class="form-select form-select-sm">
|
||||
<option value="">Select route</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label class="form-label form-label-sm mb-0">Days</label>
|
||||
|
|
@ -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 = '<option value="">' + $('<div>').text(placeholder || 'Select').html() + '</option>';
|
||||
(rows || []).forEach(function(row) {
|
||||
var id = (row && row.id !== undefined) ? String(row.id) : '';
|
||||
var label = (row && row.label !== undefined) ? String(row.label) : '';
|
||||
var desc = (row && row.secondary_label !== undefined) ? String(row.secondary_label) : '';
|
||||
if (!id || !label || id === '0') {
|
||||
return;
|
||||
}
|
||||
var text = label;
|
||||
if (desc && desc.toLowerCase() !== label.toLowerCase()) {
|
||||
text += ' - ' + desc;
|
||||
}
|
||||
html += '<option value="' + $('<div>').text(id).html() + '">' + $('<div>').text(text).html() + '</option>';
|
||||
});
|
||||
$select.html(html);
|
||||
}
|
||||
|
||||
function ensureDefaultMasterOption($select, value) {
|
||||
value = (value || '').toString().trim();
|
||||
if (!value || value === '0') {
|
||||
return;
|
||||
}
|
||||
var safeValue = value.replace(/"/g, '"');
|
||||
if ($select.find('option[value="' + safeValue + '"]').length) {
|
||||
return;
|
||||
}
|
||||
$select.append('<option value="' + $('<div>').text(value).html() + '">' + $('<div>').text(value + ' (Current)').html() + '</option>');
|
||||
}
|
||||
|
||||
function setDefaultMasterValue($select, value) {
|
||||
var raw = (value || '').toString().trim();
|
||||
if (!raw || raw === '0') {
|
||||
$select.val('');
|
||||
return;
|
||||
}
|
||||
|
||||
ensureDefaultMasterOption($select, raw);
|
||||
if ($select.find('option[value="' + raw.replace(/"/g, '"') + '"]').length) {
|
||||
$select.val(raw);
|
||||
return;
|
||||
}
|
||||
|
||||
var probe = raw.toLowerCase();
|
||||
var matchedVal = '';
|
||||
$select.find('option').each(function() {
|
||||
var txt = ($(this).text() || '').toString().trim().toLowerCase();
|
||||
if (!txt) {
|
||||
return;
|
||||
}
|
||||
if (txt === probe || txt.indexOf(probe) !== -1) {
|
||||
matchedVal = ($(this).val() || '').toString();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (matchedVal) {
|
||||
$select.val(matchedVal);
|
||||
return;
|
||||
}
|
||||
|
||||
ensureDefaultMasterOption($select, raw);
|
||||
$select.val(raw);
|
||||
}
|
||||
|
||||
function loadDefaultDoseMasters(done) {
|
||||
apiGet('<?= base_url('Opd_prescription/rx_group_dose_masters') ?>', function(data) {
|
||||
defaultDoseMasterCache = {
|
||||
dose: (data && data.dose) ? data.dose : [],
|
||||
when: (data && data.when) ? data.when : [],
|
||||
freq: (data && data.freq) ? data.freq : [],
|
||||
where: (data && data.where) ? data.where : []
|
||||
};
|
||||
|
||||
renderDefaultMasterSelect($('#med_default_dosage'), defaultDoseMasterCache.dose, 'Select dose');
|
||||
renderDefaultMasterSelect($('#med_default_when'), defaultDoseMasterCache.when, 'Select when');
|
||||
renderDefaultMasterSelect($('#med_default_freq'), defaultDoseMasterCache.freq, 'Select frequency');
|
||||
renderDefaultMasterSelect($('#med_default_where'), defaultDoseMasterCache.where, 'Select route');
|
||||
|
||||
if (typeof done === 'function') {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildMedicinePayload() {
|
||||
|
|
@ -309,10 +404,10 @@
|
|||
$('#med_salt_name').val(row.salt_name || row.sal_name || row.salt || row.saltname || '');
|
||||
$('#med_dosage_restriction').val(row.dosage_restriction || row.dose_restriction || row.restriction_note || row.restriction || '');
|
||||
$('#med_company_name').val(row.company_name || '');
|
||||
$('#med_default_dosage').val(row.dosage || '');
|
||||
$('#med_default_when').val(row.dosage_when || '');
|
||||
$('#med_default_freq').val(row.dosage_freq || '');
|
||||
$('#med_default_where').val(row.dosage_where || '');
|
||||
setDefaultMasterValue($('#med_default_dosage'), row.dosage || '');
|
||||
setDefaultMasterValue($('#med_default_when'), row.dosage_when || '');
|
||||
setDefaultMasterValue($('#med_default_freq'), row.dosage_freq || '');
|
||||
setDefaultMasterValue($('#med_default_where'), row.dosage_where || '');
|
||||
$('#med_default_days').val(row.no_of_days || '');
|
||||
$('#med_default_qty').val(row.qty || '');
|
||||
$('#med_default_remark').val(row.remark || '');
|
||||
|
|
@ -713,9 +808,11 @@
|
|||
loadList();
|
||||
loadDuplicateReport();
|
||||
loadCompanySuggestions('');
|
||||
var initialMedId = parseInt($('#med_id').val() || '0', 10);
|
||||
if (initialMedId > 0) {
|
||||
loadOne(initialMedId);
|
||||
}
|
||||
loadDefaultDoseMasters(function() {
|
||||
var initialMedId = parseInt($('#med_id').val() || '0', 10);
|
||||
if (initialMedId > 0) {
|
||||
loadOne(initialMedId);
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -761,49 +761,62 @@
|
|||
Select group and preview medicines before add.
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" id="med_name" list="medicine_suggest" placeholder="Medicine name">
|
||||
<datalist id="medicine_suggest"></datalist>
|
||||
<div class="border rounded p-3 mb-3 bg-light-subtle">
|
||||
<div class="row g-3 align-items-end mb-2">
|
||||
<div class="col-md-8">
|
||||
<label class="form-label fw-semibold mb-1">Prescribed:</label>
|
||||
<input type="text" class="form-control" id="med_name" list="medicine_suggest" placeholder="Search / enter medicine name">
|
||||
<datalist id="medicine_suggest"></datalist>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-semibold mb-1">Type</label>
|
||||
<input type="text" class="form-control" id="med_type" placeholder="TAB,CAP,SYR,INJ">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control" id="med_type" placeholder="Type">
|
||||
<div class="row g-3 align-items-end mb-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold mb-1">Dose:</label>
|
||||
<select class="form-select" id="med_dosage">
|
||||
<option value="">Select dose</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label fw-semibold mb-1">When:</label>
|
||||
<select class="form-select" id="med_when">
|
||||
<option value="">Select when</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold mb-1">Frequency:</label>
|
||||
<select class="form-select" id="med_freq">
|
||||
<option value="">Select frequency</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-semibold mb-1">Duration:</label>
|
||||
<input type="text" class="form-control" id="med_days" placeholder="e.g. 5 days / 1 month / 3 doses">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-select" id="med_dosage">
|
||||
<option value="">Dose</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-select" id="med_when">
|
||||
<option value="">When</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-select" id="med_freq">
|
||||
<option value="">Freq</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control" id="med_days" placeholder="Days">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control" id="med_qty" placeholder="Qty">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-select" id="med_where">
|
||||
<option value="">Where</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" id="med_remark" placeholder="Remark">
|
||||
</div>
|
||||
<div class="col-md-2 d-grid gap-2">
|
||||
<button type="button" class="btn btn-primary" id="btn_add_medicine">Add</button>
|
||||
<button type="button" class="btn btn-outline-danger" id="btn_clear_medicine">Remove All</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="btn_cancel_medicine_edit" style="display:none;">Cancel</button>
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold mb-1">Where:</label>
|
||||
<select class="form-select" id="med_where">
|
||||
<option value="">Body place</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label fw-semibold mb-1">Qty:</label>
|
||||
<input type="text" class="form-control" id="med_qty" placeholder="Qty">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label class="form-label fw-semibold mb-1">Medicine Advice:</label>
|
||||
<input type="text" class="form-control" id="med_remark" placeholder="Instruction / medicine advice">
|
||||
</div>
|
||||
<div class="col-md-2 d-grid gap-2">
|
||||
<button type="button" class="btn btn-primary" id="btn_add_medicine">+ADD / Update</button>
|
||||
<button type="button" class="btn btn-outline-danger" id="btn_clear_medicine">Remove All</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="btn_cancel_medicine_edit" style="display:none;">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -831,7 +844,7 @@
|
|||
<table class="table table-bordered table-sm rx-list-table" id="tbl_medicine">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Medicine</th><th>Type</th><th>Dose</th><th>When</th><th>Freq</th><th>Where</th><th>Days</th><th>Qty</th><th>Remark</th><th width="170">Action</th>
|
||||
<th>Medicine</th><th>Type</th><th>Dose</th><th>When</th><th>Frequency</th><th>Where</th><th>Duration</th><th>Qty</th><th>Medicine Advice</th><th width="170">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr><td colspan="10" class="text-muted">No medicine added</td></tr></tbody>
|
||||
|
|
@ -1129,17 +1142,18 @@
|
|||
(rows || []).forEach(function(row) {
|
||||
var id = (row && row.id !== undefined) ? String(row.id) : '';
|
||||
var label = (row && row.label !== undefined) ? String(row.label) : '';
|
||||
var localLabel = (row && row.local_label !== undefined) ? String(row.local_label) : '';
|
||||
if (!id || !label) {
|
||||
return;
|
||||
}
|
||||
html += '<option value="' + $('<div>').text(id).html() + '">' + $('<div>').text(label).html() + '</option>';
|
||||
html += '<option value="' + $('<div>').text(id).html() + '"' + (localLabel ? ' data-local-label="' + $('<div>').text(localLabel).html() + '"' : '') + '>' + $('<div>').text(label).html() + '</option>';
|
||||
});
|
||||
$select.html(html);
|
||||
}
|
||||
|
||||
function ensureMedicineMasterOption($select, value) {
|
||||
value = (value || '').toString().trim();
|
||||
if (!value) {
|
||||
if (!value || value === '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4825,18 +4839,26 @@
|
|||
if (dosage) {
|
||||
ensureMedicineMasterOption($('#med_dosage'), dosage);
|
||||
$('#med_dosage').val(dosage).trigger('change');
|
||||
} else {
|
||||
$('#med_dosage').val('').trigger('change');
|
||||
}
|
||||
if (whenValue) {
|
||||
ensureMedicineMasterOption($('#med_when'), whenValue);
|
||||
$('#med_when').val(whenValue).trigger('change');
|
||||
} else {
|
||||
$('#med_when').val('').trigger('change');
|
||||
}
|
||||
if (freqValue) {
|
||||
ensureMedicineMasterOption($('#med_freq'), freqValue);
|
||||
$('#med_freq').val(freqValue).trigger('change');
|
||||
} else {
|
||||
$('#med_freq').val('').trigger('change');
|
||||
}
|
||||
if (whereValue) {
|
||||
ensureMedicineMasterOption($('#med_where'), whereValue);
|
||||
$('#med_where').val(whereValue).trigger('change');
|
||||
} else {
|
||||
$('#med_where').val('').trigger('change');
|
||||
}
|
||||
if (daysValue) {
|
||||
$('#med_days').val(daysValue);
|
||||
|
|
|
|||
BIN
public/assets/img/logo1.png
Normal file
BIN
public/assets/img/logo1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
public/assets/img/logo_backup_before_attachment_change.png
Normal file
BIN
public/assets/img/logo_backup_before_attachment_change.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 738 B |
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 2.3 KiB |
Loading…
Reference in New Issue
Block a user