From e221581578e6eb35d205c59a2b47b1401fc19e8c Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Mon, 25 May 2026 14:07:11 +0530 Subject: [PATCH] Pharmacy product edit: smarter medicine autofill from ABDM label/detail --- app/Views/medical/product_edit.php | 320 +++++++++++++++++++++++++++-- 1 file changed, 303 insertions(+), 17 deletions(-) diff --git a/app/Views/medical/product_edit.php b/app/Views/medical/product_edit.php index 28891b1..8070ffa 100644 --- a/app/Views/medical/product_edit.php +++ b/app/Views/medical/product_edit.php @@ -208,6 +208,228 @@ $flag = static function ($v): string { $('#abdm-drug-suggest').hide().empty(); } + function normalizeSpace(text) { + return String(text || '').replace(/\s+/g, ' ').trim(); + } + + function parseDrugLabel(rawLabel) { + var label = normalizeSpace(rawLabel); + var result = { + productName: label, + genericName: '', + formulation: '' + }; + + if (!label) { + return result; + } + + var before = ''; + var inside = ''; + var after = ''; + var m = label.match(/^([^()]+?)\s*\(([^)]+)\)\s*(.*)$/); + if (m) { + before = normalizeSpace(m[1]); + inside = normalizeSpace(m[2]); + after = normalizeSpace(m[3]); + } + + if (before) { + result.productName = before; + } + + var formRegex = /\b(tablet|capsule|syrup|suspension|injection|cream|ointment|gel|drops?|solution|powder|lotion|spray|respules?|inhaler|patch|suppository|lozenge|granules?)\b/i; + var formMatch = formRegex.exec(after || label); + if (formMatch) { + result.formulation = normalizeSpace(formMatch[1]); + } + + if (inside) { + var genericTail = after; + if (formMatch && after) { + genericTail = normalizeSpace(after.substring(0, formMatch.index)); + } + // Remove common dosage-route filler just before formulation. + genericTail = normalizeSpace(genericTail.replace(/\b(oral|route|for\s+oral\s+use)\b/gi, '')); + result.genericName = normalizeSpace((inside + ' ' + genericTail).trim()); + } + + return result; + } + + function parseJsonObject(text) { + if (!text) { + return {}; + } + try { + var obj = JSON.parse(String(text)); + return (obj && typeof obj === 'object') ? obj : {}; + } catch (e) { + return {}; + } + } + + function flattenMeta(input, out) { + if (!input || typeof input !== 'object') { + return out; + } + + Object.keys(input).forEach(function (key) { + var value = input[key]; + var k = String(key || '').toLowerCase(); + + if (value === null || value === undefined) { + return; + } + + if (Array.isArray(value)) { + if (value.length && (typeof value[0] === 'string' || typeof value[0] === 'number' || typeof value[0] === 'boolean')) { + out[k] = value.map(String).join(', '); + } + value.forEach(function (child) { + if (child && typeof child === 'object') { + flattenMeta(child, out); + } + }); + return; + } + + if (typeof value === 'object') { + flattenMeta(value, out); + return; + } + + out[k] = String(value).trim(); + }); + + return out; + } + + function getMetaText(meta, keys) { + for (var i = 0; i < keys.length; i++) { + var key = String(keys[i] || '').toLowerCase(); + var value = normalizeSpace(meta[key] || ''); + if (value) { + return value; + } + } + return ''; + } + + function getMetaNumber(meta, keys) { + var raw = getMetaText(meta, keys); + if (!raw) { + return null; + } + var num = parseFloat(String(raw).replace(/[^0-9.\-]/g, '')); + return isNaN(num) ? null : num; + } + + function hasMetaKey(meta, keys) { + for (var i = 0; i < keys.length; i++) { + if (Object.prototype.hasOwnProperty.call(meta, String(keys[i] || '').toLowerCase())) { + return true; + } + } + return false; + } + + function getMetaBool(meta, keys) { + var raw = getMetaText(meta, keys).toLowerCase(); + if (!raw) { + return null; + } + if (['1', 'true', 'yes', 'y', 'on'].indexOf(raw) >= 0) { + return true; + } + if (['0', 'false', 'no', 'n', 'off'].indexOf(raw) >= 0) { + return false; + } + return null; + } + + function setFormulationValue(formulation) { + var value = normalizeSpace(formulation).toLowerCase(); + if (!value) { + return; + } + var $f = $('#input_formulation'); + var matchedVal = ''; + $f.find('option').each(function () { + var v = normalizeSpace($(this).val()).toLowerCase(); + var t = normalizeSpace($(this).text()).toLowerCase(); + if (v === value || t === value || v.indexOf(value) >= 0 || t.indexOf(value) >= 0 || value.indexOf(v) >= 0 || value.indexOf(t) >= 0) { + matchedVal = $(this).val(); + return false; + } + }); + if (matchedVal !== '') { + $f.val(matchedVal); + } + } + + function setCompanyByName(companyName) { + var needle = normalizeSpace(companyName).toLowerCase(); + if (!needle) { + return; + } + var $c = $('#input_company_name'); + var matchedVal = ''; + $c.find('option').each(function () { + var text = normalizeSpace($(this).text()).toLowerCase(); + if (!text || text === 'select') { + return; + } + if (text === needle || text.indexOf(needle) >= 0 || needle.indexOf(text) >= 0) { + matchedVal = $(this).val(); + return false; + } + }); + if (matchedVal !== '') { + $c.val(matchedVal); + } + } + + function setCategoryByName(categoryText) { + var raw = normalizeSpace(categoryText); + if (!raw) { + return; + } + var tokens = raw.split(/[|,;/]+/).map(function (x) { return normalizeSpace(x).toLowerCase(); }).filter(Boolean); + if (!tokens.length) { + return; + } + + var selected = []; + $('#med_cat_id option').each(function () { + var text = normalizeSpace($(this).text()).toLowerCase(); + if (!text) { + return; + } + var matched = tokens.some(function (t) { + return text === t || text.indexOf(t) >= 0 || t.indexOf(text) >= 0; + }); + if (matched) { + selected.push($(this).val()); + } + }); + + if (selected.length) { + $('#med_cat_id').val(selected).trigger('change'); + } + } + + function setCheckboxFromMeta(selector, meta, keys) { + if (!hasMetaKey(meta, keys)) { + return; + } + var boolVal = getMetaBool(meta, keys); + if (boolVal === null) { + return; + } + $(selector).prop('checked', !!boolVal); + } + function applyDrugDetail(detail) { if (!detail || typeof detail !== 'object') { return; @@ -219,34 +441,98 @@ $flag = static function ($v): string { var formulation = detail.formulation || ''; var packing = detail.packing || ''; - if (label) { - $('#input_item_name').val(label); - $('#abdm_drug_display').val(label); + var parsed = parseDrugLabel(label); + var payloadObj = parseJsonObject(detail.payload_json || '{}'); + var flatMeta = flattenMeta(payloadObj, {}); + + var metaGeneric = getMetaText(flatMeta, ['generic_name', 'genericname', 'generic', 'salt', 'molecule', 'composition']); + var metaCompany = getMetaText(flatMeta, ['company', 'manufacturer', 'brand_owner', 'marketer']); + var metaCategory = getMetaText(flatMeta, ['medicine_category', 'category', 'drug_category', 'schedule_category']); + var metaFormulation = getMetaText(flatMeta, ['formulation', 'dosage_form', 'drug_form']); + var metaPacking = getMetaText(flatMeta, ['packing', 'pack_size', 'package']); + var metaHsn = getMetaText(flatMeta, ['hsn_code', 'hsn', 'hscode']); + + var cgstVal = getMetaNumber(flatMeta, ['cgst', 'cgst_per', 'cgst_percent']); + var sgstVal = getMetaNumber(flatMeta, ['sgst', 'sgst_per', 'sgst_percent']); + var gstTotal = getMetaNumber(flatMeta, ['gst', 'gst_per', 'gst_percent', 'igst', 'tax_percent']); + + var finalProductName = normalizeSpace(parsed.productName || label); + var finalGeneric = normalizeSpace(generic || metaGeneric || parsed.genericName); + var finalFormulation = normalizeSpace(formulation || metaFormulation || parsed.formulation); + var finalPacking = normalizeSpace(packing || metaPacking); + var finalHsn = normalizeSpace(hsnCode || metaHsn); + + if (finalProductName) { + $('#input_item_name').val(finalProductName); } - if (generic && !$('#input_genericname').val()) { - $('#input_genericname').val(generic); + if (finalGeneric) { + $('#input_genericname').val(finalGeneric); } - if (hsnCode && !$('#input_HSNCODE').val()) { - $('#input_HSNCODE').val(hsnCode); + if (finalHsn) { + $('#input_HSNCODE').val(finalHsn); + } + if (finalFormulation) { + setFormulationValue(finalFormulation); + } + if (finalPacking && !$('#input_packing_type').val()) { + $('#input_packing_type').val(finalPacking); } - if (formulation) { - var $f = $('#input_formulation'); - var exists = $f.find('option').filter(function () { - return String($(this).val()).toLowerCase() === String(formulation).toLowerCase(); - }).length > 0; - if (exists) { - $f.val(formulation); + if (metaCompany) { + setCompanyByName(metaCompany); + } + if (metaCategory) { + setCategoryByName(metaCategory); + } + + if (cgstVal !== null) { + $('#input_CGST').val(cgstVal.toFixed(2).replace(/\.00$/, '')); + } + if (sgstVal !== null) { + $('#input_SGST').val(sgstVal.toFixed(2).replace(/\.00$/, '')); + } + if (gstTotal !== null && (cgstVal === null || sgstVal === null)) { + var half = (gstTotal / 2); + if (cgstVal === null) { + $('#input_CGST').val(half.toFixed(2).replace(/\.00$/, '')); + } + if (sgstVal === null) { + $('#input_SGST').val(half.toFixed(2).replace(/\.00$/, '')); } } - if (packing && !$('#input_packing_type').val()) { - $('#input_packing_type').val(packing); + setCheckboxFromMeta('#chk_batch_applicable', flatMeta, ['batch_applicable', 'batch_required']); + setCheckboxFromMeta('#chk_exp_date_applicable', flatMeta, ['exp_date_applicable', 'expiry_applicable']); + setCheckboxFromMeta('#chk_is_continue', flatMeta, ['is_continue', 'is_continued']); + setCheckboxFromMeta('#chk_narcotic', flatMeta, ['narcotic']); + setCheckboxFromMeta('#chk_schedule_h', flatMeta, ['schedule_h']); + setCheckboxFromMeta('#chk_schedule_h1', flatMeta, ['schedule_h1']); + setCheckboxFromMeta('#chk_schedule_x', flatMeta, ['schedule_x']); + setCheckboxFromMeta('#chk_schedule_g', flatMeta, ['schedule_g']); + setCheckboxFromMeta('#chk_high_risk', flatMeta, ['high_risk']); + + var scheduleRaw = getMetaText(flatMeta, ['schedule', 'schedule_type']); + if (scheduleRaw) { + var s = scheduleRaw.toUpperCase(); + if (s.indexOf('H1') >= 0) { + $('#chk_schedule_h1').prop('checked', true); + } + if (s.indexOf('H') >= 0) { + $('#chk_schedule_h').prop('checked', true); + } + if (s.indexOf('X') >= 0) { + $('#chk_schedule_x').prop('checked', true); + } + if (s.indexOf('G') >= 0) { + $('#chk_schedule_g').prop('checked', true); + } } + $('#abdm_drug_display').val(label || finalProductName); + $('#abdm_drug_type').val(detail.type || ''); $('#abdm_drug_identifier').val(detail.identifier || ''); - $('#abdm_drug_generic').val(generic); + $('#abdm_drug_generic').val(finalGeneric); $('#abdm_drug_payload_json').val(detail.payload_json || '{}'); $('#abdm_drug_last_synced_at').val(detail.synced_at || ''); showSelectedDrugSummary();