diff --git a/app/Controllers/Opd_prescription.php b/app/Controllers/Opd_prescription.php index e0f4b33..534234f 100644 --- a/app/Controllers/Opd_prescription.php +++ b/app/Controllers/Opd_prescription.php @@ -1936,6 +1936,89 @@ class Opd_prescription extends BaseController $scope = 'all'; } + $query = $this->request->getGet(); + $isDataTableRequest = is_array($query) && array_key_exists('draw', $query); + if ($isDataTableRequest) { + $draw = max(1, (int) ($query['draw'] ?? 1)); + $start = max(0, (int) ($query['start'] ?? 0)); + $length = (int) ($query['length'] ?? 25); + if ($length < 1 || $length > 500) { + $length = 25; + } + + $searchValue = ''; + if (isset($query['search']) && is_array($query['search'])) { + $searchValue = trim((string) ($query['search']['value'] ?? '')); + } + + $orderField = 'use_count'; + $orderDir = 'desc'; + $allowedOrderFields = ['id', 'item_name', 'use_count', 'last_used_at', 'genericname', 'company_name']; + if (isset($query['order'][0]) && is_array($query['order'][0])) { + $orderColIndex = (int) ($query['order'][0]['column'] ?? -1); + $orderDirCandidate = strtolower(trim((string) ($query['order'][0]['dir'] ?? 'desc'))); + if (in_array($orderDirCandidate, ['asc', 'desc'], true)) { + $orderDir = $orderDirCandidate; + } + + if ($orderColIndex >= 0 && isset($query['columns'][$orderColIndex]) && is_array($query['columns'][$orderColIndex])) { + $candidate = trim((string) ($query['columns'][$orderColIndex]['data'] ?? '')); + if (in_array($candidate, $allowedOrderFields, true)) { + $orderField = $candidate; + } + } + } + + $rows = $this->getOpdMedicineRows($filter, $scope, $showAll); + $recordsTotal = count($rows); + + if ($searchValue !== '') { + $needle = mb_strtolower($searchValue); + $rows = array_values(array_filter($rows, static function (array $row) use ($needle): bool { + $haystack = [ + (string) ($row['id'] ?? ''), + (string) ($row['item_name'] ?? ''), + (string) ($row['genericname'] ?? ''), + (string) ($row['company_name'] ?? ''), + (string) ($row['last_used_at'] ?? ''), + ]; + foreach ($haystack as $value) { + if (mb_stripos($value, $needle) !== false) { + return true; + } + } + return false; + })); + } + + $recordsFiltered = count($rows); + + usort($rows, static function (array $a, array $b) use ($orderField, $orderDir): int { + $numericFields = ['id', 'use_count']; + if (in_array($orderField, $numericFields, true)) { + $cmp = ((int) ($a[$orderField] ?? 0)) <=> ((int) ($b[$orderField] ?? 0)); + } else { + $cmp = strcasecmp((string) ($a[$orderField] ?? ''), (string) ($b[$orderField] ?? '')); + } + + if ($cmp === 0) { + $cmp = strcasecmp((string) ($a['item_name'] ?? ''), (string) ($b['item_name'] ?? '')); + } + + return $orderDir === 'desc' ? -$cmp : $cmp; + }); + + $pageRows = array_slice($rows, $start, $length); + + return $this->response->setJSON([ + 'draw' => $draw, + 'recordsTotal' => $recordsTotal, + 'recordsFiltered' => $recordsFiltered, + 'data' => $pageRows, + 'active_filter' => $filter, + ]); + } + return $this->response->setJSON([ 'rows' => $this->getOpdMedicineRows($filter, $scope, $showAll), 'active_filter' => $filter, diff --git a/app/Views/billing/opd_medicince_workspace.php b/app/Views/billing/opd_medicince_workspace.php index 060a5a9..89e300e 100644 --- a/app/Views/billing/opd_medicince_workspace.php +++ b/app/Views/billing/opd_medicince_workspace.php @@ -285,62 +285,10 @@ } function loadList() { - var url = ''; - var query = []; - if (activeListFilter !== 'all') { - query.push('filter=' + encodeURIComponent(activeListFilter)); + initMedMasterDataTable(); + if (medMasterDataTable) { + medMasterDataTable.ajax.reload(null, true); } - if (query.length) { - url += '?' + query.join('&'); - } - - apiGet(url, function(data) { - var rows = (data && data.rows) ? data.rows : []; - var $tb = $('#tbl_med_master tbody'); - $tb.empty(); - if (!rows.length) { - $tb.html('No medicine found'); - if ($.fn.dataTable.isDataTable('#tbl_med_master')) { - $('#tbl_med_master').DataTable().clear().destroy(); - medMasterDataTable = null; - } - if (activeListFilter === 'generic_issue') { - setMsg('normal', 'No record found with Generic/Salt issue.'); - } else if (activeListFilter === 'generic_same_name') { - setMsg('normal', 'No record found where Generic/Salt is same as Medicine Name.'); - } else if (activeListFilter === 'company_blank') { - setMsg('normal', 'No record found with blank Company Name.'); - } - return; - } - - rows.forEach(function(row) { - var medId = parseInt(row.id || 0, 10); - var isFav = parseInt(row.is_favorite || 0, 10) === 1; - var favBtn = ''; - $tb.append('' - + '' + (row.id || 0) + '' - + '' + favBtn + '' - + '' + $('
').text(row.item_name || '').html() + '' - + '' + parseInt(row.use_count || 0, 10) + '' - + '' + $('
').text(row.last_used_at || '').html() + '' - + '' + $('
').text(row.genericname || '').html() + '' - + '' + $('
').text(row.company_name || '').html() + '' - + '' - + '' - + ''); - }); - - initMedMasterDataTable(); - - if (activeListFilter === 'generic_issue') { - setMsg('normal', rows.length + ' record(s) with unclear Generic/Salt data.'); - } else if (activeListFilter === 'generic_same_name') { - setMsg('normal', rows.length + ' record(s) where Generic/Salt matches Medicine Name.'); - } else if (activeListFilter === 'company_blank') { - setMsg('normal', rows.length + ' record(s) with blank/unclear Company Name.'); - } - }); } function initMedMasterDataTable() { @@ -348,21 +296,124 @@ return; } - if ($.fn.dataTable.isDataTable('#tbl_med_master')) { - $('#tbl_med_master').DataTable().clear().destroy(); - medMasterDataTable = null; + if (medMasterDataTable) { + return; + } + + function esc(value) { + return $('
').text(value || '').html(); } medMasterDataTable = $('#tbl_med_master').DataTable({ + processing: true, + serverSide: true, paging: true, searching: true, ordering: true, info: true, pageLength: 25, + ajax: { + url: '', + type: 'GET', + data: function(d) { + d.filter = activeListFilter; + d.scope = 'all'; + d.show_all = 1; + }, + dataSrc: function(json) { + var total = parseInt((json && json.recordsFiltered) || 0, 10); + if (!total) { + if (activeListFilter === 'generic_issue') { + setMsg('normal', 'No record found with Generic/Salt issue.'); + } else if (activeListFilter === 'generic_same_name') { + setMsg('normal', 'No record found where Generic/Salt is same as Medicine Name.'); + } else if (activeListFilter === 'company_blank') { + setMsg('normal', 'No record found with blank Company Name.'); + } else { + setMsg('normal', 'No medicine found.'); + } + } else if (activeListFilter === 'generic_issue') { + setMsg('normal', total + ' record(s) with unclear Generic/Salt data.'); + } else if (activeListFilter === 'generic_same_name') { + setMsg('normal', total + ' record(s) where Generic/Salt matches Medicine Name.'); + } else if (activeListFilter === 'company_blank') { + setMsg('normal', total + ' record(s) with blank/unclear Company Name.'); + } else { + setMsg('normal', ''); + } + return (json && json.data) ? json.data : []; + }, + error: function() { + setMsg('err', 'Unable to load medicine list. Try Refresh.'); + } + }, order: [[3, 'desc'], [2, 'asc']], + columns: [ + { + data: 'id', + render: function(data) { + return parseInt(data || 0, 10); + } + }, + { + data: 'is_favorite', + render: function(data, type, row) { + var medId = parseInt((row && row.id) || 0, 10); + var isFav = parseInt(data || 0, 10) === 1; + return ''; + } + }, + { + data: 'item_name', + render: function(data) { + return esc(data); + } + }, + { + data: 'use_count', + render: function(data) { + return parseInt(data || 0, 10); + } + }, + { + data: 'last_used_at', + render: function(data) { + return esc(data); + } + }, + { + data: 'genericname', + render: function(data) { + return esc(data); + } + }, + { + data: 'company_name', + render: function(data) { + return esc(data); + } + }, + { + data: 'id', + render: function(data) { + var medId = parseInt(data || 0, 10); + return ''; + } + }, + { + data: 'id', + render: function(data) { + var medId = parseInt(data || 0, 10); + return ''; + } + } + ], columnDefs: [ { orderable: false, targets: [1, 7, 8] }, ], + language: { + emptyTable: 'No medicine found' + } }); }