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 Jerry Padgett <sjpadgett@gmail.com>
11 * @copyright Copyright (c) 2009-2021 Rod Roark <rod@sunsetsystems.com>
12 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
13 * @copyright Copyright (c) 2018-2020 Jerry Padgett <sjpadgett@gmail.com>
14 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
17 if (isset($_GET['isPortal']) && (int)$_GET['isPortal'] !== 0) {
18 require_once(__DIR__
. "/../../../src/Common/Session/SessionUtil.php");
19 OpenEMR\Common\Session\SessionUtil
::portalSessionStart();
20 if (isset($_SESSION['pid']) && isset($_SESSION['patient_portal_onsite_two'])) {
21 $ignoreAuth_onsite_portal = true;
23 OpenEMR\Common\Session\SessionUtil
::portalSessionCookieDestroy();
28 require_once("../../globals.php");
29 require_once("$srcdir/api.inc");
30 require_once("$srcdir/forms.inc");
31 require_once("$srcdir/options.inc.php");
32 require_once("$srcdir/patient.inc");
33 require_once($GLOBALS['fileroot'] . '/custom/code_types.inc.php');
34 require_once("$srcdir/FeeSheetHtml.class.php");
36 use OpenEMR\Common\Acl\AclMain
;
37 use OpenEMR\Common\Csrf\CsrfUtils
;
38 use OpenEMR\Core\Header
;
40 $CPR = 4; // cells per row
48 global $item_count, $cell_count, $historical_ids;
49 if ($item_count > 0) {
50 // echo " </td>";
53 foreach ($historical_ids as $key => $dummy) {
54 // $historical_ids[$key] .= " </td>";
55 $historical_ids[$key] .= "</td>";
64 global $cell_count, $CPR, $historical_ids;
66 if ($cell_count > 0) {
67 for (; $cell_count < $CPR; ++
$cell_count) {
68 echo "<td class='border-top-0'></td>";
69 foreach ($historical_ids as $key => $dummy) {
70 $historical_ids[$key] .= "<td class='border-top-0'></td>";
74 foreach ($historical_ids as $key => $dummy) {
75 echo $historical_ids[$key];
83 // $is_lbf is defined in trend_form.php and indicates that we are being
84 // invoked from there; in that case the current encounter is irrelevant.
85 $from_trend_form = !empty($is_lbf);
86 // Yet another invocation from somewhere other than encounter.
87 // don't show any action buttons.
88 $from_lbf_edit = isset($_GET['isShow']) ?
1 : 0;
89 $patient_portal = $ignoreAuth_onsite_portal ?
1 : 0;
90 $from_lbf_edit = $patient_portal ?
1 : $from_lbf_edit;
91 // This is true if the page is loaded into an iframe in add_edit_issue.php.
92 $from_issue_form = !empty($_REQUEST['from_issue_form']);
94 $formname = isset($_GET['formname']) ?
$_GET['formname'] : '';
95 $formid = isset($_GET['id']) ?
(int)$_GET['id'] : 0;
96 $portalid = isset($_GET['portalid']) ?
(int)$_GET['portalid'] : 0;
98 $form_origin = isset($_GET['formOrigin']) ?
(int)$_GET['formOrigin'] : null;
99 $is_portal_module = $form_origin === 2;
100 $is_portal_dashboard = $form_origin === 1; // 0 is portal
101 // can be used to assign to existing encounter
102 $portal_form_pid = 0;
103 if ($form_origin !== null) {
104 $portal_form_pid = sqlQuery(
105 "SELECT id, pid FROM `onsite_documents` WHERE `encounter` != 0 AND `encounter` = ?",
109 $is_core = !($portal_form_pid ||
$patient_portal ||
$is_portal_dashboard ||
$is_portal_module);
111 $visitid = (int)(empty($_GET['visitid']) ?
$encounter : $_GET['visitid']);
113 // If necessary get the encounter from the forms table entry for this form.
114 if ($formid && !$visitid && $is_core) {
116 "SELECT pid, encounter FROM forms WHERE " .
117 "form_id = ? AND formdir = ? AND deleted = 0",
118 array($formid, $formname)
120 $visitid = (int)$frow['encounter'];
121 if ($frow['pid'] != $pid) {
122 die("Internal error: patient ID mismatch!");
126 if (!$from_trend_form && !$visitid && !$from_lbf_edit && $is_core) {
127 die("Internal error: we do not seem to be in an encounter!");
131 getLayoutProperties($formname, $grparr, '*');
133 $formtitle = $lobj['grp_title'];
134 $formhistory = 0 +
$lobj['grp_repeats'];
135 $grp_last_update = $lobj['grp_last_update'];
137 if (!empty($lobj['grp_columns'])) {
138 $CPR = (int)$lobj['grp_columns'];
140 if (!empty($lobj['grp_size'])) {
141 $FONTSIZE = (int)$lobj['grp_size'];
143 if (!empty($lobj['grp_issue_type'])) {
144 $LBF_ISSUE_TYPE = $lobj['grp_issue_type'];
146 if (!empty($lobj['grp_aco_spec'])) {
147 $LBF_ACO = explode('|', $lobj['grp_aco_spec']);
149 if ($lobj['grp_services']) {
150 $LBF_SERVICES_SECTION = $lobj['grp_services'] == '*' ?
'' : $lobj['grp_services'];
152 if ($lobj['grp_products']) {
153 $LBF_PRODUCTS_SECTION = $lobj['grp_products'] == '*' ?
'' : $lobj['grp_products'];
155 if ($lobj['grp_diags']) {
156 $LBF_DIAGS_SECTION = $lobj['grp_diags'] == '*' ?
'' : $lobj['grp_diags'];
159 $LBF_REFERRALS_SECTION = !empty($lobj['grp_referrals']);
161 $LBF_SECTION_DISPLAY_STYLE = $lobj['grp_init_open'] ?
'block' : 'none';
163 // $LBF_ENABLE_SAVE_CLOSE = !empty($lobj['grp_save_close']);
164 $LBF_ENABLE_SAVE_CLOSE = !empty($GLOBALS['gbl_form_save_close']);
166 // Check access control.
167 if (!AclMain
::aclCheckCore('admin', 'super') && !empty($LBF_ACO)) {
168 $auth_aco_write = AclMain
::aclCheckCore($LBF_ACO[0], $LBF_ACO[1], '', 'write');
169 $auth_aco_addonly = AclMain
::aclCheckCore($LBF_ACO[0], $LBF_ACO[1], '', 'addonly');
170 // echo "\n<!-- '$auth_aco_write' '$auth_aco_addonly' -->\n"; // debugging
171 if (!$auth_aco_write && !($auth_aco_addonly && !$formid)) {
172 die(xlt('Access denied'));
176 if (isset($LBF_SERVICES_SECTION) ||
isset($LBF_PRODUCTS_SECTION) ||
isset($LBF_DIAGS_SECTION)) {
177 $fs = new FeeSheetHtml($pid, $visitid);
180 if (!$from_trend_form) {
181 $fname = $GLOBALS['OE_SITE_DIR'] . "/LBF/$formname.plugin.php";
182 if (file_exists($fname)) {
183 include_once($fname);
187 // If Save was clicked, save the info.
189 if (!empty($_POST['bn_save']) ||
!empty($_POST['bn_save_print']) ||
!empty($_POST['bn_save_continue']) ||
!empty($_POST['bn_save_close'])) {
192 // Creating a new form. Get the new form_id by inserting and deleting a dummy row.
193 // This is necessary to create the form instance even if it has no native data.
194 $newid = sqlInsert("INSERT INTO lbf_data " .
195 "( field_id, field_value ) VALUES ( '', '' )");
196 sqlStatement("DELETE FROM lbf_data WHERE form_id = ? AND " .
197 "field_id = ''", array($newid));
198 addForm($visitid, $formtitle, $newid, $formname, $pid, $userauthorized);
201 $my_form_id = $formid ?
$formid : $newid;
203 // If there is an issue ID, update it in the forms table entry.
204 if (isset($_POST['form_issue_id'])) {
206 "UPDATE forms SET issue_id = ? WHERE formdir = ? AND form_id = ? AND deleted = 0",
207 array($_POST['form_issue_id'], $formname, $my_form_id)
211 // If there is a provider ID, update it in the forms table entry.
212 if (isset($_POST['form_provider_id'])) {
214 "UPDATE forms SET provider_id = ? WHERE formdir = ? AND form_id = ? AND deleted = 0",
215 array($_POST['form_provider_id'], $formname, $my_form_id)
220 $fres = sqlStatement("SELECT * FROM layout_options " .
221 "WHERE form_id = ? AND uor > 0 AND field_id != '' AND " .
222 "edit_options != 'H' AND edit_options NOT LIKE '%0%' " .
223 "ORDER BY group_id, seq", array($formname));
224 while ($frow = sqlFetchArray($fres)) {
225 $field_id = $frow['field_id'];
226 $data_type = $frow['data_type'];
227 // If the field was not in the web form, skip it.
228 // Except if it's checkboxes, if unchecked they are not returned.
230 // if ($data_type != 21 && !isset($_POST["form_$field_id"])) continue;
232 // The above statement commented out 2015-01-12 because a LBF plugin might conditionally
233 // disable a field that is not applicable, and we need the ability to clear out the old
234 // garbage in there so it does not show up in the "report" view of the data. So we will
235 // trust that it's OK to clear any field that is defined in the layout but not returned
238 if ($data_type == 31) {
239 continue; // skip static text fields
241 $value = get_layout_form_value($frow);
242 // If edit option P or Q, save to the appropriate different table and skip the rest.
243 $source = $frow['source'];
244 if ($source == 'D' ||
$source == 'H') {
245 // Save to patient_data, employer_data or history_data.
246 if ($source == 'H') {
247 $new = array($field_id => $value);
248 updateHistoryData($pid, $new);
249 } elseif (strpos($field_id, 'em_') === 0) {
250 $field_id = substr($field_id, 3);
251 $new = array($field_id => $value);
252 updateEmployerData($pid, $new);
254 $esc_field_id = escape_sql_column_name($field_id, array('patient_data'));
256 "UPDATE patient_data SET `$esc_field_id` = ? WHERE pid = ?",
262 } elseif ($source == 'E') {
263 // Save to shared_attributes. Can't delete entries for empty fields because with the P option
264 // it's important to know when a current empty value overrides a previous value.
266 "REPLACE INTO shared_attributes SET " .
267 "pid = ?, encounter = ?, field_id = ?, last_update = NOW(), " .
268 "user_id = ?, field_value = ?",
269 array($pid, $visitid, $field_id, $_SESSION['authUserID'], $value)
272 } elseif ($source == 'V') {
273 // Save to form_encounter.
274 $esc_field_id = escape_sql_column_name($field_id, array('form_encounter'));
276 "UPDATE form_encounter SET `$esc_field_id` = ? WHERE " .
277 "pid = ? AND encounter = ?",
278 array($value, $pid, $visitid)
283 // It's a normal form field, save to lbf_data.
284 if ($formid) { // existing form
286 $query = "DELETE FROM lbf_data WHERE " .
287 "form_id = ? AND field_id = ?";
288 sqlStatement($query, array($formid, $field_id));
290 $query = "REPLACE INTO lbf_data SET field_value = ?, " .
291 "form_id = ?, field_id = ?";
292 sqlStatement($query, array($value, $formid, $field_id));
297 "INSERT INTO lbf_data " .
298 "( form_id, field_id, field_value ) VALUES ( ?, ?, ? )",
299 array($newid, $field_id, $value)
306 // Delete the request from the portal.
307 $result = cms_portal_call(array('action' => 'delpost', 'postid' => $portalid));
308 if ($result['errmsg']) {
309 die(text($result['errmsg']));
314 $bill = is_array($_POST['form_fs_bill']) ?
$_POST['form_fs_bill'] : null;
315 $prod = is_array($_POST['form_fs_prod']) ?
$_POST['form_fs_prod'] : null;
316 $alertmsg = $fs->checkInventory($prod);
317 // If there is an inventory error then no services or products will be saved, and
318 // the form will be redisplayed with an error alert and everything else saved.
320 $fs->save($bill, $prod, null, null);
321 $fs->updatePriceLevel($_POST['form_fs_pricelevel']);
325 if (!$alertmsg && !empty($_POST['bn_save_close'])) {
326 $alertmsg = FeeSheet
::closeVisit($pid, $visitid);
333 if (!$alertmsg && !$from_issue_form && empty($_POST['bn_save_continue'])) {
334 // Support custom behavior at save time, such as going to another form.
335 if (function_exists($formname . '_save_exit')) {
336 if (call_user_func($formname . '_save_exit')) {
340 formHeader("Redirecting....");
341 // If Save and Print, write the JavaScript to open a window for printing.
342 if (!empty($_POST['bn_save_print'])) {
344 "top.restoreSession();\n" .
345 "window.open('$rootdir/forms/LBF/printable.php?" .
346 "formname=" . attr_url($formname) .
347 "&formid=" . attr_url($formid) .
348 "&visitid=" . attr_url($visitid) .
349 "&patientid=" . attr_url($pid) .
358 // For portal and documents templates we need a fluid container.
359 // default container.
360 $form_container = "container";
361 if (empty($is_core)) {
362 $form_container = "container-fluid";
367 <?php Header
::setupHeader(['opener', 'common', 'datetime-picker', 'select2']); ?
>
372 border
: 1px solid
var(--primary
);
373 margin
: 0 0 0 0.8125rem
;
379 border
-width
: 0 0 1px
0;
380 border
-color
: var(--gray600
);
384 border
-width
: 1px solid
var(--gray600
) !important
;
393 <?php
include_once("{$GLOBALS['srcdir']}/options.js.php"); ?
>
395 <!-- LiterallyCanvas support
-->
396 <?php
echo lbf_canvas_head(); ?
>
397 <?php
echo signer_head(); ?
>
401 // Support for beforeunload handler.
402 var somethingChanged
= false;
404 function verifyCancel() {
405 if (somethingChanged
) {
406 if (!confirm(<?php
echo xlj('You have unsaved changes. Do you really want to close this form?'); ?
>)) {
410 somethingChanged
= false;
411 parent
.closeTab(window
.name
, false);
416 if (window
.tabbify
) {
419 if (window
.checkSkipConditions
) {
420 checkSkipConditions();
423 $
(".select-dropdown").select2({
425 <?php
require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?
>
427 if (typeof error
!== 'undefined') {
433 $
(".iframe_medium").on('click', function (e
) {
436 let url
= $
(this
).attr('href');
437 url
= encodeURI(url
);
438 dlgopen('', '', 950, 550, '', '', {
440 {text
: <?php
echo xlj('Close'); ?
>, close
: true, style
: 'default btn-sm'}
447 // Support for beforeunload handler.
448 $
('.lbfdata input, .lbfdata select, .lbfdata textarea').change(function () {
449 somethingChanged
= true;
451 window
.addEventListener("beforeunload", function (e
) {
452 if (somethingChanged
&& !top
.timed_out
) {
453 var msg
= <?php
echo xlj('You have unsaved changes.'); ?
>;
454 e
.returnValue
= msg
; // Gecko, Trident, Chrome 34+
455 return msg
; // Gecko, WebKit, Chrome <34
459 $
('.datepicker').datetimepicker({
460 <?php
$datetimepicker_timepicker = false; ?
>
461 <?php
$datetimepicker_showseconds = false; ?
>
462 <?php
$datetimepicker_formatInput = true; ?
>
463 <?php
$datetimepicker_minDate = false; ?
>
464 <?php
$datetimepicker_maxDate = false; ?
>
465 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
466 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
468 $
('.datetimepicker').datetimepicker({
469 <?php
$datetimepicker_timepicker = true; ?
>
470 <?php
$datetimepicker_showseconds = false; ?
>
471 <?php
$datetimepicker_formatInput = true; ?
>
472 <?php
$datetimepicker_minDate = false; ?
>
473 <?php
$datetimepicker_maxDate = false; ?
>
474 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
475 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
477 $
('.datepicker-past').datetimepicker({
478 <?php
$datetimepicker_timepicker = false; ?
>
479 <?php
$datetimepicker_showseconds = false; ?
>
480 <?php
$datetimepicker_formatInput = true; ?
>
481 <?php
$datetimepicker_minDate = false; ?
>
482 <?php
$datetimepicker_maxDate = '+1970/01/01'; ?
>
483 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
484 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
486 $
('.datetimepicker-past').datetimepicker({
487 <?php
$datetimepicker_timepicker = true; ?
>
488 <?php
$datetimepicker_showseconds = false; ?
>
489 <?php
$datetimepicker_formatInput = true; ?
>
490 <?php
$datetimepicker_minDate = false; ?
>
491 <?php
$datetimepicker_maxDate = '+1970/01/01'; ?
>
492 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
493 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
495 $
('.datepicker-future').datetimepicker({
496 <?php
$datetimepicker_timepicker = false; ?
>
497 <?php
$datetimepicker_showseconds = false; ?
>
498 <?php
$datetimepicker_formatInput = true; ?
>
499 <?php
$datetimepicker_minDate = '-1970/01/01'; ?
>
500 <?php
$datetimepicker_maxDate = false; ?
>
501 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
502 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
504 $
('.datetimepicker-future').datetimepicker({
505 <?php
$datetimepicker_timepicker = true; ?
>
506 <?php
$datetimepicker_showseconds = false; ?
>
507 <?php
$datetimepicker_formatInput = true; ?
>
508 <?php
$datetimepicker_minDate = '-1970/01/01'; ?
>
509 <?php
$datetimepicker_maxDate = false; ?
>
510 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
511 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
515 var mypcc
= <?php
echo js_escape($GLOBALS['phone_country_code']); ?
>;
517 // Supports customizable forms.
518 function divclick(cb
, divid
) {
519 var divstyle
= document
.getElementById(divid
).style
;
521 divstyle
.display
= 'block';
523 divstyle
.display
= 'none';
528 // The ID of the input element to receive a found code.
529 var current_sel_name
= '';
531 // This is for callback by the find-code popup.
532 // Appends to or erases the current list of related codes.
533 function set_related(codetype
, code
, selector
, codedesc
) {
534 var f
= document
.forms
[0];
535 <?php
if (isset($fs)) { ?
>
536 // This is the case of selecting a code for the Fee Sheet:
537 if (!current_sel_name
) {
539 $
.getScript('<?php echo $GLOBALS['web_root
'] ?>/library/ajax/code_attributes_ajax.php' +
540 '?codetype=' +
encodeURIComponent(codetype
) +
541 '&code=' +
encodeURIComponent(code
) +
542 '&selector=' +
encodeURIComponent(selector
) +
543 '&pricelevel=' +
encodeURIComponent(f
.form_fs_pricelevel ? f
.form_fs_pricelevel
.value
: "") +
544 '&csrf_token_form=' +
<?php
echo js_url(CsrfUtils
::collectCsrfToken()); ?
>);
549 // frc will be the input element containing the codes.
550 // frcd, if set, will be the input element containing their descriptions.
551 var frc
= f
[current_sel_name
];
553 var matches
= current_sel_name
.match(/^
(.*)__desc$
/);
558 // Allow only one code in a field unless edit option E is present.
561 if ((' ' + frc
.className +
' ').indexOf(' EditOptionE ') > -1) {
563 sd
= frcd ? frcd
.value
: s
;
571 s +
= codetype +
':' + code
;
578 if (frcd
) frcd
.value
= sd
;
582 // This invokes the "dynamic" find-code popup.
583 function sel_related(elem
, codetype
) {
584 current_sel_name
= elem ? elem
.name
: '';
585 var url
= '<?php echo $rootdir ?>/patient_file/encounter/find_code_dynamic.php';
586 if (codetype
) url +
= '?codetype=' +
encodeURIComponent(codetype
);
587 dlgopen(url
, '_blank', 800, 500);
590 // Compute the length of a string without leading and trailing spaces.
591 function trimlen(s
) {
593 var j
= s
.length
- 1;
594 for (; i
<= j
&& s
.charAt(i
) == ' '; ++i
) ;
595 for (; i
<= j
&& s
.charAt(j
) == ' '; --j
) ;
600 // This capitalizes the first letter of each word in the passed input
601 // element. It also strips out extraneous spaces.
602 function capitalizeMe(elem
) {
603 var a
= elem
.value
.split(' ');
605 for (var i
= 0; i
< a
.length
; ++i
) {
606 if (a
[i
].length
> 0) {
607 if (s
.length
> 0) s +
= ' ';
608 s +
= a
[i
].charAt(0).toUpperCase() + a
[i
].substring(1);
614 // Validation logic for form submission.
615 // Added prevent restoreSession for remotes
616 var submitButtonName
= '';
617 function validate(f
, restore
= true) {
618 var errMsgs
= new Array();
619 <?php
generate_layout_validation($formname); ?
>
620 // Validation for Fee Sheet stuff. Skipping this because CV decided (2015-11-03)
621 // that these warning messages are not appropriate for layout based visit forms.
623 // if (window.jsLineItemValidation && !jsLineItemValidation(f)) return false;
625 if (submitButtonName
== 'bn_save_close') {
626 // For "Save and Close Visit" we check for unsaved form data in the sibling iframes.
627 for (var i
= 0; i
< parent
.frames
.length
; ++i
) {
628 var w
= parent
.frames
[i
];
630 if (tmpId
.indexOf('enctabs-') == 0 && tmpId
!= window
.name
) {
631 if (typeof w
.somethingChanged
!== 'undefined' && w
.somethingChanged
) {
632 alert(<?php
echo xlj('Hold on! You have unsaved changes in another form. Please just Save this form and then complete the other one.'); ?
>);
639 somethingChanged
= false; // turn off "are you sure you want to leave"
641 top
.restoreSession();
647 // Called to open the data entry form of a specified encounter form instance.
648 // TBD: Move this to TabsWrapper.class.php.
649 function openLBFEncounterForm(formdir
, formname
, formid
) {
650 top
.restoreSession();
651 var url
= '<?php echo "$rootdir/patient_file/encounter/view_form.php?formname=" ?>' +
652 encodeURIComponent(formdir
) +
'&id=' +
encodeURIComponent(formid
);
653 parent
.twAddFrameTab('enctabs', formname
, url
);
657 function openLBFNewForm(formdir
, formname
) {
658 top
.restoreSession();
659 var url
= '<?php echo "$rootdir/patient_file/encounter/load_form.php?formname=" ?>' +
660 encodeURIComponent(formdir
);
661 parent
.twAddFrameTab('enctabs', formname
, url
);
666 // jsLineItemValidation() function for the fee sheet stuff.
667 echo $fs->jsLineItemValidation('form_fs_bill', 'form_fs_prod');
670 // Add a service line item.
671 function fs_append_service(code_type
, code
, desc
, price
) {
672 var telem
= document
.getElementById('fs_services_table');
673 var lino
= telem
.rows
.length
- 1;
674 var trelem
= telem
.insertRow(telem
.rows
.length
);
676 "<td class='text border-top-0'>" + code +
" </td>" +
677 "<td class='text border-top-0'>" + desc +
" </td>" +
678 "<td class='text border-top-0'>" +
679 "<select class='form-control' name='form_fs_bill[" + lino +
"][provid]'>" +
680 "<?php echo addslashes($fs->genProviderOptionList('-- ' . xl('Default') . ' --')) ?>" +
683 "<td class='text border-top-0 text-right'>" + price +
" </td>" +
684 "<td class='text border-top-0 text-right'>" +
685 "<input type='checkbox' name='form_fs_bill[" + lino +
"][del]' value='1' />" +
686 "<input type='hidden' name='form_fs_bill[" + lino +
"][code_type]' value='" + code_type +
"' />" +
687 "<input type='hidden' name='form_fs_bill[" + lino +
"][code]' value='" + code +
"' />" +
688 "<input type='hidden' name='form_fs_bill[" + lino +
"][price]' value='" + price +
"' />" +
692 // Add a product line item.
693 function fs_append_product(code_type
, code
, desc
, price
, warehouses
) {
694 var telem
= document
.getElementById('fs_products_table');
696 alert(<?php
echo xlj('A product was selected but there is no product section in this form.'); ?
>);
699 var lino
= telem
.rows
.length
- 1;
700 var trelem
= telem
.insertRow(telem
.rows
.length
);
702 "<td class='text border-top-0'>" + desc +
" </td>" +
703 "<td class='text border-top-0'>" +
704 "<select class='form-control' name='form_fs_prod[" + lino +
"][warehouse]'>" + warehouses +
"</select> " +
706 "<td class='text border-top-0 text-right'>" +
707 "<input type='text' class='form-control' name='form_fs_prod[" + lino +
"][units]' size='3' value='1' /> " +
709 "<td class='text border-top-0 text-right'>" + price +
" </td>" +
710 "<td class='text border-top-0 text-right'>" +
711 "<input type='checkbox' name='form_fs_prod[" + lino +
"][del]' value='1' />" +
712 "<input type='hidden' name='form_fs_prod[" + lino +
"][drug_id]' value='" + code +
"' />" +
713 "<input type='hidden' name='form_fs_prod[" + lino +
"][price]' value='" + price +
"' />" +
717 // Add a diagnosis line item.
718 function fs_append_diag(code_type
, code
, desc
) {
719 var telem
= document
.getElementById('fs_diags_table');
720 // Adding 1000 because form_fs_bill[] is shared with services and we want to avoid collisions.
721 var lino
= telem
.rows
.length
- 1 +
1000;
722 var trelem
= telem
.insertRow(telem
.rows
.length
);
724 "<td class='text border-top-0'>" + code +
" </td>" +
725 "<td class='text border-top-0'>" + desc +
" </td>" +
726 "<td class='text border-top-0 text-right'>" +
727 "<input type='checkbox' name='form_fs_bill[" + lino +
"][del]' value='1' />" +
728 "<input type='hidden' name='form_fs_bill[" + lino +
"][code_type]' value='" + code_type +
"' />" +
729 "<input type='hidden' name='form_fs_bill[" + lino +
"][code]' value='" + code +
"' />" +
730 "<input type='hidden' name='form_fs_bill[" + lino +
"][price]' value='" +
0 +
"' />" +
734 // Respond to clicking a checkbox for adding (or removing) a specific service.
735 function fs_service_clicked(cb
) {
737 // The checkbox value is a JSON array containing the service's code type, code, description,
738 // and price for each price level.
739 var a
= JSON
.parse(cb
.value
);
741 // The checkbox was UNchecked.
742 // Find last row with a matching code_type and code and set its del flag.
743 var telem
= document
.getElementById('fs_services_table');
744 var lino
= telem
.rows
.length
- 2;
745 for (; lino
>= 0; --lino
) {
746 var pfx
= "form_fs_bill[" + lino +
"]";
747 if (f
[pfx +
"[code_type]"].value
== a
[0] && f
[pfx +
"[code]"].value
== a
[1]) {
748 f
[pfx +
"[del]"].checked
= true;
754 $
.getScript('<?php echo $GLOBALS['web_root
'] ?>/library/ajax/code_attributes_ajax.php' +
755 '?codetype=' +
encodeURIComponent(a
[0]) +
756 '&code=' +
encodeURIComponent(a
[1]) +
757 '&pricelevel=' +
encodeURIComponent(f
.form_fs_pricelevel
.value
) +
758 '&csrf_token_form=' +
<?php
echo js_url(CsrfUtils
::collectCsrfToken()); ?
>);
761 // Respond to clicking a checkbox for adding (or removing) a specific product.
762 function fs_product_clicked(cb
) {
764 // The checkbox value is a JSON array containing the product's code type, code and selector.
765 var a
= JSON
.parse(cb
.value
);
767 // The checkbox was UNchecked.
768 // Find last row with a matching product ID and set its del flag.
769 var telem
= document
.getElementById('fs_products_table');
770 var lino
= telem
.rows
.length
- 2;
771 for (; lino
>= 0; --lino
) {
772 var pfx
= "form_fs_prod[" + lino +
"]";
773 if (f
[pfx +
"[code_type]"].value
== a
[0] && f
[pfx +
"[code]"].value
== a
[1]) {
774 f
[pfx +
"[del]"].checked
= true;
780 $
.getScript('<?php echo $GLOBALS['web_root
'] ?>/library/ajax/code_attributes_ajax.php' +
781 '?codetype=' +
encodeURIComponent(a
[0]) +
782 '&code=' +
encodeURIComponent(a
[1]) +
783 '&selector=' +
encodeURIComponent(a
[2]) +
784 '&pricelevel=' +
encodeURIComponent(f
.form_fs_pricelevel
.value
) +
785 '&csrf_token_form=' +
<?php
echo js_url(CsrfUtils
::collectCsrfToken()); ?
>);
788 // Respond to clicking a checkbox for adding (or removing) a specific diagnosis.
789 function fs_diag_clicked(cb
) {
791 // The checkbox value is a JSON array containing the diagnosis's code type, code, description.
792 var a
= JSON
.parse(cb
.value
);
794 // The checkbox was UNchecked.
795 // Find last row with a matching code_type and code and set its del flag.
796 var telem
= document
.getElementById('fs_diags_table');
797 var lino
= telem
.rows
.length
- 2 +
1000;
798 for (; lino
>= 0; --lino
) {
799 var pfx
= "form_fs_bill[" + lino +
"]";
800 if (f
[pfx +
"[code_type]"].value
== a
[0] && f
[pfx +
"[code]"].value
== a
[1]) {
801 f
[pfx +
"[del]"].checked
= true;
807 $
.getScript('<?php echo $GLOBALS['web_root
'] ?>/library/ajax/code_attributes_ajax.php' +
808 '?codetype=' +
encodeURIComponent(a
[0]) +
809 '&code=' +
encodeURIComponent(a
[1]) +
810 '&pricelevel=' +
encodeURIComponent(f
.form_fs_pricelevel ? f
.form_fs_pricelevel
.value
: "") +
811 '&csrf_token_form=' +
<?php
echo js_url(CsrfUtils
::collectCsrfToken()); ?
>);
814 // Respond to selecting a package of codes.
815 function fs_package_selected(sel
) {
817 // The option value is an encoded string of code types and codes.
819 $
.getScript('<?php echo $GLOBALS['web_root
'] ?>/library/ajax/code_attributes_ajax.php' +
820 '?list=' +
encodeURIComponent(sel
.value
) +
821 '&pricelevel=' +
encodeURIComponent(f
.form_fs_pricelevel ? f
.form_fs_pricelevel
.value
: "") +
822 '&csrf_token_form=' +
<?php
echo js_url(CsrfUtils
::collectCsrfToken()); ?
>);
824 sel
.selectedIndex
= 0;
827 // This is called back by code_attributes_ajax.php to complete the appending of a line item.
828 function code_attributes_handler(codetype
, code
, desc
, price
, warehouses
) {
829 if (codetype
== 'PROD') {
830 fs_append_product(codetype
, code
, desc
, price
, warehouses
);
832 else if (codetype
== 'ICD9' || codetype
== 'ICD10') {
833 fs_append_diag(codetype
, code
, desc
);
836 fs_append_service(codetype
, code
, desc
, price
);
840 function warehouse_changed(sel
) {
841 if (!confirm(<?php
echo xlj('Do you really want to change Warehouse?'); ?
>)) {
842 // They clicked Cancel so reset selection to its default state.
843 for (var i
= 0; i
< sel
.options
.length
; ++i
) {
844 sel
.options
[i
].selected
= sel
.options
[i
].defaultSelected
;
849 <?php
} // end if (isset($fs))
851 if (function_exists($formname . '_javascript')) {
852 call_user_func($formname . '_javascript');
859 <body
class="body_top"<?php
if ($from_issue_form) {
860 echo " style='background-color:var(--white)'";
862 <div
class="<?php echo $form_container ?>">
864 echo "<form method='post' " .
865 "action='$rootdir/forms/LBF/new.php?formname=" . attr_url($formname) . "&id=" . attr_url($formid) . "&portalid=" . attr_url($portalid) . "&formOrigin=" . attr_url($form_origin) . "&isPortal=" . attr_url($patient_portal) . "' " .
866 "onsubmit='return validate(this)'>\n";
868 $cmsportal_login = '';
872 if (!$from_trend_form) {
873 $enrow = sqlQuery("SELECT p.fname, p.mname, p.lname, p.cmsportal_login, " .
875 "form_encounter AS fe, forms AS f, patient_data AS p WHERE " .
876 "p.pid = ? AND f.pid = p.pid AND f.encounter = ? AND " .
877 "f.formdir = 'newpatient' AND f.deleted = 0 AND " .
878 "fe.id = f.form_id LIMIT 1", array($pid, $visitid)); ?
>
880 <div
class="<?php echo $form_container ?>">
881 <div
class="flex-row">
884 <?php
echo text($formtitle);
886 echo " " . xlt('for') . ' ';
887 echo text($enrow['fname'] ??
'') . ' ' . text($enrow['mname'] ??
'') . ' ' . text($enrow['lname'] ??
'');
888 echo ' ' . xlt('on') . ' ' . text(oeFormatShortDate(substr($enrow['date'] ??
'', 0, 10)));
893 "SELECT issue_id, provider_id FROM forms WHERE " .
894 "formdir = ? AND form_id = ? AND deleted = 0",
895 array($formname, $formid)
897 $form_issue_id = empty($firow['issue_id']) ?
0 : intval($firow['issue_id']);
898 $default = empty($firow['provider_id']) ?
$_SESSION['authUserID'] : intval($firow['provider_id']);
900 if (!$patient_portal) {
901 // Provider selector.
903 echo xlt('Provider') . ": ";
904 // TBD: Refactor this function out of the FeeSheetHTML class as that is not the best place for it.
905 echo FeeSheetHtml
::genProviderSelect('form_provider_id', '-- ' . xl("Please Select") . ' --', ($form_provider_id ??
''));
907 // If appropriate build a drop-down selector of issues of this type for this patient.
908 // We skip this if in an issue form tab because removing and adding visit form tabs is
909 // beyond the current scope of that code.
910 if (!empty($LBF_ISSUE_TYPE) && !$from_issue_form) {
912 $query = "SELECT id, title, date, begdate FROM lists WHERE pid = ? AND type = ? " .
913 "ORDER BY COALESCE(begdate, date) DESC, id DESC";
914 $ires = sqlStatement($query, array($pid, $LBF_ISSUE_TYPE));
915 echo "<select name='form_issue_id'>\n";
916 echo " <option value='0'>-- " . xlt('Select Case') . " --</option>\n";
917 while ($irow = sqlFetchArray($ires)) {
918 $issueid = $irow['id'];
919 $issuedate = oeFormatShortDate(empty($irow['begdate']) ?
$irow['date'] : $irow['begdate']);
920 echo " <option value='" . attr($issueid) . "'";
921 if ($issueid == $form_issue_id) {
924 echo ">" . text("$issuedate " . $irow['title']) . "</option>\n";
931 <?php
$cmsportal_login = $enrow['cmsportal_login'] ??
'';
932 } // end not from trend form
935 <!-- This is where a chart might display
. -->
936 <div id
="chart"></div
>
939 $shrow = getHistoryData($pid);
941 /**********************************************************
942 // Determine if this layout uses edit option "I" anywhere.
943 // If not we default to only the first group being initially open.
944 $tmprow = sqlQuery("SELECT form_id FROM layout_options " .
945 "WHERE form_id = ? AND uor > 0 AND edit_options LIKE '%I%' " .
946 "LIMIT 1", array($formname));
947 $some_group_is_open = !empty($tmprow['form_id']);
948 **********************************************************/
950 $fres = sqlStatement("SELECT * FROM layout_options " .
951 "WHERE form_id = ? AND uor > 0 " .
952 "ORDER BY group_id, seq", array($formname));
955 // $display_style = 'block';
957 // This string is the active group levels. Each leading substring represents an instance of nesting.
960 // This indicates if </table> will need to be written to end the fields in a group.
961 $group_table_active = false;
963 // This is an array keyed on forms.form_id for other occurrences of this
964 // form type. The maximum number of such other occurrences to display is
965 // in list_options.option_value for this form's list item. Values in this
966 // array are work areas for building the ending HTML for each displayed row.
968 $historical_ids = array();
970 // True if any data items in this form can be graphed.
971 $form_is_graphable = false;
975 while ($frow = sqlFetchArray($fres)) {
976 $this_group = $frow['group_id'];
977 $titlecols = $frow['titlecols'];
978 $datacols = $frow['datacols'];
979 $data_type = $frow['data_type'];
980 $field_id = $frow['field_id'];
981 $list_id = $frow['list_id'];
982 $edit_options = $frow['edit_options'];
983 $source = $frow['source'];
984 $jump_new_row = isOption($edit_options, 'J');
985 $prepend_blank_row = isOption($edit_options, 'K');
987 $graphable = isOption($edit_options, 'G') !== false;
989 $form_is_graphable = true;
992 if (isOption($edit_options, 'EP') && $patient_portal) {
996 // Accumulate action conditions into a JSON expression for the browser side.
997 accumActionConditions($frow, $condition_str);
1001 if (isOption($edit_options, 'H') !== false) {
1002 // This data comes from static history
1003 if (isset($shrow[$field_id])) {
1004 $currvalue = $shrow[$field_id];
1007 if (!$formid && $portalres) {
1008 // Copying CMS Portal form data into this field if appropriate.
1009 $currvalue = cms_field_to_lbf($data_type, $field_id, $portalres['fields']);
1012 if ($currvalue === '') {
1013 $currvalue = lbf_current_value($frow, $formid, (!empty($is_lbf)) ?
0 : $encounter);
1016 if ($currvalue === false) {
1017 continue; // column does not exist, should not happen
1020 // Handle "P" edit option to default to the previous value of a form field.
1021 if (!$from_trend_form && empty($currvalue) && isOption($edit_options, 'P') !== false) {
1022 if ($source == 'F' && !$formid) {
1023 // Form attribute for new form, get value from most recent form instance.
1024 // Form attributes of existing forms are expected to have existing values.
1026 "SELECT encounter, form_id FROM forms WHERE " .
1027 "pid = ? AND formdir = ? AND deleted = 0 " .
1028 "ORDER BY date DESC LIMIT 1",
1029 array($pid, $formname)
1031 if (!empty($tmp['encounter'])) {
1032 $currvalue = lbf_current_value($frow, $tmp['form_id'], $tmp['encounter']);
1034 } elseif ($source == 'E') {
1035 // Visit attribute, get most recent value as of this visit.
1036 // Even if the form already exists for this visit it may have a readonly value that only
1037 // exists in a previous visit and was created from a different form.
1039 "SELECT sa.field_value FROM form_encounter AS e1 " .
1040 "JOIN form_encounter AS e2 ON " .
1041 "e2.pid = e1.pid AND (e2.date < e1.date OR (e2.date = e1.date AND e2.encounter <= e1.encounter)) " .
1042 "JOIN shared_attributes AS sa ON " .
1043 "sa.pid = e2.pid AND sa.encounter = e2.encounter AND sa.field_id = ?" .
1044 "WHERE e1.pid = ? AND e1.encounter = ? " .
1045 "ORDER BY e2.date DESC, e2.encounter DESC LIMIT 1",
1046 array($field_id, $pid, $visitid)
1048 if (isset($tmp['field_value'])) {
1049 $currvalue = $tmp['field_value'];
1052 } // End "P" option logic.
1055 $this_levels = $this_group;
1057 $mincount = min(strlen($this_levels), strlen($group_levels));
1058 while ($i < $mincount && $this_levels[$i] == $group_levels[$i]) {
1061 // $i is now the number of initial matching levels.
1063 // If ending a group or starting a subgroup, terminate the current row and its table.
1064 if ($group_table_active && ($i != strlen($group_levels) ||
$i != strlen($this_levels))) {
1067 $group_table_active = false;
1070 // Close any groups that we are done with.
1071 while (strlen($group_levels) > $i) {
1072 $gname = $grparr[$group_levels]['grp_title'];
1073 $group_levels = substr($group_levels, 0, -1); // remove last character
1074 // No div for an empty group name.
1075 if (strlen($gname)) {
1080 // If there are any new groups, open them.
1081 while ($i < strlen($this_levels)) {
1083 if ($group_table_active) {
1085 $group_table_active = false;
1087 $group_levels .= $this_levels[$i++
];
1088 $grouprow = $grparr[substr($group_levels, 0, $i)];
1089 $gname = $grouprow['grp_title'];
1090 $subtitle = xl_layout_label($grouprow['grp_subtitle']);
1091 // Compute a short unique identifier for this group.
1092 $group_seq = 'lbf' . $group_levels;
1093 $group_name = $gname;
1095 $display_style = $grouprow['grp_init_open'] ?
'block' : 'none';
1097 // If group name is blank, no checkbox or div.
1098 if (strlen($gname)) {
1099 echo "<br /><span><label class='mb-1' role='button'><input class='mr-1' type='checkbox' name='form_cb_" . attr($group_seq) . "' value='1' " . "onclick='return divclick(this," . attr_js('div_' . $group_seq) . ");'";
1100 if ($display_style == 'block') {
1103 echo " /><strong>" . text(xl_layout_label($group_name)) . "</strong></label></span>\n";
1104 echo "<div id='div_" . attr($group_seq) . "' class='section table-responsive clearfix' style='display:" . attr($display_style) . ";'>\n";
1107 $group_table_active = true;
1108 echo " <table cellspacing='0' cellpadding='0' class='border-0 lbfdata'>\n";
1111 // There is a group subtitle so show it.
1112 echo "<tr><td class='font-weight-bold border-top-0 text-primary' colspan='" . attr($CPR) . "'>" . text($subtitle) . "</td></tr>\n";
1113 echo "<tr><td class='font-weight-bold border-top-0' style='height:0.3125rem;' colspan='" . attr($CPR) . "'></td></tr>\n";
1116 // $display_style = 'none';
1118 // Initialize historical data array and write date headers.
1119 $historical_ids = array();
1120 if ($formhistory > 0) {
1122 echo "<td colspan='" . attr($CPR) . "' class='font-weight-bold border-top-0 text-right'>";
1123 if (empty($is_lbf)) {
1124 // Including actual date per IPPF request 2012-08-23.
1125 echo text(oeFormatShortDate(substr($enrow['date'], 0, 10)));
1126 echo ' (' . xlt('Current') . ')';
1129 echo " </td>\n";
1130 $hres = sqlStatement(
1131 "SELECT f.form_id, fe.date " .
1132 "FROM forms AS f, form_encounter AS fe WHERE " .
1133 "f.pid = ? AND f.formdir = ? AND " .
1134 "f.form_id != ? AND f.deleted = 0 AND " .
1135 "fe.pid = f.pid AND fe.encounter = f.encounter " .
1136 "ORDER BY fe.date DESC, f.encounter DESC, f.date DESC " .
1138 array($pid, $formname, $formid, $formhistory)
1140 // For some readings like vitals there may be multiple forms per encounter.
1141 // We sort these sensibly, however only the encounter date is shown here;
1142 // at some point we may wish to show also the data entry date/time.
1143 while ($hrow = sqlFetchArray($hres)) {
1144 echo "<td colspan='" . attr($CPR) . "' class='font-weight-bold border-top-0 text-right'> " .
1145 text(oeFormatShortDate(substr($hrow['date'], 0, 10))) . "</td>\n";
1146 $historical_ids[$hrow['form_id']] = '';
1153 // Handle starting of a new row.
1154 if (($titlecols > 0 && $cell_count >= $CPR) ||
$cell_count == 0 ||
$prepend_blank_row ||
$jump_new_row) {
1156 if ($prepend_blank_row) {
1157 echo "<tr><td class='text border-top-0' colspan='" . attr($CPR) . "'> </td></tr>\n";
1159 if (isOption($edit_options, 'RS')) {
1160 echo " <tr class='RS'>";
1161 } elseif (isOption($edit_options, 'RO')) {
1162 echo " <tr class='RO'>";
1167 // Clear historical data string.
1168 foreach ($historical_ids as $key => $dummy) {
1169 $historical_ids[$key] = '';
1173 if ($item_count == 0 && $titlecols == 0) {
1177 // First item is on the "left-border"
1180 // Handle starting of a new label cell.
1181 if ($titlecols > 0) {
1183 if (isOption($edit_options, 'SP')) {
1186 echo "<td class='border-top-0 align-top' colspan='" . attr($titlecols) . "'";
1188 // unsure why this was set to always text-nowrap. will monitor and perhaps this should be
1189 // an option in line options.
1190 echo "<td class='border-top-0 align-top text-wrap' colspan='" . attr($titlecols) . "'";
1193 echo ($frow['uor'] == 2) ?
"required" : "font-weight-bold";
1200 if ($cell_count > 0) {
1201 echo " style='padding-left: 0.8125rem'";
1203 // This ID is used by action conditions and also show_graph().
1204 echo " id='label_id_" . attr($field_id) . "'";
1207 foreach ($historical_ids as $key => $dummy) {
1208 $historical_ids[$key] .= "<td colspan='" . attr($titlecols) . "' class='text border-top-0 align-top text-nowrap'>";
1211 $cell_count +
= $titlecols;
1217 if ($frow['title']) {
1218 $tmp = xl_layout_label($frow['title']);
1220 // Append colon only if label does not end with punctuation.
1221 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
1229 // Note the labels are not repeated in the history columns.
1231 // Handle starting of a new data cell.
1232 if ($datacols > 0) {
1234 if (isOption($edit_options, 'DS')) {
1235 echo "<td colspan='" . attr($datacols) . "' class='border-top-0 align-top text RS'";
1237 if (isOption($edit_options, 'DO')) {
1238 echo "<td colspan='" . attr($datacols) . "' class='border-top-0 align-top text RO'";
1240 echo "<td colspan='" . attr($datacols) . "' class='border-top-0 align-top text'";
1242 // This ID is used by action conditions.
1243 echo " id='value_id_" . attr($field_id) . "'";
1244 if ($cell_count > 0) {
1245 echo " style='padding-left: 0.4375rem'";
1250 foreach ($historical_ids as $key => $dummy) {
1251 $historical_ids[$key] .= "<td colspan='" . attr($datacols) . "' class='text border-top-0 align-top text-right'>";
1254 $cell_count +
= $datacols;
1259 // Skip current-value fields for the display-only case.
1260 if (!$from_trend_form) {
1261 if ($frow['edit_options'] == 'H') {
1262 echo generate_display_field($frow, $currvalue);
1264 generate_form_field($frow, $currvalue);
1268 // Append to historical data of other dates for this item.
1269 foreach ($historical_ids as $key => $dummy) {
1270 $value = lbf_current_value($frow, $key, 0);
1271 $historical_ids[$key] .= generate_display_field($frow, $value);
1275 // Close all open groups.
1276 if ($group_table_active) {
1279 $group_table_active = false;
1281 while (strlen($group_levels)) {
1282 $gname = $grparr[$group_levels]['grp_title'];
1283 $group_levels = substr($group_levels, 0, -1); // remove last character
1284 // No div for an empty group name.
1285 if (strlen($gname)) {
1290 $display_style = $LBF_SECTION_DISPLAY_STYLE;
1292 if (isset($LBF_SERVICES_SECTION) ||
isset($LBF_DIAGS_SECTION)) {
1293 $fs->loadServiceItems();
1296 if (isset($LBF_SERVICES_SECTION)) {
1297 // Create the checkbox and div for the Services Section.
1298 echo "<br /><span class='font-weight-bold'><input type='checkbox' name='form_cb_fs_services' value='1' " .
1299 "onclick='return divclick(this, \"div_fs_services\");'";
1300 if ($display_style == 'block') {
1303 echo " /><strong>" . xlt('Services') . "</strong></span>\n";
1304 echo "<div id='div_fs_services' class='section' style='display:" . attr($display_style) . ";'>\n";
1306 // $display_style = 'none';
1308 // If there are associated codes, generate a checkbox for each one.
1309 if ($LBF_SERVICES_SECTION) {
1310 echo "<table class='w-100' cellpadding='0' cellspacing='0'>\n";
1312 $tdpct = (int)(100 / $cols);
1314 $relcodes = explode(';', $LBF_SERVICES_SECTION);
1315 foreach ($relcodes as $codestring) {
1316 if ($codestring === '') {
1319 $codes_esc = attr($codestring);
1320 $cbval = $fs->genCodeSelectorValue($codestring);
1321 if ($count %
$cols == 0) {
1327 echo " <td class='border-top-0' width='" . attr($tdpct) . "%'>";
1328 echo "<input type='checkbox' id='form_fs_services[$codes_esc]' " .
1329 "onclick='fs_service_clicked(this)' value='" . attr($cbval) . "'";
1330 if ($fs->code_is_in_fee_sheet
) {
1333 list($codetype, $code) = explode(':', $codestring);
1334 $title = lookup_code_descriptions($codestring);
1335 $title = empty($title) ?
$code : xl_list_label($title);
1336 echo " />" . text($title);
1346 // A row for Search, Add Package, Main Provider.
1347 $ctype = $GLOBALS['ippf_specific'] ?
'MA' : '';
1348 echo "<p class='font-weight-bold'>";
1349 echo "<input type='button' value='" . xla('Search Services') . "' onclick='sel_related(null," . attr_js($ctype) . ")' /> \n";
1350 $fscres = sqlStatement("SELECT * FROM fee_sheet_options ORDER BY fs_category, fs_option");
1351 if (sqlNumRows($fscres)) {
1352 $last_category = '';
1353 echo "<select class='form-control' onchange='fs_package_selected(this)'>\n";
1354 echo " <option value=''>" . xlt('Add Package') . "</option>\n";
1355 while ($row = sqlFetchArray($fscres)) {
1356 $fs_category = $row['fs_category'];
1357 $fs_option = $row['fs_option'];
1358 $fs_codes = $row['fs_codes'];
1359 if ($fs_category !== $last_category) {
1360 if ($last_category) {
1361 echo " </optgroup>\n";
1363 echo " <optgroup label='" . xla(substr($fs_category, 1)) . "'>\n";
1364 $last_category = $fs_category;
1366 echo " <option value='" . attr($fs_codes) . "'>" . xlt(substr($fs_option, 1)) . "</option>\n";
1368 if ($last_category) {
1369 echo " </optgroup>\n";
1371 echo "</select> \n";
1373 $tmp_provider_id = $fs->provider_id ?
$fs->provider_id
: 0;
1374 if (!$tmp_provider_id && $userauthorized) {
1375 // Default to the logged-in user if they are a provider.
1376 $tmp_provider_id = $_SESSION['authUserID'];
1378 echo xlt('Main Provider') . ": ";
1379 echo $fs->genProviderSelect("form_fs_provid", ' ', $tmp_provider_id);
1383 // Generate a line for each service already in this FS.
1384 echo "<table cellpadding='0' cellspacing='2' id='fs_services_table'>\n";
1386 echo " <td class='border-top-0 font-weight-bold' colspan='2'>" . xlt('Services Provided') . " </td>\n";
1387 echo " <td class='border-top-0 font-weight-bold'>" . xlt('Provider') . " </td>\n";
1388 echo " <td class='border-top-0 font-weight-bold text-right'>" . xlt('Price') . " </td>\n";
1389 echo " <td class='border-top-0 font-weight-bold text-right'>" . xlt('Delete') . "</td>\n";
1391 foreach ($fs->serviceitems
as $lino => $li) {
1392 // Skip diagnoses; those would be in the Diagnoses section below.
1393 if ($code_types[$li['codetype']]['diag']) {
1397 echo " <td class='border-top-0 text'>" . text($li['code']) . " </td>\n";
1398 echo " <td class='border-top-0 text'>" . text($li['code_text']) . " </td>\n";
1399 echo " <td class='border-top-0 text'>" .
1400 $fs->genProviderSelect("form_fs_bill[$lino][provid]", '-- ' . xl("Default") . ' --', $li['provid']) .
1402 echo " <td class='border-top-0 text text-right'>" . text(oeFormatMoney($li['price'])) . " </td>\n";
1403 echo " <td class='border-top-0 text text-right'>\n" .
1404 " <input type='checkbox' name='form_fs_bill[" . attr($lino) . "][del]' " .
1405 "value='1'" . ($li['del'] ?
" checked" : "") . " />\n";
1406 foreach ($li['hidden'] as $hname => $hvalue) {
1407 echo " <input type='hidden' name='form_fs_bill[" . attr($lino) . "][" . attr($hname) . "]' value='" . attr($hvalue) . "' />\n";
1415 } // End Services Section
1417 if (isset($LBF_PRODUCTS_SECTION)) {
1418 // Create the checkbox and div for the Products Section.
1419 echo "<br /><span class='font-weight-bold'><input type='checkbox' name='form_cb_fs_products' value='1' " .
1420 "onclick='return divclick(this, \"div_fs_products\");'";
1421 if ($display_style == 'block') {
1424 echo " /><strong>" . xlt('Products') . "</strong></span>\n";
1425 echo "<div id='div_fs_products' class='section' style='display:" . attr($display_style) . ";'>\n";
1427 // $display_style = 'none';
1429 // If there are associated codes, generate a checkbox for each one.
1430 if ($LBF_PRODUCTS_SECTION) {
1431 echo "<table class='w-100' cellpadding='0' cellspacing='0'>\n";
1433 $tdpct = (int)(100 / $cols);
1435 $relcodes = explode(';', $LBF_PRODUCTS_SECTION);
1436 foreach ($relcodes as $codestring) {
1437 if ($codestring === '') {
1440 $codes_esc = attr($codestring);
1441 $cbval = $fs->genCodeSelectorValue($codestring);
1442 if ($count %
$cols == 0) {
1448 echo " <td class='border-top-0' width='" . attr($tdpct) . "%'>";
1449 echo "<input type='checkbox' id='form_fs_products[$codes_esc]' " .
1450 "onclick='fs_product_clicked(this)' value='" . attr($cbval) . "'";
1451 if ($fs->code_is_in_fee_sheet
) {
1454 list($codetype, $code) = explode(':', $codestring);
1456 "SELECT name FROM drugs WHERE " .
1457 "drug_id = ? ORDER BY drug_id LIMIT 1",
1460 $title = empty($crow['name']) ?
$code : xl_list_label($crow['name']);
1461 echo " />" . text($title);
1472 $ctype = $GLOBALS['ippf_specific'] ?
'MA' : '';
1473 echo "<p class='font-weight-bold'>";
1474 echo "<input type='button' value='" . xla('Search Products') . "' onclick='sel_related(null,\"PROD\")' /> ";
1477 // Generate a line for each product already in this FS.
1478 echo "<table cellpadding='0' cellspacing='2' id='fs_products_table'>\n";
1480 echo " <td class='border-top-0 font-weight-bold'>" . xlt('Products Provided') . " </td>\n";
1481 echo " <td class='border-top-0 font-weight-bold'>" . xlt('Warehouse') . " </td>\n";
1482 echo " <td class='border-top-0 font-weight-bold text-right'>" . xlt('Quantity') . " </td>\n";
1483 echo " <td class='border-top-0 font-weight-bold text-right'>" . xlt('Price') . " </td>\n";
1484 echo " <td class='border-top-0 font-weight-bold text-right'>" . xlt('Delete') . "</td>\n";
1486 $fs->loadProductItems();
1487 foreach ($fs->productitems
as $lino => $li) {
1489 echo " <td class='border-top-0 text'>" . text($li['code_text']) . " </td>\n";
1490 echo " <td class='border-top-0 text'>" .
1491 $fs->genWarehouseSelect("form_fs_prod[$lino][warehouse]", '', $li['warehouse'], false, $li['hidden']['drug_id'], true) .
1493 echo " <td class='border-top-0 text text-right'>" .
1494 "<input class='form-control' type='text' name='form_fs_prod[" . attr($lino) . "][units]' size='3' value='" . attr($li['units']) . "' />" .
1496 echo " <td class='border-top-0 text text-right'>" . text(oeFormatMoney($li['price'])) . " </td>\n";
1497 echo " <td class='border-top-0 text text-right'>\n" .
1498 " <input type='checkbox' name='form_fs_prod[" . attr($lino) . "][del]' " .
1499 "value='1'" . ($li['del'] ?
" checked" : "") . " />\n";
1500 foreach ($li['hidden'] as $hname => $hvalue) {
1501 echo " <input type='hidden' name='form_fs_prod[" . attr($lino) . "][" . attr($hname) . "]' value='" . attr($hvalue) . "' />\n";
1509 } // End Products Section
1511 if (isset($LBF_DIAGS_SECTION)) {
1512 // Create the checkbox and div for the Diagnoses Section.
1513 echo "<br /><span class='font-weight-bold'><input type='checkbox' name='form_cb_fs_diags' value='1' " .
1514 "onclick='return divclick(this, \"div_fs_diags\");'";
1515 if ($display_style == 'block') {
1518 echo " /><b>" . xlt('Diagnoses') . "</b></span>\n";
1519 echo "<div id='div_fs_diags' class='section' style='display:" . attr($display_style) . ";'>\n";
1521 // $display_style = 'none';
1523 // If there are associated codes, generate a checkbox for each one.
1524 if ($LBF_DIAGS_SECTION) {
1525 echo "<table class='w-100' cellpadding='0' cellspacing='0'>\n";
1527 $tdpct = (int)(100 / $cols);
1529 $relcodes = explode(';', $LBF_DIAGS_SECTION);
1530 foreach ($relcodes as $codestring) {
1531 if ($codestring === '') {
1534 $codes_esc = attr($codestring);
1535 $cbval = $fs->genCodeSelectorValue($codestring);
1536 if ($count %
$cols == 0) {
1542 echo " <td class='border-top-0' width='" . attr($tdpct) . "%'>";
1543 echo "<input type='checkbox' id='form_fs_diags[$codes_esc]' " .
1544 "onclick='fs_diag_clicked(this)' value='" . attr($cbval) . "'";
1545 if ($fs->code_is_in_fee_sheet
) {
1548 list($codetype, $code) = explode(':', $codestring);
1549 $title = lookup_code_descriptions($codestring);
1550 $title = empty($title) ?
$code : xl_list_label($title);
1551 echo " />" . text($title);
1561 // A row for Search.
1562 $ctype = collect_codetypes('diagnosis', 'csv');
1563 echo "<p class='font-weight-bold'>";
1564 echo "<input type='button' class='btn btn-primary' value='" . xla('Search Diagnoses') . "' onclick='sel_related(null," . attr_js($ctype) . ")' />";
1567 // Generate a line for each diagnosis already in this FS.
1568 echo "<table cellpadding='0' cellspacing='2' id='fs_diags_table'>\n";
1570 echo " <td class='border-top-0 font-weight-bold' colspan='2'>" . xlt('Diagnosis') . " </td>\n";
1571 echo " <td class='border-top-0 font-weight-bold text-right'>" . xlt('Delete') . "</td>\n";
1573 foreach ($fs->serviceitems
as $lino => $li) {
1574 // Skip anything that is not a diagnosis; those are in the Services section above.
1575 if (!$code_types[$li['codetype']]['diag']) {
1579 echo " <td class='border-top-0 text'>" . text($li['code']) . " </td>\n";
1580 echo " <td class='border-top-0 text'>" . text($li['code_text']) . " </td>\n";
1581 // The Diagnoses section shares the form_fs_bill array with the Services section.
1582 echo " <td class='border-top-0 text text-right'>\n" .
1583 " <input type='checkbox' name='form_fs_bill[" . attr($lino) . "][del]' " .
1584 "value='1'" . ($li['del'] ?
" checked" : "") . " />\n";
1585 foreach ($li['hidden'] as $hname => $hvalue) {
1586 echo " <input type='hidden' name='form_fs_bill[" . attr($lino) . "][" . attr($hname) . "]' value='" . attr($hvalue) . "' />\n";
1594 } // End Diagnoses Section
1596 if ($LBF_REFERRALS_SECTION) {
1597 // Create the checkbox and div for the Referrals Section.
1598 echo "<br /><span class='bold'><input type='checkbox' name='form_cb_referrals' value='1' " .
1599 "onclick='return divclick(this, \"div_referrals\");'";
1600 if ($display_style == 'block') {
1603 echo " /><b>" . xlt('Referrals') . "</b></span>\n";
1604 echo "<div id='div_referrals' class='section' style='display:" . attr($display_style) . ";'>\n";
1606 // $display_style = 'none';
1608 // Generate a table row for each referral in the visit.
1609 echo "<table cellpadding='0' cellspacing='5' id='referrals_table'>\n";
1611 echo " <td class='bold'>" . xlt('Date') . " </td>\n";
1612 echo " <td class='bold'>" . xlt('Type') . " </td>\n";
1613 echo " <td class='bold'>" . xlt('Reason') . " </td>\n";
1614 echo " <td class='bold'>" . xlt('Referred To') . " </td>\n";
1615 echo " <td class='bold'>" . xlt('Requested Service') . "</td>\n";
1618 $refres = sqlStatement(
1619 "SELECT f.form_id, " .
1620 "d1.field_value AS refer_external, " .
1621 "d2.field_value AS body, " .
1622 "lo.title AS refer_type, " .
1623 "ut.organization, " .
1624 "CONCAT(ut.fname,' ', ut.lname) AS referto_name, " .
1625 "d4.field_value AS refer_related_code, " .
1626 "d5.field_value AS refer_date " .
1627 "FROM forms AS f " .
1628 "LEFT JOIN lbf_data AS d1 ON d1.form_id = f.form_id AND d1.field_id = 'refer_external' " .
1629 "LEFT JOIN list_options AS lo ON list_id = 'reftype' and option_id = d1.field_value " .
1630 "LEFT JOIN lbf_data AS d2 ON d2.form_id = f.form_id AND d2.field_id = 'body' " .
1631 "LEFT JOIN lbf_data AS d3 ON d3.form_id = f.form_id AND d3.field_id = 'refer_to' " .
1632 "LEFT JOIN users AS ut ON ut.id = d3.field_value " .
1633 "LEFT JOIN lbf_data AS d4 ON d4.form_id = f.form_id AND d4.field_id = 'refer_related_code' " .
1634 "LEFT JOIN lbf_data AS d5 ON d5.form_id = f.form_id AND d5.field_id = 'refer_date' " .
1636 "f.pid = ? AND f.encounter = ? AND f.formdir = 'LBFref' AND f.deleted = 0 " .
1637 "ORDER BY refer_date, f.form_id",
1638 array($pid, $encounter)
1641 while ($refrow = sqlFetchArray($refres)) {
1643 if (!empty($refrow['refer_related_code'])) {
1644 // Get referred services.
1645 $relcodes = explode(';', $refrow['refer_related_code']);
1646 foreach ($relcodes as $codestring) {
1647 if ($codestring === '') {
1651 list($codetype, $code) = explode(':', $codestring);
1653 "SELECT code_text FROM codes WHERE " .
1654 "code_type = ? AND code = ? " .
1655 "ORDER BY active DESC, id ASC LIMIT 1",
1656 array($code_types[$codetype]['id'], $code)
1658 $code_text = empty($rrow['code_text']) ?
'' : $rrow['code_text'];
1660 $svcstring .= '<br />';
1662 $svcstring .= text("$code: $code_text");
1665 echo " <tr style='cursor:pointer;cursor:hand' " .
1666 "onclick=\"openLBFEncounterForm('LBFref', 'Referral', " .
1667 attr_js($refrow['form_id']) . ")\">\n";
1668 echo " <td class='text linkcolor'>" . text(oeFormatShortDate($refrow['refer_date'])) . " </td>\n";
1669 echo " <td class='text linkcolor'>" . text($refrow['refer_type']) . " </td>\n";
1670 echo " <td class='text linkcolor'>" . text($refrow['body']) . " </td>\n";
1671 echo " <td class='text linkcolor'>" . text($refrow['organization'] ?
$refrow['organization'] : $refrow['referto_name']) . " </td>\n";
1672 echo " <td class='text linkcolor'>" . $svcstring . " </td>\n";
1676 echo " <tr style='cursor:pointer;cursor:hand' onclick=\"openLBFNewForm('LBFref', 'Referral')\">\n";
1677 echo " <td class='bold linkcolor' colspan='5'>" . xlt('Create New Referral') . "</td>\n";
1682 } // End Referrals Section
1687 <div
class="col-12">
1688 <div
class="btn-group">
1690 if (!$from_trend_form && !$from_lbf_edit && $is_core) {
1691 // Generate price level selector if we are doing services or products.
1692 if (isset($LBF_SERVICES_SECTION) ||
isset($LBF_PRODUCTS_SECTION)) {
1693 echo xlt('Price Level') . ": ";
1694 echo $fs->generatePriceLevelSelector('form_fs_pricelevel');
1695 echo " ";
1698 <button type
="submit" class="btn btn-primary btn-save" name
="bn_save"
1699 onclick
='submitButtonName = this.name;'
1700 value
="<?php echo xla('Save'); ?>">
1701 <?php
echo xlt('Save'); ?
>
1704 <button type
='submit' class="btn btn-secondary" name
='bn_save_continue'
1705 onclick
='submitButtonName = this.name;'
1706 value
='<?php echo xla('Save
and Continue') ?>'>
1707 <?php
echo xlt('Save and Continue'); ?
>
1710 <?php
if ($LBF_ENABLE_SAVE_CLOSE) { ?
>
1711 <button type
='submit' class="btn btn-secondary" name
='bn_save_close'
1712 onclick
='submitButtonName = this.name;'
1713 value
='<?php echo xla('Save
and Close Visit
') ?>'>
1714 <?php
echo xlt('Save and Close Visit'); ?
>
1719 if (!$from_issue_form) {
1721 <button type
='submit' class="btn btn-secondary" name
='bn_save_print'
1722 onclick
='submitButtonName = this.name;'
1723 value
='<?php echo xla('Save
and Print') ?>'>
1724 <?php
echo xlt('Save and Print'); ?
>
1727 if (function_exists($formname . '_additional_buttons')) {
1728 // Allow the plug-in to insert more action buttons here.
1729 call_user_func($formname . '_additional_buttons');
1732 if ($form_is_graphable) {
1734 <button type
='button' class="btn btn-secondary btn-graph"
1735 onclick
="top.restoreSession();location='../../patient_file/encounter/trend_form.php?formname=<?php echo attr_url($formname); ?>'">
1736 <?php
echo xlt('Show Graph') ?
>
1740 } // end form is graphable
1742 <button type
='button' class="btn btn-secondary btn-cancel" onclick
="verifyCancel()">
1743 <?php
echo xlt('Cancel'); ?
>
1746 } // end not from issue form
1749 } elseif (!$from_lbf_edit && $is_core) { // $from_trend_form is true but lbf edit doesn't want button
1751 <button type
='button' class="btn btn-secondary btn-back" onclick
='window.history.back();'>
1752 <?php
echo xlt('Back') ?
>
1755 } // end from trend form
1760 <?php
if (!$from_trend_form) { // end row and container divs ?>
1764 <p style
='text-align:center' class='small'>
1765 <?php
echo text(xl('Rev.') . ' ' . substr($grp_last_update, 0, 10)); ?
>
1770 <input type
='hidden' name
='from_issue_form' value
='<?php echo attr($from_issue_form); ?>'/>
1771 <?php
if (!$is_core) {
1772 echo '<input type="hidden" name="csrf_token_form" value="' . CsrfUtils
::collectCsrfToken() . '" />';
1773 echo "\n<input type='hidden' name='bn_save_continue' value='set' />\n";
1777 <!-- include support
for the
list-add selectbox feature
-->
1778 <?php
include $GLOBALS['fileroot'] . "/library/options_listadd.inc"; ?
>
1782 // Array of action conditions for the checkSkipConditions() function.
1784 <?php
echo $condition_str; ?
>
1787 <?php
echo $date_init; ?
>
1789 if (function_exists($formname . '_javascript_onload')) {
1790 call_user_func($formname . '_javascript_onload');
1794 echo "alert(" . js_escape($alertmsg) . ");\n";
1798 * Setup channel with portal
1799 * Mainly for form submission from remote for now.
1800 * umm you never know!
1802 <?php
if (empty($is_core)) { ?
>
1804 window
.addEventListener("message", (e
) => {
1805 if (event
.origin
!== window
.location
.origin
) {
1806 signerAlertMsg(<?php
echo xlj("Request is not same origin!") ?
>, 15000);
1809 if (e
.data
.submitForm
=== true) {
1810 let pass
= validate(document
.forms
[0], false);
1812 signerAlertMsg(<?php
echo xlj("Working on request.") ?
>, 5000, 'info');
1814 document
.forms
[0].submit();
1816 signerAlertMsg(<?php
echo xlj("Form validation failed. Fix any errors and resubmit.") ?
>);
1819 } else if (e
.data
.submitForm
=== 'history') {
1821 let portal_form_pid
= Number(<?php
echo js_escape($portal_form_pid); ?
>);
1822 if (portal_form_pid
) {
1823 signerAlertMsg(<?php
echo xlj("Charting History.") ?
>, 5000, 'info');
1825 signerAlertMsg(<?php
echo xlj("Sorry. Can not update history.") ?
>, 8000, 'danger');
1828 top
.restoreSession();
1829 document
.forms
[0].action
= "<?php echo $rootdir; ?>/patient_file/history/history_save.php?requestPid=" +
encodeURIComponent(portal_form_pid
);
1830 document
.forms
[0].onsubmit
= "";
1831 document
.forms
[0].submit();
1836 if (empty($is_core) && !empty($_POST['bn_save_continue'])) { ?
>
1837 /* post event to portal with current formid from save/edit action */
1838 parent
.postMessage({formid
:<?php
echo attr($formid) ?
>}, window
.location
.origin
);