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