3 * AbstractAmcReport class
5 * Copyright (C) 2011 Ken Chapple <ken@mi-squared.com>
6 * Copyright (C) 2015 Brady Miller <brady@sparmy.com>
8 * LICENSE: This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
20 * @author Ken Chapple <ken@mi-squared.com>
21 * @author Brady Miller <brady@sparmy.com>
22 * @link http://www.open-emr.org
25 require_once( 'AmcFilterIF.php' );
26 require_once( dirname(__FILE__
)."/../../../../clinical_rules.php" );
27 require_once( dirname(__FILE__
)."/../../../../amc.php" );
29 abstract class AbstractAmcReport
implements RsReportIF
31 protected $_amcPopulation;
33 protected $_resultsArray = array();
37 protected $_beginMeasurement;
38 protected $_endMeasurement;
40 protected $_manualLabNumber;
42 public function __construct( array $rowRule, array $patientIdArray, $dateTarget, $options )
44 // require all .php files in the report's sub-folder
45 $className = get_class( $this );
46 foreach ( glob( dirname(__FILE__
)."/../reports/".$className."/*.php" ) as $filename ) {
47 require_once( $filename );
49 // require common .php files
50 foreach ( glob( dirname(__FILE__
)."/../reports/common/*.php" ) as $filename ) {
51 require_once( $filename );
53 // require clinical types
54 foreach ( glob( dirname(__FILE__
)."/../../../ClinicalTypes/*.php" ) as $filename ) {
55 require_once( $filename );
58 $this->_amcPopulation
= new AmcPopulation( $patientIdArray );
59 $this->_rowRule
= $rowRule;
60 $this->_ruleId
= isset( $rowRule['id'] ) ?
$rowRule['id'] : '';
61 // Parse measurement period, which is stored as array in $dateTarget ('dateBegin' and 'dateTarget').
62 $this->_beginMeasurement
= $dateTarget['dateBegin'];
63 $this->_endMeasurement
= $dateTarget['dateTarget'];
64 $this->_manualLabNumber
= $options['labs_manual'];
67 public abstract function createNumerator();
68 public abstract function createDenominator();
69 public abstract function getObjectToCount();
71 public function getResults() {
72 return $this->_resultsArray
;
75 public function execute()
78 // If itemization is turned on, then iterate the rule id iterator
80 // Note that when AMC rules suports different patient populations and
81 // numerator caclulation, then it will need to change placement of
82 // this and mimick the CQM rules mechanism
83 if ($GLOBALS['report_itemizing_temp_flag_and_id']) {
84 $GLOBALS['report_itemized_test_id_iterator']++
;
87 $numerator = $this->createNumerator();
88 if ( !$numerator instanceof AmcFilterIF
) {
89 throw new Exception( "Numerator must be an instance of AmcFilterIF" );
92 $denominator = $this->createDenominator();
93 if ( !$denominator instanceof AmcFilterIF
) {
94 throw new Exception( "Denominator must be an instance of AmcFilterIF" );
97 $totalPatients = count( $this->_amcPopulation
);
99 // Figure out object to be counted
100 // (patients, labs, transitions, visits, or prescriptions)
101 $object_to_count = $this->getObjectToCount();
102 if (empty($object_to_count)) {
103 $object_to_count="patients";
106 $numeratorObjects = 0;
107 $denominatorObjects = 0;
108 foreach ( $this->_amcPopulation
as $patient )
110 // If begin measurement is empty, then make the begin
111 // measurement the patient dob.
112 $tempBeginMeasurement = "";
113 if (empty($this->_beginMeasurement
)) {
114 $tempBeginMeasurement = $patient->dob
;
117 $tempBeginMeasurement = $this->_beginMeasurement
;
120 // Count Denominators
121 if ($object_to_count == "patients") {
123 if ( !$denominator->test( $patient, $tempBeginMeasurement, $this->_endMeasurement
) ) {
126 $denominatorObjects++
;
129 // Counting objects other than patients
130 // First, collect the pertinent objects
131 $objects = $this->collectObjects($patient,$object_to_count,$tempBeginMeasurement,$this->_endMeasurement
);
133 // Second, test each object
134 $objects_pass=array();
135 foreach ($objects as $object) {
136 $patient->object=$object;
137 if ( $denominator->test( $patient, $tempBeginMeasurement, $this->_endMeasurement
) ) {
138 $denominatorObjects++
;
139 array_push($objects_pass,$object);
145 if ($object_to_count == "patients") {
147 if ( !$numerator->test( $patient, $tempBeginMeasurement, $this->_endMeasurement
) ) {
150 // If itemization is turned on, then record the "failed" item
151 if ($GLOBALS['report_itemizing_temp_flag_and_id']) {
152 insertItemReportTracker($GLOBALS['report_itemizing_temp_flag_and_id'], $GLOBALS['report_itemized_test_id_iterator'], 0, $patient->id
);
160 // If itemization is turned on, then record the "passed" item
161 if ($GLOBALS['report_itemizing_temp_flag_and_id']) {
162 insertItemReportTracker($GLOBALS['report_itemizing_temp_flag_and_id'], $GLOBALS['report_itemized_test_id_iterator'], 1, $patient->id
);
168 // Counting objects other than patients
169 // test each object that passed the above denominator testing
170 foreach ($objects_pass as $object) {
171 $patient->object=$object;
172 if ( $numerator->test( $patient, $tempBeginMeasurement, $this->_endMeasurement
) ) {
175 // If itemization is turned on, then record the "passed" item
176 if ($GLOBALS['report_itemizing_temp_flag_and_id']) {
177 insertItemReportTracker($GLOBALS['report_itemizing_temp_flag_and_id'], $GLOBALS['report_itemized_test_id_iterator'], 1, $patient->id
);
183 // If itemization is turned on, then record the "failed" item
184 if ($GLOBALS['report_itemizing_temp_flag_and_id']) {
185 insertItemReportTracker($GLOBALS['report_itemizing_temp_flag_and_id'], $GLOBALS['report_itemized_test_id_iterator'], 0, $patient->id
);
194 // Deal with the manually added labs for the electronic labs AMC measure
195 if ($object_to_count == "labs") {
196 $denominatorObjects = $denominatorObjects +
$this->_manualLabNumber
;
199 $percentage = calculate_percentage( $denominatorObjects, 0, $numeratorObjects );
200 $result = new AmcResult( $this->_rowRule
, $totalPatients, $denominatorObjects, 0, $numeratorObjects, $percentage );
201 $this->_resultsArray
[]= $result;
204 private function collectObjects ($patient,$object_label,$begin,$end) {
207 $sqlBindArray = array();
209 switch ($object_label) {
210 case "transitions-in":
211 $sql = "SELECT amc_misc_data.map_id as `encounter`, amc_misc_data.date_completed as `completed`, form_encounter.date as `date` " .
212 "FROM `amc_misc_data`, `form_encounter` " .
213 "WHERE amc_misc_data.map_id = form_encounter.encounter " .
214 "AND amc_misc_data.map_category = 'form_encounter' " .
215 "AND amc_misc_data.pid = ? AND form_encounter.pid = ? " .
216 "AND amc_misc_data.amc_id = 'med_reconc_amc' " .
217 "AND form_encounter.date >= ? AND form_encounter.date <= ?";
218 array_push($sqlBindArray, $patient->id
, $patient->id
, $begin, $end);
220 case "transitions-out":
222 "FROM `transactions` " .
223 "WHERE `title` = 'LBTref' " .
225 "AND `date` >= ? AND `date` <= ?";
226 array_push($sqlBindArray, $patient->id
, $begin, $end);
230 "FROM `form_encounter` " .
232 "AND `date` >= ? AND `date` <= ?";
233 array_push($sqlBindArray, $patient->id
, $begin, $end);
235 case "encounters_office_visit":
237 "FROM `form_encounter` LEFT JOIN `enc_category_map` ON (form_encounter.pc_catid = enc_category_map.main_cat_id) " .
238 "WHERE enc_category_map.rule_enc_id = 'enc_off_vis' " .
240 "AND `date` >= ? AND `date` <= ?";
241 array_push($sqlBindArray, $patient->id
, $begin, $end);
243 case "prescriptions":
245 "FROM `prescriptions` " .
246 "WHERE `patient_id` = ? " .
247 "AND `date_added` >= ? AND `date_added` <= ?";
248 array_push($sqlBindArray, $patient->id
, $begin, $end);
251 $sql = "SELECT procedure_result.result FROM " .
252 "procedure_order, " .
253 "procedure_report, " .
254 "procedure_result " .
256 "procedure_order.patient_id = ? AND " .
257 "procedure_order.procedure_order_id = procedure_report.procedure_order_id AND " .
258 "procedure_report.procedure_report_id = procedure_result.procedure_report_id AND " .
259 "procedure_report.date_collected >= ? AND procedure_report.date_collected <= ?";
260 array_push($sqlBindArray, $patient->id
, $begin, $end);
263 case "lab_radiology":
264 $sql = "SELECT IF( u.cpoe = '1', 'Yes', 'No') as cpoe_stat FROM procedure_order pr ".
265 "INNER JOIN procedure_order_code prc ON pr.procedure_order_id = prc.procedure_order_id ".
266 "LEFT JOIN procedure_providers pp ON pr.lab_id = pp.ppid ".
267 "LEFT JOIN users u ON u.id = pp.lab_director ".
268 "WHERE pr.patient_id = ? ".
269 "AND prc.procedure_order_title LIKE '%Radiology%' ".
270 "AND (pr.date_ordered BETWEEN ? AND ?)";
271 array_push($sqlBindArray, $patient->id
, $begin, $end);
274 case "cpoe_lab_orders":
275 $sql = "SELECT IF( u.cpoe = '1', 'Yes', 'No') as cpoe_stat FROM procedure_order pr ".
276 "INNER JOIN procedure_order_code prc ON pr.procedure_order_id = prc.procedure_order_id ".
277 "LEFT JOIN procedure_providers pp ON pr.lab_id = pp.ppid ".
278 "LEFT JOIN users u ON u.id = pp.lab_director ".
279 "WHERE pr.patient_id = ? ".
280 "AND prc.procedure_order_title LIKE '%Laboratory Test%' ".
281 "AND (pr.date_ordered BETWEEN ? AND ?)";
282 array_push($sqlBindArray, $patient->id
, $begin, $end);
288 // Note the cpoe_flag and functionality does not exist in OpenEMR official codebase.
290 $sql = "SELECT cpoe_flag as cpoe_stat " .
291 "FROM `prescriptions` " .
292 "WHERE `patient_id` = ? " .
293 "AND `date_added` BETWEEN ? AND ?";
294 array_push($sqlBindArray, $patient->id
, $begin, $end);
298 $sql = "SELECT procedure_order_id FROM " .
302 "AND (date_ordered BETWEEN ? AND ?)";
303 array_push($sqlBindArray, $patient->id
, $begin, $end);
307 $rez = sqlStatement($sql, $sqlBindArray);
308 for($iter=0; $row=sqlFetchArray($rez); $iter++
) {
309 if ('transitions-out' == $object_label) {
310 $fres = sqlStatement("SELECT field_id, field_value FROM lbt_data WHERE form_id = ?",
312 while ($frow = sqlFetchArray($fres)) {
313 $row[$frow['field_id']] = $frow['field_value'];
316 $results[$iter]=$row;