Fee sheet and Codes revenue code (#7415)
[openemr.git] / interface / super / edit_list.php
blob4a2cc1796282c42c79e6207a12ac5fddb57853f2
1 <?php
3 /**
4 * Administration Lists Module.
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Robert Down <robertdown@live.com>
11 * @author Jerry Padgett <sjpadgett@gmail.com>
12 * @copyright Copyright (c) 2007-2022 Rod Roark <rod@sunsetsystems.com>
13 * @copyright Copyright (c) 2017-2018 Brady Miller <brady.g.miller@gmail.com>
14 * @copyright Copyright (c) 2022-2023 Robert Down <robertdown@live.com>
15 * @copyright Copyright (c) 2017-2023 Jerry Padgett <sjpadgett@gmail.com>
16 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
19 require_once("../globals.php");
20 require_once("$srcdir/lists.inc.php");
21 require_once("../../custom/code_types.inc.php");
22 require_once("$srcdir/options.inc.php");
24 use OpenEMR\Common\Acl\AclExtended;
25 use OpenEMR\Common\Acl\AclMain;
26 use OpenEMR\Common\Csrf\CsrfUtils;
27 use OpenEMR\Common\Logging\EventAuditLogger;
28 use OpenEMR\Common\Twig\TwigContainer;
29 use OpenEMR\Core\Header;
31 if (!empty($_POST)) {
32 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
33 CsrfUtils::csrfNotVerified();
37 // Below allows the list to default to the first item on the list
38 // when list_id is blank.
39 $blank_list_id = '';
40 if (empty($_REQUEST['list_id'] ?? null) && empty($_REQUEST['list_id_container'] ?? null)) {
41 $list_id = 'language';
42 $blank_list_id = true;
43 } else {
44 $list_id = $_REQUEST['list_id'];
47 // Check authorization.
48 $thisauth = AclMain::aclCheckCore('admin', 'super');
49 if (!$thisauth) {
50 echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("List Editor")]);
51 exit;
54 // Compute a current checksum of the data from the database for the given list.
56 function listChecksum($list_id)
58 if ($list_id == 'feesheet') {
59 $row = sqlQuery(
60 "SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
61 "fs_category, fs_option, fs_codes" .
62 "))) AS checksum FROM fee_sheet_options"
64 } elseif ($list_id == 'code_types') {
65 $row = sqlQuery(
66 "SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
67 "ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_mask, ct_fee, ct_rel, ct_nofs, ct_diag" .
68 "))) AS checksum FROM code_types"
70 } else {
71 $row = sqlQuery(
72 "SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
73 "list_id, option_id, title, seq, is_default, option_value, mapping, notes" .
74 "))) AS checksum FROM list_options WHERE " .
75 "list_id = ?",
76 array($list_id)
79 return (0 + $row['checksum']);
82 $alertmsg = '';
84 if (isset($_POST['form_checksum']) && $_POST['formaction'] == 'save') {
85 if ($_POST['form_checksum'] != listChecksum($list_id)) {
86 $alertmsg = xl('Save rejected because someone else has changed this list. Please try again.');
90 //Limit variables for filter
91 $records_per_page = 40;
92 $list_from = ( isset($_REQUEST["list_from"]) ? intval($_REQUEST["list_from"]) : 1 );
93 $list_to = ( isset($_REQUEST["list_to"]) ? intval($_REQUEST["list_to"]) : 0);
95 // If we are saving, then save.
97 if ((($_POST['formaction'] ?? '') == 'save') && $list_id && $alertmsg == '') {
98 $opt = $_POST['opt'];
99 if ($list_id == 'feesheet') {
100 // special case for the feesheet list
101 sqlStatement("DELETE FROM fee_sheet_options");
102 for ($lino = 1; isset($opt["$lino"]['category']); ++$lino) {
103 $iter = $opt["$lino"];
104 $category = trim($iter['category']);
105 $option = trim($iter['option']);
106 $codes = trim($iter['codes']);
107 if (strlen($category) > 0 && strlen($option) > 0) {
108 sqlStatement("INSERT INTO fee_sheet_options ( " .
109 "fs_category, fs_option, fs_codes " .
110 ") VALUES ( ?,?,? )", array($category, $option, $codes));
113 } elseif ($list_id == 'code_types') {
114 // special case for code types
115 sqlStatement("DELETE FROM code_types");
116 for ($lino = 1; isset($opt["$lino"]['ct_key']); ++$lino) {
117 $iter = $opt["$lino"];
118 $ct_key = trim($iter['ct_key']);
119 $ct_id = (int)trim($iter['ct_id']);
120 $ct_seq = (int)trim($iter['ct_seq']);
121 $ct_mod = (int)trim($iter['ct_mod']);
122 $ct_just = trim($iter['ct_just']);
123 $ct_mask = trim($iter['ct_mask']);
124 $ct_fee = empty($iter['ct_fee']) ? 0 : 1;
125 $ct_rel = empty($iter['ct_rel']) ? 0 : 1;
126 $ct_nofs = empty($iter['ct_nofs']) ? 0 : 1;
127 $ct_diag = empty($iter['ct_diag']) ? 0 : 1;
128 $ct_active = empty($iter['ct_active']) ? 0 : 1;
129 $ct_label = trim($iter['ct_label']);
130 $ct_external = (int)trim($iter['ct_external']);
131 $ct_claim = empty($iter['ct_claim']) ? 0 : 1;
132 $ct_proc = empty($iter['ct_proc']) ? 0 : 1;
133 $ct_term = empty($iter['ct_term']) ? 0 : 1;
134 $ct_problem = empty($iter['ct_problem']) ? 0 : 1;
135 $ct_drug = empty($iter['ct_drug']) ? 0 : 1;
136 if (strlen($ct_key) > 0 && $ct_id > 0) {
137 sqlStatement(
138 "INSERT INTO code_types ( " .
139 "ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_mask, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external, ct_claim, ct_proc, ct_term, ct_problem, ct_drug " .
140 ") VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
141 array(
142 $ct_key,
143 $ct_id,
144 $ct_seq,
145 $ct_mod,
146 $ct_just,
147 $ct_mask,
148 $ct_fee,
149 $ct_rel,
150 $ct_nofs,
151 $ct_diag,
152 $ct_active,
153 $ct_label,
154 $ct_external,
155 $ct_claim,
156 $ct_proc,
157 $ct_term,
158 $ct_problem,
159 $ct_drug
164 } elseif ($list_id == 'issue_types') {
165 // special case for issue_types
166 sqlStatement("DELETE FROM issue_types");
167 for ($lino = 1; isset($opt["$lino"]['category']); ++$lino) {
168 $iter = $opt["$lino"];
169 $it_category = trim($iter['category']);
170 $it_type = trim($iter['type']);
171 if ((strlen($it_category) > 0) && (strlen($it_type) > 0)) {
172 sqlStatement("INSERT INTO issue_types (" .
173 "`active`,`category`,`ordering`, `type`, `plural`, `singular`, `abbreviation`, `style`, " .
174 "`force_show`, `aco_spec`) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", array(
175 trim($iter['active']),
176 $it_category,
177 trim($iter['ordering']),
178 $it_type,
179 trim($iter['plural']),
180 trim($iter['singular']),
181 trim($iter['abbreviation']),
182 trim($iter['style']),
183 trim($iter['force_show']),
184 trim($iter['aco_spec']),
188 } else {
189 // all other lists
191 // collect the option toggle if using the 'immunizations' list
192 if ($list_id == 'immunizations') {
193 $ok_map_cvx_codes = isset($_POST['ok_map_cvx_codes']) ? $_POST['ok_map_cvx_codes'] : 0;
196 for ($lino = 1; isset($opt["$lino"]['id']); ++$lino) {
197 $iter = $opt["$lino"];
198 $value = empty($iter['value']) ? 0 : (trim($iter['value']));
199 $id = trim($iter['id']);
200 $real_id = trim($iter['real_id']);
202 if (strlen($real_id) > 0 || strlen($id) > 0) {
203 // Special processing for the immunizations list
204 // Map the entered cvx codes into the immunizations table cvx_code
205 // Ensure the following conditions are met to do this:
206 // $list_id == 'immunizations'
207 // $value is an integer and greater than 0
208 // $id is set, not empty and not equal to 0
209 // (note that all these filters are important. Not allowing $id
210 // of zero here is extremely important; never remove this conditional
211 // or you risk corrupting your current immunizations database entries)
212 // $ok_map_cvx_codes is equal to 1
213 if (
214 $list_id == 'immunizations' &&
215 is_int($value) &&
216 $value > 0 &&
217 isset($id) &&
218 !empty($id) &&
219 $id != 0 &&
220 $ok_map_cvx_codes == 1
222 sqlStatement("UPDATE `immunizations` " .
223 "SET `cvx_code`= ? " .
224 "WHERE `immunization_id`= ? ", array($value, $id));
227 // Force List Based Form names to start with LBF.
228 if ($list_id == 'lbfnames' && substr($id, 0, 3) != 'LBF') {
229 $id = "LBF$id";
230 $real_id = "LBF$real_id";
233 // Force Transaction Form names to start with LBT.
234 if ($list_id == 'transactions' && substr($id, 0, 3) != 'LBT') {
235 $id = "LBT$id";
236 $real_id = "LBT$real_id";
239 if ($list_id == 'apptstat' || $list_id == 'groupstat') {
240 $notes = trim($iter['apptstat_color']) . '|' . trim($iter['apptstat_timealert']);
241 } else {
242 $notes = trim($iter['notes'] ?? '');
245 if (preg_match("/Eye_QP_/", $list_id)) {
246 if (preg_match("/^[BLR]/", $id)) {
247 $stuff = explode("_", $id)[0];
248 $iter['mapping'] = substr($stuff, 1);
249 $iter['subtype'] = substr($stuff, 0, 1);
250 } else {
251 $stuff = explode("_", $id)[0];
252 $iter['mapping'] = substr($stuff, 2);
253 $iter['subtype'] = substr($stuff, 0, 2);
257 // Delete the list item
258 sqlStatement("DELETE FROM list_options WHERE list_id = ? AND option_id = ?", array($list_id, $real_id));
259 if (strlen($id) <= 0 && strlen(trim($iter['title'])) <= 0 && empty($id) && empty($iter['title'])) {
260 continue;
262 // Insert the list item
263 sqlStatement(
264 "INSERT INTO list_options ( " .
265 "list_id, option_id, title, seq, is_default, option_value, mapping, notes, codes, toggle_setting_1, toggle_setting_2, activity, subtype " .
266 ") VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
267 array(
268 $list_id,
269 $id,
270 trim($iter['title']),
271 trim($iter['seq']),
272 trim($iter['default'] ?? 0),
273 $value,
274 trim($iter['mapping'] ?? ''),
275 $notes,
276 trim($iter['codes']),
277 trim($iter['toggle_setting_1'] ?? 0),
278 trim($iter['toggle_setting_2'] ?? 0),
279 trim($iter['activity'] ?? 0),
280 trim($iter['subtype'] ?? '')
286 EventAuditLogger::instance()->newEvent(
287 "edit_list",
288 $_SESSION['authUser'],
289 $_SESSION['authProvider'],
291 "List = $list_id"
293 } elseif (!empty($_POST['formaction']) && ($_POST['formaction'] == 'addlist')) {
294 // make a new list ID from the new list name
295 $newlistID = $_POST['newlistname'];
296 $newlistID = preg_replace("/\W/", "_", $newlistID);
298 // determine the position of this new list
299 $row = sqlQuery("SELECT max(seq) AS maxseq FROM list_options WHERE list_id= 'lists'");
300 $dup_cnt = sqlQuery("SELECT count(seq) as validate FROM list_options WHERE list_id= 'lists' AND option_id = ?", array($newlistID))['validate'];
301 if ((int)$dup_cnt === 0) {
302 // add the new list to the list-of-lists
303 sqlStatement("INSERT INTO list_options ( " .
304 "list_id, option_id, title, seq, is_default, option_value " .
305 ") VALUES ( 'lists', ?, ?, ?, '1', '0')", array($newlistID, $_POST['newlistname'], ($row['maxseq'] + 1)));
306 $list_id = $newlistID;
307 } else {
308 // send error and continue.
309 echo "<script>let error=" . js_escape(xlt("The new list") . " [" . $_POST['newlistname'] . "] " . xlt("already exists! Please try again.")) . ";</script>";
311 EventAuditLogger::instance()->newEvent(
312 "add_list",
313 $_SESSION['authUser'],
314 $_SESSION['authProvider'],
316 "List = $newlistID"
318 } elseif (!empty($_POST['formaction']) && ($_POST['formaction'] == 'deletelist')) {
319 // delete the lists options
320 sqlStatement("DELETE FROM list_options WHERE list_id = ?", array($_POST['list_id']));
321 // delete the list from the master list-of-lists
322 sqlStatement("DELETE FROM list_options WHERE list_id = 'lists' AND option_id=?", array($_POST['list_id']));
323 EventAuditLogger::instance()->newEvent(
324 "delete_list",
325 $_SESSION['authUser'],
326 $_SESSION['authProvider'],
328 "List = " . $_POST['list_id']
332 $opt_line_no = 0;
334 // Given a string of multiple instances of code_type|code|selector,
335 // make a description for each.
336 // @TODO Instead should use a function from custom/code_types.inc.php and need to remove casing functions
337 function getCodeDescriptions($codes)
339 global $code_types;
340 $arrcodes = explode('~', $codes);
341 $s = '';
342 foreach ($arrcodes as $codestring) {
343 if ($codestring === '') {
344 continue;
346 $arrcode = explode('|', $codestring);
347 $code_type = $arrcode[0];
348 // test for code with a modifier.
349 $modifier = '';
350 if (stripos($arrcode[1], ':') !== false) {
351 $tmp = explode(':', $arrcode[1]);
352 if (!empty($tmp[0] ?? null)) {
353 $code = $tmp[0] ?? '';
354 $modifier = $tmp[1] ?? '';
355 $modifier .= ($tmp[2] ?? '') ? ":" . $tmp[2] : '';
356 $modifier .= ($tmp[3] ?? '') ? ":" . $tmp[3] : '';
357 $modifier .= ($tmp[4] ?? '') ? ":" . $tmp[4] : '';
359 } else {
360 $code = $arrcode[1];
362 $selector = $arrcode[2];
363 if ($code_type == 'PROD') {
364 $row = sqlQuery("SELECT name FROM drugs WHERE drug_id = ?", array($code));
365 $desc = "$code:$selector " . $row['name'];
366 } else {
367 $row = sqlQuery("SELECT code_text FROM codes WHERE " .
368 "code_type = ? AND " .
369 "code = ? ORDER BY modifier LIMIT 1", array($code_types[$code_type]['id'], $code ));
370 $desc = "$code_type:$code " . ucfirst(strtolower($row['code_text'] ?? ''));
372 $desc = str_replace('~', ' ', $desc);
373 if (!empty($modifier ?? '')) {
374 $desc .= " " . xlt("Modifier") . ": " . $modifier;
376 if ($s) {
377 $s .= '~';
379 $s .= $desc;
381 return $s;
384 // Write one option line to the form.
386 function writeOptionLine($option_id, $title, $seq, $default, $value, $mapping = '', $notes = '', $codes = '', $tog1 = '', $tog2 = '', $active = '1', $subtype = '')
388 global $opt_line_no, $list_id;
389 ++$opt_line_no;
390 $bgcolor = "#" . (($opt_line_no & 1) ? "ddddff" : "ffdddd");
391 $checked = $default ? " checked" : "";
392 $checked_tog1 = $tog1 ? " checked" : "";
393 $checked_tog2 = $tog2 ? " checked" : "";
394 $checked_active = $active ? " checked" : "";
396 echo " <tr>\n";
398 echo " <td>";
399 //New line for hidden input, for update items
400 echo "<input type='hidden' name='opt[" . attr($opt_line_no) . "][real_id]' value='" .
401 attr($option_id) . "' size='12' maxlength='127' class='optin form-control form-control-sm' />";
402 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][id]' value='" .
403 attr($option_id) . "' size='12' maxlength='127' class='optin form-control form-control-sm' />";
404 echo "</td>\n";
405 echo " <td>";
406 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][title]' value='" .
407 attr($title) . "' size='20' maxlength='127' class='optin form-control form-control-sm'>";
408 echo "</td>\n";
410 // if not english and translating lists then show the translation
411 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
412 echo " <td align='center' class='translation'>" . xlt($title) . "</td>\n";
414 echo " <td>";
415 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][seq]' value='" .
416 attr($seq) . "' size='4' maxlength='10' class='optin form-control form-control-sm' />";
417 echo "</td>\n";
419 echo " <td>";
420 echo "<input type='checkbox' name='opt[" . attr($opt_line_no) . "][default]' value='1' " .
421 "onclick='defClicked(" . attr($opt_line_no) . ")' class='optin'$checked />";
422 echo "</td>\n";
424 if (preg_match('/Eye_QP_/', $list_id)) {
425 echo " <td>";
426 echo "<select name='opt[" . attr($opt_line_no) . "][activity]' class='optin'>";
427 foreach (
428 array(
429 1 => xl('Replace'),
430 2 => xl('Append')
431 ) as $key => $desc
433 echo "<option value='" . attr($key) . "'";
434 if ($key == $active) {
435 echo " selected";
437 echo ">" . text($desc) . "</option>";
439 echo "</select>";
440 echo "</td>";
441 } else {
442 echo " <td>";
443 echo "<input type='checkbox' name='opt[" . attr($opt_line_no) . "][activity]' value='1' " . " class='optin'$checked_active />";
444 echo "</td>\n";
446 // Tax rates, contraceptive methods and LBF names have an additional attribute.
448 if ($list_id == 'taxrate' || $list_id == 'contrameth' || $list_id == 'lbfnames' || $list_id == 'transactions') {
449 echo " <td>";
450 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][value]' value='" .
451 attr($value) . "' size='8' maxlength='15' class='optin' />";
452 echo "</td>\n";
453 } elseif ($list_id == 'adjreason') {
454 // Adjustment reasons use option_value as a reason category. This is
455 // needed to distinguish between adjustments that change the invoice
456 // balance and those that just shift responsibility of payment or
457 // are used as comments.
458 echo " <td>";
459 echo "<select name='opt[" . attr($opt_line_no) . "][value]' class='optin'>";
460 foreach (
461 array(
462 1 => xl('Charge adjustment'),
463 2 => xl('Coinsurance'),
464 3 => xl('Deductible'),
465 4 => xl('Other pt resp'),
466 5 => xl('Comment'),
467 ) as $key => $desc
469 echo "<option value='" . attr($key) . "'";
470 if ($key == $value) {
471 echo " selected";
473 echo ">" . text($desc) . "</option>";
475 echo "</select>";
476 echo "</td>\n";
477 } elseif ($list_id == 'warehouse') {
478 echo " <td>\n";
479 // Build a drop-down list of facilities.
480 $query = "SELECT id, name FROM facility ORDER BY name";
481 $fres = sqlStatement($query);
482 echo "<select name='opt[" . attr($opt_line_no) . "][value]' class='optin'>";
483 echo " <option value='0'>-- " . xlt('Unassigned') . " --\n";
484 while ($frow = sqlFetchArray($fres)) {
485 $facid = $frow['id'];
486 echo " <option value='" . attr($facid) . "'";
487 if ($facid == $value) {
488 echo " selected";
490 echo ">" . text($frow['name']) . "\n";
492 echo " </select>\n";
493 echo " </td>\n";
494 } elseif ($list_id == 'abook_type') { // Address book categories use option_value to flag category as a
495 // person-centric vs company-centric vs indifferent.
496 echo " <td>";
497 echo "<select name='opt[" . attr($opt_line_no) . "][value]' class='optin'>";
498 foreach (
499 array(
500 1 => xl('Unassigned'),
501 2 => xl('Person'),
502 3 => xl('Company'),
503 ) as $key => $desc
505 echo "<option value='" . attr($key) . "'";
506 if ($key == $value) {
507 echo " selected";
509 echo ">" . text($desc) . "</option>";
511 echo "</select>";
512 echo "</td>\n";
513 } elseif ($list_id == 'immunizations') { // Immunization categories use option_value to map list items to CVX codes.
514 echo " <td>";
515 echo "<input type='text' size='10' name='opt[" . attr($opt_line_no) . "][value]' " .
516 "value='" . attr($value) . "' onclick='sel_cvxcode(this)' " .
517 "title='" . xla('Click to select or change CVX code') . "'/>";
518 echo "</td>\n";
519 } elseif ($list_id == 'ptlistcols') {
520 echo " <td>";
521 echo generate_select_list("opt[$opt_line_no][toggle_setting_1]", 'Sort_Direction', $tog1, 'Sort Direction', null, 'option');
522 echo "</td>\n";
525 if ($list_id == 'apptstat' || $list_id == 'groupstat') {
526 list($apptstat_color, $apptstat_timealert) = explode("|", $notes);
527 echo " <td>";
528 echo "<input type='text' class='jscolor' name='opt[" . attr($opt_line_no) . "][apptstat_color]' value='" .
529 attr($apptstat_color) . "' size='6' maxlength='6' class='optin' />";
530 echo "</td>\n";
531 echo " <td>";
532 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][apptstat_timealert]' value='" .
533 attr($apptstat_timealert) . "' size='2' maxlength='2' class='optin' />";
534 echo "</td>\n";
535 echo " <td>";
536 echo "<input type='checkbox' name='opt[" . attr($opt_line_no) . "][toggle_setting_1]' value='1' " .
537 "onclick='defClicked(" . attr($opt_line_no) . ")' class='optin'$checked_tog1 />";
538 echo "</td>\n";
539 echo " <td>";
540 echo "<input type='checkbox' name='opt[" . attr($opt_line_no) . "][toggle_setting_2]' value='1' " .
541 "onclick='defClicked(" . attr($opt_line_no) . ")' class='optin'$checked_tog2 />";
542 echo "</td>\n";
543 } else {
544 // IPPF includes the ability to map each list item to a "master" identifier.
545 // Sports teams use this for some extra info for fitness levels.
546 if ($GLOBALS['ippf_specific'] || $list_id == 'fitness') {
547 echo " <td>";
548 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][mapping]' value='" .
549 attr($mapping) . "' size='12' maxlength='15' class='optin' />";
550 echo "</td>\n";
552 echo " <td>";
553 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][notes]' value='" .
554 attr($notes) . "' size='25' maxlength='255' class='optin form-control form-control-sm' ";
555 echo "/>";
556 echo "</td>\n";
559 echo " <td>";
560 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][codes]' title='" .
561 xla('Code(s)') . "' value='" .
562 attr($codes) . "' onclick='select_clin_term_code(this)' size='25' maxlength='255' class='optin form-control form-control-sm' />";
563 echo "</td>\n";
565 if (preg_match('/_issue_list$/', $list_id)) {
566 echo " <td>";
567 echo generate_select_list("opt[$opt_line_no][subtype]", 'issue_subtypes', $subtype, 'Subtype', ' ', 'optin');
568 echo "</td>\n";
570 if (preg_match('/Eye_QP_/', $list_id)) {
571 echo "<input type='hidden' name='opt[" . attr($opt_line_no) . "][subtype]' value='" . attr($subtype) . "' />";
572 echo "<input type='hidden' name='opt[" . attr($opt_line_no) . "][mapping]' value='" . attr($mapping) . "' />";
574 echo " </tr>\n";
577 // Write a form line as above but for the special case of the Fee Sheet.
579 function writeFSLine($category, $option, $codes)
581 global $opt_line_no;
583 ++$opt_line_no;
584 $bgcolor = "#" . (($opt_line_no & 1) ? "ddddff" : "ffdddd");
586 $descs = getCodeDescriptions($codes);
588 echo " <tr>\n";
590 echo " <td>";
591 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][category]' value='" .
592 attr($category) . "' size='20' maxlength='63' class='optin' />";
593 echo "</td>\n";
595 echo " <td>";
596 echo "<input type='text' name='opt[" . attr($opt_line_no) . "][option]' value='" .
597 attr($option) . "' size='20' maxlength='63' class='optin' />";
598 echo "</td>\n";
600 echo " <td align='left' class='optcell'>";
601 echo " <div id='codelist_" . attr($opt_line_no) . "'>";
602 if (strlen($descs)) {
603 $arrdescs = explode('~', $descs);
604 $i = 0;
605 foreach ($arrdescs as $desc) {
606 echo "<a href='' onclick='return delete_code(" . attr($opt_line_no) . ",$i)' title='" . xla('Delete') . "'>";
607 echo "[x]&nbsp;</a>" . text($desc) . "<br />";
608 ++$i;
611 echo "</div>";
612 echo "<a href='' onclick='return select_code(" . attr($opt_line_no) . ")'>";
613 echo "[" . xlt('Add') . "]</a>";
615 echo "<input type='hidden' name='opt[" . attr($opt_line_no) . "][codes]' value='" .
616 attr($codes) . "' />";
617 echo "<input type='hidden' name='opt[" . attr($opt_line_no) . "][descs]' value='" .
618 attr($descs) . "' />";
619 echo "</td>\n";
621 echo " </tr>\n";
626 * Helper functions for writeITLine() and writeCTLine().
628 function ctGenCell($opt_line_no, $data_array, $name, $size, $maxlength, $title = '')
630 $value = isset($data_array[$name]) ? $data_array[$name] : '';
631 $s = " <td";
632 if ($title) {
633 $s .= " title='" . attr($title) . "'";
635 $s .= ">";
636 $s .= "<input type='text' name='opt[" . attr($opt_line_no) . "][" . attr($name) . "]' value='";
637 $s .= attr($value);
638 $s .= "' size='" . attr($size) . "' maxlength='" . attr($maxlength) . "' class='optin' />";
639 $s .= "</td>\n";
640 return $s;
643 function ctGenCbox($opt_line_no, $data_array, $name, $title = '')
645 $checked = empty($data_array[$name]) ? '' : 'checked ';
646 $s = " <td";
647 if ($title) {
648 $s .= " title='" . attr($title) . "'";
650 $s .= ">";
651 $s .= "<input type='checkbox' name='opt[" . attr($opt_line_no) . "][" . attr($name) . "]' value='1' ";
652 $s .= "$checked/>";
653 $s .= "</td>\n";
654 return $s;
657 function ctSelector($opt_line_no, $data_array, $name, $option_array, $title = '')
659 $value = isset($data_array[$name]) ? $data_array[$name] : '';
660 $s = " <td title='" . attr($title) . "'>";
661 $s .= "<select name='opt[" . attr($opt_line_no) . "][" . attr($name) . "]' class='optin'>";
662 foreach ($option_array as $key => $desc) {
663 $s .= "<option value='" . attr($key) . "'";
664 if ($key == $value) {
665 $s .= " selected";
667 $s .= ">" . text($desc) . "</option>";
669 $s .= "</select>";
670 $s .= "</td>\n";
671 return $s;
674 // Write a form line as above but for the special case of Code Types.
676 function writeCTLine($ct_array)
678 global $opt_line_no, $ct_external_options;
680 ++$opt_line_no;
681 $bgcolor = "#" . (($opt_line_no & 1) ? "ddddff" : "ffdddd");
683 echo " <tr>\n";
685 echo ctGenCBox(
686 $opt_line_no,
687 $ct_array,
688 'ct_active',
689 xl('Is this code type active?')
691 echo ctGenCell(
692 $opt_line_no,
693 $ct_array,
694 'ct_key',
697 xl('Unique human-readable identifier for this type')
699 echo ctGenCell(
700 $opt_line_no,
701 $ct_array,
702 'ct_id',
705 xl('Unique numeric identifier for this type')
707 echo ctGenCell(
708 $opt_line_no,
709 $ct_array,
710 'ct_label',
713 xl('Label for this type')
715 // if not english and translating lists then show the translation
716 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
717 echo " <td align='center' class='translation'>" . xlt($ct_array['ct_label']) . "</td>\n";
719 echo ctGenCell(
720 $opt_line_no,
721 $ct_array,
722 'ct_seq',
725 xl('Numeric display order')
727 echo ctGenCell(
728 $opt_line_no,
729 $ct_array,
730 'ct_mod',
733 xl('Length of modifier, 0 if none')
735 echo ctGenCell(
736 $opt_line_no,
737 $ct_array,
738 'ct_just',
741 xl('If billing justification is used enter the name of the diagnosis code type.')
743 echo ctGenCell(
744 $opt_line_no,
745 $ct_array,
746 'ct_mask',
749 xl('Specifies formatting for codes. # = digit, @ = alpha, * = any character. Empty if not used.')
751 echo ctGenCBox(
752 $opt_line_no,
753 $ct_array,
754 'ct_claim',
755 xl('Is this code type used in claims?')
757 echo ctGenCBox(
758 $opt_line_no,
759 $ct_array,
760 'ct_fee',
761 xl('Are fees charged for this type?')
763 echo ctGenCBox(
764 $opt_line_no,
765 $ct_array,
766 'ct_rel',
767 xl('Does this type allow related codes?')
769 echo ctGenCBox(
770 $opt_line_no,
771 $ct_array,
772 'ct_nofs',
773 xl('Is this type hidden in the fee sheet?')
775 echo ctGenCBox(
776 $opt_line_no,
777 $ct_array,
778 'ct_proc',
779 xl('Is this a procedure/service type?')
781 echo ctGenCBox(
782 $opt_line_no,
783 $ct_array,
784 'ct_diag',
785 xl('Is this a diagnosis type?')
787 echo ctGenCBox(
788 $opt_line_no,
789 $ct_array,
790 'ct_term',
791 xl('Is this a Clinical Term code type?')
793 echo ctGenCBox(
794 $opt_line_no,
795 $ct_array,
796 'ct_problem',
797 xl('Is this a Medical Problem code type?')
799 echo ctGenCBox(
800 $opt_line_no,
801 $ct_array,
802 'ct_drug',
803 xl('Is this a Medication type?')
805 echo ctSelector(
806 $opt_line_no,
807 $ct_array,
808 'ct_external',
809 $ct_external_options,
810 xl('Is this using external sql tables? If it is, then choose the format.')
812 echo " </tr>\n";
816 * Special case of Issue Types
818 function writeITLine($it_array)
820 global $opt_line_no, $ISSUE_TYPE_CATEGORIES, $ISSUE_TYPE_STYLES;
821 ++$opt_line_no;
822 $bgcolor = "#" . (($opt_line_no & 1) ? "ddddff" : "ffdddd");
823 echo " <tr>\n";
824 echo ctSelector($opt_line_no, $it_array, 'category', $ISSUE_TYPE_CATEGORIES, xl('OpenEMR Application Category'));
825 echo ctGenCBox($opt_line_no, $it_array, 'active', xl('Is this active?'));
826 echo ctGenCell($opt_line_no, $it_array, 'ordering', 4, 10, xl('Order{{Sequence}}'));
827 echo ctGenCell($opt_line_no, $it_array, 'type', 15, 75, xl('Issue Type'));
828 echo ctGenCell($opt_line_no, $it_array, 'plural', 15, 75, xl('Plural'));
829 // if not english and translating lists then show the translation
830 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
831 echo " <td align='center' class='translation'>" . xlt($it_array['plural']) . "</td>\n";
833 echo ctGenCell($opt_line_no, $it_array, 'singular', 15, 75, xl('Singular'));
834 // if not english and translating lists then show the translation
835 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
836 echo " <td align='center' class='translation'>" . xlt($it_array['singular']) . "</td>\n";
838 echo ctGenCell($opt_line_no, $it_array, 'abbreviation', 5, 10, xl('Abbreviation'));
839 // if not english and translating lists then show the translation
840 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
841 echo " <td align='center' class='translation'>" . xlt($it_array['abbreviation']) . "</td>\n";
843 echo ctSelector($opt_line_no, $it_array, 'style', $ISSUE_TYPE_STYLES, xl('Standard; Simplified: only title, start date, comments and an Active checkbox;no diagnosis, occurrence, end date, referred-by or sports fields. ; Football Injury'));
844 echo ctGenCBox($opt_line_no, $it_array, 'force_show', xl('Show this category on the patient summary screen even if no issues have been entered for this category.'));
846 echo "<td>";
847 echo "<select name='opt[" . attr($opt_line_no) . "][aco_spec]' class='optin'>";
848 echo "<option value=''></option>";
849 echo AclExtended::genAcoHtmlOptions($it_array['aco_spec']);
850 echo "</select>";
851 echo "</td>";
853 echo " </tr>\n";
857 <html>
859 <head>
860 <?php echo Header::setupHeader(['select2', 'jscolor']); ?>
861 <title><?php echo xlt('List Editor'); ?></title>
862 <style>
863 .optin {
864 background-color: transparent;
867 .help {
868 cursor: help;
871 .translation {
872 color: var(--success);
874 #theform input[type=text],
875 .optin {
876 color: var(--black);
878 </style>
879 <script>
880 $(function () {
881 $(".select-dropdown").select2({
882 theme: "bootstrap4",
883 <?php require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?>
885 if (typeof error !== 'undefined') {
886 if (error) {
887 alertMsg(error);
891 $(document).on('select2:open', () => {
892 document.querySelector('.select2-search__field').focus();
894 // Keeping track of code picker requests.
895 var current_lino = 0;
896 var current_sel_name = '';
897 var current_sel_clin_term = '';
899 // Helper function to set the contents of a div.
900 // This is for Fee Sheet administration.
901 function setDivContent(id, content) {
902 if (document.getElementById) {
903 var x = document.getElementById(id);
904 x.innerHTML = '';
905 x.innerHTML = content;
907 else if (document.all) {
908 var x = document.all[id];
909 x.innerHTML = content;
913 // Given a line number, redisplay its descriptive list of codes.
914 // This is for Fee Sheet administration.
915 function displayCodes(lino) {
916 var f = document.forms[0];
917 var s = '';
918 var descs = f['opt[' + lino + '][descs]'].value;
919 if (descs.length) {
920 var arrdescs = descs.split('~');
921 for (var i = 0; i < arrdescs.length; ++i) {
922 s += "<a href='' onclick='return delete_code(" + lino + "," + i + ")' title='<?php echo xla('Delete'); ?>'>";
923 s += "[x]&nbsp;</a>" + arrdescs[i] + "<br />";
926 setDivContent('codelist_' + lino, s);
929 // Helper function to remove a Fee Sheet code.
930 function dc_substring(s, i) {
931 var r = '';
932 var j = s.indexOf('~', i);
933 if (j < 0) { // deleting last segment
934 if (i > 0) r = s.substring(0, i - 1); // omits trailing ~
936 else { // not last segment
937 r = s.substring(0, i) + s.substring(j + 1);
939 return r;
942 // Remove a generated Fee Sheet code.
943 function delete_code(lino, seqno) {
944 var f = document.forms[0];
945 var celem = f['opt[' + lino + '][codes]'];
946 var delem = f['opt[' + lino + '][descs]'];
947 var ci = 0;
948 var di = 0;
949 for (var i = 0; i < seqno; ++i) {
950 ci = celem.value.indexOf('~', ci) + 1;
951 di = delem.value.indexOf('~', di) + 1;
953 celem.value = dc_substring(celem.value, ci);
954 delem.value = dc_substring(delem.value, di);
955 displayCodes(lino);
956 return false;
959 // This invokes the find-code popup.
960 // For Fee Sheet administration.
961 function select_code(lino) {
962 current_sel_name = '';
963 current_sel_clin_term = '';
964 current_lino = lino;
965 dlgopen('../patient_file/encounter/find_code_dynamic.php', '_blank', 900, 600);
966 return false;
969 // This invokes the find-code popup.
970 // For CVX/immunization code administration.
971 function sel_cvxcode(e) {
972 current_sel_clin_term = '';
973 current_sel_name = e.name;
974 dlgopen('../patient_file/encounter/find_code_dynamic.php?codetype=CVX', '_blank', 900, 600);
977 // This invokes the find-code popup.
978 function select_clin_term_code(e) {
979 current_sel_name = '';
980 current_sel_clin_term = e.name;
981 dlgopen('../patient_file/encounter/find_code_dynamic.php', '_blank', 900, 600);
984 // This is for callback by the find-code popup.
985 function set_related(codetype, code, selector, codedesc, modifier = '') {
986 var f = document.forms[0];
987 if (current_sel_clin_term) {
988 // Coming from the Clinical Terms Code(s) edit
989 var e = f[current_sel_clin_term];
990 var s = e.value;
991 if (code) {
992 if (s.length > 0) {
993 s += ';';
995 s += codetype + ':' + code;
997 else {
998 s = '';
1000 e.value = s;
1002 else if (current_sel_name) {
1003 // Coming from Immunizations edit
1004 var e = f[current_sel_name];
1005 var s = e.value;
1006 if (code) {
1007 s = code;
1009 else {
1010 s = '0';
1012 e.value = s;
1014 else {
1015 // Coming from Fee Sheet edit
1016 var celem = f['opt[' + current_lino + '][codes]'];
1017 var delem = f['opt[' + current_lino + '][descs]'];
1018 var i = 0;
1019 while ((i = codedesc.indexOf('~')) >= 0) {
1020 codedesc = codedesc.substring(0, i) + ' ' + codedesc.substring(i+1);
1022 if (code) {
1023 if (modifier) {
1024 code = code + ':' + modifier;
1026 if (celem.value) {
1027 celem.value += '~';
1028 delem.value += '~';
1030 celem.value += codetype + '|' + code + '|' + selector;
1031 if (codetype == 'PROD') {
1032 delem.value += code + ':' + selector + ' ' + codedesc;
1033 } else {
1034 delem.value += codetype + ':' + code + ' ' + codedesc;
1036 } else {
1037 celem.value = '';
1038 delem.value = '';
1040 displayCodes(current_lino);
1044 // This is for callback by the find-code popup.
1045 // Deletes the specified codetype:code from the currently selected list.
1046 function del_related(s) {
1047 var f = document.forms[0];
1048 if (current_sel_clin_term) {
1049 // Coming from the Clinical Terms Code(s) edit
1050 my_del_related(s, f[current_sel_clin_term], false);
1052 else if (current_sel_name) {
1053 // Coming from Immunizations edit
1054 f[current_sel_name].value = '0';
1056 else {
1057 // Coming from Fee Sheet edit
1058 f['opt[' + current_lino + '][codes]'].value = '';
1059 f['opt[' + current_lino + '][descs]'].value = '';
1060 displayCodes(current_lino);
1064 // This is for callback by the find-code popup.
1065 // Returns the array of currently selected codes with each element in codetype:code format.
1066 function get_related() {
1067 var f = document.forms[0];
1068 if (current_sel_clin_term) {
1069 return f[current_sel_clin_term].value.split(';');
1071 return [];
1074 // Called when a "default" checkbox is clicked. Clears all the others.
1075 function defClicked(lino) {
1076 var f = document.forms[0];
1077 for (var i = 1; f['opt[' + i + '][default]']; ++i) {
1078 if (i != lino) f['opt[' + i + '][default]'].checked = false;
1082 // Form validation and submission.
1083 // This needs more validation.
1084 function mysubmit() {
1085 var f = document.forms[0];
1086 if (f.list_id.value == 'code_types') {
1087 for (var i = 1; f['opt[' + i + '][ct_key]'].value; ++i) {
1088 var ikey = 'opt[' + i + ']';
1089 for (var j = i + 1; f['opt[' + j + '][ct_key]'].value; ++j) {
1090 var jkey = 'opt[' + j + ']';
1091 if (f[ikey + '[ct_key]'].value == f[jkey + '[ct_key]'].value) {
1092 alert(<?php echo xlj('Error: duplicated name on line') ?> + ' ' + j);
1093 return;
1095 if (parseInt(f[ikey + '[ct_id]'].value) == parseInt(f[jkey + '[ct_id]'].value)) {
1096 alert(<?php echo xlj('Error: duplicated ID on line') ?> + ' ' + j);
1097 return;
1102 else if (f['opt[1][id]']) {
1103 // Check for duplicate IDs.
1104 for (var i = 1; f['opt[' + i + '][id]']; ++i) {
1105 var ikey = 'opt[' + i + '][id]';
1106 if (f[ikey].value == '') continue;
1107 for (var j = i+1; f['opt[' + j + '][id]']; ++j) {
1108 var jkey = 'opt[' + j + '][id]';
1109 if (f[ikey].value.toUpperCase() == f[jkey].value.toUpperCase()) {
1110 alert(<?php echo xlj('Error: duplicated ID') ?> + ': ' + f[jkey].value);
1111 f[jkey].scrollIntoView();
1112 f[jkey].focus();
1113 f[jkey].select();
1114 return;
1119 f.submit();
1122 // This is invoked when a new list is chosen.
1123 // Disables all buttons and actions so certain bad things cannot happen.
1124 function listSelected() {
1125 var f = document.forms[0];
1126 // For jQuery 1.6 and later, change ".attr" to ".prop".
1127 $(":button").attr("disabled", true);
1128 f.formaction.value = '';
1129 f.submit();
1132 </script>
1134 </head>
1136 <body class="body_top">
1137 <form method='post' name='theform' id='theform' action='edit_list.php'>
1138 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
1139 <input type="hidden" id="list_from" name="list_from" value="<?php echo attr($list_from);?>"/>
1140 <input type="hidden" id="list_to" name="list_to" value="<?php echo attr($list_to);?>"/>
1141 <nav class="navbar navbar-light bg-light navbar-expand-md fixed-top">
1142 <div class="container-fluid">
1143 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar-list" aria-controls="navbar-list" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
1144 <a class="navbar-brand" href="#"><?php echo xlt('Manage Lists'); ?></a>
1146 <!-- Collect the nav links, forms, and other content for toggling -->
1147 <div class="collapse navbar-collapse" id="navbar-list">
1148 <ul class="nav navbar-nav">
1149 <li class="nav-item"><a class="nav-link" href="#" data-toggle="modal" data-target="#modal-new-list"><i class="fa fa-plus"></i>&nbsp;<?php echo xlt('New List'); ?></a></li>
1150 <li class="nav-item"><a class="nav-link deletelist" href="#" id="<?php echo attr($list_id); ?>"><i class="fa fa-trash"></i>&nbsp;<?php echo xlt('Delete List'); ?></a></li>
1151 </ul>
1152 <input type="hidden" name="formaction" id="formaction" />
1153 <div class="form-inline my-2 my-lg-0 navbar-left">
1154 <select name='list_id' class="form-control select-dropdown" id="list_id">
1155 <?php
1157 * Keep proper list name (otherwise list name changes according to
1158 * the options shown on the screen).
1160 $list_id_container = $_GET["list_id_container"] ?? null;
1161 if (isset($_GET["list_id_container"]) && strlen($list_id_container) > 0) {
1162 $list_id = $list_id_container;
1165 // List order depends on language translation options.
1166 $lang_id = empty($_SESSION['language_choice']) ? '1' : $_SESSION['language_choice'];
1168 if (!$GLOBALS['translate_lists']) {
1169 $res = sqlStatement("SELECT option_id, title FROM list_options WHERE " .
1170 "list_id = 'lists' ORDER BY title, seq");
1171 } else {
1172 // Use and sort by the translated list name.
1173 $res = sqlStatement(
1174 "SELECT lo.option_id, " .
1175 "COALESCE((SELECT ld.definition FROM lang_constants AS lc, lang_definitions AS ld " .
1176 "WHERE lc.constant_name = lo.title AND ld.cons_id = lc.cons_id AND ld.lang_id = ? " .
1177 "AND ld.definition IS NOT NULL AND ld.definition != '' LIMIT 1), lo.title) AS title " .
1178 "FROM list_options AS lo " .
1179 "WHERE lo.list_id = 'lists' AND lo.edit_options = 1 " .
1180 "ORDER BY title, lo.seq",
1181 array($lang_id)
1185 while ($row = sqlFetchArray($res)) {
1186 // This allows the list to default to the first item on the list
1187 // when the list_id request parameter is blank.
1188 if (($blank_list_id) && ($list_id == 'language')) {
1189 $list_id = $row['option_id'];
1190 $blank_list_id = false;
1193 $key = $row['option_id'];
1194 echo "<option value='" . attr($key) . "'";
1195 if ($key == $list_id) {
1196 echo " selected";
1198 echo ">" . text($row['title']) . "</option>\n";
1202 </select>
1203 </div>
1205 <!--Added filter-->
1206 <script>
1207 function lister() {
1208 var queryParams = getQueryStringAsObject();
1209 var list_from = parseInt($("#list-from").val());
1210 var list_to = parseInt($("#list-to").val());
1211 var list_id_container = $("#list_id").val();
1213 if( list_from > list_to ){
1214 alert(<?php echo xlj("Please enter a enter valid range"); ?>);
1215 return false;
1217 if( list_from >= 0 ){
1218 queryParams['list_from'] = list_from;
1221 if( list_to >= 0 ){
1222 queryParams['list_to'] = list_to;
1224 if( list_id_container.length > 0 ){
1225 queryParams['list_id_container'] = list_id_container;
1227 var urlParts = document.URL.split('?');
1228 var newUrl = urlParts[0] + '?' + $.param(queryParams);
1229 window.location.replace(newUrl);
1231 </script>
1232 <?php
1233 $urlFrom = ($list_from > 0 ? $list_from : 1);
1234 $urlTo = ($list_to > 0 ? $list_to : $records_per_page);
1236 <div class="blck-filter float-left w-auto my-2 my-lg-0" style="display: none;">
1237 <div id="input-type-from" class="float-left"><?php echo xlt("From"); ?>&nbsp;<input autocomplete="off" id="list-from" value="<?php echo attr($urlFrom);?>" style="margin-right: 10px; width: 40px;">
1238 <?php echo xlt("To{{Range}}"); ?>&nbsp;<input autocomplete="off" id="list-to" value="<?php echo attr($urlTo); ?>" style=" margin-right: 10px; width: 40px;">
1239 </div>
1240 <div class="float-left"><input type="button" value="<?php echo xla('Show records'); ?>" onclick="lister()"></div>
1241 </div>
1242 <!--Happy end-->
1243 <div class="float-left ml-2 my-2 my-lg-0" id="total-record"></div>
1244 </div><!-- /.navbar-collapse -->
1245 </div>
1246 </nav>
1248 <table class="table table-striped table-sm" style="margin-top: 55px;">
1249 <thead>
1250 <tr>
1251 <?php if ($list_id == 'feesheet') : ?>
1252 <th><?php echo xlt('Group'); ?></th>
1253 <th><?php echo xlt('Option'); ?></th>
1254 <th><?php echo xlt('Generates'); ?></th>
1255 <?php elseif ($list_id == 'code_types') : ?>
1256 <th><?php echo xlt('Active{{Code}}'); ?></th>
1257 <th><?php echo xlt('Key'); ?></th>
1258 <th><?php echo xlt('ID'); ?></th>
1259 <th><?php echo xlt('Label'); ?></th>
1260 <?php //show translation column if not english and the translation lists flag is set
1261 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
1262 echo "<th class='font-weight-bold'>" . xlt('Translation') . "<span class='help' title='" . xla('The translated Title that will appear in current language') . "'> (?)</span></th>";
1263 } ?>
1264 <th><?php echo xlt('Seq'); ?></th>
1265 <th><?php echo xlt('ModLength'); ?></th>
1266 <th><?php echo xlt('Justify'); ?></th>
1267 <th><?php echo xlt('Mask'); ?></th>
1268 <th><?php echo xlt('Claims'); ?></th>
1269 <th><?php echo xlt('Fees'); ?></th>
1270 <th><?php echo xlt('Relations'); ?></th>
1271 <th><?php echo xlt('Hide'); ?></th>
1272 <th><?php echo xlt('Procedure'); ?></th>
1273 <th><?php echo xlt('Diagnosis'); ?></th>
1274 <th><?php echo xlt('Clinical Term'); ?></th>
1275 <th><?php echo xlt('Medical Problem'); ?></th>
1276 <th><?php echo xlt('Drug'); ?></th>
1277 <th><?php echo xlt('External'); ?></th>
1278 <?php elseif ($list_id == 'apptstat' || $list_id == 'groupstat') : ?>
1279 <th><?php echo xlt('ID'); ?></th>
1280 <th><?php echo xlt('Title'); ?></th>
1281 <th><?php echo xlt('Order{{Sequence}}'); ?></th>
1282 <th><?php echo xlt('Default'); ?></th>
1283 <th><?php echo xlt('Active{{Appointment}}'); ?></th>
1284 <th><?php echo xlt('Color'); ?></th>
1285 <th><?php echo xlt('Alert Time'); ?></th>
1286 <th><?php echo xlt('Check In'); ?>&nbsp;&nbsp;&nbsp;&nbsp;</th>
1287 <th><?php echo xlt('Check Out'); ?></th>
1288 <th><?php echo xlt('Code(s)'); ?></th>
1289 <?php elseif ($list_id == 'issue_types') : ?>
1290 <th><?php echo xlt('OpenEMR Application Category'); ?></th>
1291 <th><?php echo xlt('Active{{Issue}}'); ?></th>
1292 <th><?php echo xlt('Order{{Sequence}}'); ?></th>
1293 <th><?php echo xlt('Type'); ?></th>
1294 <th><?php echo xlt('Plural'); ?></th>
1295 <?php //show translation column if not english and the translation lists flag is set
1296 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
1297 echo "<th>" . xlt('Translation') . "<span class='help' title='" . xla('The translated Title that will appear in current language') . "'> (?)</span></th>";
1298 } ?>
1299 <th><?php echo xlt('Singular'); ?></th>
1300 <?php //show translation column if not english and the translation lists flag is set
1301 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
1302 echo "<th>" . xlt('Translation') . "<span class='help' title='" . xla('The translated Title that will appear in current language') . "'> (?)</span></th>";
1303 } ?>
1304 <th><?php echo xlt('Mini'); ?></th>
1305 <?php //show translation column if not english and the translation lists flag is set
1306 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
1307 echo "<th>" . xlt('Translation') . "<span class='help' title='" . xla('The translated Title that will appear in current language') . "'> (?)</span></th>";
1308 } ?>
1309 <th><?php echo xlt('Style'); ?></th>
1310 <th><?php echo xlt('Force Show'); ?></th>
1311 <th><?php echo xlt('Access Control'); ?></th>
1312 <?php else : ?>
1313 <th title='<?php echo xla('Click to edit'); ?>'><?php echo xlt('ID'); ?></th>
1314 <th><?php echo xlt('Title'); ?></th>
1315 <?php //show translation column if not english and the translation lists flag is set
1316 if ($GLOBALS['translate_lists'] && $_SESSION['language_choice'] > 1) {
1317 echo "<th>" . xlt('Translation') . "<span class='help' title='" . xla('The translated Title that will appear in current language') . "'> (?)</span></th>";
1318 } ?>
1319 <th><?php echo xlt('Order{{Sequence}}'); ?></th>
1320 <th><?php echo xlt('Default'); ?></th>
1321 <th><?php echo xlt('Active'); ?></th>
1322 <?php if ($list_id == 'taxrate') { ?>
1323 <th><?php echo xlt('Rate'); ?></th>
1324 <?php } elseif ($list_id == 'contrameth') { ?>
1325 <th><?php echo xlt('Effectiveness'); ?></th>
1326 <?php } elseif ($list_id == 'lbfnames' || $list_id == 'transactions') { ?>
1327 <th title='<?php echo xla('Number of past history columns'); ?>'><?php echo xlt('Repeats'); ?></th>
1328 <?php } elseif ($list_id == 'fitness') { ?>
1329 <th><?php echo xlt('Color:Abbr'); ?></th>
1330 <?php } elseif ($list_id == 'adjreason' || $list_id == 'abook_type') { ?>
1331 <th><?php echo xlt('Type'); ?></th>
1332 <?php } elseif ($list_id == 'warehouse') { ?>
1333 <th><?php echo xlt('Facility'); ?></th>
1334 <?php } elseif ($list_id == 'immunizations') { ?>
1335 <th>&nbsp;&nbsp;&nbsp;&nbsp;<?php echo xlt('CVX Code Mapping'); ?></th>
1336 <?php } elseif ($list_id == 'ptlistcols') { ?>
1337 <th>&nbsp;&nbsp;&nbsp;&nbsp;<?php echo xlt('Default Sort Direction'); ?></th>
1338 <?php }
1339 if ($GLOBALS['ippf_specific']) { ?>
1340 <th><?php echo xlt('Global ID'); ?></th>
1341 <?php } ?>
1342 <th><?php
1343 if ($list_id == 'language') {
1344 echo xlt('ISO 639 Code');
1345 } elseif ($list_id == 'personal_relationship' || $list_id == 'religious_affiliation' || $list_id == 'ethnicity' || $list_id == 'race' || $list_id == 'drug_route') {
1346 echo xlt('HL7-V3 Concept Code');
1347 } elseif ($list_id == 'Immunization_Completion_Status') {
1348 echo xlt('Treatment Completion Status');
1349 } elseif ($list_id == 'race') {
1350 echo xlt('CDC Code');
1351 } elseif ($list_id == 'Immunization_Manufacturer') {
1352 echo xlt('MVX Code');
1353 } elseif ($list_id == 'marital') {
1354 echo xlt('Marital Status');
1355 } elseif ($list_id == 'county') {
1356 echo xlt('INCITS Code'); //International Committee for Information Technology Standards
1357 } elseif ($list_id == 'immunization_registry_status' || $list_id == 'imm_vac_eligibility_results') {
1358 echo xlt('IIS Code');
1359 } elseif ($list_id == 'publicity_code') {
1360 echo xlt('CDC Code');
1361 } elseif ($list_id == 'immunization_refusal_reason' || $list_id == 'immunization_informationsource') {
1362 echo xlt('CDC-NIP Code');
1363 } elseif ($list_id == 'next_of_kin_relationship' || $list_id == 'immunization_administered_site') {
1364 echo xlt('HL7 Code');
1365 } elseif ($list_id == 'immunization_observation') {
1366 echo xlt('LOINC Code');
1367 } elseif ($list_id == 'page_validation') {
1368 echo xlt('Page Validation');
1369 } elseif ($list_id == 'lbfnames') {
1370 echo xlt('Attributes');
1371 } elseif ($list_id == "external_patient_education") {
1372 echo xlt('External URL');
1373 } elseif ($list_id == "default_open_tabs") {
1374 echo xlt("URL");
1375 } else {
1376 echo xlt('Notes');
1377 } ?></th>
1379 <th><?php echo xlt('Code(s)'); ?></th>
1380 <?php
1381 if (preg_match('/_issue_list$/', $list_id)) { ?>
1382 <th><?php echo xlt('Subtype'); ?></th>
1383 <?php
1385 endif; // end not fee sheet ?>
1386 </tr>
1387 </thead>
1388 <tbody>
1389 <?php
1390 // Get the selected list's elements.
1391 if ($list_id) {
1392 $sql_limits = 'ASC LIMIT 0, ' . escape_limit($records_per_page);
1393 $total_rows = 0;
1394 if ($list_from > 0) {
1395 $list_from--;
1397 if ($list_to > 0) {
1398 $sql_limits = " ASC LIMIT " . escape_limit($list_from) . (intval($list_to) > 0 ? ", " . escape_limit($list_to - $list_from) : "");
1401 if ($list_id == 'feesheet') {
1402 $res = sqlStatement("SELECT count(*) as total_rows FROM fee_sheet_options ORDER BY fs_category, fs_option");
1403 $total_rows = sqlFetchArray($res)["total_rows"];
1405 $res = sqlStatement("SELECT * FROM fee_sheet_options " .
1406 "ORDER BY fs_category, fs_option " . $sql_limits);
1407 while ($row = sqlFetchArray($res)) {
1408 writeFSLine($row['fs_category'], $row['fs_option'], $row['fs_codes']);
1410 for ($i = 0; $i < 3; ++$i) {
1411 writeFSLine('', '', '');
1413 } elseif ($list_id == 'code_types') {
1414 $res = sqlStatement("SELECT count(*) as total_rows FROM code_types ORDER BY ct_seq, ct_key");
1415 $total_rows = sqlFetchArray($res)["total_rows"];
1417 $res = sqlStatement("SELECT * FROM code_types " .
1418 "ORDER BY ct_seq, ct_key " . $sql_limits);
1419 while ($row = sqlFetchArray($res)) {
1420 writeCTLine($row);
1422 for ($i = 0; $i < 3; ++$i) {
1423 writeCTLine(array());
1425 } elseif ($list_id == 'issue_types') {
1426 $res = sqlStatement("SELECT count(*) as total_rows FROM issue_types ORDER BY category, ordering");
1427 $total_rows = sqlFetchArray($res)["total_rows"];
1429 $res = sqlStatement("SELECT * FROM issue_types " .
1430 "ORDER BY category, ordering " . $sql_limits);
1431 while ($row = sqlFetchArray($res)) {
1432 writeITLine($row);
1434 for ($i = 0; $i < 3; ++$i) {
1435 writeITLine(array());
1437 } else {
1438 $res = sqlStatement("SELECT count(*) as total_rows
1439 FROM list_options AS lo
1440 RIGHT JOIN list_options as lo2 on lo2.option_id = lo.list_id AND lo2.list_id = 'lists' AND lo2.edit_options = 1
1441 WHERE lo.list_id = ? AND lo.edit_options = 1", array($list_id));
1442 $total_rows = sqlFetchArray($res)["total_rows"];
1445 $res = sqlStatement("SELECT lo.*
1446 FROM list_options AS lo
1447 RIGHT JOIN list_options as lo2 on lo2.option_id = lo.list_id AND lo2.list_id = 'lists' AND lo2.edit_options = 1
1448 WHERE lo.list_id = ? AND lo.edit_options = 1
1449 ORDER BY seq,title " . $sql_limits, array($list_id));
1451 while ($row = sqlFetchArray($res)) {
1452 writeOptionLine(
1453 $row['option_id'],
1454 $row['title'],
1455 $row['seq'],
1456 $row['is_default'],
1457 $row['option_value'],
1458 $row['mapping'],
1459 $row['notes'],
1460 $row['codes'],
1461 $row['toggle_setting_1'],
1462 $row['toggle_setting_2'],
1463 $row['activity'],
1464 $row['subtype']
1467 for ($i = 0; $i < 3; ++$i) {
1468 writeOptionLine('', '', '', '', 0);
1473 </tbody>
1474 </table>
1476 <?php if ($list_id == 'immunizations') { ?>
1477 <p> <?php echo xlt('Is it ok to map these CVX codes to already existent immunizations?') ?>
1478 <input type='checkbox' name='ok_map_cvx_codes' id='ok_map_cvx_codes' value='1'/>
1479 </p>
1480 <?php } // end if($list_id == 'immunizations') ?>
1483 <button type="submit" name='form_save' id='form_save' class="btn btn-secondary btn-save"><?php echo xlt('Save'); ?></button>
1484 </p>
1486 <input type='hidden' name='form_checksum' value='<?php echo listChecksum($list_id); ?>' />
1488 </form>
1490 <div class="modal fade" id="modal-new-list" tabindex="-1" role="dialog">
1491 <div class="modal-dialog" role="document">
1492 <div class="modal-content">
1493 <form action="edit_list.php" method="post" class="form">
1494 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
1495 <div class="modal-header">
1496 <h4 class="modal-title"><?php echo xlt('New List'); ?></h4>
1497 <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo xla('Close'); ?>"><i class="fa fa-times" aria-hidden="true"></i></button>
1498 </div>
1499 <div class="modal-body">
1500 <label for="newlistname" class="control-label"><?php echo xlt('List Name'); ?></label>
1501 <input type="text" size="20" class="form-control" maxlength="100" name="newlistname" id="newlistname" />
1502 <input type="hidden" name="formaction" value="addlist">
1504 </div>
1505 <div class="modal-footer text-right">
1506 <button type="submit" class="btn btn-secondary btn-save"><?php echo xlt('Save'); ?></button>
1507 <button type="button" class="btn btn-link btn-cancel" data-dismiss="modal"><?php echo xlt('Cancel'); ?></button>
1508 </div>
1509 </form>
1510 </div><!-- /.modal-content -->
1511 </div><!-- /.modal-dialog -->
1512 </div><!-- /.modal #modal-new-list -->
1514 <script>
1515 // jQuery stuff to make the page a little easier to use
1517 $(function () {
1518 $("#form_save").click(function (e) {
1519 e.preventDefault();
1520 SaveChanges();
1522 $("#list_id").change(function () {
1523 $("#list_from").val(1);
1524 $("#list_to").val('');
1526 $('#theform').submit();
1529 $(".newlist").click(function () {
1530 NewList(this);
1532 $(".savenewlist").click(function () {
1533 SaveNewList(this);
1535 $(".deletelist").click(function () {
1536 DeleteList(this);
1539 var totalRecords = '<?php echo attr($res->_numOfRows);?>';
1540 var totalRecordDiv = $('#total-record');
1541 if( totalRecordDiv ){
1542 totalRecordDiv.text("<?php echo xlt("Showing items"); ?>: <?php echo ( $list_to > 0 ? attr($list_from + 1) . " - " . attr($list_to) : attr($res->_numOfRows) );?> of <?php echo attr($total_rows);?>");
1545 var queryParams = getQueryStringAsObject();
1546 var listIdCont = null;
1547 if (typeof queryParams['list_id_container'] !== 'undefined') {
1548 listIdCont = queryParams['list_id_container'];
1552 if( totalRecords >= <?php echo attr($records_per_page);?> || listIdCont != null || $("#list_to").val() > 0) {
1553 $(".blck-filter").show();
1556 //prevent Enter button press on filter
1557 $('.blck-filter').on('keyup keypress', function(e)
1559 var keyCode = e.keyCode || e.which;
1560 if(keyCode == 13)
1562 return false;
1566 var SaveChanges = function () {
1567 $("#formaction").val("save");
1568 // $('#theform').submit();
1569 mysubmit();
1572 // show the DIV to create a new list
1573 var NewList = function (btnObj) {
1574 // show the field details DIV
1575 $('#newlistdetail').css('visibility', 'visible');
1576 $('#newlistdetail').css('display', 'block');
1577 $(btnObj).parent().append($("#newlistdetail"));
1578 $('#newlistdetail > #newlistname').focus();
1580 // save the new list
1581 var SaveNewList = function () {
1582 // the list name can only have letters, numbers, spaces and underscores
1583 // AND it cannot start with a number
1584 if ($("#newlistname").val().match(/^\d+/)) {
1585 alert(<?php echo xlj('List names cannot start with numbers.'); ?>);
1586 return false;
1588 var validname = $("#newlistname").val().replace(/[^A-za-z0-9 -]/g, "_"); // match any non-word characters and replace them
1589 if (validname != $("#newlistname").val()) {
1590 if (!confirm(<?php echo xlj('Your list name has been changed to meet naming requirements.'); ?> + '\n' + <?php echo xlj('Please compare the new name'); ?> + ', \'' + validname + '\' ' + <?php echo xlj('with the old name'); ?> + ', \'' + $("#newlistname").val() + '\'.\n' + <?php echo xlj('Do you wish to continue with the new name?'); ?>)) {
1591 return false;
1594 $("#newlistname").val(validname);
1596 // submit the form to add a new field to a specific group
1597 $("#formaction").val("addlist");
1598 $("#theform").submit();
1600 // actually delete an entire list from the database
1601 var DeleteList = function (btnObj) {
1602 var listid = $(btnObj).attr("id");
1603 if (confirm(<?php echo xlj('WARNING'); ?> + ' - ' + <?php echo xlj('This action cannot be undone.'); ?> + '\n' + <?php echo xlj('Are you sure you wish to delete the entire list'); ?> + '(' + listid + ")?")) {
1604 // submit the form to add a new field to a specific group
1605 $("#formaction").val("deletelist");
1606 $("#deletelistname").val(listid);
1607 $("#theform").submit();
1612 function getQueryStringAsObject() {
1613 var paramsString = document.URL.split('?');
1614 var paramsFull = (paramsString.length > 1) ? paramsString[1].split('&') : [];
1615 var listIdCont = null;
1616 var queryParameter;
1617 var resObject = {};
1618 for (var i = 0; i < paramsFull.length; i++ ) {
1619 queryParameter = paramsFull[i].split('=');
1620 resObject[queryParameter[0]] = queryParameter[1];
1622 return resObject;
1625 <?php
1626 if ($alertmsg) {
1627 echo " alert(" . js_escape($alertmsg) . ");\n";
1631 </script>
1632 </body>
1633 </html>