internationalization of the date widget, see feature request tracker item 2967294
[openemr.git] / interface / reports / ippf_statistics.php
blobab840ae148a1b7c3b4d669d6dcddc4ee43332274
1 <?php
2 // Copyright (C) 2008-2009 Rod Roark <rod@sunsetsystems.com>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 // This module creates statistical reports related to family planning
10 // and sexual and reproductive health.
12 include_once("../globals.php");
13 include_once("../../library/patient.inc");
14 include_once("../../library/acl.inc");
16 // Might want something different here.
18 if (! acl_check('acct', 'rep')) die("Unauthorized access.");
20 $report_type = empty($_GET['t']) ? 'i' : $_GET['t'];
22 $from_date = fixDate($_POST['form_from_date']);
23 $to_date = fixDate($_POST['form_to_date'], date('Y-m-d'));
24 $form_by = $_POST['form_by']; // this is a scalar
25 $form_show = $_POST['form_show']; // this is an array
26 $form_facility = isset($_POST['form_facility']) ? $_POST['form_facility'] : '';
27 $form_sexes = isset($_POST['form_sexes']) ? $_POST['form_sexes'] : '3';
28 $form_cors = isset($_POST['form_cors']) ? $_POST['form_cors'] : '1';
29 $form_output = isset($_POST['form_output']) ? 0 + $_POST['form_output'] : 1;
31 if (empty($form_by)) $form_by = '1';
32 if (empty($form_show)) $form_show = array('1');
34 // One of these is chosen as the left column, or Y-axis, of the report.
36 if ($report_type == 'm') {
37 $report_title = xl('Member Association Statistics Report');
38 $arr_by = array(
39 101 => xl('MA Category'),
40 102 => xl('Specific Service'),
41 17 => xl('Patient'),
42 9 => xl('Internal Referrals'),
43 10 => xl('External Referrals'),
44 103 => xl('Referral Source'),
45 2 => xl('Total'),
47 $arr_content = array(
48 1 => xl('Services'),
49 2 => xl('Unique Clients'),
50 4 => xl('Unique New Clients')
52 $arr_report = array(
53 // Items are content|row|column|column|...
54 /*****************************************************************
55 '2|2|3|4|5|8|11' => xl('Client Profile - Unique Clients'),
56 '4|2|3|4|5|8|11' => xl('Client Profile - New Clients'),
57 *****************************************************************/
60 else if ($report_type == 'g') {
61 $report_title = xl('GCAC Statistics Report');
62 $arr_by = array(
63 13 => xl('Abortion-Related Categories'),
64 1 => xl('Total SRH & Family Planning'),
65 12 => xl('Pre-Abortion Counseling'),
66 5 => xl('Abortion Method'), // includes surgical and drug-induced
67 8 => xl('Post-Abortion Followup'),
68 7 => xl('Post-Abortion Contraception'),
69 11 => xl('Complications of Abortion'),
70 10 => xl('External Referrals'),
71 20 => xl('External Referral Followups'),
73 $arr_content = array(
74 1 => xl('Services'),
75 2 => xl('Unique Clients'),
76 4 => xl('Unique New Clients'),
78 $arr_report = array(
79 /*****************************************************************
80 '1|11|13' => xl('Complications by Service Provider'),
81 *****************************************************************/
84 else {
85 $report_title = xl('IPPF Statistics Report');
86 $arr_by = array(
87 3 => xl('General Service Category'),
88 4 => xl('Specific Service'),
89 6 => xl('Contraceptive Method'),
90 9 => xl('Internal Referrals'),
91 10 => xl('External Referrals'),
93 $arr_content = array(
94 1 => xl('Services'),
95 3 => xl('New Acceptors'),
97 $arr_report = array(
101 if ($report_type == 'm') {
103 else {
106 // This will become the array of reportable values.
107 $areport = array();
109 // This accumulates the bottom line totals.
110 $atotals = array();
112 $arr_show = array(
113 '.total' => array('title' => 'Total'),
114 '.age' => array('title' => 'Age Category'),
115 ); // info about selectable columns
117 $arr_titles = array(); // will contain column headers
119 // Query layout_options table to generate the $arr_show table.
120 // Table key is the field ID.
121 $lres = sqlStatement("SELECT field_id, title, data_type, list_id, description " .
122 "FROM layout_options WHERE " .
123 "form_id = 'DEM' AND uor > 0 AND field_id NOT LIKE 'em%' " .
124 "ORDER BY group_name, seq, title");
125 while ($lrow = sqlFetchArray($lres)) {
126 $fid = $lrow['field_id'];
127 if ($fid == 'fname' || $fid == 'mname' || $fid == 'lname') continue;
128 $arr_show[$fid] = $lrow;
129 $arr_titles[$fid] = array();
132 // Compute age in years given a DOB and "as of" date.
134 function getAge($dob, $asof='') {
135 if (empty($asof)) $asof = date('Y-m-d');
136 $a1 = explode('-', substr($dob , 0, 10));
137 $a2 = explode('-', substr($asof, 0, 10));
138 $age = $a2[0] - $a1[0];
139 if ($a2[1] < $a1[1] || ($a2[1] == $a1[1] && $a2[2] < $a1[2])) --$age;
140 // echo "<!-- $dob $asof $age -->\n"; // debugging
141 return $age;
144 $cellcount = 0;
146 function genStartRow($att) {
147 global $cellcount, $form_output;
148 if ($form_output != 3) echo " <tr $att>\n";
149 $cellcount = 0;
152 function genEndRow() {
153 global $form_output;
154 if ($form_output == 3) {
155 echo "\n";
157 else {
158 echo " </tr>\n";
162 /*********************************************************************
163 function genAnyCell($data, $right=false, $class='') {
164 global $cellcount;
165 if ($_POST['form_csvexport']) {
166 if ($cellcount) echo ',';
167 echo '"' . $data . '"';
169 else {
170 echo " <td";
171 if ($class) echo " class='$class'";
172 if ($right) echo " align='right'";
173 echo ">$data</td>\n";
175 ++$cellcount;
177 *********************************************************************/
179 function getListTitle($list, $option) {
180 $row = sqlQuery("SELECT title FROM list_options WHERE " .
181 "list_id = '$list' AND option_id = '$option'");
182 if (empty($row['title'])) return $option;
183 return $row['title'];
186 // Usually this generates one cell, but allows for two or more.
188 function genAnyCell($data, $right=false, $class='') {
189 global $cellcount, $form_output;
190 if (!is_array($data)) {
191 $data = array(0 => $data);
193 foreach ($data as $datum) {
194 if ($form_output == 3) {
195 if ($cellcount) echo ',';
196 echo '"' . $datum . '"';
198 else {
199 echo " <td";
200 if ($class) echo " class='$class'";
201 if ($right) echo " align='right'";
202 echo ">$datum</td>\n";
204 ++$cellcount;
208 function genHeadCell($data, $right=false) {
209 genAnyCell($data, $right, 'dehead');
212 // Create an HTML table cell containing a numeric value, and track totals.
214 function genNumCell($num, $cnum) {
215 global $atotals, $form_output;
216 $atotals[$cnum] += $num;
217 if (empty($num) && $form_output != 3) $num = '&nbsp;';
218 genAnyCell($num, true, 'detail');
221 // Translate an IPPF code to the corresponding descriptive name of its
222 // contraceptive method, or to an empty string if none applies.
224 function getContraceptiveMethod($code) {
225 $key = '';
226 if (preg_match('/^111101/', $code)) {
227 $key = xl('Pills');
229 else if (preg_match('/^11111[1-9]/', $code)) {
230 $key = xl('Injectables');
232 else if (preg_match('/^11112[1-9]/', $code)) {
233 $key = xl('Implants');
235 else if (preg_match('/^111132/', $code)) {
236 $key = xl('Patch');
238 else if (preg_match('/^111133/', $code)) {
239 $key = xl('Vaginal Ring');
241 else if (preg_match('/^112141/', $code)) {
242 $key = xl('Male Condoms');
244 else if (preg_match('/^112142/', $code)) {
245 $key = xl('Female Condoms');
247 else if (preg_match('/^11215[1-9]/', $code)) {
248 $key = xl('Diaphragms/Caps');
250 else if (preg_match('/^11216[1-9]/', $code)) {
251 $key = xl('Spermicides');
253 else if (preg_match('/^11317[1-9]/', $code)) {
254 $key = xl('IUD');
256 else if (preg_match('/^145212/', $code)) {
257 $key = xl('Emergency Contraception');
259 else if (preg_match('/^121181.13/', $code)) {
260 $key = xl('Female VSC');
262 else if (preg_match('/^122182.13/', $code)) {
263 $key = xl('Male VSC');
265 else if (preg_match('/^131191.10/', $code)) {
266 $key = xl('Awareness-Based');
268 return $key;
271 // Translate an IPPF code to the corresponding descriptive name of its
272 // abortion method, or to an empty string if none applies.
274 function getAbortionMethod($code) {
275 $key = '';
276 if (preg_match('/^25222[34]/', $code)) {
277 if (preg_match('/^2522231/', $code)) {
278 $key = xl('D&C');
280 else if (preg_match('/^2522232/', $code)) {
281 $key = xl('D&E');
283 else if (preg_match('/^2522233/', $code)) {
284 $key = xl('MVA');
286 else if (preg_match('/^252224/', $code)) {
287 $key = xl('Medical');
289 else {
290 $key = xl('Other Surgical');
293 return $key;
296 /*********************************************************************
297 // Helper function to look up the GCAC issue associated with a visit.
298 // Ideally this is the one and only GCAC issue linked to the encounter.
299 // However if there are multiple such issues, or if only unlinked issues
300 // are found, then we pick the one with its start date closest to the
301 // encounter date.
303 function getGcacData($row, $what, $morejoins="") {
304 $patient_id = $row['pid'];
305 $encounter_id = $row['encounter'];
306 $encdate = substr($row['encdate'], 0, 10);
307 $query = "SELECT $what " .
308 "FROM lists AS l " .
309 "JOIN lists_ippf_gcac AS lg ON l.type = 'ippf_gcac' AND lg.id = l.id " .
310 "LEFT JOIN issue_encounter AS ie ON ie.pid = '$patient_id' AND " .
311 "ie.encounter = '$encounter_id' AND ie.list_id = l.id " .
312 "$morejoins " .
313 "WHERE l.pid = '$patient_id' AND " .
314 "l.activity = 1 AND l.type = 'ippf_gcac' " .
315 "ORDER BY ie.pid DESC, ABS(DATEDIFF(l.begdate, '$encdate')) ASC " .
316 "LIMIT 1";
317 // Note that reverse-ordering by ie.pid is a trick for sorting
318 // issues linked to the encounter (non-null values) first.
319 return sqlQuery($query);
322 // Get the "client status" field from the related GCAC issue.
324 function getGcacClientStatus($row) {
325 $irow = getGcacData($row, "lo.title", "LEFT JOIN list_options AS lo ON " .
326 "lo.list_id = 'clientstatus' AND lo.option_id = lg.client_status");
327 if (empty($irow['title'])) {
328 $key = xl('Indeterminate');
330 else {
331 // The client status description should be just fine for this.
332 $key = $irow['title'];
334 return $key;
336 *********************************************************************/
338 // Get the "client status" as descriptive text.
339 // This comes from the most recent GCAC visit form for visits within
340 // the past 2 weeks, although there really should be such a form
341 // attached to the visit associated with $row.
343 function getGcacClientStatus($row) {
344 $pid = $row['pid'];
345 $encdate = $row['encdate'];
346 $query = "SELECT lo.title " .
347 "FROM forms AS f, form_encounter AS fe, lbf_data AS d, list_options AS lo " .
348 "WHERE f.pid = '$pid' AND " .
349 "f.formdir = 'LBFgcac' AND " .
350 "f.deleted = 0 AND " .
351 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
352 "fe.date <= '$encdate' AND " .
353 "DATE_ADD(fe.date, INTERVAL 14 DAY) > '$encdate' AND " .
354 "d.form_id = f.form_id AND " .
355 "d.field_id = 'client_status' AND " .
356 "lo.list_id = 'clientstatus' AND " .
357 "lo.option_id = d.field_value " .
358 "ORDER BY d.form_id DESC LIMIT 1";
359 $irow = sqlQuery($query);
360 // echo "<!-- $query -->\n"; // debugging
361 return empty($irow['title']) ? xl('Indeterminate') : $irow['title'];
364 // Helper function called after the reporting key is determined for a row.
366 function loadColumnData($key, $row) {
367 global $areport, $arr_titles, $form_cors, $from_date, $to_date, $arr_show;
369 // If first instance of this key, initialize its arrays.
370 if (empty($areport[$key])) {
371 $areport[$key] = array();
372 $areport[$key]['.prp'] = 0; // previous pid
373 $areport[$key]['.wom'] = 0; // number of services for women
374 $areport[$key]['.men'] = 0; // number of services for men
375 $areport[$key]['.age'] = array(0,0,0,0,0,0,0,0,0); // age array
376 foreach ($arr_show as $askey => $dummy) {
377 if (substr($askey, 0, 1) == '.') continue;
378 $areport[$key][$askey] = array();
382 // Skip this key if we are counting unique patients and the key
383 // has already seen this patient.
384 if ($form_cors == '2' && $row['pid'] == $areport[$key]['.prp']) return;
386 // If we are counting new acceptors, then require a unique patient
387 // whose contraceptive start date is within the reporting period.
388 if ($form_cors == '3') {
389 // if ($row['pid'] == $areport[$key]['prp']) return;
390 if ($row['pid'] == $areport[$key]['.prp']) return;
391 // Check contraceptive start date.
392 if (!$row['contrastart'] || $row['contrastart'] < $from_date ||
393 $row['contrastart'] > $to_date) return;
396 // If we are counting new clients, then require a unique patient
397 // whose registration date is within the reporting period.
398 if ($form_cors == '4') {
399 if ($row['pid'] == $areport[$key]['.prp']) return;
400 // Check registration date.
401 if (!$row['regdate'] || $row['regdate'] < $from_date ||
402 $row['regdate'] > $to_date) return;
405 // Flag this patient as having been encountered for this report row.
406 // $areport[$key]['prp'] = $row['pid'];
407 $areport[$key]['.prp'] = $row['pid'];
409 // Increment the correct sex category.
410 if (strcasecmp($row['sex'], 'Male') == 0)
411 ++$areport[$key]['.men'];
412 else
413 ++$areport[$key]['.wom'];
415 // Increment the correct age category.
416 $age = getAge(fixDate($row['DOB']), $row['encdate']);
417 $i = min(intval(($age - 5) / 5), 8);
418 if ($age < 11) $i = 0;
419 ++$areport[$key]['.age'][$i];
421 foreach ($arr_show as $askey => $dummy) {
422 if (substr($askey, 0, 1) == '.') continue;
423 $status = empty($row[$askey]) ? 'Unspecified' : $row[$askey];
424 $areport[$key][$askey][$status] += 1;
425 $arr_titles[$askey][$status] += 1;
429 // This is called for each IPPF service code that is selected.
431 function process_ippf_code($row, $code) {
432 global $areport, $arr_titles, $form_by;
434 $key = 'Unspecified';
436 // SRH including Family Planning
438 if ($form_by === '1') {
439 if (preg_match('/^1/', $code)) {
440 $key = xl('SRH - Family Planning');
442 else if (preg_match('/^2/', $code)) {
443 $key = xl('SRH Non Family Planning');
445 else {
446 return;
450 // General Service Category
452 else if ($form_by === '3') {
453 if (preg_match('/^1/', $code)) {
454 $key = xl('SRH - Family Planning');
456 else if (preg_match('/^2/', $code)) {
457 $key = xl('SRH Non Family Planning');
459 else if (preg_match('/^3/', $code)) {
460 $key = xl('Non-SRH Medical');
462 else if (preg_match('/^4/', $code)) {
463 $key = xl('Non-SRH Non-Medical');
465 else {
466 $key = xl('Invalid Service Codes');
470 // Abortion-Related Category
472 else if ($form_by === '13') {
473 if (preg_match('/^252221/', $code)) {
474 $key = xl('Pre-Abortion Counseling');
476 else if (preg_match('/^252222/', $code)) {
477 $key = xl('Pre-Abortion Consultation');
479 else if (preg_match('/^252223/', $code)) {
480 $key = xl('Induced Abortion');
482 else if (preg_match('/^252224/', $code)) {
483 $key = xl('Medical Abortion');
485 else if (preg_match('/^252225/', $code)) {
486 $key = xl('Incomplete Abortion Treatment');
488 else if (preg_match('/^252226/', $code)) {
489 $key = xl('Post-Abortion Care');
491 else if (preg_match('/^252227/', $code)) {
492 $key = xl('Post-Abortion Counseling');
494 else if (preg_match('/^25222/', $code)) {
495 $key = xl('Other/Generic Abortion-Related');
497 else {
498 return;
502 // Specific Services. One row for each IPPF code.
504 else if ($form_by === '4') {
505 $key = $code;
508 // Abortion Method.
510 else if ($form_by === '5') {
511 $key = getAbortionMethod($code);
512 if (empty($key)) return;
515 // Contraceptive Method.
517 else if ($form_by === '6') {
518 $key = getContraceptiveMethod($code);
519 if (empty($key)) return;
522 /*******************************************************************
523 // Contraceptive method for new contraceptive adoption following abortion.
524 // Get it from the IPPF code if an abortion issue is linked to the visit.
525 // Note we are handling this during processing of services rather than
526 // by enumerating issues, because we need the service date.
528 else if ($form_by === '7') {
529 $key = getContraceptiveMethod($code);
530 if (empty($key)) return;
531 $patient_id = $row['pid'];
532 $encounter_id = $row['encounter'];
533 $query = "SELECT COUNT(*) AS count " .
534 "FROM lists AS l " .
535 "JOIN issue_encounter AS ie ON ie.pid = '$patient_id' AND " .
536 "ie.encounter = '$encounter_id' AND ie.list_id = l.id " .
537 "WHERE l.pid = '$patient_id' AND " .
538 "l.activity = 1 AND l.type = 'ippf_gcac'";
539 // echo "<!-- $key: $query -->\n"; // debugging
540 $irow = sqlQuery($query);
541 if (empty($irow['count'])) return;
543 *******************************************************************/
545 // Post-Abortion Care and Followup by Source.
546 // Requirements just call for counting sessions, but this way the columns
547 // can be anything - age category, religion, whatever.
549 else if ($form_by === '8') {
550 if (preg_match('/^25222[67]/', $code)) { // all post-abortion care and followup
551 $key = getGcacClientStatus($row);
552 } else {
553 return;
557 /*******************************************************************
558 // Complications of abortion by abortion method and complication type.
559 // These may be noted either during recovery or during a followup visit.
560 // Again, driven by services in order to report by service date.
561 // Note: If there are multiple complications, they will all be reported.
563 else if ($form_by === '11') {
564 $compl_type = '';
565 if (preg_match('/^25222[345]/', $code)) { // all abortions including incomplete
566 $compl_type = 'rec_compl';
568 else if (preg_match('/^25222[67]/', $code)) { // all post-abortion care and followup
569 $compl_type = 'fol_compl';
571 else {
572 return;
574 $irow = getGcacData($row, "lg.$compl_type, lo.title",
575 "LEFT JOIN list_options AS lo ON lo.list_id = 'in_ab_proc' AND " .
576 "lo.option_id = lg.in_ab_proc");
577 if (empty($irow)) return; // this should not happen
578 if (empty($irow[$compl_type])) return; // ok, no complications
579 // We have one or more complications.
580 $abtype = empty($irow['title']) ? xl('Indeterminate') : $irow['title'];
581 $acompl = explode('|', $irow[$compl_type]);
582 foreach ($acompl as $compl) {
583 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
584 "list_id = 'complication' AND option_id = '$compl'");
585 $key = "$abtype / " . $crow['title'];
586 loadColumnData($key, $row);
588 return; // because loadColumnData() is already done.
590 *******************************************************************/
592 // Pre-Abortion Counseling. Three possible situations:
593 // Provided abortion in the MA clinics
594 // Referred to other service providers (govt,private clinics)
595 // Decided not to have the abortion
597 else if ($form_by === '12') {
598 if (preg_match('/^252221/', $code)) { // all pre-abortion counseling
599 $key = getGcacClientStatus($row);
600 } else {
601 return;
605 // Patient Name.
607 else if ($form_by === '17') {
608 $key = $row['lname'] . ', ' . $row['fname'] . ' ' . $row['mname'];
611 else {
612 return; // no match, so do nothing
615 // OK we now have the reporting key for this issue.
616 loadColumnData($key, $row);
618 } // end function process_ippf_code()
620 // This is called for each MA service code that is selected.
622 function process_ma_code($row) {
623 global $form_by, $arr_content, $form_cors;
625 $key = 'Unspecified';
627 // One row for each service category.
629 if ($form_by === '101') {
630 if (!empty($row['lo_title'])) $key = xl($row['lo_title']);
633 // Specific Services. One row for each MA code.
635 else if ($form_by === '102') {
636 $key = $row['code'];
639 // One row for each referral source.
641 else if ($form_by === '103') {
642 $key = $row['referral_source'];
645 // Just one row.
647 else if ($form_by === '2') {
648 $key = $arr_content[$form_cors];
651 else {
652 return;
655 loadColumnData($key, $row);
658 function LBFgcac_query($pid, $encounter, $name) {
659 $query = "SELECT d.form_id, d.field_value " .
660 "FROM forms AS f, form_encounter AS fe, lbf_data AS d " .
661 "WHERE f.pid = '$pid' AND " .
662 "f.encounter = '$encounter' AND " .
663 "f.formdir = 'LBFgcac' AND " .
664 "f.deleted = 0 AND " .
665 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
666 "d.form_id = f.form_id AND " .
667 "d.field_id = '$name'";
668 return sqlStatement($query);
671 function LBFgcac_title($form_id, $field_id, $list_id) {
672 $query = "SELECT lo.title " .
673 "FROM lbf_data AS d, list_options AS lo WHERE " .
674 "d.form_id = '$form_id' AND " .
675 "d.field_id = '$field_id' AND " .
676 "lo.list_id = '$list_id' AND " .
677 "lo.option_id = d.field_value " .
678 "LIMIT 1";
679 $row = sqlQuery($query);
680 return empty($row['title']) ? '' : $row['title'];
683 // This is called for each encounter that is selected.
685 function process_visit($row) {
686 global $form_by;
688 if ($form_by !== '7' && $form_by !== '11') return;
690 // New contraceptive method following abortion.
692 if ($form_by === '7') {
693 $dres = LBFgcac_query($row['pid'], $row['encounter'], 'contrameth');
694 while ($drow = sqlFetchArray($dres)) {
695 $a = explode('|', $drow['field_value']);
696 foreach ($a as $methid) {
697 if (empty($methid)) continue;
698 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
699 "list_id = 'contrameth' AND option_id = '$methid'");
700 $key = $crow['title'];
701 if (empty($key)) $key = xl('Indeterminate');
702 loadColumnData($key, $row);
707 // Complications of abortion by abortion method and complication type.
708 // These may be noted either during recovery or during a followup visit.
709 // Note: If there are multiple complications, they will all be reported.
711 else if ($form_by === '11') {
712 $dres = LBFgcac_query($row['pid'], $row['encounter'], 'complications');
713 while ($drow = sqlFetchArray($dres)) {
714 $a = explode('|', $drow['field_value']);
715 foreach ($a as $complid) {
716 if (empty($complid)) continue;
717 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
718 "list_id = 'complication' AND option_id = '$complid'");
719 $abtype = LBFgcac_title($drow['form_id'], 'in_ab_proc', 'in_ab_proc');
720 if (empty($abtype)) $abtype = xl('Indeterminate');
721 $key = "$abtype / " . $crow['title'];
722 loadColumnData($key, $row);
727 // loadColumnData() already done as needed.
730 /*********************************************************************
731 // This is called for each issue that is selected.
733 function process_issue($row) {
734 global $form_by;
736 $key = 'Unspecified';
738 // Pre-Abortion Counseling. Three possible rows:
739 // Provided abortion in the MA clinics
740 // Referred to other service providers (govt,private clinics)
741 // Decided not to have the abortion
743 if ($form_by === '12') {
745 // TBD: Assign one of the 3 keys, or just return.
749 // Others TBD
751 else {
752 return;
755 // TBD: Load column data from the issue.
756 // loadColumnData($key, $row);
758 *********************************************************************/
760 // This is called for each selected referral.
761 // Row keys are the first specified MA code, if any.
763 function process_referral($row) {
764 global $form_by;
765 $key = 'Unspecified';
767 if (!empty($row['refer_related_code'])) {
768 $relcodes = explode(';', $row['refer_related_code']);
769 foreach ($relcodes as $codestring) {
770 if ($codestring === '') continue;
771 list($codetype, $code) = explode(':', $codestring);
773 if ($codetype !== 'IPPF') continue;
775 if ($form_by === '1') {
776 if (preg_match('/^[12]/', $code)) {
777 $key = xl('SRH Referrals');
778 loadColumnData($key, $row);
779 break;
782 else { // $form_by is 9 (internal) or 10 or 20 (external) referrals
783 $key = $code;
784 break;
786 } // end foreach
789 if ($form_by !== '1') loadColumnData($key, $row);
792 // If we are doing the CSV export then generate the needed HTTP headers.
793 // Otherwise generate HTML.
795 if ($form_output == 3) {
796 header("Pragma: public");
797 header("Expires: 0");
798 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
799 header("Content-Type: application/force-download");
800 header("Content-Disposition: attachment; filename=service_statistics_report.csv");
801 header("Content-Description: File Transfer");
803 else {
805 <html>
806 <head>
807 <?php html_header_show(); ?>
808 <title><?php echo $report_title; ?></title>
809 <style type="text/css">@import url(../../library/dynarch_calendar.css);</style>
810 <style type="text/css">
811 body { font-family:sans-serif; font-size:10pt; font-weight:normal }
812 .dehead { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:bold }
813 .detail { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:normal }
814 </style>
815 <script type="text/javascript" src="../../library/textformat.js"></script>
816 <script type="text/javascript" src="../../library/dynarch_calendar.js"></script>
817 <?php include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?>
818 <script type="text/javascript" src="../../library/dynarch_calendar_setup.js"></script>
819 <script language="JavaScript">
820 var mypcc = '<?php echo $GLOBALS['phone_country_code'] ?>';
822 // Begin experimental code
824 function selectByValue(sel, val) {
825 for (var i = 0; i < sel.options.length; ++i) {
826 if (sel.options[i].value == val) sel.options[i].selected = true;
830 function selreport() {
831 var f = document.forms[0];
832 var isdis = 'visible';
833 var s = f.form_report;
834 var v = (s.selectedIndex < 0) ? '' : s.options[s.selectedIndex].value;
835 if (v.length > 0) {
836 isdis = 'hidden';
837 var a = v.split("|");
838 f.form_cors.selectedIndex = -1;
839 f.form_by.selectedIndex = -1;
840 f['form_show[]'].selectedIndex = -1;
841 selectByValue(f.form_cors, a[0]);
842 selectByValue(f.form_by, a[1]);
843 for (var i = 2; i < a.length; ++i) {
844 selectByValue(f['form_show[]'], a[i]);
847 f.form_by.style.visibility = isdis;
848 f.form_cors.style.visibility = isdis;
849 f['form_show[]'].style.visibility = isdis;
852 // End experimental code
854 </script>
855 </head>
857 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
859 <center>
861 <h2><?php echo $report_title; ?></h2>
863 <form name='theform' method='post'
864 action='ippf_statistics.php?t=<?php echo $report_type ?>'>
866 <table border='0' cellspacing='5' cellpadding='1'>
868 <!-- Begin experimental code -->
869 <tr<?php if (empty($arr_report)) echo " style='display:none'"; ?>>
870 <td valign='top' class='dehead' nowrap>
871 <?php xl('Report','e'); ?>:
872 </td>
873 <td valign='top' class='detail' colspan='3'>
874 <select name='form_report' title='Predefined reports' onchange='selreport()'>
875 <?php
876 echo " <option value=''>" . xl('Custom') . "</option>\n";
877 foreach ($arr_report as $key => $value) {
878 echo " <option value='$key'";
879 if ($key == $form_report) echo " selected";
880 echo ">" . $value . "</option>\n";
883 </select>
884 </td>
885 <td valign='top' class='detail'>
886 &nbsp;
887 </td>
888 </tr>
889 <!-- End experimental code -->
891 <tr>
892 <td valign='top' class='dehead' nowrap>
893 <?php xl('Rows','e'); ?>:
894 </td>
895 <td valign='top' class='detail'>
896 <select name='form_by' title='Left column of report'>
897 <?php
898 foreach ($arr_by as $key => $value) {
899 echo " <option value='$key'";
900 if ($key == $form_by) echo " selected";
901 echo ">" . $value . "</option>\n";
904 </select>
905 </td>
906 <td valign='top' class='dehead' nowrap>
907 <?php xl('Content','e'); ?>:
908 </td>
909 <td valign='top' class='detail'>
910 <select name='form_cors' title='<?php xl('What is to be counted?','e'); ?>'>
911 <?php
912 foreach ($arr_content as $key => $value) {
913 echo " <option value='$key'";
914 if ($key == $form_cors) echo " selected";
915 echo ">$value</option>\n";
918 </select>
919 </td>
920 <td valign='top' class='detail'>
921 &nbsp;
922 </td>
923 </tr>
924 <tr>
925 <td valign='top' class='dehead' nowrap>
926 <?php xl('Columns','e'); ?>:
927 </td>
928 <td valign='top' class='detail'>
929 <select name='form_show[]' size='4' multiple
930 title='<?php xl('Hold down Ctrl to select multiple items','e'); ?>'>
931 <?php
932 foreach ($arr_show as $key => $value) {
933 $title = $value['title'];
934 if (empty($title) || $key == 'title') $title = $value['description'];
935 echo " <option value='$key'";
936 if (is_array($form_show) && in_array($key, $form_show)) echo " selected";
937 echo ">$title</option>\n";
940 </select>
941 </td>
942 <td valign='top' class='dehead' nowrap>
943 <?php xl('Filters','e'); ?>:
944 </td>
945 <td colspan='2' class='detail' style='border-style:solid;border-width:1px;border-color:#cccccc'>
946 <table>
947 <tr>
948 <td valign='top' class='detail' nowrap>
949 <?php xl('Sex','e'); ?>:
950 </td>
951 <td class='detail' valign='top'>
952 <select name='form_sexes' title='<?php xl('To filter by sex','e'); ?>'>
953 <?php
954 foreach (array(3 => xl('Men and Women'), 1 => xl('Women Only'), 2 => xl('Men Only')) as $key => $value) {
955 echo " <option value='$key'";
956 if ($key == $form_sexes) echo " selected";
957 echo ">$value</option>\n";
960 </select>
961 </td>
962 </tr>
963 <tr>
964 <td valign='top' class='detail' nowrap>
965 <?php xl('Facility','e'); ?>:
966 </td>
967 <td valign='top' class='detail'>
968 <?php
969 // Build a drop-down list of facilities.
971 $query = "SELECT id, name FROM facility ORDER BY name";
972 $fres = sqlStatement($query);
973 echo " <select name='form_facility'>\n";
974 echo " <option value=''>-- All Facilities --\n";
975 while ($frow = sqlFetchArray($fres)) {
976 $facid = $frow['id'];
977 echo " <option value='$facid'";
978 if ($facid == $_POST['form_facility']) echo " selected";
979 echo ">" . $frow['name'] . "\n";
981 echo " </select>\n";
983 </td>
984 </tr>
985 <tr>
986 <td colspan='2' class='detail' nowrap>
987 <?php xl('From','e'); ?>
988 <input type='text' name='form_from_date' id='form_from_date' size='10' value='<?php echo $from_date ?>'
989 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='Start date yyyy-mm-dd'>
990 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
991 id='img_from_date' border='0' alt='[?]' style='cursor:pointer'
992 title='<?php xl('Click here to choose a date','e'); ?>'>
993 <?php xl('To','e'); ?>
994 <input type='text' name='form_to_date' id='form_to_date' size='10' value='<?php echo $to_date ?>'
995 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='End date yyyy-mm-dd'>
996 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
997 id='img_to_date' border='0' alt='[?]' style='cursor:pointer'
998 title='<?php xl('Click here to choose a date','e'); ?>'>
999 </td>
1000 </tr>
1001 </table>
1002 </td>
1003 </tr>
1004 <tr>
1005 <td valign='top' class='dehead' nowrap>
1006 <?php xl('To','e'); ?>:
1007 </td>
1008 <td colspan='3' valign='top' class='detail' nowrap>
1009 <?php
1010 foreach (array(1 => 'Screen', 2 => 'Printer', 3 => 'Export File') as $key => $value) {
1011 echo " <input type='radio' name='form_output' value='$key'";
1012 if ($key == $form_output) echo ' checked';
1013 echo " />$value &nbsp;";
1016 </td>
1017 <td align='right' valign='top' class='detail' nowrap>
1018 <input type='submit' name='form_submit' value='<?php xl('Submit','e'); ?>'
1019 title='<?php xl('Click to generate the report','e'); ?>' />
1020 </td>
1021 </tr>
1022 <tr>
1023 <td colspan='5' height="1">
1024 </td>
1025 </tr>
1026 </table>
1027 <?php
1028 } // end not export
1030 if ($_POST['form_submit']) {
1031 $pd_fields = '';
1032 foreach ($arr_show as $askey => $asval) {
1033 if (substr($askey, 0, 1) == '.') continue;
1034 if ($askey == 'regdate' || $askey == 'sex' || $askey == 'DOB' ||
1035 $askey == 'lname' || $askey == 'fname' || $askey == 'mname' ||
1036 $askey == 'contrastart' || $askey == 'referral_source') continue;
1037 $pd_fields .= ', pd.' . $askey;
1040 $sexcond = '';
1041 if ($form_sexes == '1') $sexcond = "AND pd.sex NOT LIKE 'Male' ";
1042 else if ($form_sexes == '2') $sexcond = "AND pd.sex LIKE 'Male' ";
1044 // Get referrals and related patient data.
1045 if ($form_by === '9' || $form_by === '10' || $form_by === '20' || $form_by === '1') {
1047 $exttest = "t.refer_external = '1'";
1048 $datefld = "t.refer_date";
1050 if ($form_by === '9') {
1051 $exttest = "t.refer_external = '0'";
1053 else if ($form_by === '20') {
1054 $datefld = "t.reply_date";
1057 $query = "SELECT " .
1058 "t.refer_related_code, t.pid, pd.regdate, pd.referral_source, " .
1059 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1060 "pd.contrastart$pd_fields " .
1061 "FROM transactions AS t " .
1062 "JOIN patient_data AS pd ON pd.pid = t.pid $sexcond" .
1063 "WHERE t.title = 'Referral' AND $datefld IS NOT NULL AND " .
1064 "$datefld >= '$from_date' AND $datefld <= '$to_date' AND $exttest " .
1065 "ORDER BY t.pid, t.id";
1066 $res = sqlStatement($query);
1067 while ($row = sqlFetchArray($res)) {
1068 process_referral($row);
1071 /*****************************************************************
1072 else if ($form_by === '12') {
1073 // We are reporting on a date range, and assume the applicable date is
1074 // the issue start date which is presumably also the date of pre-
1075 // abortion counseling. The issue end date and the surgery date are
1076 // not of interest here.
1077 $query = "SELECT " .
1078 "l.type, l.begdate, l.pid, " .
1079 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, pd.userlist5, " .
1080 "pd.country_code, pd.status, pd.state, pd.occupation, " .
1081 "lg.client_status, lg.ab_location " .
1082 "FROM lists AS l " .
1083 "JOIN patient_data AS pd ON pd.pid = l.pid $sexcond" .
1084 "LEFT OUTER JOIN lists_ippf_gcac AS lg ON l.type = 'ippf_gcac' AND lg.id = l.id " .
1085 // "LEFT OUTER JOIN lists_ippf_con AS lc ON l.type = 'contraceptive' AND lc.id = l.id " .
1086 "WHERE l.begdate >= '$from_date' AND l.begdate <= '$to_date' AND " .
1087 "l.activity = 1 AND l.type = 'ippf_gcac' " .
1088 "ORDER BY l.pid, l.id";
1089 $res = sqlStatement($query);
1090 while ($row = sqlFetchArray($res)) {
1091 process_issue($row);
1094 *****************************************************************/
1096 // else {
1097 if ($form_by !== '9' && $form_by !== '10' && $form_by !== '20') {
1098 // This gets us all MA codes, with encounter and patient
1099 // info attached and grouped by patient and encounter.
1100 $query = "SELECT " .
1101 "fe.pid, fe.encounter, fe.date AS encdate, pd.regdate, " .
1102 "f.user AS provider, " .
1103 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1104 "pd.contrastart, pd.referral_source$pd_fields, " .
1105 "b.code_type, b.code, c.related_code, lo.title AS lo_title " .
1106 "FROM form_encounter AS fe " .
1107 "JOIN forms AS f ON f.pid = fe.pid AND f.encounter = fe.encounter AND " .
1108 "f.formdir = 'newpatient' AND f.form_id = fe.id AND f.deleted = 0 " .
1109 "JOIN patient_data AS pd ON pd.pid = fe.pid $sexcond" .
1110 "LEFT OUTER JOIN billing AS b ON " .
1111 "b.pid = fe.pid AND b.encounter = fe.encounter AND b.activity = 1 " .
1112 "AND b.code_type = 'MA' " .
1113 "LEFT OUTER JOIN codes AS c ON b.code_type = 'MA' AND c.code_type = '12' AND " .
1114 "c.code = b.code AND c.modifier = b.modifier " .
1115 "LEFT OUTER JOIN list_options AS lo ON " .
1116 "lo.list_id = 'superbill' AND lo.option_id = c.superbill " .
1117 "WHERE fe.date >= '$from_date 00:00:00' AND " .
1118 "fe.date <= '$to_date 23:59:59' ";
1120 if ($form_facility) {
1121 $query .= "AND fe.facility_id = '$form_facility' ";
1123 $query .= "ORDER BY fe.pid, fe.encounter, b.code";
1124 $res = sqlStatement($query);
1126 $prev_encounter = 0;
1128 while ($row = sqlFetchArray($res)) {
1129 if ($row['encounter'] != $prev_encounter) {
1130 $prev_encounter = $row['encounter'];
1131 process_visit($row);
1133 if ($row['code_type'] === 'MA') {
1134 process_ma_code($row);
1135 if (!empty($row['related_code'])) {
1136 $relcodes = explode(';', $row['related_code']);
1137 foreach ($relcodes as $codestring) {
1138 if ($codestring === '') continue;
1139 list($codetype, $code) = explode(':', $codestring);
1140 if ($codetype !== 'IPPF') continue;
1141 process_ippf_code($row, $code);
1145 } // end while
1146 } // end if
1148 // Sort everything by key for reporting.
1149 ksort($areport);
1150 foreach ($arr_titles as $atkey => $dummy) ksort($arr_titles[$atkey]);
1152 if ($form_output != 3) {
1153 echo "<table border='0' cellpadding='1' cellspacing='2' width='98%'>\n";
1154 } // end not csv export
1156 genStartRow("bgcolor='#dddddd'");
1158 // If the key is an MA or IPPF code, then add a column for its description.
1159 if ($form_by === '4' || $form_by === '102' || $form_by === '9' ||
1160 $form_by === '10' || $form_by === '20')
1162 genHeadCell(array($arr_by[$form_by], xl('Description')));
1163 } else {
1164 genHeadCell($arr_by[$form_by]);
1167 // Generate headings for values to be shown.
1168 foreach ($form_show as $value) {
1169 // if ($value == '1') { // Total Services
1170 if ($value == '.total') { // Total Services
1171 genHeadCell(xl('Total'));
1173 // else if ($value == '2') { // Age
1174 else if ($value == '.age') { // Age
1175 genHeadCell(xl('0-10' ), true);
1176 genHeadCell(xl('11-14'), true);
1177 genHeadCell(xl('15-19'), true);
1178 genHeadCell(xl('20-24'), true);
1179 genHeadCell(xl('25-29'), true);
1180 genHeadCell(xl('30-34'), true);
1181 genHeadCell(xl('35-39'), true);
1182 genHeadCell(xl('40-44'), true);
1183 genHeadCell(xl('45+' ), true);
1186 else if ($arr_show[$value]['list_id']) {
1187 foreach ($arr_titles[$value] as $key => $dummy) {
1188 genHeadCell(getListTitle($arr_show[$value]['list_id'],$key), true);
1191 else if (!empty($arr_titles[$value])) {
1192 foreach ($arr_titles[$value] as $key => $dummy) {
1193 genHeadCell($key, true);
1198 if ($form_output != 3) {
1199 genHeadCell(xl('Total'), true);
1202 genEndRow();
1204 $encount = 0;
1206 foreach ($areport as $key => $varr) {
1207 $bgcolor = (++$encount & 1) ? "#ddddff" : "#ffdddd";
1209 $dispkey = $key;
1211 // If the key is an MA or IPPF code, then add a column for its description.
1212 if ($form_by === '4' || $form_by === '102' || $form_by === '9' ||
1213 $form_by === '10' || $form_by === '20')
1215 $dispkey = array($key, '');
1216 $type = $form_by === '102' ? 12 : 11; // MA or IPPF
1217 $crow = sqlQuery("SELECT code_text FROM codes WHERE " .
1218 "code_type = '$type' AND code = '$key' ORDER BY id LIMIT 1");
1219 if (!empty($crow['code_text'])) $dispkey[1] = $crow['code_text'];
1222 genStartRow("bgcolor='$bgcolor'");
1224 genAnyCell($dispkey, false, 'detail');
1226 // This is the column index for accumulating column totals.
1227 $cnum = 0;
1228 $totalsvcs = $areport[$key]['.wom'] + $areport[$key]['.men'];
1230 // Generate data for this row.
1231 foreach ($form_show as $value) {
1232 // if ($value == '1') { // Total Services
1233 if ($value == '.total') { // Total Services
1234 genNumCell($totalsvcs, $cnum++);
1236 else if ($value == '.age') { // Age
1237 for ($i = 0; $i < 9; ++$i) {
1238 genNumCell($areport[$key]['.age'][$i], $cnum++);
1241 else if (!empty($arr_titles[$value])) {
1242 foreach ($arr_titles[$value] as $title => $dummy) {
1243 genNumCell($areport[$key][$value][$title], $cnum++);
1248 // Write the Total column data.
1249 if ($form_output != 3) {
1250 $atotals[$cnum] += $totalsvcs;
1251 genAnyCell($totalsvcs, true, 'dehead');
1254 genEndRow();
1255 } // end foreach
1257 if ($form_output != 3) {
1258 // Generate the line of totals.
1259 genStartRow("bgcolor='#dddddd'");
1261 // If the key is an MA or IPPF code, then add a column for its description.
1262 if ($form_by === '4' || $form_by === '102' || $form_by === '9' ||
1263 $form_by === '10' || $form_by === '20')
1265 genHeadCell(array(xl('Totals'), ''));
1266 } else {
1267 genHeadCell(xl('Totals'));
1270 for ($cnum = 0; $cnum < count($atotals); ++$cnum) {
1271 genHeadCell($atotals[$cnum], true);
1273 genEndRow();
1274 // End of table.
1275 echo "</table>\n";
1278 } // end of if refresh or export
1280 if ($form_output != 3) {
1282 </form>
1283 </center>
1285 <script language='JavaScript'>
1286 selreport();
1287 Calendar.setup({inputField:"form_from_date", ifFormat:"%Y-%m-%d", button:"img_from_date"});
1288 Calendar.setup({inputField:"form_to_date", ifFormat:"%Y-%m-%d", button:"img_to_date"});
1289 <?php if ($form_output == 2) { ?>
1290 window.print();
1291 <?php } ?>
1292 </script>
1294 </body>
1295 </html>
1296 <?php
1297 } // end not export