fix to prior commit
[openemr.git] / library / report_database.inc
blobc79427c2e1fb6800215e20549ca28113efcba9d2
1 <?php
2 /**
3  * Report tracking, storing and viewing functions using the report_results sql table.
4  *
5  * Supports generic tracking, storing and viewing of reports by utilizing a vertical
6  * table entitled report_results. This allows flexible placement of tokens for report
7  * setting etc. Also supports itemization of results (per patient tracking).
8  * <pre>Tokens that are reserved include:
9  *   'bookmark'          - Allows bookmarking of a new report id (used to allow tracking
10  *                         progress via ajax calls). If exist, value is always set to '1'.
11  *   'progress'          - Either set to 'pending' or 'complete'.
12  *   'type'              - Set to type of report
13  *   'total_items'       - Set to total number of items that will be processed (ie. such as patients)
14  *   'progress_items'    - Set to number of items (ie. such as patients)
15  *   'data'              - Contains the data of the report
16  *   'date_report'       - Set to date of the report (date and time)
17  *   'date_report_complete'       - Set to date of the report completion (date and time)
18  * </pre>
19  *
20  * These functions should not ever attempt to write to
21  * session variables, because the session_write_close() function
22  * is typically called before utilizing these functions.
23  *
24  * Copyright (C) 2012 Brady Miller <brady@sparmy.com>
25  *
26  * LICENSE: This program is free software; you can redistribute it and/or
27  * modify it under the terms of the GNU General Public License
28  * as published by the Free Software Foundation; either version 2
29  * of the License, or (at your option) any later version.
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33  * GNU General Public License for more details.
34  * You should have received a copy of the GNU General Public License
35  * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
36  *
37  * @package OpenEMR
38  * @author  Brady Miller <brady@sparmy.com>
39  * @link    http://www.open-emr.org
40  */
42 /**
43  * Return listing of report results.
44  *
45  * @param   timestamp  $start  Start of date range
46  * @param   timestamp  $end    End of date range
47  * @return  sql-query          Listing of report results
48  */
49 function listingReportDatabase($start_date='',$end_date='') {
51   // set $end_date to today's date if empty
52   $end_date = ($end_date) ? $end_date : date('Y-m-d H:i:s');
54   // Collect pertinent information as a pivot table (ie. converting vertical to horizontal row)
55   if (empty($start_date)) {
56     $res = sqlStatement("SELECT *, TIMESTAMPDIFF(MINUTE,pt.date_report,pt.date_report_complete) as `report_time_processing`
57                          FROM (
58                            SELECT `report_id`,
59                            MAX(if( `field_id` = 'date_report', `field_value`, 0 )) as `date_report`,
60                            MAX(if( `field_id` = 'date_report_complete', `field_value`, 0 )) as `date_report_complete`,
61                            MAX(if( `field_id` = 'progress', `field_value`, 0 )) as `progress`,
62                            MAX(if( `field_id` = 'total_items', `field_value`, 0 )) as `total_items`,
63                            MAX(if( `field_id` = 'progress_items', `field_value`, 0 )) as `progress_items`,
64                            MAX(if( `field_id` = 'type', `field_value`, 0 )) as `type`
65                            FROM `report_results`
66                            GROUP BY `report_id`
67                          ) AS pt
68                          WHERE pt.date_report < ?
69                          ORDER BY pt.report_id", array($end_date));
70   }
71   else {
72     $res = sqlStatement("SELECT *, TIMESTAMPDIFF(MINUTE,pt.date_report,pt.date_report_complete) as `report_time_processing`
73                          FROM (
74                            SELECT `report_id`,
75                            MAX(if( `field_id` = 'date_report', `field_value`, 0 )) as `date_report`,
76                            MAX(if( `field_id` = 'date_report_complete', `field_value`, 0 )) as `date_report_complete`,
77                            MAX(if( `field_id` = 'progress', `field_value`, 0 )) as `progress`,
78                            MAX(if( `field_id` = 'total_items', `field_value`, 0 )) as `total_items`,
79                            MAX(if( `field_id` = 'progress_items', `field_value`, 0 )) as `progress_items`,
80                            MAX(if( `field_id` = 'type', `field_value`, 0 )) as `type`
81                            FROM `report_results`
82                            GROUP BY `report_id`
83                          ) AS pt
84                          WHERE pt.date_report > ? AND pt.date_report < ?
85                          ORDER BY pt.report_id", array($start_date,$end_date));
86   }
88   return $res;
91 /**
92  * Simply reserves a report id for use in the report results tracking/storing/viewing item in database..
93  *
94  * @return  integer           Report id that was assigned in database
95  */
96 function bookmarkReportDatabase() {
98   // Retrieve a new report id
99   $query = sqlQuery("SELECT max(`report_id`) as max_report_id FROM `report_results`");
100   if (empty($query)) {
101     $new_report_id = 1;
102   }
103   else {
104    $new_report_id = $query['max_report_id'] + 1;
105   }
107   // Set the bookmark token
108   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,"bookmark",1));
110   return $new_report_id;
114  * Initiate a report results tracking/storing/viewing item in database.
116  * @param   string   $type       Report type identifier
117  * @param   array    $fields     Array containing pertinent report details (Do NOT use 'bookmark', 'progress','type','progress_patients', 'data', 'date_report' or 'no_json_support' as keys in array; they will be ignored)
118  * @param   integer  $report_id  Report id (if have already bookmarked a report id)
119  * @return  integer              Report id that is assigned to the report
120  */
121 function beginReportDatabase($type,$fields,$report_id=NULL) {
123   // Retrieve a new report id, if needed.
124   if (empty($report_id)) {
125     $query = sqlQuery("SELECT max(`report_id`) as max_report_id FROM `report_results`");
126     if (empty($query)) {
127       $new_report_id = 1;
128     }
129     else {
130      $new_report_id = $query['max_report_id'] + 1;
131     }
132   }
133   else {
134     $new_report_id = $report_id;
135   }
137   // Set the required tokens
138   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,"progress","pending"));
139   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,"type",$type));
140   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,"progress_items","0"));
141   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,"data",""));
142   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,"date_report",date("Y-m-d H:i:s")));
144   // Set the fields tokens
145   if (!empty($fields)) {
146    foreach ($fields as $key=>$value) {
148     // skip the special tokens
149     if (($key == "type") ||
150         ($key == "data") ||
151         ($key == "progress") ||
152         ($key == "progress_items") ||
153         ($key == "total_items") ||
154         ($key == "date_report") ||
155         ($key == "date_report_complete") ||
156         ($key == "bookmark") ) continue;
158     // place the token
159     sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($new_report_id,$key,$value));
160    }
161   }
163   // Return the report id
164   return $new_report_id;
168  * Insert total items to process in database.
169  * For performance reasons, it is assumed that the total_items does not already exists in current database entry.
171  * @param   integer  $report_id    Report id
172  * @param   integer  $total_items  Total number of items that will be processed
173  */
174 function setTotalItemsReportDatabase($report_id,$total_items) {
175   // Insert the total items that are to be processed
176   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($report_id,"total_items",$total_items));
180  * Update report results in database(basically update number of items (patients) that has been processed in pending reports).
181  * For performance reasons, it is assumed that the progress_items token already exists in current database entry.
183  * @param   integer  $report_id           Report id
184  * @param   integer  $items_processed  Number of items that have been processed
185  */
186 function updateReportDatabase($report_id,$items_processed) {
187   // Update the items that have been processed
188   sqlStatement("UPDATE `report_results` SET `field_value`=? WHERE `report_id`=? AND `field_id`='progress_items'", array($items_processed,$report_id) );
192  * Store (finished) report results (in json format) in database.
193  * For performance reasons, it is assumed that the data and progress tokens already exists in current database entry.
194  * For performance reasons, it is assumed that the date_report_complete does not already exists in current database entry.
196  * @param   integer  $report_id  Report id
197  * @param   string   $data       Report results/data
198  */
199 function finishReportDatabase($report_id,$data) {
201   // Record the data
202   sqlStatement("UPDATE `report_results` SET `field_value`=? WHERE `report_id`=? AND `field_id`='data'", array($data,$report_id) );
204   // Record the finish date/time
205   sqlStatement("INSERT INTO `report_results` (`report_id`,`field_id`,`field_value`) VALUES (?,?,?)", array ($report_id,"date_report_complete",date("Y-m-d H:i:s")));
207   // Set progress to complete
208   sqlStatement("UPDATE `report_results` SET `field_value`='complete' WHERE `report_id`=? AND `field_id`='progress'", array($report_id) );
212  * Collect report results from database.
214  * @param   integer  $report_id  Report id
215  * @return  array                Array of id/values for a report
216  */
217 function collectReportDatabase($report_id) {
219   // Collect the rows of data
220   $res = sqlStatement("SELECT * FROM `report_results` WHERE `report_id`=?", array($report_id));
222   // Convert data into an array
223   $final_array = array();
224   while ($row = sqlFetchArray($res)) {
225     $final_array = array_merge($final_array,array($row['field_id']=>$row['field_value']));
226   }
228   return $final_array;
232  * Get status of report from database.
234  * @param   integer  $report_id  Report id
235  * @return  string               Status report (PENDING, COMPLETE, or return a string with progress)
236  */
237 function getStatusReportDatabase($report_id) {
239   // Collect the pertinent rows of data
240   $res = sqlStatement("SELECT `field_id`, `field_value` FROM `report_results` WHERE `report_id`=? AND (`field_id`='progress' OR `field_id`='total_items' OR `field_id`='progress_items')", array($report_id));
242   // If empty, then just return Pending, since stil haven't likely created the entries yet
243   if (sqlNumRows($res) < 1) {
244     return "PENDING";
245   }
247   // Place into an array for quick processing
248   $final_array = array();
249   while ($row = sqlFetchArray($res)) {
250     $final_array = array_merge($final_array,array($row['field_id']=>$row['field_value']));
251   }
253   if ($final_array['progress'] == "complete") {
254     // return COMPLETE
255     return "COMPLETE";
256   }
257   else {
258     $final_array['progress_items'] = ($final_array['progress_items']) ? $final_array['progress_items'] : 0;
259     return $final_array['progress_items'] . " / " . $final_array['total_items'] . " " . xl("Patients");
260   }
264  * Insert itemization item into database.
266  * @param   integer  $report_id         Report id
267  * @param   integer  $itemized_test_id  Itemized test id
268  * @param   integer  $pass              0 is fail, 1 is pass, 2 is exclude
269  * @param   integer  $patient_id        Patient pid
270  * @param   integer  $$numerator_label  Numerator label (if applicable)
271  */
272 function insertItemReportTracker($report_id, $itemized_test_id, $pass, $patient_id, $numerator_label='') {
273   $sqlParameters = array($report_id,$itemized_test_id,$numerator_label,$pass,$patient_id);
274   sqlStatementCdrEngine("INSERT INTO `report_itemized` (`report_id`,`itemized_test_id`,`numerator_label`,`pass`,`pid`) VALUES (?,?,?,?,?)", $sqlParameters);
278  * Collect a rules display title for itemized report.
280  * @param   integer  $report_id         Report id
281  * @param   integer  $itemized_test_id  Itemized test id
282  * @param   integer  $numerator_label   Numerator label (if applicable)
283  * @return  string/boolean              Rule title for itemization display (false if nothing found)
284  */
285 function collectItemizedRuleDisplayTitle($report_id, $itemized_test_id, $numerator_label='') {
286   $dispTitle = "";
287   $report_view = collectReportDatabase($report_id);
288   $type_report = $report_view['type'];
289   $dataSheet = json_decode($report_view['data'],TRUE);
290   foreach ($dataSheet as $row) {
291     if (isset($row['is_main']) || isset($row['is_sub'])) {
292       if (isset($row['is_main'])) {
293         // Store this
294         $dispTitle = generate_display_field(array('data_type'=>'1','list_id'=>'clinical_rules'),$row['id']);
295       }
296       if ( ($row['itemized_test_id'] == $itemized_test_id) && ($row['numerator_label'] == $numerator_label) ) {
297         // We have a hit, build on the $dispTitle created above
298         if (isset($row['is_main'])) {
299           $tempCqmAmcString = "";
300           if (($type_report == "cqm") || ($type_report == "cqm_2011") || ($type_report == "cqm_2014")) {
301             if (!empty($row['cqm_pqri_code'])) {
302               $tempCqmAmcString .= " " . xlt('PQRI') . ":" . text($row['cqm_pqri_code']) . " ";
303             }
304             if (!empty($row['cqm_nqf_code'])) {
305               $tempCqmAmcString .= " " . xlt('NQF') . ":" . text($row['cqm_nqf_code']) . " ";
306             }
307           }
308           if ($type_report == "amc") {
309             if (!empty($row['amc_code'])) {
310               $tempCqmAmcString .= " " . xlt('AMC-2011') . ":" . text($row['amc_code']) . " ";
311             }
312             if (!empty($row['amc_code_2014'])) {
313               $tempCqmAmcString .= " " . xlt('AMC-2014') . ":" . text($row['amc_code_2014']) . " ";
314             }
315           }
316           if ($type_report == "amc_2011") {
317             if (!empty($row['amc_code'])) {
318               $tempCqmAmcString .= " " . xlt('AMC-2011') . ":" . text($row['amc_code']) . " ";
319             }
320           }
321           if ($type_report == "amc_2014_stage1") {
322             if (!empty($row['amc_code_2014'])) {
323               $tempCqmAmcString .= " " . xlt('AMC-2014 Stage I'). ":" . text($row['amc_code_2014']) . " ";
324             }
325           }
326           if ($type_report == "amc_2014_stage2") {
327             if (!empty($row['amc_code_2014'])) {
328               $tempCqmAmcString .= " " . xlt('AMC-2014 Stage II'). ":" . text($row['amc_code_2014']) . " ";
329             }
330           }
332           if (!empty($tempCqmAmcString)) {
333             $dispTitle .=  "(".$tempCqmAmcString.")";
334           }
335           if ( !(empty($row['concatenated_label'])) ) {
336             $dispTitle .= ", " . xlt($row['concatenated_label']) . " ";
337           }
338         }
339         else { // isset($row['is_sub']
340           $dispTitle .= " - " .  generate_display_field(array('data_type'=>'1','list_id'=>'rule_action_category'),$row['action_category']);
341           $dispTitle .= ": " . generate_display_field(array('data_type'=>'1','list_id'=>'rule_action'),$row['action_item']);
342         }
343         return $dispTitle;
344       }
345     }
346   }
347   return false;
351  * Collect patient listing from CDR reports itemization.
353  * @param   integer  $report_id         Report id
354  * @param   integer  $itemized_test_id  Itemized test id
355  * @param   string   $pass              options are 'fail', 'pass', 'exclude', 'init_patients', 'exception' and 'all'
356  * @param   integer  $numerator_label   Numerator label (if applicable)
357  * @param   integer  $sqllimit          Sql query pagination info
358  * @param   integer  $fstart            Sql query pagination info
359  * @return  array/integer               Array list or a count
360  */
361 function collectItemizedPatientsCdrReport($report_id,$itemized_test_id,$pass='all',$numerator_label='',$count=false,$sqllimit='all',$fstart=0) {
363   if ($count) {
364     $given = " COUNT(DISTINCT `patient_data`.`pid`) AS total_listings ";
365   }
366   else {
367     $given = " DISTINCT `patient_data`.*, DATE_FORMAT(`patient_data`.`DOB`,'%m/%d/%Y') as DOB_TS ";
368   }
369   $orderby = " `patient_data`.`lname` ASC, `patient_data`.`fname` ASC ";
371   // set $pass_sql
372   switch ($pass) {
373     case "fail":
374       $pass_sql=0;
375       break;
376     case "pass":
377       $pass_sql=1;
378       break;
379     case "exclude":
380       $pass_sql=2;
381       break;
382     case "init_patients":
383       $pass_sql=3;
384       break;
385     case "exception":
386       $pass_sql=4;
387       break;
388   }
390   $sqlParameters = array($report_id,$itemized_test_id,$numerator_label);
392   if ($pass == "all") {
393     $sql_where = " WHERE `report_itemized`.`pass` != 3 AND `report_itemized`.`report_id` = ? AND `report_itemized`.`itemized_test_id` = ? AND `report_itemized`.`numerator_label` = ? ";
394   }
395   else if ($pass == "fail") {
396     $exlPidArr = array();
397     $exludeResult = collectItemizedPatientsCdrReport($report_id,$itemized_test_id,'exclude',$numerator_label,false,$sqllimit,$fstart);
398     foreach($exludeResult as $exlResArr){
399       $exlPidArr[] = $exlResArr['pid'];
400     }
402     $sql_where = " WHERE `report_itemized`.`report_id` = ? AND `report_itemized`.`itemized_test_id` = ? AND `report_itemized`.`numerator_label` = ? AND `report_itemized`.`pass` = ? ";
404     if(count($exlPidArr) > 0){
405       $exlPids = implode(",", $exlPidArr);
406       $sql_where .= " AND patient_data.pid NOT IN(" . add_escape_custom($exlPids) . ") ";
407     }
408     array_push($sqlParameters,$pass_sql);
409   }
410   else {
411     $sql_where = " WHERE `report_itemized`.`report_id` = ? AND `report_itemized`.`itemized_test_id` = ? AND `report_itemized`.`numerator_label` = ? AND `report_itemized`.`pass` = ? ";
412     array_push($sqlParameters,$pass_sql);
413   }
415   $sql_query = "SELECT " . $given . " FROM `patient_data` JOIN `report_itemized` ON `patient_data`.`pid` = `report_itemized`.`pid` " . $sql_where. " ORDER BY " . $orderby;
417   if ($sqllimit != "all") $sql_query .= " limit " . escape_limit($fstart) . ", " . escape_limit($sqllimit);
419   if ($count) {
420     $rez = sqlQueryCdrEngine($sql_query,$sqlParameters);
421     return $rez['total_listings'];
422   }
423   else {
424     $rez = sqlStatementCdrEngine($sql_query,$sqlParameters);
425     // create array of listing for return
426     for($iter=0; $row=sqlFetchArray($rez); $iter++) {
427       $returnval[$iter]=$row;
428     }
429     return $returnval;
430   }