fix: fix effective date end fatal error from prior commit (#6176)
[openemr.git] / interface / patient_file / summary / demographics.php
blob183b30a2f5caa34f5c7e62775cbbb53d1e1879e9
1 <?php
3 /**
5 * Patient summary screen.
7 * @package OpenEMR
8 * @link http://www.open-emr.org
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Sharon Cohen <sharonco@matrix.co.il>
11 * @author Stephen Waite <stephen.waite@cmsvt.com>
12 * @author Ranganath Pathak <pathak@scrs1.org>
13 * @author Tyler Wrenn <tyler@tylerwrenn.com>
14 * @author Robert Down <robertdown@live.com>
15 * @copyright Copyright (c) 2017-2020 Brady Miller <brady.g.miller@gmail.com>
16 * @copyright Copyright (c) 2017 Sharon Cohen <sharonco@matrix.co.il>
17 * @copyright Copyright (c) 2018-2020 Stephen Waite <stephen.waite@cmsvt.com>
18 * @copyright Copyright (c) 2018 Ranganath Pathak <pathak@scrs1.org>
19 * @copyright Copyright (c) 2020 Tyler Wrenn <tyler@tylerwrenn.com>
20 * @copyright Copyright (c) 2021-2022 Robert Down <robertdown@live.com
21 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
24 require_once("../../globals.php");
25 require_once("$srcdir/patient.inc.php");
26 require_once("$srcdir/options.inc.php");
27 require_once("../history/history.inc.php");
28 require_once("$srcdir/clinical_rules.php");
29 require_once("$srcdir/group.inc.php");
30 require_once(__DIR__ . "/../../../library/appointments.inc.php");
32 use OpenEMR\Billing\EDI270;
33 use OpenEMR\Common\Acl\AclMain;
34 use OpenEMR\Common\Csrf\CsrfUtils;
35 use OpenEMR\Common\Session\SessionUtil;
36 use OpenEMR\Common\Twig\TwigContainer;
37 use OpenEMR\Core\Header;
38 use OpenEMR\Events\Patient\Summary\Card\RenderEvent as CardRenderEvent;
39 use OpenEMR\Events\Patient\Summary\Card\SectionEvent;
40 use OpenEMR\Events\Patient\Summary\Card\RenderModel;
41 use OpenEMR\Events\Patient\Summary\Card\CardInterface;
42 use OpenEMR\Events\PatientDemographics\ViewEvent;
43 use OpenEMR\Events\PatientDemographics\RenderEvent;
44 use OpenEMR\FHIR\SMART\SmartLaunchController;
45 use OpenEMR\Menu\PatientMenuRole;
46 use OpenEMR\OeUI\OemrUI;
47 use OpenEMR\Patient\Cards\PortalCard;
48 use OpenEMR\Reminder\BirthdayReminder;
49 use Symfony\Component\EventDispatcher\EventDispatcher;
51 $twig = new TwigContainer(null, $GLOBALS['kernel']);
53 // Set session for pid (via setpid). Also set session for encounter (if applicable)
54 if (isset($_GET['set_pid'])) {
55 require_once("$srcdir/pid.inc.php");
56 setpid($_GET['set_pid']);
57 if (isset($_GET['set_encounterid']) && ((int)$_GET['set_encounterid'] > 0)) {
58 $encounter = (int)$_GET['set_encounterid'];
59 SessionUtil::setSession('encounter', $encounter);
63 // Note: it would eventually be a good idea to move this into
64 // it's own module that people can remove / add if they don't
65 // want smart support in their system.
66 $smartLaunchController = new SMARTLaunchController($GLOBALS["kernel"]->getEventDispatcher());
67 $smartLaunchController->registerContextEvents();
69 /**
70 * @var EventDispatcher
72 $ed = $GLOBALS['kernel']->getEventDispatcher();
74 $active_reminders = false;
75 $all_allergy_alerts = false;
76 if ($GLOBALS['enable_cdr']) {
77 //CDR Engine stuff
78 if ($GLOBALS['enable_allergy_check'] && $GLOBALS['enable_alert_log']) {
79 //Check for new allergies conflicts and throw popup if any exist(note need alert logging to support this)
80 $new_allergy_alerts = allergy_conflict($pid, 'new', $_SESSION['authUser']);
81 if (!empty($new_allergy_alerts)) {
82 $pod_warnings = '';
83 foreach ($new_allergy_alerts as $new_allergy_alert) {
84 $pod_warnings .= js_escape($new_allergy_alert) . ' + "\n"';
86 $allergyWarningMessage = '<script>alert(' . xlj('WARNING - FOLLOWING ACTIVE MEDICATIONS ARE ALLERGIES') . ' + "\n" + ' . $pod_warnings . ')</script>';
90 if ((empty($_SESSION['alert_notify_pid']) || ($_SESSION['alert_notify_pid'] != $pid)) && isset($_GET['set_pid']) && $GLOBALS['enable_cdr_crp']) {
91 // showing a new patient, so check for active reminders and allergy conflicts, which use in active reminder popup
92 $active_reminders = active_alert_summary($pid, "reminders-due", '', 'default', $_SESSION['authUser'], true);
93 if ($GLOBALS['enable_allergy_check']) {
94 $all_allergy_alerts = allergy_conflict($pid, 'all', $_SESSION['authUser'], true);
97 SessionUtil::setSession('alert_notify_pid', $pid);
98 // can not output html until after above setSession call
99 if (!empty($allergyWarningMessage)) {
100 echo $allergyWarningMessage;
103 //Check to see is only one insurance is allowed
104 if ($GLOBALS['insurance_only_one']) {
105 $insurance_array = array('primary');
106 } else {
107 $insurance_array = array('primary', 'secondary', 'tertiary');
110 function print_as_money($money)
112 preg_match("/(\d*)\.?(\d*)/", $money, $moneymatches);
113 $tmp = wordwrap(strrev($moneymatches[1]), 3, ",", 1);
114 $ccheck = strrev($tmp);
115 if ($ccheck[0] == ",") {
116 $tmp = substr($ccheck, 1, strlen($ccheck) - 1);
119 if ($moneymatches[2] != "") {
120 return "$ " . strrev($tmp) . "." . $moneymatches[2];
121 } else {
122 return "$ " . strrev($tmp);
126 // get an array from Photos category
127 function pic_array($pid, $picture_directory)
129 $pics = array();
130 $sql_query = "select documents.id from documents join categories_to_documents " .
131 "on documents.id = categories_to_documents.document_id " .
132 "join categories on categories.id = categories_to_documents.category_id " .
133 "where categories.name like ? and documents.foreign_id = ? and documents.deleted = 0";
134 if ($query = sqlStatement($sql_query, array($picture_directory, $pid))) {
135 while ($results = sqlFetchArray($query)) {
136 array_push($pics, $results['id']);
140 return ($pics);
143 // Get the document ID's in a specific catg.
144 // this is only used in one place, here for id photos
145 function get_document_by_catg($pid, $doc_catg, $limit = 1)
147 $results = null;
149 if ($pid and $doc_catg) {
150 $query = sqlStatement("SELECT d.id, d.date, d.url
151 FROM documents AS d, categories_to_documents AS cd, categories AS c
152 WHERE d.foreign_id = ?
153 AND cd.document_id = d.id
154 AND c.id = cd.category_id
155 AND c.name LIKE ?
156 ORDER BY d.date DESC LIMIT " . escape_limit($limit), array($pid, $doc_catg));
158 while ($result = sqlFetchArray($query)) {
159 $results[] = $result['id'];
161 return ($results ?? false);
164 function isPortalEnabled(): bool
166 if (
167 !$GLOBALS['portal_onsite_two_enable']
169 return false;
172 return true;
175 function isPortalSiteAddressValid(): bool
177 if (
178 // maybe can use filter_var() someday but the default value in GLOBALS
179 // fails with FILTER_VALIDATE_URL
180 !isset($GLOBALS['portal_onsite_two_address'])
182 return false;
185 return true;
188 function isPortalAllowed($pid): bool
190 $return = false;
192 $portalStatus = sqlQuery("SELECT allow_patient_portal FROM patient_data WHERE pid = ?", [$pid]);
193 if ($portalStatus['allow_patient_portal'] == 'YES') {
194 $return = true;
196 return $return;
199 function isApiAllowed($pid): bool
201 $return = false;
203 $apiStatus = sqlQuery("SELECT prevent_portal_apps FROM patient_data WHERE pid = ?", [$pid]);
204 if (strtoupper($apiStatus['prevent_portal_apps'] ?? '') != 'YES') {
205 $return = true;
207 return $return;
210 function areCredentialsCreated($pid): bool
212 $return = false;
213 $credentialsCreated = sqlQuery("SELECT date_created FROM `patient_access_onsite` WHERE `pid`=?", [$pid]);
214 if ($credentialsCreated['date_created'] ?? null) {
215 $return = true;
218 return $return;
221 function isContactEmail($pid): bool
223 $return = false;
225 $email = sqlQuery("SELECT email, email_direct FROM patient_data WHERE pid = ?", [$pid]);
226 if (!empty($email['email']) || !empty($email['email_direct'])) {
227 $return = true;
229 return $return;
232 function isEnforceSigninEmailPortal(): bool
234 if (
235 $GLOBALS['enforce_signin_email']
237 return true;
240 return false;
243 function deceasedDays($days_deceased)
245 $deceased_days = intval($days_deceased['days_deceased'] ?? '');
246 if ($deceased_days == 0) {
247 $num_of_days = xl("Today");
248 } elseif ($deceased_days == 1) {
249 $num_of_days = $deceased_days . " " . xl("day ago");
250 } elseif ($deceased_days > 1 && $deceased_days < 90) {
251 $num_of_days = $deceased_days . " " . xl("days ago");
252 } elseif ($deceased_days >= 90 && $deceased_days < 731) {
253 $num_of_days = "~" . round($deceased_days / 30) . " " . xl("months ago"); // function intdiv available only in php7
254 } elseif ($deceased_days >= 731) {
255 $num_of_days = xl("More than") . " " . round($deceased_days / 365) . " " . xl("years ago");
258 if (strlen($days_deceased['date_deceased'] ?? '') > 10 && $GLOBALS['date_display_format'] < 1) {
259 $deceased_date = substr($days_deceased['date_deceased'], 0, 10);
260 } else {
261 $deceased_date = oeFormatShortDate($days_deceased['date_deceased'] ?? '');
264 return xlt("Deceased") . " - " . text($deceased_date) . " (" . text($num_of_days) . ")";
267 $deceased = is_patient_deceased($pid);
270 // Display image in 'widget style'
271 function image_widget($doc_id, $doc_catg)
273 global $pid, $web_root;
274 $docobj = new Document($doc_id);
275 $image_file = $docobj->get_url_file();
276 $image_file_name = $docobj->get_name();
277 $image_width = $GLOBALS['generate_doc_thumb'] == 1 ? '' : 'width=100';
278 $extension = substr($image_file_name, strrpos($image_file_name, "."));
279 $viewable_types = array('.png', '.jpg', '.jpeg', '.png', '.bmp', '.PNG', '.JPG', '.JPEG', '.PNG', '.BMP');
280 if (in_array($extension, $viewable_types)) { // extension matches list
281 $to_url = "<td> <a href = '$web_root" .
282 "/controller.php?document&retrieve&patient_id=" . attr_url($pid) . "&document_id=" . attr_url($doc_id) . "&as_file=false&original_file=true&disable_exit=false&show_original=true'" .
283 " onclick='top.restoreSession();' class='image_modal'>" .
284 " <img src = '$web_root" .
285 "/controller.php?document&retrieve&patient_id=" . attr_url($pid) . "&document_id=" . attr_url($doc_id) . "&as_file=false'" .
286 " $image_width alt='" . attr($doc_catg) . ":" . attr($image_file_name) . "'> </a> </td> <td class='align-middle'>" .
287 text($doc_catg) . '<br />&nbsp;' . text($image_file_name) . "</td>";
288 } else {
289 $to_url = "<td> <a href='" . $web_root . "/controller.php?document&retrieve" .
290 "&patient_id=" . attr_url($pid) . "&document_id=" . attr_url($doc_id) . "'" .
291 " onclick='top.restoreSession()' class='btn btn-primary btn-sm'>" .
292 "<span>" .
293 xlt("View") . "</a> &nbsp;" .
294 text("$doc_catg - $image_file_name") .
295 "</span> </td>";
298 echo "<table><tr>";
299 echo $to_url;
300 echo "</tr></table>";
303 // Determine if the Vitals form is in use for this site.
304 $tmp = sqlQuery("SELECT count(*) AS count FROM registry WHERE directory = 'vitals' AND state = 1");
305 $vitals_is_registered = $tmp['count'];
307 // Get patient/employer/insurance information.
309 $result = getPatientData($pid, "*, DATE_FORMAT(DOB,'%Y-%m-%d') as DOB_YMD");
310 $result2 = getEmployerData($pid);
311 $result3 = getInsuranceData(
312 $pid,
313 "primary",
314 "copay,
315 provider,
316 DATE_FORMAT(`date`,'%Y-%m-%d') as effdate,
317 DATE_FORMAT(`date_end`,'%Y-%m-%d') as effdate_end"
319 $insco_name = "";
320 if (!empty($result3['provider'])) { // Use provider in case there is an ins record w/ unassigned insco
321 $insco_name = getInsuranceProvider($result3['provider']);
324 $arrOeUiSettings = array(
325 'page_id' => 'core.mrd',
326 'heading_title' => xl('Medical Record Dashboard'),
327 'include_patient_name' => true,
328 'expandable' => true,
329 'expandable_files' => array(), //all file names need suffix _xpd
330 'action' => "", //conceal, reveal, search, reset, link or back
331 'action_title' => "",
332 'action_href' => "", //only for actions - reset, link or back
333 'show_help_icon' => true,
334 'help_file_name' => "medical_dashboard_help.php"
336 $oemr_ui = new OemrUI($arrOeUiSettings);
338 <!DOCTYPE html>
339 <html>
341 <head>
342 <?php
343 Header::setupHeader(['common']);
344 require_once("$srcdir/options.js.php");
346 <script>
347 // Process click on diagnosis for referential cds popup.
348 function referentialCdsClick(codetype, codevalue) {
349 top.restoreSession();
350 // Force a new window instead of iframe to address cross site scripting potential
351 dlgopen('../education.php?type=' + encodeURIComponent(codetype) + '&code=' + encodeURIComponent(codevalue), '_blank', 1024, 750,true);
354 function oldEvt(apptdate, eventid) {
355 let title = <?php echo xlj('Appointments'); ?>;
356 dlgopen('../../main/calendar/add_edit_event.php?date=' + encodeURIComponent(apptdate) + '&eid=' + encodeURIComponent(eventid), '_blank', 800, 500, '', title);
359 function advdirconfigure() {
360 dlgopen('advancedirectives.php', '_blank', 400, 500);
363 function refreshme() {
364 top.restoreSession();
365 location.reload();
368 // Process click on Delete link.
369 function deleteme() { // @todo don't think this is used any longer!!
370 dlgopen('../deleter.php?patient=' + <?php echo js_url($pid); ?> + '&csrf_token_form=' + <?php echo js_url(CsrfUtils::collectCsrfToken()); ?>, '_blank', 500, 450, '', '', {
371 allowResize: false,
372 allowDrag: false,
373 dialogId: 'patdel',
374 type: 'iframe'
376 return false;
379 // Called by the deleteme.php window on a successful delete.
380 function imdeleted() {
381 top.clearPatient();
384 function newEvt() {
385 let title = <?php echo xlj('Appointments'); ?>;
386 let url = '../../main/calendar/add_edit_event.php?patientid=' + <?php echo js_url($pid); ?>;
387 dlgopen(url, '_blank', 800, 500, '', title);
388 return false;
391 function getWeno() {
392 top.restoreSession();
393 location.href = '../../weno/indexrx.php'
396 function toggleIndicator(target, div) {
397 // <i id="show_hide" class="fa fa-lg small fa-eye-slash" title="Click to Hide"></i>
398 $mode = $(target).find(".indicator").text();
399 if ($mode == <?php echo xlj('collapse'); ?>) {
400 $(target).find(".indicator").text(<?php echo xlj('expand'); ?>);
401 $("#" + div).hide();
402 $.post("../../../library/ajax/user_settings.php", {
403 target: div,
404 mode: 0,
405 csrf_token_form: <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>
407 } else {
408 $(target).find(".indicator").text(<?php echo xlj('collapse'); ?>);
409 $("#" + div).show();
410 $.post("../../../library/ajax/user_settings.php", {
411 target: div,
412 mode: 1,
413 csrf_token_form: <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>
418 // edit prescriptions dialog.
419 // called from stats.php.
421 function editScripts(url) {
422 var AddScript = function() {
423 var __this = $(this);
424 __this.find("#clearButton").css("display", "");
425 __this.find("#backButton").css("display", "");
426 __this.find("#addButton").css("display", "none");
428 var iam = top.frames.editScripts;
429 iam.location.href = '<?php echo $GLOBALS['webroot'] ?>/controller.php?prescription&edit&id=0&pid=' + <?php echo js_url($pid); ?>;
431 var ListScripts = function() {
432 var __this = $(this);
433 __this.find("#clearButton").css("display", "none");
434 __this.find("#backButton").css("display", "none");
435 __this.find("#addButton").css("display", "");
436 var iam = top.frames.editScripts
437 iam.location.href = '<?php echo $GLOBALS['webroot'] ?>/controller.php?prescription&list&id=' + <?php echo js_url($pid); ?>;
440 let title = <?php echo xlj('Prescriptions'); ?>;
441 let w = 960; // for weno width
443 dlgopen(url, 'editScripts', w, 400, '', '', {
444 buttons: [{
445 text: <?php echo xlj('Add'); ?>,
446 close: false,
447 id: 'addButton',
448 class: 'btn-primary btn-sm',
449 click: AddScript
452 text: <?php echo xlj('Clear'); ?>,
453 close: false,
454 id: 'clearButton',
455 style: 'display:none;',
456 class: 'btn-primary btn-sm',
457 click: AddScript
460 text: <?php echo xlj('Back'); ?>,
461 close: false,
462 id: 'backButton',
463 style: 'display:none;',
464 class: 'btn-primary btn-sm',
465 click: ListScripts
468 text: <?php echo xlj('Quit'); ?>,
469 close: true,
470 id: 'doneButton',
471 class: 'btn-secondary btn-sm'
474 onClosed: 'refreshme',
475 allowResize: true,
476 allowDrag: true,
477 dialogId: 'editscripts',
478 type: 'iframe'
483 * async function fetchHtml(...)
485 * @param {*} url
486 * @param {boolean} embedded
487 * @param {boolean} sessionRestore
488 * @returns {text}
490 async function fetchHtml(url, embedded = false, sessionRestore = false) {
491 if (sessionRestore === true) {
492 // restore cookie before fetch.
493 top.restoreSession();
495 let csrf = new FormData;
496 // a security given.
497 csrf.append("csrf_token_form", <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>);
498 if (embedded === true) {
499 // special formatting in certain widgets.
500 csrf.append("embeddedScreen", true);
503 const response = await fetch(url, {
504 method: 'POST',
505 credentials: 'same-origin',
506 body: csrf
508 return await response.text();
512 * async function placeHtml(...) will await fetch of html then place in divId.
513 * This function will return a promise for use to init various items regarding
514 * inserted HTML if needed.
515 * If divId does not exist, then will skip.
516 * Example
518 * @param {*} url
519 * @param {string} divId id
520 * @param {boolean} embedded
521 * @param {boolean} sessionRestore
522 * @returns {object} promise
524 async function placeHtml(url, divId, embedded = false, sessionRestore = false) {
525 const contentDiv = document.getElementById(divId);
526 if (contentDiv) {
527 await fetchHtml(url, embedded, sessionRestore).then(fragment => {
528 contentDiv.innerHTML = fragment;
533 if (typeof load_location === 'undefined') {
534 function load_location(location) {
535 top.restoreSession();
536 document.location = location;
540 $(function() {
541 var msg_updation = '';
542 <?php
543 if ($GLOBALS['erx_enable']) {
544 $soap_status = sqlStatement("select soap_import_status,pid from patient_data where pid=? and soap_import_status in ('1','3')", array($pid));
545 while ($row_soapstatus = sqlFetchArray($soap_status)) { ?>
546 top.restoreSession();
547 $.ajax({
548 type: "POST",
549 url: "../../soap_functions/soap_patientfullmedication.php",
550 dataType: "html",
551 data: {
552 patient: <?php echo js_escape($row_soapstatus['pid']); ?>,
554 async: false,
555 success: function(thedata) {
556 //alert(thedata);
557 msg_updation += thedata;
559 error: function() {
560 alert('ajax error');
564 top.restoreSession();
565 $.ajax({
566 type: "POST",
567 url: "../../soap_functions/soap_allergy.php",
568 dataType: "html",
569 data: {
570 patient: <?php echo js_escape($row_soapstatus['pid']); ?>,
572 async: false,
573 success: function(thedata) {
574 //alert(thedata);
575 msg_updation += thedata;
577 error: function() {
578 alert('ajax error');
581 <?php
582 if ($GLOBALS['erx_import_status_message']) { ?>
583 if (msg_updation)
584 alert(msg_updation);
585 <?php
591 // load divs
592 placeHtml("stats.php", "stats_div", true);
593 placeHtml("pnotes_fragment.php", 'pnotes_ps_expand').then(() => {
594 // must be delegated event!
595 $(this).on("click", ".complete_btn", function() {
596 let btn = $(this);
597 let csrf = new FormData;
598 csrf.append("csrf_token_form", <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>);
599 fetch("pnotes_fragment.php?docUpdateId=" + encodeURIComponent(btn.attr('data-id')), {
600 method: "POST",
601 credentials: 'same-origin',
602 body: csrf
604 .then(function() {
605 placeHtml("pnotes_fragment.php", 'pnotes_ps_expand');
609 placeHtml("disc_fragment.php", "disclosures_ps_expand");
610 placeHtml("labdata_fragment.php", "labdata_ps_expand");
611 placeHtml("track_anything_fragment.php", "track_anything_ps_expand");
612 <?php if ($vitals_is_registered && AclMain::aclCheckCore('patients', 'med')) { ?>
613 // Initialize the Vitals form if it is registered and user is authorized.
614 placeHtml("vitals_fragment.php", "vitals_ps_expand");
615 <?php } ?>
617 <?php if ($GLOBALS['enable_cdr'] && $GLOBALS['enable_cdr_crw']) { ?>
618 placeHtml("clinical_reminders_fragment.php", "clinical_reminders_ps_expand", true, true).then(() => {
619 // (note need to place javascript code here also to get the dynamic link to work)
620 $(".medium_modal").on('click', function(e) {
621 e.preventDefault();
622 e.stopPropagation();
623 dlgopen('', '', 800, 200, '', '', {
624 buttons: [{
625 text: <?php echo xlj('Close'); ?>,
626 close: true,
627 style: 'secondary btn-sm'
629 onClosed: 'refreshme',
630 allowResize: false,
631 allowDrag: true,
632 dialogId: 'demreminder',
633 type: 'iframe',
634 url: $(this).attr('href')
638 <?php } // end crw
641 <?php if ($GLOBALS['enable_cdr'] && $GLOBALS['enable_cdr_prw']) { ?>
642 placeHtml("patient_reminders_fragment.php", "patient_reminders_ps_expand", false, true);
643 <?php } // end prw
646 <?php
647 // Initialize for each applicable LBF form.
648 $gfres = sqlStatement("SELECT grp_form_id
649 FROM layout_group_properties
650 WHERE grp_form_id LIKE 'LBF%'
651 AND grp_group_id = ''
652 AND grp_repeats > 0
653 AND grp_activity = 1
654 ORDER BY grp_seq, grp_title");
655 while ($gfrow = sqlFetchArray($gfres)) { ?>
656 $(<?php echo js_escape("#" . $gfrow['grp_form_id'] . "_ps_expand"); ?>).load("lbf_fragment.php?formname=" + <?php echo js_url($gfrow['grp_form_id']); ?>, {
657 csrf_token_form: <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>
659 <?php } ?>
660 tabbify();
662 // modal for dialog boxes
663 $(".large_modal").on('click', function(e) {
664 e.preventDefault();
665 e.stopPropagation();
666 dlgopen('', '', 1000, 600, '', '', {
667 buttons: [{
668 text: <?php echo xlj('Close'); ?>,
669 close: true,
670 style: 'secondary btn-sm'
672 allowResize: true,
673 allowDrag: true,
674 dialogId: '',
675 type: 'iframe',
676 url: $(this).attr('href')
680 $(".rx_modal").on('click', function(e) {
681 e.preventDefault();
682 e.stopPropagation();
683 var title = <?php echo xlj('Amendments'); ?>;
684 dlgopen('', 'editAmendments', 800, 300, '', title, {
685 onClosed: 'refreshme',
686 allowResize: true,
687 allowDrag: true,
688 dialogId: '',
689 type: 'iframe',
690 url: $(this).attr('href')
694 // modal for image viewer
695 $(".image_modal").on('click', function(e) {
696 e.preventDefault();
697 e.stopPropagation();
698 dlgopen('', '', 400, 300, '', <?php echo xlj('Patient Images'); ?>, {
699 allowResize: true,
700 allowDrag: true,
701 dialogId: '',
702 type: 'iframe',
703 url: $(this).attr('href')
707 $(".deleter").on('click', function(e) {
708 e.preventDefault();
709 e.stopPropagation();
710 dlgopen('', '', 600, 360, '', '', {
711 buttons: [{
712 text: <?php echo xlj('Close'); ?>,
713 close: true,
714 style: 'secondary btn-sm'
716 //onClosed: 'imdeleted',
717 allowResize: false,
718 allowDrag: false,
719 dialogId: 'patdel',
720 type: 'iframe',
721 url: $(this).attr('href')
725 $(".iframe1").on('click', function(e) {
726 e.preventDefault();
727 e.stopPropagation();
728 dlgopen('', '', 350, 300, '', '', {
729 buttons: [{
730 text: <?php echo xlj('Close'); ?>,
731 close: true,
732 style: 'secondary btn-sm'
734 allowResize: true,
735 allowDrag: true,
736 dialogId: '',
737 type: 'iframe',
738 url: $(this).attr('href')
741 // for patient portal
742 $(".small_modal").on('click', function(e) {
743 e.preventDefault();
744 e.stopPropagation();
745 dlgopen('', '', 550, 550, '', '', {
746 buttons: [{
747 text: <?php echo xlj('Close'); ?>,
748 close: true,
749 style: 'secondary btn-sm'
751 allowResize: true,
752 allowDrag: true,
753 dialogId: '',
754 type: 'iframe',
755 url: $(this).attr('href')
759 function openReminderPopup() {
760 top.restoreSession()
761 dlgopen('', 'reminders', 500, 250, '', '', {
762 buttons: [{
763 text: <?php echo xlj('Close'); ?>,
764 close: true,
765 style: 'secondary btn-sm'
767 allowResize: true,
768 allowDrag: true,
769 dialogId: '',
770 type: 'iframe',
771 url: $("#reminder_popup_link").attr('href')
775 <?php if ($GLOBALS['patient_birthday_alert']) {
776 // To display the birthday alert:
777 // 1. The patient is not deceased
778 // 2. The birthday is today (or in the past depending on global selection)
779 // 3. The notification has not been turned off (or shown depending on global selection) for this year
780 $birthdayAlert = new BirthdayReminder($pid, $_SESSION['authUserID']);
781 if ($birthdayAlert->isDisplayBirthdayAlert()) {
783 // show the active reminder modal
784 dlgopen('', 'bdayreminder', 300, 170, '', false, {
785 allowResize: false,
786 allowDrag: true,
787 dialogId: '',
788 type: 'iframe',
789 url: $("#birthday_popup").attr('href')
792 <?php } elseif ($active_reminders || $all_allergy_alerts) { ?>
793 openReminderPopup();
794 <?php } ?>
795 <?php } elseif ($active_reminders || $all_allergy_alerts) { ?>
796 openReminderPopup();
797 <?php } ?>
799 // $(".card-title").on('click', "button", (e) => {
800 // console.debug("click");
801 // updateUserVisibilitySetting(e);
802 // });
806 * Change the preference to expand/collapse a given card.
808 * For the given e element, find the corresponding card body, determine if it is collapsed
809 * or shown, and then save the state to the user preferences via an async fetch call POST'ing
810 * the updated setting.
812 * @var e element The Button that was clicked to collapse/expand the card
814 async function updateUserVisibilitySetting(e) {
815 const targetID = e.target.getAttribute("data-target");
816 const target = document.querySelector(targetID);
817 const targetStr = targetID.substring(1);
819 let formData = new FormData();
820 formData.append("csrf_token_form", <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>);
821 formData.append("target", targetStr);
822 formData.append("mode", (target.classList.contains("show")) ? 0 : 1);
824 const response = await fetch("../../../library/ajax/user_settings.php", {
825 method: "POST",
826 credentials: 'same-origin',
827 body: formData,
830 const update = await response.text();
831 return update;
834 // Update the User's visibility setting when the card header is clicked
835 function cardTitleButtonClickListener() {
836 const buttons = document.querySelectorAll(".card-title a[data-toggle='collapse']");
837 buttons.forEach((b) => {
838 b.addEventListener("click", (e) => {
839 updateUserVisibilitySetting(e);
844 // JavaScript stuff to do when a new patient is set.
846 function setMyPatient() {
847 <?php
848 if (isset($_GET['set_pid'])) {
849 $date_of_death = is_patient_deceased($pid);
850 if (!empty($date_of_death)) {
851 $date_of_death = $date_of_death['date_deceased'];
854 parent.left_nav.setPatient(<?php echo js_escape($result['fname'] . " " . $result['lname']) .
855 "," . js_escape($pid) . "," . js_escape($result['pubpid']) . ",'',";
856 if (empty($date_of_death)) {
857 echo js_escape(" " . xl('DOB') . ": " . oeFormatShortDate($result['DOB_YMD']) . " " . xl('Age') . ": " . getPatientAgeDisplay($result['DOB_YMD']));
858 } else {
859 echo js_escape(" " . xl('DOB') . ": " . oeFormatShortDate($result['DOB_YMD']) . " " . xl('Age at death') . ": " . oeFormatAge($result['DOB_YMD'], $date_of_death));
860 } ?>);
861 var EncounterDateArray = new Array;
862 var CalendarCategoryArray = new Array;
863 var EncounterIdArray = new Array;
864 var Count = 0;
865 <?php
866 //Encounter details are stored to javacript as array.
867 $result4 = sqlStatement("SELECT fe.encounter,fe.date,openemr_postcalendar_categories.pc_catname FROM form_encounter AS fe " .
868 " left join openemr_postcalendar_categories on fe.pc_catid=openemr_postcalendar_categories.pc_catid WHERE fe.pid = ? order by fe.date desc", array($pid));
869 if (sqlNumRows($result4) > 0) {
870 while ($rowresult4 = sqlFetchArray($result4)) { ?>
871 EncounterIdArray[Count] = <?php echo js_escape($rowresult4['encounter']); ?>;
872 EncounterDateArray[Count] = <?php echo js_escape(oeFormatShortDate(date("Y-m-d", strtotime($rowresult4['date'])))); ?>;
873 CalendarCategoryArray[Count] = <?php echo js_escape(xl_appt_category($rowresult4['pc_catname'])); ?>;
874 Count++;
875 <?php
879 parent.left_nav.setPatientEncounter(EncounterIdArray, EncounterDateArray, CalendarCategoryArray);
880 <?php
881 } // end setting new pid
883 parent.left_nav.syncRadios();
884 <?php if ((isset($_GET['set_pid'])) && (isset($_GET['set_encounterid'])) && (intval($_GET['set_encounterid']) > 0)) {
885 $query_result = sqlQuery("SELECT `date` FROM `form_encounter` WHERE `encounter` = ?", array($encounter)); ?>
886 encurl = 'encounter/encounter_top.php?set_encounter=' + <?php echo js_url($encounter); ?> + '&pid=' + <?php echo js_url($pid); ?>;
887 parent.left_nav.setEncounter(<?php echo js_escape(oeFormatShortDate(date("Y-m-d", strtotime($query_result['date'])))); ?>, <?php echo js_escape($encounter); ?>, 'enc');
888 top.restoreSession();
889 parent.left_nav.loadFrame('enc2', 'enc', 'patient_file/' + encurl);
890 <?php } // end setting new encounter id (only if new pid is also set)
894 $(window).on('load', function() {
895 setMyPatient();
898 document.addEventListener("DOMContentLoaded", () => {
899 cardTitleButtonClickListener();
901 </script>
903 <style>
904 /* Bad practice to override here, will get moved to base style theme */
905 .card {
906 box-shadow: 1px 1px 1px hsl(0 0% 0% / .2);
907 border-radius: 0;
910 <?php
911 if (!empty($GLOBALS['right_justify_labels_demographics']) && ($_SESSION['language_direction'] == 'ltr')) { ?>
912 div.tab td.label_custom, div.label_custom {
913 text-align: right !important;
916 div.tab td.data, div.data {
917 padding-left: 0.5em;
918 padding-right: 2em;
920 <?php
921 } ?>
923 <?php
924 // This is for layout font size override.
925 $grparr = array();
926 getLayoutProperties('DEM', $grparr, 'grp_size');
927 if (!empty($grparr['']['grp_size'])) {
928 $FONTSIZE = round($grparr['']['grp_size'] * 1.333333);
929 $FONTSIZE = round($FONTSIZE * 0.0625, 2);
932 /* Override font sizes in the theme. */
933 #DEM .groupname {
934 font-size: <?php echo attr($FONTSIZE); ?>rem;
937 #DEM .label {
938 font-size: <?php echo attr($FONTSIZE); ?>rem;
941 #DEM .data {
942 font-size: <?php echo attr($FONTSIZE); ?>rem;
945 #DEM .data td {
946 font-size: <?php echo attr($FONTSIZE); ?>rem;
949 <?php } ?> :root {
950 --white: #fff;
951 --bg: hsl(0 0% 90%);
954 body {
955 background: var(--bg) !important;
958 section {
959 background: var(--white);
960 margin-top: .25em;
961 padding: .25em;
964 .section-header-dynamic {
965 border-bottom: none;
967 </style>
968 <title><?php echo xlt("Dashboard{{patient file}}"); ?></title>
969 </head>
971 <body class="mt-1 patient-demographic bg-light">
973 <?php
974 // Create and fire the patient demographics view event
975 $viewEvent = new ViewEvent($pid);
976 $viewEvent = $GLOBALS["kernel"]->getEventDispatcher()->dispatch($viewEvent, ViewEvent::EVENT_HANDLE, 10);
977 $thisauth = AclMain::aclCheckCore('patients', 'demo');
979 if (!$thisauth || !$viewEvent->authorized()) {
980 echo $twig->getTwig()->render('core/unauthorized-partial.html.twig', ['pageTitle' => xl("Medical Dashboard")]);
981 exit();
985 <div id="container_div" class="<?php echo $oemr_ui->oeContainer(); ?> mb-2">
986 <a href='../reminder/active_reminder_popup.php' id='reminder_popup_link' style='display: none' onclick='top.restoreSession()'></a>
987 <a href='../birthday_alert/birthday_pop.php?pid=<?php echo attr_url($pid); ?>&user_id=<?php echo attr_url($_SESSION['authUserID']); ?>' id='birthday_popup' style='display: none;' onclick='top.restoreSession()'></a>
988 <?php
990 if ($thisauth) {
991 if ($result['squad'] && !AclMain::aclCheckCore('squads', $result['squad'])) {
992 $thisauth = 0;
996 if ($thisauth) :
997 require_once("$include_root/patient_file/summary/dashboard_header.php");
998 endif;
1000 $list_id = "dashboard"; // to indicate nav item is active, count and give correct id
1001 // Collect the patient menu then build it
1002 $menuPatient = new PatientMenuRole($twig);
1003 $menuPatient->displayHorizNavBarMenu();
1004 // Get the document ID of the patient ID card if access to it is wanted here.
1005 $idcard_doc_id = false;
1006 if ($GLOBALS['patient_id_category_name']) {
1007 $idcard_doc_id = get_document_by_catg($pid, $GLOBALS['patient_id_category_name'], 3);
1010 <div class="main mb-5">
1011 <!-- start main content div -->
1012 <div class="row">
1013 <div class="col-md-8">
1014 <?php
1016 if ($deceased > 0) :
1017 echo $twig->getTwig()->render('patient/partials/deceased.html.twig', [
1018 'deceasedDays' => deceasedDays($deceased),
1020 endif;
1022 $sectionRenderEvents = $ed->dispatch(new SectionEvent('primary'), SectionEvent::EVENT_HANDLE);
1023 $sectionCards = $sectionRenderEvents->getCards();
1025 $t = $twig->getTwig();
1027 foreach ($sectionCards as $card) {
1028 $_auth = $card->getAcl();
1029 if (!AclMain::aclCheckCore($_auth[0], $_auth[1])) {
1030 continue;
1033 $btnLabel = false;
1034 if ($card->canAdd()) {
1035 $btnLabel = 'Add';
1036 } elseif ($card->canEdit()) {
1037 $btnLabel = 'Edit';
1040 $viewArgs = [
1041 'title' => $card->getTitle(),
1042 'id' => $card->getIdentifier(),
1043 'initiallyCollapsed' => !$card->isInitiallyCollapsed(),
1044 'card_bg_color' => $card->getBackgroundColorClass(),
1045 'card_text_color' => $card->getTextColorClass(),
1046 'forceAlwaysOpen' => !$card->canCollapse(),
1047 'btnLabel' => $btnLabel,
1048 'btnLink' => 'test',
1051 echo $t->render($card->getTemplateFile(), array_merge($card->getTemplateVariables(), $viewArgs));
1054 if (!$GLOBALS['hide_billing_widget']) :
1055 $forceBillingExpandAlways = ($GLOBALS['force_billing_widget_open']) ? true : false;
1056 $patientbalance = get_patient_balance($pid, false);
1057 $insurancebalance = get_patient_balance($pid, true) - $patientbalance;
1058 $totalbalance = $patientbalance + $insurancebalance;
1059 $unallocated_amt = get_unallocated_patient_balance($pid);
1061 $id = "billing_ps_expand";
1062 $dispatchResult = $ed->dispatch(new CardRenderEvent('billing'), CardRenderEvent::EVENT_HANDLE);
1064 $viewArgs = [
1065 'title' => xl('Billing'),
1066 'id' => $id,
1067 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1068 'hideBtn' => true,
1069 'patientBalance' => $patientbalance,
1070 'insuranceBalance' => $insurancebalance,
1071 'totalBalance' => $totalbalance,
1072 'unallocated' => $unallocated_amt,
1073 'forceAlwaysOpen' => $forceBillingExpandAlways,
1074 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1075 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1078 if (!empty($result['billing_note'])) {
1079 $viewArgs['billingNote'] = $result['billing_note'];
1082 if (!empty($result3['provider'])) {
1083 $viewArgs['provider'] = true;
1084 $viewArgs['insName'] = $insco_name;
1085 $viewArgs['copay'] = $result3['copay'];
1086 $viewArgs['effDate'] = $result3['effdate'];
1087 $viewArgs['effDateEnd'] = $result3['effdate_end'];
1090 echo $twig->getTwig()->render('patient/card/billing.html.twig', $viewArgs);
1091 endif; // End the hide_billing_widget
1093 // if anyone wants to render anything before the patient demographic list
1094 $GLOBALS["kernel"]->getEventDispatcher()->dispatch(new RenderEvent($pid), RenderEvent::EVENT_SECTION_LIST_RENDER_BEFORE, 10);
1096 if (AclMain::aclCheckCore('patients', 'demo')) :
1097 $dispatchResult = $ed->dispatch(new CardRenderEvent('demographic'), CardRenderEvent::EVENT_HANDLE);
1098 // Render the Demographics box
1099 $viewArgs = [
1100 'title' => xl("Demographics"),
1101 'id' => "demographics_ps_expand",
1102 'btnLabel' => "Edit",
1103 'btnLink' => "demographics_full.php",
1104 'linkMethod' => "html",
1105 'auth' => ACLMain::aclCheckCore('patients', 'demo', '', 'write'),
1106 'requireRestore' => (!isset($_SESSION['patient_portal_onsite_two'])) ? true : false,
1107 'initiallyCollapsed' => getUserSetting("demographics_ps_expand") == true ? true : false,
1108 'tabID' => "DEM",
1109 'result' => $result,
1110 'result2' => $result2,
1111 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1112 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1114 echo $twig->getTwig()->render('patient/card/tab_base.html.twig', $viewArgs);
1116 // Insurance
1117 $insArr = [];
1118 $insInBinder = '?';
1119 for ($y = 1; count($insurance_array) > $y; $y++) {
1120 $insInBinder .= ',?';
1122 $sql = "SELECT * FROM insurance_data WHERE pid = ? AND type IN(" . $insInBinder . ") ORDER BY type, date DESC";
1123 $params[] = $pid;
1124 $params = array_merge($params, $insurance_array);
1125 $res = sqlStatement($sql, $params);
1126 $prior_ins_type = '';
1128 while ($row = sqlFetchArray($res)) {
1129 if ($row['provider']) {
1130 // since the query is sorted by DATE DESC can use prior ins type to identify
1131 $row['isOld'] = (!empty($row['date_end']) && $row['date_end'] <= date("Y-m-d")) ? true : false;
1132 $icobj = new InsuranceCompany($row['provider']);
1133 $adobj = $icobj->get_address();
1134 $insco_name = trim($icobj->get_name());
1135 $row['insco'] = [
1136 'name' => trim($icobj->get_name()),
1137 'address' => [
1138 'line1' => $adobj->get_line1(),
1139 'line2' => $adobj->get_line2(),
1140 'city' => $adobj->get_city(),
1141 'state' => $adobj->get_state(),
1142 'postal' => $adobj->get_zip(),
1143 'country' => $adobj->get_country()
1146 $row['policy_type'] = (!empty($row['policy_type'])) ? $policy_types[$row['policy_type']] : false;
1147 $row['dispFromDate'] = $row['date'] ? true : false;
1148 $mname = ($row['subscriber_mname'] != "") ? $row['subscriber_mname'] : "";
1149 $row['subscriber_full_name'] = str_replace("%mname%", $mname, "{$row['subscriber_fname']} %mname% {$row['subscriber_lname']}");
1150 $row['until_date'] = $row['isOld'] ? $row['isOld'] : xlt('Present');
1151 $insArr[] = $row;
1152 $prior_ins_type = $row['type'];
1153 } else {
1154 $row['isOld'] = (strcmp($row['type'], $prior_ins_type) == 0) ? true : false;
1155 $row['dispFromDate'] = $row['date'] ? true : false;
1156 $row['insco'] = [
1157 'name' => 'Self-Pay',
1158 'address' => [
1159 'line1' => '',
1160 'line2' => '',
1161 'city' => '',
1162 'state' => '',
1163 'postal' => '',
1164 'country' => ''
1167 $row['policy_type'] = false;
1168 $mname = ''; //($row['subscriber_mname'] != "") ? $row['subscriber_mname'] : "";
1169 $row['subscriber_full_name'] = ' '; // str_replace("%mname%", $mname, "{$row['subscriber_fname']} %mname% {$row['subscriber_lname']}");
1170 $row['until_date'] = ($row['isOld']) ? $row['isOld'] : xlt("Present");
1171 $prior_ins_type = $row['type'];
1172 if ($row['type'] != 'primary') {
1173 continue;
1175 $insArr[] = $row;
1179 if ($GLOBALS["enable_oa"]) {
1180 if (($_POST['status_update'] ?? '') === 'true') {
1181 unset($_POST['status_update']);
1182 $showEligibility = true;
1183 $ok = EDI270::requestEligibleTransaction($pid);
1184 if ($ok === true) {
1185 ob_start();
1186 EDI270::showEligibilityInformation($pid, false);
1187 $output = ob_get_contents();
1188 ob_end_clean();
1189 } else {
1190 $output = $ok;
1192 } else {
1193 ob_start();
1194 EDI270::showEligibilityInformation($pid, true);
1195 $output = ob_get_contents();
1196 ob_end_clean();
1198 } else {
1199 ob_start();
1200 EDI270::showEligibilityInformation($pid, true);
1201 $output = ob_get_contents();
1202 ob_end_clean();
1205 $id = "insurance_ps_expand";
1206 $dispatchResult = $ed->dispatch(new CardRenderEvent('insurance'), CardRenderEvent::EVENT_HANDLE);
1207 $viewArgs = [
1208 'title' => xl("Insurance"),
1209 'id' => $id,
1210 'btnLabel' => "Edit",
1211 'btnLink' => "demographics_full.php",
1212 'linkMethod' => 'html',
1213 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1214 'ins' => $insArr,
1215 'eligibility' => $output,
1216 'enable_oa' => $GLOBALS['enable_oa'],
1217 'auth' => AclMain::aclCheckCore('patients', 'demo', '', 'write'),
1218 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1219 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1222 if (count($insArr) > 0) {
1223 echo $twig->getTwig()->render('patient/card/insurance.html.twig', $viewArgs);
1225 endif; // end if demographics authorized
1227 if (AclMain::aclCheckCore('patients', 'notes')) :
1228 $dispatchResult = $ed->dispatch(new CardRenderEvent('note'), CardRenderEvent::EVENT_HANDLE);
1229 // Notes expand collapse widget
1230 $id = "pnotes_ps_expand";
1231 $viewArgs = [
1232 'title' => xl("Messages"),
1233 'id' => $id,
1234 'btnLabel' => "Edit",
1235 'btnLink' => "pnotes_full.php?form_active=1",
1236 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1237 'linkMethod' => "html",
1238 'bodyClass' => "notab",
1239 'auth' => AclMain::aclCheckCore('patients', 'notes', '', 'write'),
1240 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1241 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1243 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1244 endif; // end if notes authorized
1246 if (AclMain::aclCheckCore('patients', 'reminder') && $GLOBALS['enable_cdr'] && $GLOBALS['enable_cdr_prw']) :
1247 // patient reminders collapse widget
1248 $dispatchResult = $ed->dispatch(new CardRenderEvent('reminder'), CardRenderEvent::EVENT_HANDLE);
1249 $id = "patient_reminders_ps_expand";
1250 $viewArgs = [
1251 'title' => xl('Patient Reminders'),
1252 'id' => $id,
1253 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1254 'btnLabel' => 'Edit',
1255 'btnLink' => '../reminder/patient_reminders.php?mode=simple&patient_id=' . attr_url($pid),
1256 'linkMethod' => 'html',
1257 'bodyClass' => 'notab collapse show',
1258 'auth' => AclMain::aclCheckCore('patients', 'reminder', '', 'write'),
1259 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1260 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1262 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1263 endif; //end if prw is activated
1265 if (AclMain::aclCheckCore('patients', 'disclosure')) :
1266 $authWriteDisclosure = AclMain::aclCheckCore('patients', 'disclosure', '', 'write');
1267 $authAddonlyDisclosure = AclMain::aclCheckCore('patients', 'disclosure', '', 'addonly');
1268 $dispatchResult = $ed->dispatch(new CardRenderEvent('disclosure'), CardRenderEvent::EVENT_HANDLE);
1269 // disclosures expand collapse widget
1270 $id = "disclosures_ps_expand";
1271 $viewArgs = [
1272 'title' => xl('Disclosures'),
1273 'id' => $id,
1274 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1275 'btnLabel' => 'Edit',
1276 'btnLink' => 'disclosure_full.php',
1277 'linkMethod' => 'html',
1278 'bodyClass' => 'notab collapse show',
1279 'auth' => ($authWriteDisclosure || $authAddonlyDisclosure),
1280 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1281 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1283 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1284 endif; // end if disclosures authorized
1286 if ($GLOBALS['amendments'] && AclMain::aclCheckCore('patients', 'amendment')) :
1287 $dispatchResult = $ed->dispatch(new CardRenderEvent('amendment'), CardRenderEvent::EVENT_HANDLE);
1288 // Amendments widget
1289 $sql = "SELECT * FROM amendments WHERE pid = ? ORDER BY amendment_date DESC";
1290 $result = sqlStatement($sql, [$pid]);
1291 $amendments = [];
1292 while ($row = sqlFetchArray($result)) {
1293 $amendments[] = $row;
1296 $id = "amendments_ps_expand";
1297 $viewArgs = [
1298 'title' => xl('Amendments'),
1299 'id' => $id,
1300 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1301 'btnLabel' => 'Edit',
1302 'btnLink' => $GLOBALS['webroot'] . "/interface/patient_file/summary/list_amendments.php?id=" . attr_url($pid),
1303 'btnCLass' => '',
1304 'linkMethod' => 'html',
1305 'bodyClass' => 'notab collapse show',
1306 'auth' => AclMain::aclCheckCore('patients', 'amendment', '', ['write', 'addonly']),
1307 'amendments' => $amendments,
1308 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1309 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1311 echo $twig->getTwig()->render('patient/card/amendments.html.twig', $viewArgs);
1312 endif; // end amendments authorized
1314 if (AclMain::aclCheckCore('patients', 'lab')) :
1315 $dispatchResult = $ed->dispatch(new CardRenderEvent('lab'), CardRenderEvent::EVENT_HANDLE);
1316 // labdata expand collapse widget
1317 // check to see if any labdata exist
1318 $spruch = "SELECT procedure_report.date_collected AS date
1319 FROM procedure_report
1320 JOIN procedure_order ON procedure_report.procedure_order_id = procedure_order.procedure_order_id
1321 WHERE procedure_order.patient_id = ?
1322 ORDER BY procedure_report.date_collected DESC";
1323 $existLabdata = sqlQuery($spruch, array($pid));
1324 $widgetAuth = ($existLabdata) ? true : false;
1326 $id = "labdata_ps_expand";
1327 $viewArgs = [
1328 'title' => xl('Labs'),
1329 'id' => $id,
1330 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1331 'btnLabel' => 'Trend',
1332 'btnLink' => "../summary/labdata.php",
1333 'linkMethod' => 'html',
1334 'bodyClass' => 'collapse show',
1335 'auth' => $widgetAuth,
1336 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1337 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1339 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1340 endif; // end labs authorized
1342 if ($vitals_is_registered && AclMain::aclCheckCore('patients', 'med')) :
1343 $dispatchResult = $ed->dispatch(new CardRenderEvent('vital_sign'), CardRenderEvent::EVENT_HANDLE);
1344 // vitals expand collapse widget
1345 // check to see if any vitals exist
1346 $existVitals = sqlQuery("SELECT * FROM form_vitals WHERE pid=?", array($pid));
1347 $widgetAuth = ($existVitals) ? true : false;
1349 $id = "vitals_ps_expand";
1350 $viewArgs = [
1351 'title' => xl('Vitals'),
1352 'id' => $id,
1353 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1354 'btnLabel' => 'Trend',
1355 'btnLink' => "../encounter/trend_form.php?formname=vitals",
1356 'linkMethod' => 'html',
1357 'bodyClass' => 'collapse show',
1358 'auth' => $widgetAuth,
1359 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1360 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1362 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1363 endif; // end vitals
1365 // if anyone wants to render anything after the patient demographic list
1366 $GLOBALS["kernel"]->getEventDispatcher()->dispatch(new RenderEvent($pid), RenderEvent::EVENT_SECTION_LIST_RENDER_AFTER, 10);
1368 // This generates a section similar to Vitals for each LBF form that
1369 // supports charting. The form ID is used as the "widget label".
1370 $gfres = sqlStatement("SELECT grp_form_id AS option_id, grp_title AS title, grp_aco_spec
1371 FROM layout_group_properties
1372 WHERE grp_form_id LIKE 'LBF%'
1373 AND grp_group_id = ''
1374 AND grp_repeats > 0
1375 AND grp_activity = 1
1376 ORDER BY grp_seq, grp_title");
1378 while ($gfrow = sqlFetchArray($gfres)) :
1379 // $jobj = json_decode($gfrow['notes'], true);
1380 $LBF_ACO = empty($gfrow['grp_aco_spec']) ? false : explode('|', $gfrow['grp_aco_spec']);
1381 if ($LBF_ACO && !AclMain::aclCheckCore($LBF_ACO[0], $LBF_ACO[1])) {
1382 continue;
1385 // vitals expand collapse widget
1386 $widgetAuth = false;
1387 if (!$LBF_ACO || AclMain::aclCheckCore($LBF_ACO[0], $LBF_ACO[1], '', 'write')) {
1388 // check to see if any instances exist for this patient
1389 $existVitals = sqlQuery("SELECT * FROM forms WHERE pid = ? AND formdir = ? AND deleted = 0", [$pid, $vitals_form_id]);
1390 $widgetAuth = $existVitals;
1393 $dispatchResult = $ed->dispatch(new CardRenderEvent($gfrow['title']), CardRenderEvent::EVENT_HANDLE);
1394 $viewArgs = [
1395 'title' => xl($gfrow['title']),
1396 'id' => $vitals_form_id,
1397 'initiallyCollapsed' => getUserSetting($vitals_form_id) == true ? true : false,
1398 'btnLabel' => 'Trend',
1399 'btnLink' => "../encounter/trend_form.php?formname=vitals",
1400 'linkMethod' => 'html',
1401 'bodyClass' => 'notab collapse show',
1402 'auth' => $widgetAuth,
1403 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1404 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1406 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1407 endwhile; // end while
1409 </div> <!-- end left column div -->
1410 <div class="col-md-4">
1411 <!-- start right column div -->
1412 <?php
1413 // it's important enough to always show it
1414 $portalCard = new PortalCard($GLOBALS);
1416 $sectionRenderEvents = $ed->dispatch(new SectionEvent('secondary'), SectionEvent::EVENT_HANDLE);
1417 $sectionCards = $sectionRenderEvents->getCards();
1419 $t = $twig->getTwig();
1421 foreach ($sectionCards as $card) {
1422 $_auth = $card->getAcl();
1423 $auth = AclMain::aclCheckCore($_auth[0], $_auth[1]);
1424 if (!$auth) {
1425 continue;
1428 $btnLabel = false;
1429 if ($card->canAdd()) {
1430 $btnLabel = 'Add';
1431 } elseif ($card->canEdit()) {
1432 $btnLabel = 'Edit';
1435 $viewArgs = [
1436 'card' => $card,
1437 'title' => $card->getTitle(),
1438 'id' => $card->getIdentifier() . "_expand",
1439 'auth' => $auth,
1440 'linkMethod' => 'html',
1441 'initiallyCollapsed' => !$card->isInitiallyCollapsed(),
1442 'card_bg_color' => $card->getBackgroundColorClass(),
1443 'card_text_color' => $card->getTextColorClass(),
1444 'forceAlwaysOpen' => !$card->canCollapse(),
1445 'btnLabel' => $btnLabel,
1446 'btnLink' => "javascript:$('#patient_portal').collapse('toggle')",
1449 echo $t->render($card->getTemplateFile(), array_merge($card->getTemplateVariables(), $viewArgs));
1452 if ($GLOBALS['erx_enable']) :
1453 $dispatchResult = $ed->dispatch(new CardRenderEvent('demographics'), CardRenderEvent::EVENT_HANDLE);
1454 echo $twig->getTwig()->render('patient/partials/erx.html.twig', [
1455 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1456 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1458 endif;
1460 // If there is an ID Card or any Photos show the widget
1461 $photos = pic_array($pid, $GLOBALS['patient_photo_category_name']);
1462 if ($photos or $idcard_doc_id) {
1463 $id = "photos_ps_expand";
1464 $dispatchResult = $ed->dispatch(new CardRenderEvent('patient_photo'), CardRenderEvent::EVENT_HANDLE);
1465 $viewArgs = [
1466 'title' => xl("ID Card / Photos"),
1467 'id' => $id,
1468 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1469 'btnLabel' => 'Edit',
1470 'linkMethod' => "javascript",
1471 'bodyClass' => 'collapse show',
1472 'auth' => false,
1473 'patientIDCategoryID' => $GLOBALS['patient_id_category_name'],
1474 'patientPhotoCategoryName' => $GLOBALS['patient_photo_category_name'],
1475 'photos' => $photos,
1476 'idCardDocID' => $idcard_doc_id,
1477 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1478 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1480 echo $twig->getTwig()->render('patient/card/photo.html.twig', $viewArgs);
1483 // Advance Directives
1484 if ($GLOBALS['advance_directives_warning']) {
1485 // advance directives expand collapse widget
1487 $counterFlag = false; //flag to record whether any categories contain ad records
1488 $query = "SELECT id FROM categories WHERE name='Advance Directive'";
1489 $myrow2 = sqlQuery($query);
1490 $advDirArr = [];
1491 if ($myrow2) {
1492 $parentId = $myrow2['id'];
1493 $query = "SELECT id, name FROM categories WHERE parent=?";
1494 $resNew1 = sqlStatement($query, array($parentId));
1495 while ($myrows3 = sqlFetchArray($resNew1)) {
1496 $categoryId = $myrows3['id'];
1497 $nameDoc = $myrows3['name'];
1498 $query = "SELECT documents.date, documents.id
1499 FROM documents
1500 INNER JOIN categories_to_documents ON categories_to_documents.document_id=documents.id
1501 WHERE categories_to_documents.category_id=?
1502 AND documents.foreign_id=?
1503 AND documents.deleted = 0
1504 ORDER BY documents.date DESC";
1505 $resNew2 = sqlStatement($query, array($categoryId, $pid));
1506 $limitCounter = 0; // limit to one entry per category
1507 while (($myrows4 = sqlFetchArray($resNew2)) && ($limitCounter == 0)) {
1508 $dateTimeDoc = $myrows4['date'];
1509 // remove time from datetime stamp
1510 $tempParse = explode(" ", $dateTimeDoc);
1511 $dateDoc = $tempParse[0];
1512 $idDoc = $myrows4['id'];
1513 $tmp = [
1514 'pid' => $pid,
1515 'docID' => $idDoc,
1516 'docName' => $nameDoc,
1517 'docDate' => $dateDoc,
1519 $advDirArr[] = $tmp;
1520 $limitCounter = $limitCounter + 1;
1521 $counterFlag = true;
1525 $id = "adv_directives_ps_expand";
1527 $dispatchResult = $ed->dispatch(new CardRenderEvent('advance_directive'), CardRenderEvent::EVENT_HANDLE);
1528 $viewArgs = [
1529 'title' => xl("Advance Directives"),
1530 'id' => $id,
1531 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1532 'btnLabel' => 'Edit',
1533 'linkMethod' => "javascript",
1534 'btnLink' => "return advdirconfigure();",
1535 'bodyClass' => 'collapse show',
1536 'auth' => true,
1537 'advDirArr' => $advDirArr,
1538 'counterFlag' => $counterFlag,
1539 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1540 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1542 echo $twig->getTwig()->render('patient/card/adv_dir.html.twig', $viewArgs);
1544 } // close advanced dir block
1546 // Show Clinical Reminders for any user that has rules that are permitted.
1547 $clin_rem_check = resolve_rules_sql('', '0', true, '', $_SESSION['authUser']);
1548 $cdr = $GLOBALS['enable_cdr'];
1549 $cdr_crw = $GLOBALS['enable_cdr_crw'];
1550 if (!empty($clin_rem_check) && $cdr && $cdr_crw && AclMain::aclCheckCore('patients', 'alert')) {
1551 // clinical summary expand collapse widget
1552 $id = "clinical_reminders_ps_expand";
1553 $dispatchResult = $ed->dispatch(new CardRenderEvent('clinical_reminders'), CardRenderEvent::EVENT_HANDLE);
1554 $viewArgs = [
1555 'title' => xl("Clinical Reminders"),
1556 'id' => $id,
1557 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1558 'btnLabel' => "Edit",
1559 'btnLink' => "../reminder/clinical_reminders.php?patient_id=" . attr_url($pid),
1560 'linkMethod' => "html",
1561 'auth' => AclMain::aclCheckCore('patients', 'alert', '', 'write'),
1562 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1563 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1565 echo $twig->getTwig()->render('patient/card/loader.html.twig', $viewArgs);
1566 } // end if crw
1568 $displayAppts = false;
1569 $displayRecurrAppts = false;
1570 $displayPastAppts = false;
1572 // Show current and upcoming appointments.
1573 // Recurring appointment support and Appointment Display Sets
1574 // added to Appointments by Ian Jardine ( epsdky ).
1575 if (isset($pid) && !$GLOBALS['disable_calendar'] && AclMain::aclCheckCore('patients', 'appt')) {
1576 $displayAppts = true;
1577 $current_date2 = date('Y-m-d');
1578 $events = array();
1579 $apptNum = (int) $GLOBALS['number_of_appts_to_show'];
1580 $apptNum2 = ($apptNum != 0) ? abs($apptNum) : 10;
1582 $mode1 = !$GLOBALS['appt_display_sets_option'];
1583 $colorSet1 = $GLOBALS['appt_display_sets_color_1'];
1584 $colorSet2 = $GLOBALS['appt_display_sets_color_2'];
1585 $colorSet3 = $GLOBALS['appt_display_sets_color_3'];
1586 $colorSet4 = $GLOBALS['appt_display_sets_color_4'];
1587 $extraAppts = ($mode1) ? 1 : 6;
1588 $extraApptDate = '';
1590 $past_appts = [];
1591 $recallArr = [];
1593 $events = fetchNextXAppts($current_date2, $pid, $apptNum2 + $extraAppts, true);
1595 if ($events) {
1596 $selectNum = 0;
1597 $apptNumber = count($events);
1599 if ($apptNumber <= $apptNum2) {
1600 $extraApptDate = '';
1602 } elseif ($mode1 && $apptNumber == $apptNum2 + 1) {
1603 $extraApptDate = $events[$apptNumber - 1]['pc_eventDate'];
1604 array_pop($events);
1605 --$apptNumber;
1606 $selectNum = 1;
1608 } elseif ($apptNumber == $apptNum2 + 6) {
1609 $extraApptDate = $events[$apptNumber - 1]['pc_eventDate'];
1610 array_pop($events);
1611 --$apptNumber;
1612 $selectNum = 2;
1614 } else { // mode 2 - $apptNum2 < $apptNumber < $apptNum2 + 6
1615 $extraApptDate = '';
1616 $selectNum = 2;
1620 $limitApptIndx = $apptNum2 - 1;
1621 $limitApptDate = $events[$limitApptIndx]['pc_eventDate'] ?? '';
1623 switch ($selectNum) {
1624 case 2:
1625 $lastApptIndx = $apptNumber - 1;
1626 $thisNumber = $lastApptIndx - $limitApptIndx;
1627 for ($i = 1; $i <= $thisNumber; ++$i) {
1628 if ($events[$limitApptIndx + $i]['pc_eventDate'] != $limitApptDate) {
1629 $extraApptDate = $events[$limitApptIndx + $i]['pc_eventDate'];
1630 $events = array_slice($events, 0, $limitApptIndx + $i);
1631 break;
1634 // Break in the loop to improve performance
1635 case 1:
1636 $firstApptIndx = 0;
1637 for ($i = 1; $i <= $limitApptIndx; ++$i) {
1638 if ($events[$limitApptIndx - $i]['pc_eventDate'] != $limitApptDate) {
1639 $firstApptIndx = $apptNum2 - $i;
1640 break;
1643 // Break in the loop to improve performance
1646 if ($extraApptDate) {
1647 if ($extraApptDate != $limitApptDate) {
1648 $apptStyle2 = " style='background-color:" . attr($colorSet3) . ";'";
1649 } else {
1650 $apptStyle2 = " style='background-color:" . attr($colorSet4) . ";'";
1655 $count = 0;
1656 $toggleSet = true;
1657 $priorDate = "";
1658 $therapyGroupCategories = array();
1659 $query = sqlStatement("SELECT pc_catid FROM openemr_postcalendar_categories WHERE pc_cattype = 3 AND pc_active = 1");
1660 while ($result = sqlFetchArray($query)) {
1661 $therapyGroupCategories[] = $result['pc_catid'];
1664 // Build the UI Loop
1665 $appts = [];
1666 foreach ($events as $row) {
1667 $count++;
1668 $dayname = date("D", strtotime($row['pc_eventDate']));
1669 $displayMeridiem = ($GLOBALS['time_display_format'] == 0) ? "" : "am";
1670 $disphour = substr($row['pc_startTime'], 0, 2) + 0;
1671 $dispmin = substr($row['pc_startTime'], 3, 2);
1672 if ($disphour >= 12 && $GLOBALS['time_display_format'] == 1) {
1673 $displayMeridiem = "pm";
1674 if ($disphour > 12) {
1675 $disphour -= 12;
1679 // Note the translaution occurs here instead of in teh Twig file for some specific concatenation needs
1680 $etitle = xl('(Click to edit)');
1681 if ($row['pc_hometext'] != "") {
1682 $etitle = xl('Comments') . ": " . ($row['pc_hometext']) . "\r\n" . $etitle;
1685 $row['etitle'] = $etitle;
1687 if ($extraApptDate && $count > $firstApptIndx) {
1688 $apptStyle = $apptStyle2;
1689 } else {
1690 if ($row['pc_eventDate'] != $priorDate) {
1691 $priorDate = $row['pc_eventDate'];
1692 $toggleSet = !$toggleSet;
1695 $bgColor = ($toggleSet) ? $colorSet2 : $colorSet1;
1698 $row['pc_eventTime'] = sprintf("%02d", $disphour) . ":{$dispmin}";
1699 $row['pc_status'] = generate_display_field(array('data_type' => '1', 'list_id' => 'apptstat'), $row['pc_apptstatus']);
1700 if ($row['pc_status'] == 'None') {
1701 $row['pc_status'] = 'Scheduled';
1704 if (in_array($row['pc_catid'], $therapyGroupCategories)) {
1705 $row['groupName'] = getGroup($row['pc_gid'])['group_name'];
1708 $row['uname'] = text($row['ufname'] . " " . $row['ulname']);
1709 $row['bgColor'] = $bgColor;
1710 $row['dayName'] = $dayname;
1711 $row['displayMeridiem'] = $displayMeridiem;
1712 $row['jsEvent'] = attr_js(preg_replace("/-/", "", $row['pc_eventDate'])) . ', ' . attr_js($row['pc_eid']);
1713 $appts[] = $row;
1716 if ($resNotNull) {
1717 // Show Recall if one exists
1718 $query = sqlStatement("SELECT * FROM `medex_recalls` WHERE `r_pid` = ?", [(int)$pid]);
1719 $recallArr = [];
1720 while ($result2 = sqlFetchArray($query)) {
1721 //tabYourIt('recall', 'main/messages/messages.php?go=' + choice);
1722 //parent.left_nav.loadFrame('1', tabNAME, url);
1723 $recallArr[] = [
1724 'date' => $result2['r_eventDate'],
1725 'reason' => $result2['r_reason'],
1727 $count2++;
1729 $id = "recall_ps_expand";
1730 $dispatchResult = $ed->dispatch(new CardRenderEvent('recall'), CardRenderEvent::EVENT_HANDLE);
1731 echo $twig->getTwig()->render('patient/card/recall.html.twig', [
1732 'title' => xl('Recall'),
1733 'id' => $id,
1734 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1735 'recalls' => $recallArr,
1736 'recallsAvailable' => ($count < 1 && empty($count2)) ? false : true,
1737 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1738 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1741 } // End of Appointments Widget.
1743 /* Widget that shows recurrences for appointments. */
1744 $recurr = [];
1745 if (isset($pid) && !$GLOBALS['disable_calendar'] && $GLOBALS['appt_recurrences_widget'] && AclMain::aclCheckCore('patients', 'appt')) {
1746 $displayRecurrAppts = true;
1747 $count = 0;
1748 $toggleSet = true;
1749 $priorDate = "";
1751 //Fetch patient's recurrences. Function returns array with recurrence appointments' category, recurrence pattern (interpreted), and end date.
1752 $recurrences = fetchRecurrences($pid);
1753 if (!empty($recurrences)) {
1754 foreach ($recurrences as $row) {
1755 if (!recurrence_is_current($row['pc_endDate'])) {
1756 continue;
1759 if (ends_in_a_week($row['pc_endDate'])) {
1760 $row['close_to_end'] = true;
1762 $recurr[] = $row;
1766 /* End of recurrence widget */
1768 // Show PAST appointments.
1769 // added by Terry Hill to allow reverse sorting of the appointments
1770 $direction = "ASC";
1771 if ($GLOBALS['num_past_appointments_to_show'] < 0) {
1772 $direction = "DESC";
1773 ($showpast = -1 * $GLOBALS['num_past_appointments_to_show']);
1774 } else {
1775 $showpast = $GLOBALS['num_past_appointments_to_show'];
1778 if (isset($pid) && !$GLOBALS['disable_calendar'] && $showpast > 0 && AclMain::aclCheckCore('patients', 'appt')) {
1779 $displayPastAppts = true;
1781 $query = "SELECT e.pc_eid, e.pc_aid, e.pc_title, e.pc_eventDate, e.pc_startTime, e.pc_hometext, u.fname, u.lname, u.mname, c.pc_catname, e.pc_apptstatus, e.pc_facility
1782 FROM openemr_postcalendar_events AS e,
1783 users AS u,
1784 openemr_postcalendar_categories AS c
1785 WHERE e.pc_pid = ?
1786 AND e.pc_eventDate < CURRENT_DATE
1787 AND u.id = e.pc_aid
1788 AND e.pc_catid = c.pc_catid
1789 ORDER BY e.pc_eventDate " . escape_sort_order($direction) . " , e.pc_startTime DESC LIMIT " . escape_limit($showpast);
1791 $pres = sqlStatement($query, array($pid));
1793 $count = 0;
1795 while ($row = sqlFetchArray($pres)) {
1796 $count++;
1797 $dayname = date("D", strtotime($row['pc_eventDate']));
1798 $displayMeridiem = ($GLOBALS['time_display_format'] == 0) ? "" : "am";
1799 $disphour = substr($row['pc_startTime'], 0, 2) + 0;
1800 $dispmin = substr($row['pc_startTime'], 3, 2);
1801 if ($disphour >= 12) {
1802 $displayMeridiem = "pm";
1803 if ($disphour > 12 && $GLOBALS['time_display_format'] == 1) {
1804 $disphour -= 12;
1808 $petitle = xl('(Click to edit)');
1809 if ($row['pc_hometext'] != "") {
1810 $petitle = xl('Comments') . ": " . ($row['pc_hometext']) . "\r\n" . $petitle;
1812 $row['etitle'] = $petitle;
1814 $row['pc_status'] = generate_display_field(array('data_type' => '1', 'list_id' => 'apptstat'), $row['pc_apptstatus']);
1816 $row['dayName'] = $dayname;
1817 $row['displayMeridiem'] = $displayMeridiem;
1818 $row['pc_eventTime'] = sprintf("%02d", $disphour) . ":{$dispmin}";
1819 $row['uname'] = text($row['fname'] . " " . $row['lname']);
1820 $row['jsEvent'] = attr_js(preg_replace("/-/", "", $row['pc_eventDate'])) . ', ' . attr_js($row['pc_eid']);
1821 $past_appts[] = $row;
1824 // END of past appointments
1826 // Display the Appt card
1827 $id = "appointments_ps_expand";
1828 $dispatchResult = $ed->dispatch(new CardRenderEvent('appointment'), CardRenderEvent::EVENT_HANDLE);
1829 echo $twig->getTwig()->render('patient/card/appointments.html.twig', [
1830 'title' => xl("Appointments"),
1831 'id' => $id,
1832 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1833 'btnLabel' => "Add",
1834 'btnLink' => "return newEvt()",
1835 'linkMethod' => "javascript",
1836 'appts' => $appts,
1837 'recurrAppts' => $recurr,
1838 'pastAppts' => $past_appts,
1839 'displayAppts' => $displayAppts,
1840 'displayRecurrAppts' => $displayRecurrAppts,
1841 'displayPastAppts' => $displayPastAppts,
1842 'extraApptDate' => $extraApptDate,
1843 'therapyGroupCategories' => $therapyGroupCategories,
1844 'auth' => $resNotNull && (AclMain::aclCheckCore('patients', 'appt', '', 'write') || AclMain::aclCheckCore('patients', 'appt', '', 'addonly')),
1845 'resNotNull' => $resNotNull,
1846 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1847 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1850 echo "<div id=\"stats_div\"></div>";
1852 // TRACK ANYTHING
1853 // Determine if track_anything form is in use for this site.
1854 $tmp = sqlQuery("SELECT count(*) AS count FROM registry WHERE directory = 'track_anything' AND state = 1");
1855 $track_is_registered = $tmp['count'];
1856 if ($track_is_registered) {
1857 $spruch = "SELECT id FROM forms WHERE pid = ? AND formdir = ?";
1858 $existTracks = sqlQuery($spruch, array($pid, "track_anything"));
1859 $id = "track_anything_ps_expand";
1860 $dispatchResult = $ed->dispatch(new CardRenderEvent('track_anything'), CardRenderEvent::EVENT_HANDLE);
1861 echo $twig->getTwig()->render('patient/card/loader.html.twig', [
1862 'title' => xl("Tracks"),
1863 'id' => $id,
1864 'initiallyCollapsed' => (getUserSetting($id) == 0) ? false : true,
1865 'btnLink' => "../../forms/track_anything/create.php",
1866 'linkMethod' => "html",
1867 'prependedInjection' => $dispatchResult->getPrependedInjection(),
1868 'appendedInjection' => $dispatchResult->getAppendedInjection(),
1870 } // end track_anything
1872 if ($thisauth) :
1873 echo $twig->getTwig()->render('patient/partials/delete.html.twig', [
1874 'isAdmin' => AclMain::aclCheckCore('admin', 'super'),
1875 'allowPatientDelete' => $GLOBALS['allow_pat_delete'],
1876 'csrf' => CsrfUtils::collectCsrfToken(),
1877 'pid' => $pid
1879 endif;
1881 </div> <!-- end right column div -->
1882 </div> <!-- end div.main > row:first -->
1883 </div> <!-- end main content div -->
1884 </div><!-- end container div -->
1885 <?php $oemr_ui->oeBelowContainerDiv(); ?>
1886 <script>
1887 // Array of skip conditions for the checkSkipConditions() function.
1888 var skipArray = [
1889 <?php echo ($condition_str ?? ''); ?>
1891 checkSkipConditions();
1895 var isPost = <?php echo js_escape($showEligibility ?? false); ?>;
1896 var listId = '#' + <?php echo js_escape($list_id); ?>;
1897 $(function() {
1898 $(listId).addClass("active");
1899 if (isPost === true) {
1900 $("#eligibility").click();
1901 $("#eligibility").get(0).scrollIntoView();
1904 </script>
1905 </body>
1906 <?php $ed->dispatch(new RenderEvent($pid), RenderEvent::EVENT_RENDER_POST_PAGELOAD, 10); ?>
1907 </html>