Support multiline Drug Allergy/ADR with history carry-forward and auto-sync prescribed medicine defaults to master

This commit is contained in:
DevSoftTech Server 2026-11-03 14:21:31 +05:30
parent 385e34fec9
commit 9e5f607f00
3 changed files with 365 additions and 7 deletions

View File

@ -1092,6 +1092,7 @@ $routes->get('Opd_prescription/medicine_list/(:num)', 'Opd_prescription::medicin
$routes->get('Opd_prescription/vitals_get/(:num)', 'Opd_prescription::vitals_get/$1');
$routes->post('Opd_prescription/vitals_save', 'Opd_prescription::vitals_save');
$routes->post('Opd_prescription/medicine_add', 'Opd_prescription::medicine_add');
$routes->post('Opd_prescription/medicine_sync_master_defaults', 'Opd_prescription::medicine_sync_master_defaults');
$routes->post('Opd_prescription/medicine_favorite_toggle', 'Opd_prescription::medicine_favorite_toggle');
$routes->post('Opd_prescription/medicine_update/(:num)', 'Opd_prescription::medicine_update/$1');
$routes->post('Opd_prescription/medicine_remove/(:num)', 'Opd_prescription::medicine_remove/$1');

View File

@ -165,6 +165,49 @@ class Opd_prescription extends BaseController
}
}
$nabhHistory = $this->getPatientNabhHistory($patientId, $opdId);
$nabhPrefilledFromHistory = false;
if (empty($prescription)) {
if ($this->hasMeaningfulNabhHistory($nabhHistory)) {
$prescription = [(object) $nabhHistory];
$nabhPrefilledFromHistory = true;
}
} else {
$first = $prescription[0];
$curStatus = strtolower(trim((string) ($first->drug_allergy_status ?? '')));
$curDetails = trim((string) ($first->drug_allergy_details ?? ''));
$curAdr = trim((string) ($first->adr_history ?? ''));
$curMeds = trim((string) ($first->current_medications ?? ''));
if (($curStatus === '' || in_array($curStatus, ['allergies not known', 'not known'], true)) && $curDetails === '' && ! empty($nabhHistory['drug_allergy_status'])) {
$histStatusNorm = strtolower(trim((string) $nabhHistory['drug_allergy_status']));
if (! in_array($histStatusNorm, ['', 'allergies not known', 'not known'], true) || ! empty($nabhHistory['drug_allergy_details'])) {
$first->drug_allergy_status = (string) $nabhHistory['drug_allergy_status'];
$nabhPrefilledFromHistory = true;
}
}
if ($curDetails === '' && ! empty($nabhHistory['drug_allergy_details']) && ! in_array(strtolower(trim((string) ($first->drug_allergy_status ?? ''))), ['no known drug allergy', 'none'], true)) {
$first->drug_allergy_details = (string) $nabhHistory['drug_allergy_details'];
if (in_array(strtolower(trim((string) ($first->drug_allergy_status ?? ''))), ['', 'allergies not known', 'not known'], true)) {
$first->drug_allergy_status = 'Known';
}
$nabhPrefilledFromHistory = true;
}
if ($curAdr === '' && ! empty($nabhHistory['adr_history'])) {
$first->adr_history = (string) $nabhHistory['adr_history'];
$nabhPrefilledFromHistory = true;
}
if ($curMeds === '' && ! empty($nabhHistory['current_medications'])) {
$first->current_medications = (string) $nabhHistory['current_medications'];
$nabhPrefilledFromHistory = true;
}
$prescription[0] = $first;
}
if (false) {
if (false) {
}
}
return view('billing/opd_prescription_basic', [
'opd_id' => $opdId,
'opd_master' => $opdMaster,
@ -175,6 +218,7 @@ class Opd_prescription extends BaseController
'addiction_flags' => $this->getPatientAddictionFlags($patientId),
'co_morbidities' => $this->getCoMorbiditiesWithSelection($patientId),
'co_morbidities_prefilled_from_history' => $this->hasHistoricalCoMorbiditySelection($patientId),
'nabh_prefilled_from_history' => $nabhPrefilledFromHistory ?? false,
'history_alerts' => $this->buildPatientHistoryAlerts((int) ($opdRow->p_id ?? 0), $opdId),
'left_remarks' => $this->fetchPatientRemarks((int) ($opdRow->p_id ?? 0), 8),
]);
@ -490,6 +534,11 @@ class Opd_prescription extends BaseController
? mb_strtolower($allergyStatusNormalized)
: strtolower($allergyStatusNormalized);
$allergyDetails = trim((string) ($payload['drug_allergy_details'] ?? ''));
if ($allergyDetails !== '' && in_array($allergyStatusNorm, ['', 'allergies not known', 'not known'], true)) {
$payload['drug_allergy_status'] = 'Known';
$allergyStatusRaw = 'Known';
$allergyStatusNorm = 'known';
}
if ($allergyStatusRaw === '') {
return $this->response->setJSON([
@ -720,6 +769,7 @@ class Opd_prescription extends BaseController
$morbidityIds = $this->parseNumericList((string) $this->request->getPost('morbidities_list'));
$this->syncPatientMorbidities((int) ($opdRow->p_id ?? 0), $morbidityIds);
$this->syncPatientNabhHistory((int) ($opdRow->p_id ?? 0), $nabhInput);
if (in_array('Prescriber_Remarks', $fields, true)) {
$coMorbiditiesText = trim((string) $this->request->getPost('morbidities_text'));
@ -9054,6 +9104,12 @@ class Opd_prescription extends BaseController
}
$this->applyDoseMasterStringFields($insert, $fields);
if ($medId <= 0) {
$medId = $this->resolveMedicineMasterIdByName($medName);
}
if ($medId > 0) {
$this->syncMedicineMasterDefaults($medId, $insert);
}
$user = auth()->user();
if (in_array('update_by', $fields, true)) {
@ -9203,6 +9259,9 @@ class Opd_prescription extends BaseController
if (! empty($update)) {
$this->db->table($table)->where('id', $medId)->update($update);
foreach (glob(WRITEPATH . 'cache/medicine_search_*') ?: [] as $cacheFile) {
@unlink($cacheFile);
}
$detailsUpdated = true;
}
}
@ -9283,6 +9342,49 @@ class Opd_prescription extends BaseController
*
* @param array<string, mixed> $defaults
*/
public function medicine_sync_master_defaults()
{
if (! $this->request->isAJAX()) {
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
}
$medId = (int) $this->request->getPost('med_id');
$medName = trim((string) $this->request->getPost('med_name'));
$medType = trim((string) $this->request->getPost('med_type'));
if ($medId <= 0 && $medName !== '') {
$medId = $this->resolveMedicineMasterIdByName($medName);
}
if ($medId <= 0) {
return $this->response->setJSON([
'update' => 0,
'med_id' => 0,
'csrfName' => csrf_token(),
'csrfHash' => csrf_hash(),
]);
}
$this->syncMedicineMasterDefaults($medId, [
'med_name' => $medName,
'med_type' => $medType,
'dosage' => trim((string) $this->request->getPost('dosage')),
'dosage_when' => trim((string) $this->request->getPost('dosage_when')),
'dosage_freq' => trim((string) $this->request->getPost('dosage_freq')),
'dosage_where' => trim((string) $this->request->getPost('dosage_where')),
'no_of_days' => trim((string) $this->request->getPost('no_of_days')),
'qty' => trim((string) $this->request->getPost('qty')),
'remark' => trim((string) $this->request->getPost('remark')),
]);
return $this->response->setJSON([
'update' => 1,
'med_id' => $medId,
'csrfName' => csrf_token(),
'csrfHash' => csrf_hash(),
]);
}
private function syncMedicineMasterDefaults(int $medId, array $defaults): void
{
if ($medId <= 0) {
@ -9300,6 +9402,7 @@ class Opd_prescription extends BaseController
}
$fieldMap = [
'med_type' => $this->resolveFirstField($fields, ['formulation']),
'dosage' => $this->resolveFirstField($fields, ['dosage']),
'dosage_when' => $this->resolveFirstField($fields, ['dosage_when']),
'dosage_freq' => $this->resolveFirstField($fields, ['dosage_freq']),
@ -9316,6 +9419,11 @@ class Opd_prescription extends BaseController
}
$value = trim((string) ($defaults[$payloadKey] ?? ''));
if ($payloadKey === 'med_type') {
$value = $this->normalizeMedicineFormulation($value, (string) ($defaults['med_name'] ?? ''));
} elseif (in_array($payloadKey, ['dosage', 'dosage_when', 'dosage_freq', 'dosage_where'], true)) {
$value = $this->sanitizeMedicineMasterDefaultField($value, $payloadKey);
}
if ($value === '') {
continue;
}
@ -9328,6 +9436,9 @@ class Opd_prescription extends BaseController
}
$this->db->table($table)->where('id', $medId)->update($update);
foreach (glob(WRITEPATH . 'cache/medicine_search_*') ?: [] as $cacheFile) {
@unlink($cacheFile);
}
}
/**
@ -9495,6 +9606,7 @@ class Opd_prescription extends BaseController
}
if ($masterMedId > 0) {
$this->trackMedicineUsage($masterMedId);
$this->syncMedicineMasterDefaults($masterMedId, array_replace($current, $update));
}
$sessionId = (int) ($current['opd_pre_id'] ?? 0);
@ -10131,13 +10243,146 @@ class Opd_prescription extends BaseController
return $unmapped;
}
private function hasMeaningfulNabhHistory(array $history): bool
{
$statusNorm = strtolower(trim((string) ($history['drug_allergy_status'] ?? '')));
if (! in_array($statusNorm, ['', 'allergies not known', 'not known'], true)) {
return true;
}
return trim((string) ($history['drug_allergy_details'] ?? '')) !== ''
|| trim((string) ($history['adr_history'] ?? '')) !== ''
|| trim((string) ($history['current_medications'] ?? '')) !== '';
}
private function getPatientNabhHistory(int $patientId, int $currentOpdId = 0): array
{
$history = [
'drug_allergy_status' => '',
'drug_allergy_details' => '',
'adr_history' => '',
'current_medications' => '',
];
if ($patientId <= 0) {
return $history;
}
if ($this->db->tableExists('patient_master')) {
$pFields = $this->db->getFieldNames('patient_master') ?? [];
$select = [];
foreach (array_keys($history) as $f) {
if (in_array($f, $pFields, true)) {
$select[] = $f;
}
}
if (! empty($select)) {
$pRow = $this->db->table('patient_master')
->select(implode(',', $select))
->where('id', $patientId)
->get(1)
->getRowArray() ?? [];
foreach ($select as $f) {
$val = trim((string) ($pRow[$f] ?? ''));
if ($val !== '') {
$history[$f] = $val;
}
}
}
}
if ($this->db->tableExists('opd_prescription')) {
$builder = $this->db->table('opd_prescription')
->where('p_id', $patientId);
if ($currentOpdId > 0) {
$builder->where('opd_id !=', $currentOpdId);
}
$rows = $builder->orderBy('id', 'DESC')->limit(20)->get()->getResultArray();
foreach ($rows as $row) {
$nabh = $this->hydrateNabhPrescriptionFields($row, (string) ($row['Prescriber_Remarks'] ?? ''));
$statusVal = trim((string) ($nabh['drug_allergy_status'] ?? ''));
$statusNorm = strtolower($statusVal);
$detailsVal = trim((string) ($nabh['drug_allergy_details'] ?? ''));
$adrVal = trim((string) ($nabh['adr_history'] ?? ''));
$medsVal = trim((string) ($nabh['current_medications'] ?? ''));
if (($history['drug_allergy_status'] === '' || in_array(strtolower($history['drug_allergy_status']), ['allergies not known', 'not known'], true))
&& (! in_array($statusNorm, ['', 'allergies not known', 'not known'], true) || $detailsVal !== '')
) {
$history['drug_allergy_status'] = $detailsVal !== '' && in_array($statusNorm, ['', 'allergies not known', 'not known'], true)
? 'Known'
: $statusVal;
}
if ($history['drug_allergy_details'] === '' && $detailsVal !== '' && ! in_array(strtolower($history['drug_allergy_status']), ['no known drug allergy', 'none'], true)) {
$history['drug_allergy_details'] = $detailsVal;
if (in_array(strtolower($history['drug_allergy_status']), ['', 'allergies not known', 'not known'], true)) {
$history['drug_allergy_status'] = 'Known';
}
}
if ($history['adr_history'] === '' && $adrVal !== '') {
$history['adr_history'] = $adrVal;
}
if ($history['current_medications'] === '' && $medsVal !== '') {
$history['current_medications'] = $medsVal;
}
if ($history['drug_allergy_status'] !== '' && $history['adr_history'] !== '' && $history['current_medications'] !== '') {
break;
}
}
}
return $history;
}
private function syncPatientNabhHistory(int $patientId, array $input): void
{
if ($patientId <= 0 || ! $this->db->tableExists('patient_master')) {
return;
}
$pFields = $this->db->getFieldNames('patient_master') ?? [];
$update = [];
$statusVal = trim((string) ($input['drug_allergy_status'] ?? ''));
$statusNorm = strtolower($statusVal);
$detailsVal = trim((string) ($input['drug_allergy_details'] ?? ''));
$adrVal = trim((string) ($input['adr_history'] ?? ''));
$medsVal = trim((string) ($input['current_medications'] ?? ''));
if ($detailsVal !== '' && in_array($statusNorm, ['', 'allergies not known', 'not known'], true)) {
$statusVal = 'Known';
$statusNorm = 'known';
}
if (in_array('drug_allergy_status', $pFields, true) && ($detailsVal !== '' || ! in_array($statusNorm, ['', 'allergies not known', 'not known'], true))) {
$update['drug_allergy_status'] = $statusVal;
}
if (in_array('drug_allergy_details', $pFields, true)) {
if (in_array($statusNorm, ['no known drug allergy', 'none'], true)) {
$update['drug_allergy_details'] = '';
} elseif ($detailsVal !== '') {
$update['drug_allergy_details'] = $detailsVal;
}
}
if (in_array('adr_history', $pFields, true) && $adrVal !== '') {
$update['adr_history'] = $adrVal;
}
if (in_array('current_medications', $pFields, true) && $medsVal !== '') {
$update['current_medications'] = $medsVal;
}
if (! empty($update)) {
$this->db->table('patient_master')->where('id', $patientId)->update($update);
}
}
private function extractNabhFieldsFromRemarks(string $remarks): array
{
$extract = static function (string $pattern, string $source): string {
if (preg_match($pattern, $source, $m) !== 1) {
return '';
}
return trim((string) ($m[1] ?? ''));
return str_replace(' \\n ', "\n", trim((string) ($m[1] ?? '')));
};
return [
@ -10151,6 +10396,9 @@ class Opd_prescription extends BaseController
private function upsertNabhFieldsIntoRemarks(string $remarks, array $input): string
{
$clean = $this->stripNabhFieldsFromRemarks($remarks);
foreach ($input as $k => $v) {
$input[$k] = preg_replace('/\r\n|\r|\n/', ' \\n ', trim((string) $v)) ?? trim((string) $v);
}
$lines = [];
if (trim((string) ($input['drug_allergy_status'] ?? '')) !== '') {
@ -10271,7 +10519,7 @@ class Opd_prescription extends BaseController
return '';
}
return trim((string) ($m[1] ?? ''));
return str_replace(' \\n ', "\n", trim((string) ($m[1] ?? '')));
};
return [
@ -13706,6 +13954,28 @@ OPD SNAPSHOT JSON: " . $payload;
];
}
$nabhAlerts = $this->hydrateNabhPrescriptionFields($row, (string) ($row['Prescriber_Remarks'] ?? ''));
$nabhAllergyDetails = trim((string) ($nabhAlerts['drug_allergy_details'] ?? ''));
$nabhAllergyStatus = trim((string) ($nabhAlerts['drug_allergy_status'] ?? ''));
if ($nabhAllergyDetails !== '' || in_array(strtolower($nabhAllergyStatus), ['known', 'no known drug allergy'], true)) {
$alerts[] = [
'type' => 'Drug Allergy',
'message' => $dateLabel . ': ' . ($nabhAllergyDetails !== '' ? ($nabhAllergyStatus !== '' ? $nabhAllergyStatus . ' - ' : '') . $nabhAllergyDetails : $nabhAllergyStatus),
];
}
if (trim((string) ($nabhAlerts['adr_history'] ?? '')) !== '') {
$alerts[] = [
'type' => 'ADR History',
'message' => $dateLabel . ': ' . trim((string) $nabhAlerts['adr_history']),
];
}
if (trim((string) ($nabhAlerts['current_medications'] ?? '')) !== '') {
$alerts[] = [
'type' => 'Current Medications',
'message' => $dateLabel . ': ' . trim((string) $nabhAlerts['current_medications']),
];
}
$historyFields = $this->hydratePatientHistoryFields($row, (string) ($row['Prescriber_Remarks'] ?? ''));
$historyLabels = [
'obstetric_history' => 'Obstetric History',

View File

@ -924,16 +924,22 @@
</div>
<div class="col-md-8">
<label class="form-label mb-1">Drug Allergy Details <span class="small text-muted">(when status = Known)</span></label>
<input type="text" class="form-control form-control-sm rx-instant" id="drug_allergy_details" placeholder="e.g. Penicillin rash, NSAID gastritis" value="<?= esc($opd_prescription[0]->drug_allergy_details ?? '') ?>">
<textarea class="form-control form-control-sm rx-instant rx-field" id="drug_allergy_details" rows="2" maxlength="4000" placeholder="e.g. Penicillin rash, NSAID gastritis (multiple lines allowed)"><?= esc($opd_prescription[0]->drug_allergy_details ?? '') ?></textarea>
<div class="rx-counter" id="counter_drug_allergy_details">0/4000</div>
<div id="drug_allergy_details_error" class="invalid-feedback d-block" style="display:none;"></div>
</div>
<div class="col-md-6">
<label class="form-label mb-1">ADR History</label>
<input type="text" class="form-control form-control-sm rx-instant" id="adr_history" placeholder="Previous adverse drug reaction details" value="<?= esc($opd_prescription[0]->adr_history ?? '') ?>">
<textarea class="form-control form-control-sm rx-instant rx-field" id="adr_history" rows="2" maxlength="4000" placeholder="Previous adverse drug reaction details (multiple lines allowed)"><?= esc($opd_prescription[0]->adr_history ?? '') ?></textarea>
<div class="rx-counter" id="counter_adr_history">0/4000</div>
</div>
<div class="col-md-6">
<label class="form-label mb-1">Current Medications</label>
<input type="text" class="form-control form-control-sm rx-instant" id="current_medications" placeholder="Current/ongoing medicines" value="<?= esc($opd_prescription[0]->current_medications ?? '') ?>">
<textarea class="form-control form-control-sm rx-instant rx-field" id="current_medications" rows="2" maxlength="4000" placeholder="Current/ongoing medicines (multiple lines allowed)"><?= esc($opd_prescription[0]->current_medications ?? '') ?></textarea>
<div class="rx-counter" id="counter_current_medications">0/4000</div>
<?php if (!empty($nabh_prefilled_from_history ?? false)) { ?>
<div class="small text-muted mt-1">Prefilled from patient history.</div>
<?php } ?>
</div>
</div>
</div>
@ -2415,7 +2421,12 @@
var matchedVal = '';
$sel.find('option').each(function() {
var optVal = ($(this).val() || '').toString().trim().toLowerCase();
var txt = ($(this).text() || '').toString().trim().toLowerCase();
if (optVal === probe) {
matchedVal = ($(this).val() || '').toString();
return false;
}
if (!txt) {
return;
}
@ -4333,6 +4344,12 @@
}
$('#drug_allergy_status,#drug_allergy_details').on('input change', function() {
if (this.id === 'drug_allergy_details' && ($(this).val() || '').trim() !== '') {
var curStatus = ($('#drug_allergy_status').val() || '').trim().toLowerCase();
if (curStatus === '' || curStatus === 'allergies not known' || curStatus === 'not known') {
$('#drug_allergy_status').val('Known');
}
}
$(this).removeClass('is-invalid');
if (this.id === 'drug_allergy_status') {
$('#drug_allergy_status_error').text('').hide();
@ -9794,7 +9811,67 @@
}
});
var isApplyingMedicineSelection = false;
var medMasterSyncTimer = null;
function updateLocalMedicineMasterCache(medId, medName, defaults) {
var upperName = (medName || '').toString().trim().toUpperCase();
(medicineSuggestRows || []).forEach(function(r) {
if ((medId > 0 && parseInt(r.id || 0, 10) === medId) || (upperName && (r.med_name || '').toString().trim().toUpperCase() === upperName)) {
if (defaults.med_type) { r.med_type = defaults.med_type; }
if (defaults.dosage !== undefined && defaults.dosage !== '') { r.dosage = defaults.dosage; }
if (defaults.dosage_when !== undefined && defaults.dosage_when !== '') { r.dosage_when = defaults.dosage_when; }
if (defaults.dosage_freq !== undefined && defaults.dosage_freq !== '') { r.dosage_freq = defaults.dosage_freq; }
if (defaults.dosage_where !== undefined && defaults.dosage_where !== '') { r.dosage_where = defaults.dosage_where; }
if (defaults.no_of_days !== undefined && defaults.no_of_days !== '') { r.no_of_days = defaults.no_of_days; }
if (defaults.qty !== undefined && defaults.qty !== '') { r.qty = defaults.qty; }
if (defaults.remark !== undefined && defaults.remark !== '') { r.remark = defaults.remark; }
}
});
medicineSearchCache = {};
try {
localStorage.removeItem(medicineSearchLocalDbKey);
} catch (e) {}
}
function scheduleSyncMedicineMasterDefaults() {
if (isApplyingMedicineSelection) {
return;
}
var medName = ($('#med_name').val() || '').toString().trim();
var medId = parseInt($('#med_name').data('med-id') || '0', 10);
if (!medName && medId <= 0) {
return;
}
if (medMasterSyncTimer) {
clearTimeout(medMasterSyncTimer);
}
medMasterSyncTimer = setTimeout(function() {
medMasterSyncTimer = null;
var curName = ($('#med_name').val() || '').toString().trim();
var curId = parseInt($('#med_name').data('med-id') || '0', 10);
if (!curName && curId <= 0) {
return;
}
var defaults = {
med_id: curId,
med_name: curName,
med_type: ($('#med_type').val() || '').toString().trim(),
dosage: ($('#med_dosage').val() || '').toString().trim(),
dosage_when: ($('#med_when').val() || '').toString().trim(),
dosage_freq: ($('#med_freq').val() || '').toString().trim(),
dosage_where: ($('#med_where').val() || '').toString().trim(),
no_of_days: ($('#med_days').val() || '').toString().trim(),
qty: ($('#med_qty').val() || '').toString().trim(),
remark: ($('#med_remark').val() || '').toString().trim()
};
updateLocalMedicineMasterCache(curId, curName, defaults);
apiPost('<?= base_url('Opd_prescription/medicine_sync_master_defaults') ?>', defaults, function() {});
}, 350);
}
function applyMedicineSelection(rowData) {
isApplyingMedicineSelection = true;
var medName = (rowData.med_name || '').toString().trim();
if (medName) { $('#med_name').val(medName); }
var resolvedMedType = setMedTypeSelectValue($('#med_type'), (rowData.med_type || '').toString(), medName);
@ -9819,7 +9896,7 @@
}
if (whenValue) {
ensureMedicineMasterOption($('#med_when'), whenValue);
$('#med_when').val(whenValue).trigger('change');
setMedicineSelectByLabel('med_when', whenValue);
} else {
$('#med_when').val('').trigger('change');
}
@ -9831,13 +9908,15 @@
}
if (whereValue) {
ensureMedicineMasterOption($('#med_where'), whereValue);
$('#med_where').val(whereValue).trigger('change');
setMedicineSelectByLabel('med_where', whereValue);
} else {
$('#med_where').val('').trigger('change');
autoSelectDefaultRoute(resolvedMedType || rowData.med_type || $('#med_type').val(), $('#med_where'));
}
if (daysValue) {
$('#med_days').val(daysValue);
} else {
$('#med_days').val('');
}
if (qtyValue) {
$('#med_qty').val(qtyValue);
@ -9846,8 +9925,11 @@
}
if (remarkValue) {
$('#med_remark').val(remarkValue);
} else {
$('#med_remark').val('');
}
isApplyingMedicineSelection = false;
var medId = parseInt(rowData.id || 0, 10);
var isFav = parseInt(rowData.is_favorite || 0, 10) === 1;
if (medId > 0) {
@ -9862,6 +9944,10 @@
}
}
$('#med_type, #med_dosage, #med_freq, #med_when, #med_where, #med_days, #med_remark').on('change blur', function() {
scheduleSyncMedicineMasterDefaults();
});
var medNameHighlightIdx = -1;
function highlightMedNameItem(idx) {
@ -10096,6 +10182,7 @@
$('#opd_session_id').val(data.opd_session_id || sid);
clearMedicineForm(true);
loadMedicineList();
updateLocalMedicineMasterCache(payload.med_id, payload.med_name, payload);
$('.jsError').removeClass('text-danger text-muted').addClass('text-success').text(data.error_text || 'Medicine saved.');
// Keep typing flow fast: move cursor back to medicine field.
setTimeout(function() {