* @author Brady Miller * @author Jerry Padgett * @copyright Copyright (c) 2015 Roberto Vasquez * @copyright Copyright (c) 2018 Brady Miller * @copyright Copyright (c) 2018-2021 Jerry Padgett * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 */ require_once(__DIR__ . "/../../globals.php"); require_once("$srcdir/forms.inc.php"); require_once("$srcdir/patient.inc.php"); require_once("$srcdir/lists.inc.php"); require_once(__DIR__ . "/../../../custom/code_types.inc.php"); if ($GLOBALS['enable_group_therapy']) { require_once("$srcdir/group.inc.php"); } use OpenEMR\Common\Acl\AclMain; use OpenEMR\Billing\BillingUtilities; use OpenEMR\Billing\InvoiceSummary; use OpenEMR\Common\Csrf\CsrfUtils; use OpenEMR\Common\Forms\FormLocator; use OpenEMR\Common\Forms\FormReportRenderer; use OpenEMR\Common\Logging\SystemLogger; use OpenEMR\Common\Session\PatientSessionUtil; use OpenEMR\Common\Session\SessionWrapperFactory; use OpenEMR\Core\Header; $session = SessionWrapperFactory::getInstance()->getWrapper(); $is_group = ($attendant_type == 'gid') ? true : false; if (isset($_GET['pid']) && $_GET['pid'] != $session->get('pid')) { PatientSessionUtil::setPid($_GET['pid']); } // "issue" parameter exists if we are being invoked by clicking an issue title // in the left_nav menu. Currently that is just for athletic teams. In this // case we only display encounters that are linked to the specified issue. $issue = empty($_GET['issue']) ? 0 : 0 + $_GET['issue']; //maximum number of encounter entries to display on this page: // $N = 12; //Get the default encounter from Globals $default_encounter = $GLOBALS['default_encounter_view']; //'0'=clinical, '1' = billing // Get relevant ACL info. $auth_notes_a = AclMain::aclCheckCore('encounters', 'notes_a'); $auth_notes = AclMain::aclCheckCore('encounters', 'notes'); $auth_coding_a = AclMain::aclCheckCore('encounters', 'coding_a'); $auth_coding = AclMain::aclCheckCore('encounters', 'coding'); $auth_relaxed = AclMain::aclCheckCore('encounters', 'relaxed'); $auth_med = AclMain::aclCheckCore('patients', 'med'); $auth_demo = AclMain::aclCheckCore('patients', 'demo'); $glog_view_write = AclMain::aclCheckCore("groups", "glog", false, ['view', 'write']); $tmp = getPatientData($pid, "squad"); if (($tmp['squad'] ?? null) && ! AclMain::aclCheckCore('squads', $tmp['squad'])) { $auth_notes_a = $auth_notes = $auth_coding_a = $auth_coding = $auth_med = $auth_demo = $auth_relaxed = 0; } // Perhaps the view choice should be saved as a session variable. // $tmp = sqlQuery("select authorized from users " . "where id = ?", [$session->get('authUserID')]); $billing_view = ($tmp['authorized']) ? 0 : 1; if (isset($_GET['billing'])) { $billing_view = empty($_GET['billing']) ? 0 : 1; } else { $billing_view = ($default_encounter == 0) ? 0 : 1; } // form locator will cache form locations (so modules can extend) // form report renderer will render the form reports $logger = new SystemLogger(); $formLocator = new FormLocator($logger); $formReportRenderer = new FormReportRenderer($formLocator, $logger); //Get Document List by Encounter ID function getDocListByEncID($encounter, $raw_encounter_date, $pid): void { global $ISSUE_TYPES, $auth_med; $documents = getDocumentsByEncounter($pid, $encounter); if (!empty($documents) && count($documents) > 0) { foreach ($documents as $documentrow) { if ($auth_med) { $irow = sqlQuery("SELECT type, title, begdate FROM lists WHERE id = ? LIMIT 1", [$documentrow['list_id']]); if ($irow) { $tcode = $irow['type']; if ($ISSUE_TYPES[$tcode]) { $tcode = $ISSUE_TYPES[$tcode][2]; } echo text("$tcode: " . $irow['title']); } } else { echo "(" . xlt('No access') . ")"; } // Get the notes for this document and display as title for the link. $queryString = "SELECT date,note FROM notes WHERE foreign_id = ? ORDER BY date"; $noteResultSet = sqlStatement($queryString, [$documentrow['id']]); $note = ''; while ($row = sqlFetchArray($noteResultSet)) { $note .= oeFormatShortDate(date('Y-m-d', strtotime((string) $row['date']))) . " : " . $row['note'] . "\n"; } $docTitle = $note ?: xl("View document"); $docHref = $GLOBALS['webroot'] . "/controller.php?document&view&patient_id=" . attr_url($pid) . "&doc_id=" . attr_url($documentrow['id']); echo ""; } } } // This is called to generate a line of output for a patient document. // function showDocument(&$drow): void { global $ISSUE_TYPES, $auth_med; $docdate = $drow['docdate']; // if doc is already tagged by encounter it already has its own row so return $doc_tagged_enc = $drow['encounter_id']; if ($doc_tagged_enc) { return; } echo "\n"; // show date echo "" . text(oeFormatShortDate($docdate)) . "\n"; // show associated issue, if any echo ""; if ($auth_med) { $irow = sqlQuery("SELECT type, title, begdate " . "FROM lists WHERE " . "id = ? " . "LIMIT 1", [$drow['list_id']]); if ($irow) { $tcode = $irow['type']; if ($ISSUE_TYPES[$tcode]) { $tcode = $ISSUE_TYPES[$tcode][2]; } echo text("$tcode: " . $irow['title']); } } else { echo "(" . xlt('No access') . ")"; } echo "\n"; // show document name and category echo "" . text(xl('Document') . ": " . $drow['document_name'] . '-' . $drow['id'] . ' (' . xl_document_category($drow['name']) . ')') . "\n"; echo " \n"; echo "\n"; } function generatePageElement($start, $pagesize, $billing, $issue, $text): void { if ($start < 0) { $start = 0; } $url = "encounters.php?pagestart=" . attr_url($start) . "&pagesize=" . attr_url($pagesize); $url .= "&billing=" . attr_url($billing); $url .= "&issue=" . attr_url($issue); echo "" . $text . ""; } ?> get('language_direction') == "rtl") { ?>
\n\n"; echo "

