Pharmacy product edit: smarter medicine autofill from ABDM label/detail

This commit is contained in:
DevSoftTech Server 2026-05-25 14:07:11 +05:30
parent 0558ac5a2e
commit e221581578

View File

@ -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();