minor change to prior commit
[openemr.git] / library / report.inc
blob2b13c022f36674fe07fa5222c78966ef42eaa949
1 <?php
3 /**
4  * report.inc
5  *
6  * @package   OpenEMR
7  * @link      http://www.open-emr.org
8  * @author    Brady Miller <brady.g.miller@gmail.com>
9  * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
10  * @license   https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
11  */
13 require_once($GLOBALS["srcdir"] . "/options.inc.php");
15 use OpenEMR\Common\Acl\AclMain;
17 $patient_data_array = array(
18 'title' => xl('Title') . ": ",
19 'fname' => xl('First Name') . ": ",
20 'mname' => xl('Middle Name') . ": ",
21 'lname' => xl('Last Name') . ": ",
22 'sex' => xl('Sex') . ": ",
23 'ss' => xl('SS') . ": ",
24 'DOB' => xl('Date of Birth') . ": ",
25 'street' => xl('Street') . ": ",
26 'city' => xl('City') . ": ",
27 'state' => xl('State') . ": ",
28 'postal_code' => xl('Zip') . ": ",
29 'country_code' => xl('Country') . ": ",
30 'occupation' => xl('Occupation') . ": ",
31 'phone_home' => xl('Home Phone') . ": ",
32 'phone_biz' => xl('Business Phone') . ": ",
33 'phone_contact' => xl('Contact Phone') . ": ",
34 'contact_relationship' => xl('Contact Person') . ": ",
35 'hipaa_mail' => xl('Allows Mail') . ": ",
36 'hipaa_voice' => xl('Allows Voice msgs') . ": ",
37 'hipaa_notice' => xl('Notice Received') . ": ",
38 'hipaa_message' => xl('Leave Message With') . ": "
41 $history_data_array = array(
42 'coffee' => xl('Coffee Use') . ": ",
43 'tobacco' => xl('Tobacco Use') . ": ",
44 'alcohol' => xl('Alcohol Use') . ": ",
45 'sleep_patterns' => xl('Sleep Patterns') . ": ",
46 'exercise_patterns' => xl('Exercise Patterns') . ": ",
47 'seatbelt_use' => xl('Seatbelt Use') . ": ",
48 'counseling' => xl('Counseling') . ": ",
49 'hazardous_activities' => xl('Hazardous Activities') . ": ",
50 'last_breast_exam' => xl('Last Breast Exam') . ": ",
51 'last_mammogram' => xl('Last Mammogram') . ": ",
52 'last_gynocological_exam' => xl('Last Gyn. Exam') . ": ",
53 'last_rectal_exam' => xl('Last Rectal Exam') . ": ",
54 'last_prostate_exam' => xl('Last Prostate Exam') . ": ",
55 'last_physical_exam' => xl('Last Physical Exam') . ": ",
56 'last_sigmoidoscopy_colonoscopy' => xl('Last Sigmoid/Colonoscopy') . ": ",
57 'cataract_surgery' => xl('Last Cataract Surgery') . ": ",
58 'tonsillectomy' => xl('Last Tonsillectomy') . ": ",
59 'cholecystestomy' => xl('Last Cholecystestomy') . ": ",
60 'heart_surgery' => xl('Last Heart Surgery') . ": ",
61 'hysterectomy' => xl('Last Hysterectomy') . ": ",
62 'hernia_repair' => xl('Last Hernia Repair') . ": ",
63 'hip_replacement' => xl('Last Hip Replacement') . ": ",
64 'knee_replacement' => xl('Last Knee Replacement') . ": ",
65 'appendectomy' => xl('Last Appendectomy') . ": ",
66 'history_mother' => xl('Mothers History') . ": ",
67 'history_father' => xl('Fathers History') . ": ",
68 'history_siblings' => xl('Sibling History') . ": ",
69 'history_offspring' => xl('Offspring History') . ": ",
70 'history_spouse' => xl('Spouses History') . ": ",
71 'relatives_cancer' => xl('Relatives Cancer') . ": ",
72 'relatives_tuberculosis' => xl('Relatives Tuberculosis') . ": ",
73 'relatives_diabetes' => xl('Relatives Diabetes') . ": ",
74 'relatives_high_blood_pressure' => xl('Relatives Blood Pressure') . ": ",
75 'relatives_heart_problems' => xl('Relatives Heart') . ": ",
76 'relatives_stroke' => xl('Relatives Stroke') . ": ",
77 'relatives_epilepsy' => xl('Relatives Epilepsy') . ": ",
78 'relatives_mental_illness' => xl('Relatives Mental Illness') . ": ",
79 'relatives_suicide' => xl('Relatives Suicide') . ": "
82 $employer_data_array = array(
83 'name' => xl('Employer') . ": ",
84 'street' => xl('Address') . ": ",
85 'city' => xl('City') . ": ",
86 'postal_code' => xl('Zip') . ": ",
87 'state' => xl('State') . ": ",
88 'country' => xl('Country') . ": "
91 $insurance_data_array = array(
92 'provider_name' => xl('Provider') . ": ",
93 'plan_name' => xl('Plan Name') . ": ",
94 'policy_number' => xl('Policy Number') . ": ",
95 'group_number' => xl('Group Number') . ": ",
96 'subscriber_fname' => xl('Subscriber First Name') . ": ",
97 'subscriber_mname' => xl('Subscriber Middle Name') . ": ",
98 'subscriber_lname' => xl('Subscriber Last Name') . ": ",
99 'subscriber_relationship' => xl('Subscriber Relationship') . ": ",
100 'subscriber_ss' => xl('Subscriber SS') . ": ",
101 'subscriber_DOB' => xl('Subscriber Date of Birth') . ": ",
102 'subscriber_phone' => xl('Subscribter Phone') . ": ",
103 'subscriber_street' => xl('Subscriber Address') . ": ",
104 'subscriber_postal_code' => xl('Subscriber Zip') . ": ",
105 'subscriber_city' => xl('Subscriber City') . ": ",
106 'subscriber_state' => xl('Subscriber State') . ": ",
107 'subscriber_country' => xl('Subscriber Country') . ": ",
108 'subscriber_employer' => xl('Subscriber Employer') . ": ",
109 'subscriber_employer_street' => xl('Subscriber Employer Street') . ": ",
110 'subscriber_employer_city' => xl('Subscriber Employer City') . ": ",
111 'subscriber_employer_postal_code' => xl('Subscriber Employer Zip') . ": ",
112 'subscriber_employer_state' => xl('Subscriber Employer State') . ": ",
113 'subscriber_employer_country' => xl('Subscriber Employer Country') . ": "
116 function getPatientReport($pid)
118     $sql = "select * from patient_data where pid=? order by date ASC";
119     $res = sqlStatement($sql, array($pid));
120     while ($list = sqlFetchArray($res)) {
121         while (list($key, $value) = each($list)) {
122             if ($ret[$key]['content'] != $value && $ret[$key]['date'] < $list['date']) {
123                 $ret[$key]['title'] = $key;
124                 $ret[$key]['content'] = $value;
125                 $ret[$key]['date'] = $list['date'];
126             }
127         }
128     }
130     return $ret;
133 function getHistoryReport($pid)
135     $sql = "select * from history_data where pid=? order by date ASC";
136     $res = sqlStatement($sql, array($pid));
137     while ($list = sqlFetchArray($res)) {
138         while (list($key, $value) = each($list)) {
139             if ($ret[$key]['content'] != $value && $ret[$key]['date'] < $list['date']) {
140                 $ret[$key]['content'] = $value;
141                 $ret[$key]['date'] = $list['date'];
142             }
143         }
144     }
146     return $ret;
149 function getInsuranceReport($pid, $type = "primary")
151     $sql = "select * from insurance_data where pid=? and type=? order by date ASC";
152     $res = sqlStatement($sql, array($pid, $type));
153     while ($list = sqlFetchArray($res)) {
154         while (list($key, $value) = each($list)) {
155             if ($ret[$key]['content'] != $value && $ret[$key]['date'] < $list['date']) {
156                 $ret[$key]['content'] = $value;
157                 $ret[$key]['date'] = $list['date'];
158             }
159         }
160     }
162     return $ret;
165 function getEmployerReport($pid)
167     $sql = "select * from employer_data where pid=? order by date ASC";
168     $res = sqlStatement($sql, array($pid));
169     while ($list = sqlFetchArray($res)) {
170         while (list($key, $value) = each($list)) {
171             if ($ret[$key]['content'] != $value && $ret[$key]['date'] < $list['date']) {
172                 $ret[$key]['content'] = $value;
173                 $ret[$key]['date'] = $list['date'];
174             }
175         }
176     }
178     return $ret;
181 function getListsReport($id)
183     $sql = "select * from lists where id=? order by date ASC";
184     $res = sqlStatement($sql, array($id));
185     while ($list = sqlFetchArray($res)) {
186         while (list($key, $value) = each($list)) {
187             if ($ret[$key]['content'] != $value && $ret[$key]['date'] < $list['date']) {
188                 $ret[$key]['content'] = $value;
189                 $ret[$key]['date'] = $list['date'];
190             }
191         }
192     }
194     return $ret;
197 function printListData($pid, $list_type, $list_activity = "%")
199     $res = sqlStatement("select * from lists where pid=? and type=? and activity like ? order by date", array($pid, $list_type, $list_activity));
200     while ($result = sqlFetchArray($res)) {
201         print "<span class='bold'>" . text($result["title"]) . ":</span><span class='text'> " . text($result["comments"]) . "</span><br />\n";
202     }
205 function printPatientNotes($pid)
207   // exclude ALL deleted notes
208     $res = sqlStatement("select * from pnotes where pid = ? and deleted != 1 and activity = 1 order by date", array($pid));
209     while ($result = sqlFetchArray($res)) {
210         print "<span class='bold'>" . text(oeFormatSDFT(strtotime($result["date"]))) .
211         ":</span><span class='text'> " .
212             nl2br(text(oeFormatPatientNote($result['body']))) . "</span><br />\n";
213     }
216 // Get the current value for a layout based transaction field.
218 function lbt_current_value($frow, $formid)
220     $formname = $frow['form_id'];
221     $field_id = $frow['field_id'];
222     $currvalue = '';
223     if ($formid) {
224         $ldrow = sqlQuery("SELECT field_value FROM lbt_data WHERE " .
225         "form_id = ? AND field_id = ?", array($formid, $field_id));
226         if (!empty($ldrow)) {
227             $currvalue = $ldrow['field_value'];
228         }
229     }
231     return $currvalue;
234 // Display a particular transaction.
236 function lbt_report($id, $formname)
238     $arr = array();
239     $fres = sqlStatement("SELECT * FROM layout_options " .
240     "WHERE form_id = ? AND uor > 0 " .
241     "ORDER BY group_id, seq", array($formname));
242     while ($frow = sqlFetchArray($fres)) {
243         $field_id  = $frow['field_id'];
244         $currvalue = lbt_current_value($frow, $id);
245         // For brevity, skip fields without a value.
246         if ($currvalue === '') {
247             continue;
248         }
250         $arr[$field_id] = wordwrap($currvalue, 30, "\n", true);
251     }
253     echo "<table>\n";
254     display_layout_rows($formname, $arr);
255     echo "</table>\n";
258 // Display all transactions for the specified patient.
260 function printPatientTransactions($pid)
262     $res = sqlStatement("SELECT * FROM transactions WHERE pid = ? ORDER BY date", array($pid));
263     while ($row = sqlFetchArray($res)) {
264         echo "<p><span class='bold'>" .
265         text(oeFormatSDFT(strtotime($row['date']))) .
266         " (" .
267         generate_display_field(array('data_type' => '1','list_id' => 'transactions'), $row['title']) .
268         ")</span><br />\n";
269         lbt_report($row['id'], $row['title']);
270         echo "</p>\n";
271     }
274 function printPatientBilling($pid)
276     $res = sqlStatement("select * from billing where pid=? order by date", array($pid));
277     while ($result = sqlFetchArray($res)) {
278         echo "<span class='bold'>" . text(oeFormatSDFT(strtotime($result["date"]))) . " : </span>";
279         echo "<span class='text'>(" . text($result["code_type"]) . ") ";
280         echo $result['code_type'] == 'COPAY' ? text(oeFormatMoney($result['code'])) : text($result['code']);
281         echo " - " . wordwrap(text($result['code_text']), 70, "\n", true) . "</span>";
282         echo "<br />\n";
283     }
286 function getPatientBillingEncounter($pid, $encounter)
288     $erow = sqlQuery("SELECT provider_id FROM form_encounter WHERE " .
289     "pid = ? AND encounter = ? " .
290     "ORDER BY id DESC LIMIT 1", array($pid, $encounter));
291     $inv_provider = $erow['provider_id'] + 0;
292     $sql = "SELECT b.*, u.id, u.fname, u.mname, u.lname, " .
293     "CONCAT(u.fname,' ', u.lname) AS provider_name, u.federaltaxid " .
294     "FROM billing AS b " .
295     "LEFT JOIN users AS u ON " .
296     "( b.provider_id != 0 AND u.id = b.provider_id ) OR " .
297     "( b.provider_id  = 0 AND u.id = ? ) " .
298     "WHERE pid= ? AND " .
299     "encounter = ? " .
300     "AND activity = '1' ORDER BY date";
302     $res = sqlStatement($sql, array($inv_provider, $pid, $encounter));
303     $billings = array();
304     while ($result = sqlFetchArray($res)) {
305         $billings[] = $result;
306     }
308     return $billings;
311 function printPatientForms($pid, $cols)
313     //this function takes a $pid
314     $inclookupres = sqlStatement("select distinct formdir from forms where pid=? AND deleted=0", array($pid));
315     while ($result = sqlFetchArray($inclookupres)) {
316         include_once($GLOBALS['incdir'] . "/forms/" . $result["formdir"] . "/report.php");
317     }
319     $res = sqlStatement("select * from forms where pid=? AND deleted=0 order by date", array($pid));
320     while ($result = sqlFetchArray($res)) {
321         if ($result["form_name"] == "New Patient Encounter") {
322             echo "<div class='text encounter'>\n";
323             echo "<h1>" . text($result["form_name"]) . "</h1>";
325             // display the provider info
326             $tmp = sqlQuery("SELECT u.title, u.fname, u.mname, u.lname " .
327                                     "FROM forms AS f, users AS u WHERE " .
328                                     "f.pid = ? AND f.encounter = ? AND " .
329                                     "f.formdir = 'newpatient' AND u.username = f.user " .
330                                     " AND f.deleted=0 " . //--JRM--
331                                     "ORDER BY f.id LIMIT 1", array($pid, $result['encounter']));
332             echo " " . xlt('Provider') . ": " . text($tmp['title']) . " " .
333                 text($tmp['fname']) . " " . text($tmp['mname']) . " " . text($tmp['lname']);
334             echo "<br/>";
335         } else {
336             echo "<div class='text encounter_form'>";
337             echo "<h1>" . text($result["form_name"]) . "</h1>";
338         }
340         echo "(" . text(oeFormatSDFT(strtotime($result["date"]))) . ") ";
342         if (AclMain::aclCheckCore('acct', 'rep') || AclMain::aclCheckCore('acct', 'eob') || AclMain::aclCheckCore('acct', 'bill')) {
343             if ($result["form_name"] == "New Patient Encounter") {
344                 // display billing info
345                 echo "<br/>";
346                 $bres = sqlStatement(
347                     "SELECT b.date, b.code, b.code_text " .
348                     "FROM billing AS b, code_types AS ct WHERE " .
349                     "b.pid = ? AND " .
350                     "b.encounter = ? AND " .
351                     "b.activity = 1 AND " .
352                     "b.code_type = ct.ct_key AND " .
353                     "ct.ct_diag = 0 " .
354                     "ORDER BY b.date",
355                     array($pid, $result['encounter'])
356                 );
357                 while ($brow = sqlFetchArray($bres)) {
358                     echo "<span class='bold'>&nbsp;" . xlt('Procedure') . ": </span><span class='text'>" .
359                         text($brow['code']) . " " . text($brow['code_text']) . "</span><br />\n";
360                 }
361             }
362         }
364         call_user_func($result["formdir"] . "_report", $pid, $result["encounter"], $cols, $result["form_id"]);
366         echo "</div>";
367     }
370 function getRecHistoryData($pid)
372     //data is returned as a multi-level array:
373     //column name->dates->values
374     //$return["lname"][0..n]["date"]
375     //$return["lname"][0..n]["value"]
376     $res = sqlStatement("select * from history_data where pid=? order by date", array($pid));
378     while ($result = sqlFetchArray($res)) {
379         foreach ($result as $key => $val) {
380             if ($key == "pid" || $key == "date" || $key == "id") {
381                 continue;
382             } else {
383                 $curdate = $result["date"];
384                 if (($retar[$key][$arcount[$key]]["value"] != $val)) {
385                     $arcount[$key]++;
386                     $retar[$key][$arcount[$key]]["value"] = $val;
387                     $retar[$key][$arcount[$key]]["date"] = $curdate;
388                 }
389             }
390         }
391     }
393     return $retar;
396 function getRecEmployerData($pid)
398     //data is returned as a multi-level array:
399     //column name->dates->values
400     //$return["lname"][0..n]["date"]
401     //$return["lname"][0..n]["value"]
402     $res = sqlStatement("select * from employer_data where pid=? order by date", array($pid));
404     while ($result = sqlFetchArray($res)) {
405         foreach ($result as $key => $val) {
406             if ($key == "pid" || $key == "date" || $key == "id") {
407                 continue;
408             } else {
409                 $curdate = $result["date"];
410                 if (($retar[$key][$arcount[$key]]["value"] != $val)) {
411                     $arcount[$key]++;
412                     $retar[$key][$arcount[$key]]["value"] = $val;
413                     $retar[$key][$arcount[$key]]["date"] = $curdate;
414                 }
415             }
416         }
417     }
419     return $retar;
422 function getRecPatientData($pid)
424     //data is returned as a multi-level array:
425     //column name->dates->values
426     //$return["lname"][0..n]["date"]
427     //$return["lname"][0..n]["value"]
428     $res = sqlStatement("select * from patient_data where pid=? order by date", array($pid));
430     while ($result = sqlFetchArray($res)) {
431         foreach ($result as $key => $val) {
432             if ($key == "pid" || $key == "date" || $key == "id") {
433                 continue;
434             } else {
435                 $curdate = $result["date"];
436                 if (($retar[$key][$arcount[$key]]["value"] != $val)) {
437                     $arcount[$key]++;
438                     $retar[$key][$arcount[$key]]["value"] = $val;
439                     $retar[$key][$arcount[$key]]["date"] = $curdate;
440                 }
441             }
442         }
443     }
445     return $retar;
448 function getRecInsuranceData($pid, $ins_type)
450     //data is returned as a multi-level array:
451     //column name->dates->values
452     //$return["lname"][0..n]["date"]
453     //$return["lname"][0..n]["value"]
454     $res = sqlStatement("select *, ic.name as provider_name from insurance_data left join insurance_companies as ic on ic.id = provider where pid=? and type=? order by date", array($pid,$ins_type));
456     while ($result = sqlFetchArray($res)) {
457         foreach ($result as $key => $val) {
458             if ($key == "pid" || $key == "date" || $key == "id") {
459                 continue;
460             } else {
461                 $curdate = $result["date"];
462                 if (($retar[$key][$arcount[$key]]["value"] != $val)) {
463                     $arcount[$key]++;
464                     $retar[$key][$arcount[$key]]["value"] = $val;
465                     $retar[$key][$arcount[$key]]["date"] = $curdate;
466                 }
467             }
468         }
469     }
471     return $retar;
474 function printRecData($data_array, $recres, $N)
476     //this function generates a formatted history of all changes to the data
477     //it is a multi-level recursive function that exhaustively displays all of
478     //the changes, with dates, of any data in the database under the given
479     //argument restrictions.
480     //$data_array is an array with table_column_name => "display name"
481     //$recres is the return from getRecPatientData for example
482     //$N is the number of items to display in one row
483     print "<table><tr>\n";
484     $count = 0;
485     foreach ($data_array as $akey => $aval) {
486         if ($count == $N) {
487             print "</tr><tr>\n";
488             $count = 0;
489         }
491         print "<td valign='top'><span class='bold'>" . text($aval) . "</span><br /><span class=text>";
492         printData($recres, $akey, "<br />", "Y-m-d");
493         print "</span></td>\n";
494         $count++;
495     }
497     print "</tr></table>\n";
500 function printData($retar, $key, $sep, $date_format)
502     //$retar[$key]
503     if (@array_key_exists($key, $retar)) {
504         $length = sizeof($retar[$key]);
505         for ($iter = $length; $iter >= 1; $iter--) {
506             if ($retar[$key][$iter]["value"] != "0000-00-00 00:00:00") {
507                 print text($retar[$key][$iter]["value"]) . " (" . text(oeFormatSDFT(strtotime($retar[$key][$iter]["date"]))) . ")$sep";
508             }
509         }
510     }
513 function printRecDataOne($data_array, $recres, $N)
515     //this function is like printRecData except it will only print out those elements that
516     //have values. when they do have values, this function will only print out the most recent
517     //value of each element.
518     //this may be considered a compressed data viewer.
519     //this function generates a formatted history of all changes to the data
520     //$data_array is an array with table_column_name => "display name"
521     //$recres is the return from getRecPatientData for example
522     //$N is the number of items to display in one row
523     print "<table><tr>\n";
524     $count = 0;
525     foreach ($data_array as $akey => $aval) {
526         if (!empty($recres[$akey]) && sizeof($recres[$akey]) > 0 && ($recres[$akey][1]["value"] != "0000-00-00 00:00:00")) {
527             if ($count == $N) {
528                 print "</tr><tr>\n";
529                 $count = 0;
530             }
532             print "<td valign='top'><span class='bold'>" . text($aval) . "</span><br /><span class='text'>";
533             printDataOne($recres, $akey, "<br />", "Y-m-d");
534             print "</span></td>\n";
535             $count++;
536         }
537     }
539     print "</tr></table>\n";
542 function printDataOne($retar, $key, $sep, $date_format)
544     //this function supports the printRecDataOne function above
545     if (@array_key_exists($key, $retar)) {
546         $length = sizeof($retar[$key]);
547         if ($retar[$key][$length]["value"] != "0000-00-00 00:00:00") {
548             $tmp = $retar[$key][$length]["value"];
549             if (strstr($key, 'DOB')) {
550                 $tmp = oeFormatShortDate($tmp);
551             }
553             print text($tmp) . $sep;
554         }
555     }