(" . xlt('Encounters not authorized') . ")

\n"; echo "\n\n"; exit(); } $pagestart = 0; if (isset($_GET['pagesize'])) { $pagesize = $_GET['pagesize']; } else { $pagesize = array_key_exists('encounter_page_size', $GLOBALS) ? $GLOBALS['encounter_page_size'] : 0; } $pagestart = $_GET['pagestart'] ?? 0; $getStringForPage = "&pagesize=" . attr_url($pagesize) . "&pagestart=" . attr_url($pagestart); ?>     :
$name = getPatientNameFirstLast($pid); $dob = text(oeFormatShortDate(getPatientData($pid, "DOB")['DOB'])); $external_id = getPatientData($pid, "pubpid")['pubpid']; echo text($name) . " (" . text($external_id) . ")" . "    DOB: " . $dob ; } ?>
get('therapy_group'); } $query = "SELECT fe.*, f.user, u.fname, u.mname, u.lname " . $from . "ORDER BY fe.date DESC, fe.id DESC"; $countQuery = "SELECT COUNT(*) as c " . $from; $countRes = sqlStatement($countQuery, $sqlBindArray); $count = sqlFetchArray($countRes); $numRes += $count['c']; if ($pagesize > 0) { $query .= " LIMIT " . escape_limit($pagestart) . "," . escape_limit($pagesize); } $upper = $pagestart + $pagesize; if (($upper > $numRes) || ($pagesize == 0)) { $upper = $numRes; } if (($pagesize > 0) && ($pagestart > 0)) { generatePageElement($pagestart - $pagesize, $pagesize, $billing_view, $issue, "⇐" . htmlspecialchars(xl("Prev"), ENT_NOQUOTES) . " "); } echo (($pagesize > 0) ? ($pagestart + 1) : "1") . "-" . $upper . " " . htmlspecialchars(xl('of'), ENT_NOQUOTES) . " " . $numRes; if (($pagesize > 0) && ($pagestart + $pagesize <= $numRes)) { generatePageElement($pagestart + $pagesize, $pagesize, $billing_view, $issue, " " . htmlspecialchars(xl("Next"), ENT_NOQUOTES) . "⇒"); } $res4 = sqlStatement($query, $sqlBindArray); while ($result4 = sqlFetchArray($res4)) { // $href = "javascript:window.toencounter(" . $result4['encounter'] . ")"; $reason_string = ""; $auth_sensitivity = true; $raw_encounter_date = ''; $raw_encounter_date = date("Y-m-d", strtotime((string) $result4["date"])); $encounter_date = date("D F jS", strtotime((string) $result4["date"])); //fetch acl for given pc_catid $postCalendarCategoryACO = AclMain::fetchPostCalendarCategoryACO($result4['pc_catid']); if ($postCalendarCategoryACO) { $postCalendarCategoryACO = explode('|', (string) $postCalendarCategoryACO); $authPostCalendarCategory = AclMain::aclCheckCore($postCalendarCategoryACO[0], $postCalendarCategoryACO[1]); } else { // if no aco is set for category $authPostCalendarCategory = true; } if (!empty($result4["reason"])) { $reason_string .= text($result4["reason"]) . "
\n"; } // else // $reason_string = "(No access)"; if ($result4['sensitivity']) { $auth_sensitivity = AclMain::aclCheckCore('sensitivities', $result4['sensitivity']); if (!$auth_sensitivity || !$authPostCalendarCategory) { $reason_string = "(" . xlt("No access") . ")"; } } // This generates document lines as appropriate for the date order. while ($drow && $raw_encounter_date && $drow['docdate'] > $raw_encounter_date) { showDocument($drow); $drow = sqlFetchArray($dres); } // Fetch all forms for this encounter, if the user is authorized to see // this encounter's notes and this is the clinical view. $encarr = []; $encounter_rows = 1; if ( !$billing_view && $auth_sensitivity && $authPostCalendarCategory && ($auth_notes_a || ($auth_notes && $result4['user'] == $session->get('authUser'))) ) { $attendant_id = $attendant_type == 'pid' ? $pid : $therapy_group; $encarr = getFormByEncounter($attendant_id, $result4['encounter'], "formdir, user, form_name, form_id, deleted"); $encounter_rows = count($encarr); } $rawdata = $result4['encounter'] . "~" . oeFormatShortDate($raw_encounter_date); echo "\n"; // show encounter date echo "\n"; if ($billing_view) { // Show billing note that you can click on to edit. $feid = $result4['id'] ?: 0; // form_encounter id echo "\n"; // *************** end billing view ********************* } else { if ($attendant_type == 'pid' && !$issue) { // only for patient encounter and if listing for multiple issues // show issues for this encounter echo "\n"; } // end if (!$issue) // show encounter reason/title echo "\n"; if ($attendant_type == 'pid') { // show user (Provider) for the encounter $provname = 'Unknown'; if (!empty($result4['lname']) || !empty($result4['fname'])) { $provname = $result4['lname']; if (!empty($result4['fname']) || !empty($result4['mname'])) { $provname .= ', ' . $result4['fname'] . ' ' . $result4['mname']; } } echo "\n"; // for therapy group view } else { $counselors = ''; foreach (explode(',', (string) $result4['counselors']) as $userId) { $counselors .= getUserNameById($userId) . ', '; } $counselors = rtrim($counselors, ", "); echo "\n"; } } // end not billing view //this is where we print out the text of the billing that occurred on this encounter $thisauth = $auth_coding_a; if (!$thisauth && $auth_coding) { if ($result4['user'] == $session->get('authUser')) { $thisauth = $auth_coding; } } $coded = ""; $arid = 0; if ($thisauth && $auth_sensitivity && $authPostCalendarCategory) { $binfo = ['', '', '', '', '']; if ($subresult2 = BillingUtilities::getBillingByEncounter($pid, $result4['encounter'], "code_type, code, modifier, code_text, fee")) { // Get A/R info, if available, for this encounter. $arinvoice = []; $arlinkbeg = ""; $arlinkend = ""; if ($billing_view) { $tmp = sqlQuery("SELECT id FROM form_encounter WHERE " . "pid = ? AND encounter = ?", [$pid, $result4['encounter']]); $arid = (int) $tmp['id']; if ($arid) { $arinvoice = InvoiceSummary::arGetInvoiceSummary($pid, $result4['encounter'], true); } if ($arid) { $arlinkbeg = ""; $arlinkend = ""; } } // Throw in product sales. $query = "SELECT s.drug_id, s.fee, d.name " . "FROM drug_sales AS s " . "LEFT JOIN drugs AS d ON d.drug_id = s.drug_id " . "WHERE s.pid = ? AND s.encounter = ? " . "ORDER BY s.sale_id"; $sres = sqlStatement($query, [$pid,$result4['encounter']]); while ($srow = sqlFetchArray($sres)) { $subresult2[] = ['code_type' => 'PROD', 'code' => 'PROD:' . $srow['drug_id'], 'modifier' => '', 'code_text' => $srow['name'], 'fee' => $srow['fee']]; } // This creates 5 columns of billing information: // billing code, charges, payments, adjustments, balance. foreach ($subresult2 as $iter2) { // Next 2 lines were to skip diagnoses, but that seems unpopular. // if ($iter2['code_type'] != 'COPAY' && // !$code_types[$iter2['code_type']]['fee']) continue; $title = $iter2['code_text']; $codekey = $iter2['code']; $codekeydisp = $iter2['code_type'] . " - " . $iter2['code']; if ($iter2['code_type'] == 'COPAY') { $codekey = 'CO-PAY'; $codekeydisp = xl('CO-PAY'); } if ($iter2['modifier']) { $codekey .= ':' . $iter2['modifier']; $codekeydisp .= ':' . $iter2['modifier']; } if ($binfo[0]) { $binfo[0] .= '
'; } if ($issue && !$billing_view) { // Single issue clinical view: show code description after the code. $binfo[0] .= $arlinkbeg . text($codekeydisp) . " " . text($title) . $arlinkend; } else { // Otherwise offer the description as a tooltip. $binfo[0] .= "" . $arlinkbeg . text($codekeydisp) . $arlinkend . ""; } if ($billing_view) { if ($binfo[1]) { for ($i = 1; $i < 5; ++$i) { $binfo[$i] .= '
'; } } if (empty($arinvoice[$codekey])) { // If no invoice, show the fee. if ($arlinkbeg) { $binfo[1] .= ' '; } else { $binfo[1] .= text(oeFormatMoney($iter2['fee'])); } for ($i = 2; $i < 5; ++$i) { $binfo[$i] .= ' '; } } else { $binfo[1] .= text(oeFormatMoney($arinvoice[$codekey]['chg'] + ($arinvoice[$codekey]['adj'] ?? null))); $binfo[2] .= text(oeFormatMoney($arinvoice[$codekey]['chg'] - $arinvoice[$codekey]['bal'])); $binfo[3] .= text(oeFormatMoney($arinvoice[$codekey]['adj'] ?? null)); $binfo[4] .= text(oeFormatMoney($arinvoice[$codekey]['bal'])); unset($arinvoice[$codekey]); } } } // end foreach // Pick up any remaining unmatched invoice items from the accounting // system. Display them in red, as they should be unusual. // Except copays aren't unusual but displaying them in red // helps billers spot them quickly :) if (!empty($arinvoice)) { foreach ($arinvoice as $codekey => $val) { if ($binfo[0]) { for ($i = 0; $i < 5; ++$i) { $binfo[$i] .= '
'; } } for ($i = 0; $i < 5; ++$i) { $binfo[$i] .= "

"; } $binfo[0] .= text($codekey); $binfo[1] .= text(oeFormatMoney($val['chg'] + $val['adj'])); $binfo[2] .= text(oeFormatMoney($val['chg'] - $val['bal'])); $binfo[3] .= text(oeFormatMoney($val['adj'])); $binfo[4] .= text(oeFormatMoney($val['bal'])); for ($i = 0; $i < 5; ++$i) { $binfo[$i] .= ""; } } } } // end if there is billing echo "

\n"; for ($i = 1; $i < 5; ++$i) { echo "\n"; } } /* end if authorized */ else { echo "\n"; } // show insurance if ($attendant_type == 'pid' && !$GLOBALS['ippf_specific']) { $insured = oeFormatShortDate($raw_encounter_date); if ($auth_demo) { $responsible = -1; if ($arid) { $responsible = InvoiceSummary::arResponsibleParty($pid, $result4['encounter']); } $subresult5 = getInsuranceDataByDate($pid, $raw_encounter_date, "primary"); if (!empty($subresult5["provider_name"])) { $style = $responsible == 1 ? " style='color: var(--danger)'" : ""; $insured = " " . xlt('Primary') . ": " . text($subresult5["provider_name"]) . "
\n"; } else { $insured = " " . xlt('Primary') . ":
\n"; } $subresult6 = getInsuranceDataByDate($pid, $raw_encounter_date, "secondary"); if (!empty($subresult6["provider_name"])) { $style = $responsible == 2 ? " style='color: var(--danger)'" : ""; $insured .= " " . xlt('Secondary') . ": " . text($subresult6["provider_name"]) . "
\n"; } $subresult7 = getInsuranceDataByDate($pid, $raw_encounter_date, "tertiary"); if ($subresult6 && !empty($subresult7["provider_name"])) { $style = $responsible == 3 ? " style='color: var(--danger)'" : ""; $insured .= " " . xlt('Tertiary') . ": " . text($subresult7["provider_name"]) . "
\n"; } if ($responsible == 0) { $insured .= " " . xlt('Patient') . "
\n"; } } else { $insured = " (" . xlt("No access") . ")"; } echo "\n"; } if ($GLOBALS['enable_group_therapy'] && !$billing_view && $therapy_group == 0) { $encounter_type = sqlQuery("SELECT pc_catname, pc_cattype FROM openemr_postcalendar_categories where pc_catid = ?", [$result4['pc_catid']]); echo "\n"; } if ($GLOBALS['enable_follow_up_encounters']) { $symbol = ( !empty($result4['parent_encounter_id']) ) ? '' : null; echo "\n"; } if ($GLOBALS['enable_group_therapy'] && !$billing_view && $therapy_group == 0) { $group_name = ($encounter_type['pc_cattype'] == 3 && is_numeric($result4['external_id'])) ? getGroup($result4['external_id'])['group_name'] : ""; echo "\n"; } if ($GLOBALS['enable_follow_up_encounters']) { $encounterId = ( !empty($result4['parent_encounter_id']) ) ? $result4['parent_encounter_id'] : $result4['id']; echo "\n"; } echo "\n"; } // end while // Dump remaining document lines if count not exceeded. while ($drow) { showDocument($drow); $drow = sqlFetchArray($dres); } ?>
 
" . text(oeFormatShortDate($raw_encounter_date)) . ""; echo "
"; echo "
"; echo $result4['billing_note'] ? nl2br(text($result4['billing_note'])) : ''; echo "
"; echo "
"; echo "
"; if ($auth_med && $auth_sensitivity && $authPostCalendarCategory) { $ires = sqlStatement("SELECT lists.type, lists.title, lists.begdate " . "FROM issue_encounter, lists WHERE " . "issue_encounter.pid = ? AND " . "issue_encounter.encounter = ? AND " . "lists.id = issue_encounter.list_id " . "ORDER BY lists.type, lists.begdate", [$pid,$result4['encounter']]); for ($i = 0; $irow = sqlFetchArray($ires); ++$i) { if ($i > 0) { echo "
"; } $tcode = $irow['type']; if ($ISSUE_TYPES[$tcode]) { $tcode = $ISSUE_TYPES[$tcode][2]; } echo text("$tcode: " . $irow['title']); } } else { echo "(" . xlt('No access') . ")"; } echo "
" . $reason_string; //Display the documents tagged to this encounter getDocListByEncID($result4['encounter'], $raw_encounter_date, $pid); echo "
"; // Now show a line for each encounter form, if the user is authorized to // see this encounter's notes. foreach ($encarr as $enc) { if ($enc['formdir'] == 'newpatient' || $enc['formdir'] == 'newGroupEncounter') { continue; } // skip forms whose 'deleted' flag is set to 1 --JRM-- if ($enc['deleted'] == 1) { continue; } // Skip forms that we are not authorized to see. --JRM-- // pardon the wonky logic $formdir = $enc['formdir']; if ( ($auth_notes_a) || ($auth_notes && $enc['user'] == $session->get('authUser')) || ($auth_relaxed && ($formdir == 'sports_fitness' || $formdir == 'podiatry')) ) { } else { continue; } // Show the form name. In addition, for the specific-issue case show // the data collected by the form (this used to be a huge tooltip // but we did away with that). // $formdir = $enc['formdir']; if ($issue) { // note per comments this is only used for athletic teams.. echo text(xl_form_title($enc['form_name'])); echo "
"; echo "
"; // render out the form, whether its LBF or a standard file. $formReportRenderer->renderReport( $formdir, "encounters.php", $pid, $result4['encounter'], 2, $enc['form_id'] ); echo "
"; } else { $formDiv = "
" . xla("Click or change focus to dismiss") . "'>"; $formDiv .= text(xl_form_title($enc['form_name'])); $formDiv .= "
"; echo $formDiv; } } // end encounter Forms loop echo "
"; echo "
" . text($provname) . "" . text($counselors) . "" . $binfo[0] . "" . $binfo[$i] . "(" . xlt("No access") . ")" . $insured . "" . xlt($encounter_type['pc_catname']) . " " . $symbol . " " . text($group_name) . "