ongoing internationalization of date widget
[openemr.git] / interface / reports / ippf_statistics.php
blobb3abd1c0a1c27a63504ba17d50f045cc0feb42b2
1 <?php
2 /**
3 * This module creates statistical reports related to family planning
4 * and sexual and reproductive health.
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @copyright Copyright (c) 2008-2015 Rod Roark <rod@sunsetsystems.com>
11 * @copyright Copyright (c) 2017 Brady Miller <brady.g.miller@gmail.com>
12 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
15 include_once("../globals.php");
16 include_once("../../library/patient.inc");
17 include_once("../../library/acl.inc");
19 use OpenEMR\Services\FacilityService;
21 // Might want something different here.
23 if (! acl_check('acct', 'rep')) {
24 die("Unauthorized access.");
27 $facilityService = new FacilityService();
29 $report_type = empty($_GET['t']) ? 'i' : $_GET['t'];
31 $from_date = fixDate($_POST['form_from_date']);
32 $to_date = fixDate($_POST['form_to_date'], date('Y-m-d'));
33 $form_by = $_POST['form_by']; // this is a scalar
34 $form_show = $_POST['form_show']; // this is an array
35 $form_facility = isset($_POST['form_facility']) ? $_POST['form_facility'] : '';
36 $form_sexes = isset($_POST['form_sexes']) ? $_POST['form_sexes'] : '3';
37 $form_content = isset($_POST['form_content']) ? $_POST['form_content'] : '1';
38 $form_output = isset($_POST['form_output']) ? 0 + $_POST['form_output'] : 1;
40 if (empty($form_by)) {
41 $form_by = '1';
44 if (empty($form_show)) {
45 $form_show = array('1');
48 // One of these is chosen as the left column, or Y-axis, of the report.
50 if ($report_type == 'm') {
51 $report_title = xl('Member Association Statistics Report');
52 $arr_by = array(
53 101 => xl('MA Category'),
54 102 => xl('Specific Service'),
55 // 6 => xl('Contraceptive Method'),
56 // 104 => xl('Specific Contraceptive Service');
57 17 => xl('Patient'),
58 9 => xl('Internal Referrals'),
59 10 => xl('External Referrals'),
60 103 => xl('Referral Source'),
61 2 => xl('Total'),
63 $arr_content = array(
64 1 => xl('Services'),
65 2 => xl('Unique Clients'),
66 4 => xl('Unique New Clients'),
67 // 5 => xl('Contraceptive Products'),
69 $arr_report = array(
70 // Items are content|row|column|column|...
71 /*****************************************************************
72 '2|2|3|4|5|8|11' => xl('Client Profile - Unique Clients'),
73 '4|2|3|4|5|8|11' => xl('Client Profile - New Clients'),
74 *****************************************************************/
76 } else if ($report_type == 'g') {
77 $report_title = xl('GCAC Statistics Report');
78 $arr_by = array(
79 13 => xl('Abortion-Related Categories'),
80 1 => xl('Total SRH & Family Planning'),
81 12 => xl('Pre-Abortion Counseling'),
82 5 => xl('Abortion Method'), // includes surgical and drug-induced
83 8 => xl('Post-Abortion Followup'),
84 7 => xl('Post-Abortion Contraception'),
85 11 => xl('Complications of Abortion'),
86 10 => xl('External Referrals'),
87 20 => xl('External Referral Followups'),
89 $arr_content = array(
90 1 => xl('Services'),
91 2 => xl('Unique Clients'),
92 4 => xl('Unique New Clients'),
94 $arr_report = array(
95 /*****************************************************************
96 '1|11|13' => xl('Complications by Service Provider'),
97 *****************************************************************/
99 } else {
100 $report_title = xl('IPPF Statistics Report');
101 $arr_by = array(
102 3 => xl('General Service Category'),
103 4 => xl('Specific Service'),
104 104 => xl('Specific Contraceptive Service'),
105 6 => xl('Contraceptive Method'),
106 9 => xl('Internal Referrals'),
107 10 => xl('External Referrals'),
109 $arr_content = array(
110 1 => xl('Services'),
111 3 => xl('New Acceptors'),
112 5 => xl('Contraceptive Products'),
114 $arr_report = array(
118 // This will become the array of reportable values.
119 $areport = array();
121 // This accumulates the bottom line totals.
122 $atotals = array();
124 $arr_show = array(
125 '.total' => array('title' => 'Total'),
126 '.age2' => array('title' => 'Age Category (2)'),
127 '.age9' => array('title' => 'Age Category (9)'),
128 ); // info about selectable columns
130 $arr_titles = array(); // will contain column headers
132 // Query layout_options table to generate the $arr_show table.
133 // Table key is the field ID.
134 $lres = sqlStatement("SELECT field_id, title, data_type, list_id, description " .
135 "FROM layout_options WHERE " .
136 "form_id = 'DEM' AND uor > 0 AND field_id NOT LIKE 'em%' " .
137 "ORDER BY group_name, seq, title");
138 while ($lrow = sqlFetchArray($lres)) {
139 $fid = $lrow['field_id'];
140 if ($fid == 'fname' || $fid == 'mname' || $fid == 'lname') {
141 continue;
144 $arr_show[$fid] = $lrow;
145 $arr_titles[$fid] = array();
148 // Compute age in years given a DOB and "as of" date.
150 function getAge($dob, $asof = '')
152 if (empty($asof)) {
153 $asof = date('Y-m-d');
156 $a1 = explode('-', substr($dob, 0, 10));
157 $a2 = explode('-', substr($asof, 0, 10));
158 $age = $a2[0] - $a1[0];
159 if ($a2[1] < $a1[1] || ($a2[1] == $a1[1] && $a2[2] < $a1[2])) {
160 --$age;
163 // echo "<!-- $dob $asof $age -->\n"; // debugging
164 return $age;
167 $cellcount = 0;
169 function genStartRow($att)
171 global $cellcount, $form_output;
172 if ($form_output != 3) {
173 echo " <tr $att>\n";
176 $cellcount = 0;
179 function genEndRow()
181 global $form_output;
182 if ($form_output == 3) {
183 echo "\n";
184 } else {
185 echo " </tr>\n";
189 /*********************************************************************
190 function genAnyCell($data, $right=false, $class='') {
191 global $cellcount;
192 if ($_POST['form_csvexport']) {
193 if ($cellcount) echo ',';
194 echo '"' . $data . '"';
196 else {
197 echo " <td";
198 if ($class) echo " class='$class'";
199 if ($right) echo " align='right'";
200 echo ">$data</td>\n";
202 ++$cellcount;
204 *********************************************************************/
206 function getListTitle($list, $option)
208 $row = sqlQuery("SELECT title FROM list_options WHERE " .
209 "list_id = '$list' AND option_id = '$option'");
210 if (empty($row['title'])) {
211 return $option;
214 return $row['title'];
217 // Usually this generates one cell, but allows for two or more.
219 function genAnyCell($data, $right = false, $class = '', $colspan = 1)
221 global $cellcount, $form_output;
222 if (!is_array($data)) {
223 $data = array(0 => $data);
226 foreach ($data as $datum) {
227 if ($form_output == 3) {
228 if ($cellcount) {
229 echo ',';
232 echo '"' . $datum . '"';
233 } else {
234 echo " <td";
235 if ($class) {
236 echo " class='$class'";
239 if ($colspan > 1) {
240 echo " colspan='$colspan' align='center'";
241 } else if ($right) {
242 echo " align='right'";
245 echo ">$datum</td>\n";
248 ++$cellcount;
252 function genHeadCell($data, $right = false, $colspan = 1)
254 genAnyCell($data, $right, 'dehead', $colspan);
257 // Create an HTML table cell containing a numeric value, and track totals.
259 function genNumCell($num, $cnum)
261 global $atotals, $form_output;
262 $atotals[$cnum] += $num;
263 if (empty($num) && $form_output != 3) {
264 $num = '&nbsp;';
267 genAnyCell($num, true, 'detail');
270 // Translate an IPPF code to the corresponding descriptive name of its
271 // contraceptive method, or to an empty string if none applies.
273 function getContraceptiveMethod($code)
275 $key = '';
276 if (preg_match('/^111101/', $code)) {
277 $key = xl('Pills');
278 } else if (preg_match('/^11111[1-9]/', $code)) {
279 $key = xl('Injectables');
280 } else if (preg_match('/^11112[1-9]/', $code)) {
281 $key = xl('Implants');
282 } else if (preg_match('/^111132/', $code)) {
283 $key = xl('Patch');
284 } else if (preg_match('/^111133/', $code)) {
285 $key = xl('Vaginal Ring');
286 } else if (preg_match('/^112141/', $code)) {
287 $key = xl('Male Condoms');
288 } else if (preg_match('/^112142/', $code)) {
289 $key = xl('Female Condoms');
290 } else if (preg_match('/^11215[1-9]/', $code)) {
291 $key = xl('Diaphragms/Caps');
292 } else if (preg_match('/^11216[1-9]/', $code)) {
293 $key = xl('Spermicides');
294 } else if (preg_match('/^11317[1-9]/', $code)) {
295 $key = xl('IUD');
296 } else if (preg_match('/^145212/', $code)) {
297 $key = xl('Emergency Contraception');
298 } else if (preg_match('/^121181.13/', $code)) {
299 $key = xl('Female VSC');
300 } else if (preg_match('/^122182.13/', $code)) {
301 $key = xl('Male VSC');
302 } else if (preg_match('/^131191.10/', $code)) {
303 $key = xl('Awareness-Based');
306 return $key;
309 // Helper function to find a contraception-related IPPF code from
310 // the related_code element of the given array.
312 function getRelatedContraceptiveCode($row)
314 if (!empty($row['related_code'])) {
315 $relcodes = explode(';', $row['related_code']);
316 foreach ($relcodes as $codestring) {
317 if ($codestring === '') {
318 continue;
321 list($codetype, $code) = explode(':', $codestring);
322 if ($codetype !== 'IPPF') {
323 continue;
326 // Check if the related code concerns contraception.
327 $tmp = getContraceptiveMethod($code);
328 if (!empty($tmp)) {
329 return $code;
334 return '';
337 // Helper function to find an abortion-method IPPF code from
338 // the related_code element of the given array.
340 function getRelatedAbortionMethod($row)
342 if (!empty($row['related_code'])) {
343 $relcodes = explode(';', $row['related_code']);
344 foreach ($relcodes as $codestring) {
345 if ($codestring === '') {
346 continue;
349 list($codetype, $code) = explode(':', $codestring);
350 if ($codetype !== 'IPPF') {
351 continue;
354 // Check if the related code concerns contraception.
355 $tmp = getAbortionMethod($code);
356 if (!empty($tmp)) {
357 return $code;
362 return '';
365 // Translate an IPPF code to the corresponding descriptive name of its
366 // abortion method, or to an empty string if none applies.
368 function getAbortionMethod($code)
370 $key = '';
371 if (preg_match('/^25222[34]/', $code)) {
372 if (preg_match('/^2522231/', $code)) {
373 $key = xl('D&C');
374 } else if (preg_match('/^2522232/', $code)) {
375 $key = xl('D&E');
376 } else if (preg_match('/^2522233/', $code)) {
377 $key = xl('MVA');
378 } else if (preg_match('/^252224/', $code)) {
379 $key = xl('Medical');
380 } else {
381 $key = xl('Other Surgical');
385 return $key;
388 /*********************************************************************
389 // Helper function to look up the GCAC issue associated with a visit.
390 // Ideally this is the one and only GCAC issue linked to the encounter.
391 // However if there are multiple such issues, or if only unlinked issues
392 // are found, then we pick the one with its start date closest to the
393 // encounter date.
395 function getGcacData($row, $what, $morejoins="") {
396 $patient_id = $row['pid'];
397 $encounter_id = $row['encounter'];
398 $encdate = substr($row['encdate'], 0, 10);
399 $query = "SELECT $what " .
400 "FROM lists AS l " .
401 "JOIN lists_ippf_gcac AS lg ON l.type = 'ippf_gcac' AND lg.id = l.id " .
402 "LEFT JOIN issue_encounter AS ie ON ie.pid = '$patient_id' AND " .
403 "ie.encounter = '$encounter_id' AND ie.list_id = l.id " .
404 "$morejoins " .
405 "WHERE l.pid = '$patient_id' AND " .
406 "l.activity = 1 AND l.type = 'ippf_gcac' " .
407 "ORDER BY ie.pid DESC, ABS(DATEDIFF(l.begdate, '$encdate')) ASC " .
408 "LIMIT 1";
409 // Note that reverse-ordering by ie.pid is a trick for sorting
410 // issues linked to the encounter (non-null values) first.
411 return sqlQuery($query);
414 // Get the "client status" field from the related GCAC issue.
416 function getGcacClientStatus($row) {
417 $irow = getGcacData($row, "lo.title", "LEFT JOIN list_options AS lo ON " .
418 "lo.list_id = 'clientstatus' AND lo.option_id = lg.client_status");
419 if (empty($irow['title'])) {
420 $key = xl('Indeterminate');
422 else {
423 // The client status description should be just fine for this.
424 $key = $irow['title'];
426 return $key;
428 *********************************************************************/
430 // Determine if a recent gcac service was performed.
432 function hadRecentAbService($pid, $encdate)
434 $query = "SELECT COUNT(*) AS count " .
435 "FROM form_encounter AS fe, billing AS b, codes AS c WHERE " .
436 "fe.pid = '$pid' AND " .
437 "fe.date <= '$encdate' AND " .
438 "DATE_ADD(fe.date, INTERVAL 14 DAY) > '$encdate' AND " .
439 "b.pid = fe.pid AND " .
440 "b.encounter = fe.encounter AND " .
441 "b.activity = 1 AND " .
442 "b.code_type = 'MA' AND " .
443 "c.code_type = '12' AND " .
444 "c.code = b.code AND c.modifier = b.modifier AND " .
445 "( c.related_code LIKE '%IPPF:252223%' OR c.related_code LIKE '%IPPF:252224%' )";
446 $tmp = sqlQuery($query);
447 return !empty($tmp['count']);
450 // Get the "client status" as descriptive text.
452 function getGcacClientStatus($row)
454 $pid = $row['pid'];
455 $encdate = $row['encdate'];
457 if (hadRecentAbService($pid, $encdate)) {
458 return xl('MA Client Accepting Abortion');
461 // Check for a GCAC visit form.
462 // This will the most recent GCAC visit form for visits within
463 // the past 2 weeks, although there really should be such a form
464 // attached to the visit associated with $row.
465 $query = "SELECT lo.title " .
466 "FROM forms AS f, form_encounter AS fe, lbf_data AS d, list_options AS lo " .
467 "WHERE f.pid = '$pid' AND " .
468 "f.formdir = 'LBFgcac' AND " .
469 "f.deleted = 0 AND " .
470 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
471 "fe.date <= '$encdate' AND " .
472 "DATE_ADD(fe.date, INTERVAL 14 DAY) > '$encdate' AND " .
473 "d.form_id = f.form_id AND " .
474 "d.field_id = 'client_status' AND " .
475 "lo.list_id = 'clientstatus' AND " .
476 "lo.option_id = d.field_value " .
477 "ORDER BY d.form_id DESC LIMIT 1";
478 $irow = sqlQuery($query);
479 if (!empty($irow['title'])) {
480 return $irow['title'];
483 // Check for a referred abortion.
485 $query = "SELECT COUNT(*) AS count " .
486 "FROM transactions AS t, codes AS c WHERE " .
487 "t.title = 'Referral' AND " .
488 "t.refer_date IS NOT NULL AND " .
489 "t.refer_date <= '$encdate' AND " .
490 "DATE_ADD(t.refer_date, INTERVAL 14 DAY) > '$encdate' AND " .
491 "t.refer_related_code LIKE 'REF:%' AND " .
492 "c.code_type = '16' AND " .
493 "c.code = SUBSTRING(t.refer_related_code, 5) AND " .
494 "( c.related_code LIKE '%IPPF:252223%' OR c.related_code LIKE '%IPPF:252224%' )";
496 $query = "SELECT COUNT(*) AS count " .
497 "FROM transactions AS t " .
498 "LEFT JOIN codes AS c ON t.refer_related_code LIKE 'REF:%' AND " .
499 "c.code_type = '16' AND " .
500 "c.code = SUBSTRING(t.refer_related_code, 5) " .
501 "WHERE " .
502 "t.title = 'Referral' AND " .
503 "t.refer_date IS NOT NULL AND " .
504 "t.refer_date <= '$encdate' AND " .
505 "DATE_ADD(t.refer_date, INTERVAL 14 DAY) > '$encdate' AND " .
506 "( t.refer_related_code LIKE '%IPPF:252223%' OR " .
507 "t.refer_related_code LIKE '%IPPF:252224%' OR " .
508 "( c.related_code IS NOT NULL AND " .
509 "( c.related_code LIKE '%IPPF:252223%' OR " .
510 "c.related_code LIKE '%IPPF:252224%' )))";
512 $tmp = sqlQuery($query);
513 if (!empty($tmp['count'])) {
514 return xl('Outbound Referral');
517 return xl('Indeterminate');
520 // Helper function called after the reporting key is determined for a row.
522 function loadColumnData($key, $row, $quantity = 1)
524 global $areport, $arr_titles, $form_content, $from_date, $to_date, $arr_show;
526 // If first instance of this key, initialize its arrays.
527 if (empty($areport[$key])) {
528 $areport[$key] = array();
529 $areport[$key]['.prp'] = 0; // previous pid
530 $areport[$key]['.wom'] = 0; // number of services for women
531 $areport[$key]['.men'] = 0; // number of services for men
532 $areport[$key]['.age2'] = array(0,0); // age array
533 $areport[$key]['.age9'] = array(0,0,0,0,0,0,0,0,0); // age array
534 foreach ($arr_show as $askey => $dummy) {
535 if (substr($askey, 0, 1) == '.') {
536 continue;
539 $areport[$key][$askey] = array();
543 // Skip this key if we are counting unique patients and the key
544 // has already seen this patient.
545 if ($form_content == '2' && $row['pid'] == $areport[$key]['.prp']) {
546 return;
549 // If we are counting new acceptors, then require a unique patient
550 // whose contraceptive start date is within the reporting period.
551 if ($form_content == '3') {
552 // if ($row['pid'] == $areport[$key]['prp']) return;
553 if ($row['pid'] == $areport[$key]['.prp']) {
554 return;
557 // Check contraceptive start date.
558 if (!$row['contrastart'] || $row['contrastart'] < $from_date ||
559 $row['contrastart'] > $to_date) {
560 return;
564 // If we are counting new clients, then require a unique patient
565 // whose registration date is within the reporting period.
566 if ($form_content == '4') {
567 if ($row['pid'] == $areport[$key]['.prp']) {
568 return;
571 // Check registration date.
572 if (!$row['regdate'] || $row['regdate'] < $from_date ||
573 $row['regdate'] > $to_date) {
574 return;
578 // Flag this patient as having been encountered for this report row.
579 // $areport[$key]['prp'] = $row['pid'];
580 $areport[$key]['.prp'] = $row['pid'];
582 // Increment the correct sex category.
583 if (strcasecmp($row['sex'], 'Male') == 0) {
584 $areport[$key]['.men'] += $quantity;
585 } else {
586 $areport[$key]['.wom'] += $quantity;
589 // Increment the correct age categories.
590 $age = getAge(fixDate($row['DOB']), $row['encdate']);
591 $i = min(intval(($age - 5) / 5), 8);
592 if ($age < 11) {
593 $i = 0;
596 $areport[$key]['.age9'][$i] += $quantity;
597 $i = $age < 25 ? 0 : 1;
598 $areport[$key]['.age2'][$i] += $quantity;
600 foreach ($arr_show as $askey => $dummy) {
601 if (substr($askey, 0, 1) == '.') {
602 continue;
605 $status = empty($row[$askey]) ? 'Unspecified' : $row[$askey];
606 $areport[$key][$askey][$status] += $quantity;
607 $arr_titles[$askey][$status] += $quantity;
611 // This is called for each IPPF service code that is selected.
613 function process_ippf_code($row, $code, $quantity = 1)
615 global $areport, $arr_titles, $form_by, $form_content;
617 $key = 'Unspecified';
619 // SRH including Family Planning
621 if ($form_by === '1') {
622 if (preg_match('/^1/', $code)) {
623 $key = xl('SRH - Family Planning');
624 } else if (preg_match('/^2/', $code)) {
625 $key = xl('SRH Non Family Planning');
626 } else {
627 if ($form_content != 5) {
628 return;
631 } // General Service Category
633 else if ($form_by === '3') {
634 if (preg_match('/^1/', $code)) {
635 $key = xl('SRH - Family Planning');
636 } else if (preg_match('/^2/', $code)) {
637 $key = xl('SRH Non Family Planning');
638 } else if (preg_match('/^3/', $code)) {
639 $key = xl('Non-SRH Medical');
640 } else if (preg_match('/^4/', $code)) {
641 $key = xl('Non-SRH Non-Medical');
642 } else {
643 $key = xl('Invalid Service Codes');
645 } // Abortion-Related Category
647 else if ($form_by === '13') {
648 if (preg_match('/^252221/', $code)) {
649 $key = xl('Pre-Abortion Counseling');
650 } else if (preg_match('/^252222/', $code)) {
651 $key = xl('Pre-Abortion Consultation');
652 } else if (preg_match('/^252223/', $code)) {
653 $key = xl('Induced Abortion');
654 } else if (preg_match('/^252224/', $code)) {
655 $key = xl('Medical Abortion');
656 } else if (preg_match('/^252225/', $code)) {
657 $key = xl('Incomplete Abortion Treatment');
658 } else if (preg_match('/^252226/', $code)) {
659 $key = xl('Post-Abortion Care');
660 } else if (preg_match('/^252227/', $code)) {
661 $key = xl('Post-Abortion Counseling');
662 } else if (preg_match('/^25222/', $code)) {
663 $key = xl('Other/Generic Abortion-Related');
664 } else {
665 if ($form_content != 5) {
666 return;
669 } // Specific Services. One row for each IPPF code.
671 else if ($form_by === '4') {
672 $key = $code;
673 } // Specific Contraceptive Services. One row for each IPPF code.
675 else if ($form_by === '104') {
676 if ($form_content != 5) {
677 // Skip codes not for contraceptive services.
678 $tmp = getContraceptiveMethod($code);
679 if (empty($tmp)) {
680 return;
684 $key = $code;
685 } // Abortion Method.
687 else if ($form_by === '5') {
688 $key = getAbortionMethod($code);
689 if (empty($key)) {
690 if ($form_content != 5) {
691 return;
694 $key = 'Unspecified';
696 } // Contraceptive Method.
698 else if ($form_by === '6') {
699 $key = getContraceptiveMethod($code);
700 if (empty($key)) {
701 if ($form_content != 5) {
702 return;
705 $key = 'Unspecified';
707 } /*******************************************************************
708 // Contraceptive method for new contraceptive adoption following abortion.
709 // Get it from the IPPF code if an abortion issue is linked to the visit.
710 // Note we are handling this during processing of services rather than
711 // by enumerating issues, because we need the service date.
713 else if ($form_by === '7') {
714 $key = getContraceptiveMethod($code);
715 if (empty($key)) return;
716 $patient_id = $row['pid'];
717 $encounter_id = $row['encounter'];
718 $query = "SELECT COUNT(*) AS count " .
719 "FROM lists AS l " .
720 "JOIN issue_encounter AS ie ON ie.pid = '$patient_id' AND " .
721 "ie.encounter = '$encounter_id' AND ie.list_id = l.id " .
722 "WHERE l.pid = '$patient_id' AND " .
723 "l.activity = 1 AND l.type = 'ippf_gcac'";
724 // echo "<!-- $key: $query -->\n"; // debugging
725 $irow = sqlQuery($query);
726 if (empty($irow['count'])) return;
728 *******************************************************************/
730 // Contraceptive method for new contraceptive adoption following abortion.
731 // Get it from the IPPF code if there is a suitable recent GCAC form.
733 else if ($form_by === '7') {
734 $key = getContraceptiveMethod($code);
735 if (empty($key)) {
736 return;
739 $patient_id = $row['pid'];
740 $encdate = $row['encdate'];
741 // Skip this if no recent gcac service nor gcac form with acceptance.
742 if (!hadRecentAbService($patient_id, $encdate)) {
743 $query = "SELECT COUNT(*) AS count " .
744 "FROM forms AS f, form_encounter AS fe, lbf_data AS d " .
745 "WHERE f.pid = '$patient_id' AND " .
746 "f.formdir = 'LBFgcac' AND " .
747 "f.deleted = 0 AND " .
748 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
749 "fe.date <= '$encdate' AND " .
750 "DATE_ADD(fe.date, INTERVAL 14 DAY) > '$encdate' AND " .
751 "d.form_id = f.form_id AND " .
752 "d.field_id = 'client_status' AND " .
753 "( d.field_value = 'maaa' OR d.field_value = 'refout' )";
754 $irow = sqlQuery($query);
755 if (empty($irow['count'])) {
756 return;
759 } // Post-Abortion Care and Followup by Source.
760 // Requirements just call for counting sessions, but this way the columns
761 // can be anything - age category, religion, whatever.
763 else if ($form_by === '8') {
764 if (preg_match('/^25222[567]/', $code)) { // care, followup and incomplete abortion treatment
765 $key = getGcacClientStatus($row);
766 } else {
767 return;
769 } /*******************************************************************
770 // Complications of abortion by abortion method and complication type.
771 // These may be noted either during recovery or during a followup visit.
772 // Again, driven by services in order to report by service date.
773 // Note: If there are multiple complications, they will all be reported.
775 else if ($form_by === '11') {
776 $compl_type = '';
777 if (preg_match('/^25222[345]/', $code)) { // all abortions including incomplete
778 $compl_type = 'rec_compl';
780 else if (preg_match('/^25222[67]/', $code)) { // all post-abortion care and followup
781 $compl_type = 'fol_compl';
783 else {
784 return;
786 $irow = getGcacData($row, "lg.$compl_type, lo.title",
787 "LEFT JOIN list_options AS lo ON lo.list_id = 'in_ab_proc' AND " .
788 "lo.option_id = lg.in_ab_proc");
789 if (empty($irow)) return; // this should not happen
790 if (empty($irow[$compl_type])) return; // ok, no complications
791 // We have one or more complications.
792 $abtype = empty($irow['title']) ? xl('Indeterminate') : $irow['title'];
793 $acompl = explode('|', $irow[$compl_type]);
794 foreach ($acompl as $compl) {
795 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
796 "list_id = 'complication' AND option_id = '$compl'");
797 $key = "$abtype / " . $crow['title'];
798 loadColumnData($key, $row);
800 return; // because loadColumnData() is already done.
802 *******************************************************************/
804 // Pre-Abortion Counseling. Three possible situations:
805 // Provided abortion in the MA clinics
806 // Referred to other service providers (govt,private clinics)
807 // Decided not to have the abortion
809 else if ($form_by === '12') {
810 if (preg_match('/^252221/', $code)) { // all pre-abortion counseling
811 $key = getGcacClientStatus($row);
812 } else {
813 return;
815 } // Patient Name.
817 else if ($form_by === '17') {
818 $key = $row['lname'] . ', ' . $row['fname'] . ' ' . $row['mname'];
819 } else {
820 return; // no match, so do nothing
823 // OK we now have the reporting key for this issue.
824 loadColumnData($key, $row, $quantity);
825 } // end function process_ippf_code()
827 // This is called for each MA service code that is selected.
829 function process_ma_code($row)
831 global $form_by, $arr_content, $form_content;
833 $key = 'Unspecified';
835 // One row for each service category.
837 if ($form_by === '101') {
838 if (!empty($row['lo_title'])) {
839 $key = xl($row['lo_title']);
841 } // Specific Services. One row for each MA code.
843 else if ($form_by === '102') {
844 $key = $row['code'];
845 } // One row for each referral source.
847 else if ($form_by === '103') {
848 $key = $row['referral_source'];
849 } // Just one row.
851 else if ($form_by === '2') {
852 $key = $arr_content[$form_content];
853 } else {
854 return;
857 loadColumnData($key, $row);
860 function LBFgcac_query($pid, $encounter, $name)
862 $query = "SELECT d.form_id, d.field_value " .
863 "FROM forms AS f, form_encounter AS fe, lbf_data AS d " .
864 "WHERE f.pid = '$pid' AND " .
865 "f.encounter = '$encounter' AND " .
866 "f.formdir = 'LBFgcac' AND " .
867 "f.deleted = 0 AND " .
868 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
869 "d.form_id = f.form_id AND " .
870 "d.field_id = '$name'";
871 return sqlStatement($query);
874 function LBFgcac_title($form_id, $field_id, $list_id)
876 $query = "SELECT lo.title " .
877 "FROM lbf_data AS d, list_options AS lo WHERE " .
878 "d.form_id = '$form_id' AND " .
879 "d.field_id = '$field_id' AND " .
880 "lo.list_id = '$list_id' AND " .
881 "lo.option_id = d.field_value " .
882 "LIMIT 1";
883 $row = sqlQuery($query);
884 return empty($row['title']) ? '' : $row['title'];
887 // This is called for each encounter that is selected.
889 function process_visit($row)
891 global $form_by;
893 if ($form_by !== '7' && $form_by !== '11') {
894 return;
897 // New contraceptive method following abortion. These should only be
898 // present for inbound referrals.
900 if ($form_by === '7') {
901 // We think this case goes away, but not sure yet.
902 /*****************************************************************
903 $dres = LBFgcac_query($row['pid'], $row['encounter'], 'contrameth');
904 while ($drow = sqlFetchArray($dres)) {
905 $a = explode('|', $drow['field_value']);
906 foreach ($a as $methid) {
907 if (empty($methid)) continue;
908 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
909 "list_id = 'contrameth' AND option_id = '$methid'");
910 $key = $crow['title'];
911 if (empty($key)) $key = xl('Indeterminate');
912 loadColumnData($key, $row);
915 *****************************************************************/
916 } // Complications of abortion by abortion method and complication type.
917 // These may be noted either during recovery or during a followup visit.
918 // Note: If there are multiple complications, they will all be reported.
920 else if ($form_by === '11') {
921 $dres = LBFgcac_query($row['pid'], $row['encounter'], 'complications');
922 while ($drow = sqlFetchArray($dres)) {
923 $a = explode('|', $drow['field_value']);
924 foreach ($a as $complid) {
925 if (empty($complid)) {
926 continue;
929 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
930 "list_id = 'complication' AND option_id = '$complid'");
931 $abtype = LBFgcac_title($drow['form_id'], 'in_ab_proc', 'in_ab_proc');
932 if (empty($abtype)) {
933 $abtype = xl('Indeterminate');
936 $key = "$abtype / " . $crow['title'];
937 loadColumnData($key, $row);
942 // loadColumnData() already done as needed.
945 /*********************************************************************
946 // This is called for each issue that is selected.
948 function process_issue($row) {
949 global $form_by;
951 $key = 'Unspecified';
953 // Pre-Abortion Counseling. Three possible rows:
954 // Provided abortion in the MA clinics
955 // Referred to other service providers (govt,private clinics)
956 // Decided not to have the abortion
958 if ($form_by === '12') {
960 // TBD: Assign one of the 3 keys, or just return.
964 // Others TBD
966 else {
967 return;
970 // TBD: Load column data from the issue.
971 // loadColumnData($key, $row);
973 *********************************************************************/
975 // This is called for each selected referral.
976 // Row keys are the first specified MA code, if any.
978 function process_referral($row)
980 global $form_by;
981 $key = 'Unspecified';
983 // For followups we care about the actual service provided, otherwise
984 // the requested service.
985 $related_code = $form_by === '20' ?
986 $row['reply_related_code'] : $row['refer_related_code'];
988 if (!empty($related_code)) {
989 $relcodes = explode(';', $related_code);
990 foreach ($relcodes as $codestring) {
991 if ($codestring === '') {
992 continue;
995 list($codetype, $code) = explode(':', $codestring);
997 if ($codetype == 'REF') {
998 // This is the expected case; a direct IPPF code is obsolete.
999 $rrow = sqlQuery("SELECT related_code FROM codes WHERE " .
1000 "code_type = '16' AND code = '$code' AND active = 1 " .
1001 "ORDER BY id LIMIT 1");
1002 if (!empty($rrow['related_code'])) {
1003 list($codetype, $code) = explode(':', $rrow['related_code']);
1007 if ($codetype !== 'IPPF') {
1008 continue;
1011 if ($form_by === '1') {
1012 if (preg_match('/^[12]/', $code)) {
1013 $key = xl('SRH Referrals');
1014 loadColumnData($key, $row);
1015 break;
1017 } else { // $form_by is 9 (internal) or 10 or 20 (external) referrals
1018 $key = $code;
1019 break;
1021 } // end foreach
1024 if ($form_by !== '1') {
1025 loadColumnData($key, $row);
1029 function uses_description($form_by)
1031 return ($form_by === '4' || $form_by === '102' || $form_by === '9' ||
1032 $form_by === '10' || $form_by === '20' || $form_by === '104');
1035 // If we are doing the CSV export then generate the needed HTTP headers.
1036 // Otherwise generate HTML.
1038 if ($form_output == 3) {
1039 header("Pragma: public");
1040 header("Expires: 0");
1041 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
1042 header("Content-Type: application/force-download");
1043 header("Content-Disposition: attachment; filename=service_statistics_report.csv");
1044 header("Content-Description: File Transfer");
1045 } else {
1047 <html>
1048 <head>
1049 <?php html_header_show(); ?>
1050 <title><?php echo $report_title; ?></title>
1052 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
1053 <link rel="stylesheet" href="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-datetimepicker-2-5-4/build/jquery.datetimepicker.min.css">
1055 <style type="text/css">
1056 body { font-family:sans-serif; font-size:10pt; font-weight:normal }
1057 .dehead { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:bold }
1058 .detail { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:normal }
1059 </style>
1061 <script type="text/javascript" src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-min-3-1-1/index.js"></script>
1062 <script type="text/javascript" src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-datetimepicker-2-5-4/build/jquery.datetimepicker.full.min.js"></script>
1063 <script type="text/javascript" src="../../library/textformat.js?v=<?php echo $v_js_includes; ?>"></script>
1065 <script language="JavaScript">
1067 // Begin experimental code
1069 function selectByValue(sel, val) {
1070 for (var i = 0; i < sel.options.length; ++i) {
1071 if (sel.options[i].value == val) sel.options[i].selected = true;
1075 function selreport() {
1076 var f = document.forms[0];
1077 var isdis = 'visible';
1078 var s = f.form_report;
1079 var v = (s.selectedIndex < 0) ? '' : s.options[s.selectedIndex].value;
1080 if (v.length > 0) {
1081 isdis = 'hidden';
1082 var a = v.split("|");
1083 f.form_content.selectedIndex = -1;
1084 f.form_by.selectedIndex = -1;
1085 f['form_show[]'].selectedIndex = -1;
1086 selectByValue(f.form_content, a[0]);
1087 selectByValue(f.form_by, a[1]);
1088 for (var i = 2; i < a.length; ++i) {
1089 selectByValue(f['form_show[]'], a[i]);
1092 f.form_by.style.visibility = isdis;
1093 f.form_content.style.visibility = isdis;
1094 f['form_show[]'].style.visibility = isdis;
1097 // End experimental code
1099 $(document).ready(function() {
1100 $('.datepicker').datetimepicker({
1101 <?php $datetimepicker_timepicker = false; ?>
1102 <?php $datetimepicker_showseconds = false; ?>
1103 <?php $datetimepicker_formatInput = false; ?>
1104 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
1105 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
1109 </script>
1110 </head>
1112 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
1114 <center>
1116 <h2><?php echo $report_title; ?></h2>
1118 <form name='theform' method='post'
1119 action='ippf_statistics.php?t=<?php echo $report_type ?>'>
1121 <table border='0' cellspacing='5' cellpadding='1'>
1123 <!-- Begin experimental code -->
1124 <tr<?php echo (empty($arr_report)) ? " style='display:none'" : ""; ?>>
1125 <td valign='top' class='dehead' nowrap>
1126 <?php xl('Report', 'e'); ?>:
1127 </td>
1128 <td valign='top' class='detail' colspan='3'>
1129 <select name='form_report' title='Predefined reports' onchange='selreport()'>
1130 <?php
1131 echo " <option value=''>" . xl('Custom') . "</option>\n";
1132 foreach ($arr_report as $key => $value) {
1133 echo " <option value='$key'";
1134 if ($key == $form_report) {
1135 echo " selected";
1138 echo ">" . $value . "</option>\n";
1141 </select>
1142 </td>
1143 <td valign='top' class='detail'>
1144 &nbsp;
1145 </td>
1146 </tr>
1147 <!-- End experimental code -->
1149 <tr>
1150 <td valign='top' class='dehead' nowrap>
1151 <?php xl('Rows', 'e'); ?>:
1152 </td>
1153 <td valign='top' class='detail'>
1154 <select name='form_by' title='Left column of report'>
1155 <?php
1156 foreach ($arr_by as $key => $value) {
1157 echo " <option value='$key'";
1158 if ($key == $form_by) {
1159 echo " selected";
1162 echo ">" . $value . "</option>\n";
1165 </select>
1166 </td>
1167 <td valign='top' class='dehead' nowrap>
1168 <?php xl('Content', 'e'); ?>:
1169 </td>
1170 <td valign='top' class='detail'>
1171 <select name='form_content' title='<?php xl('What is to be counted?', 'e'); ?>'>
1172 <?php
1173 foreach ($arr_content as $key => $value) {
1174 echo " <option value='$key'";
1175 if ($key == $form_content) {
1176 echo " selected";
1179 echo ">$value</option>\n";
1182 </select>
1183 </td>
1184 <td valign='top' class='detail'>
1185 &nbsp;
1186 </td>
1187 </tr>
1188 <tr>
1189 <td valign='top' class='dehead' nowrap>
1190 <?php xl('Columns', 'e'); ?>:
1191 </td>
1192 <td valign='top' class='detail'>
1193 <select name='form_show[]' size='4' multiple
1194 title='<?php xl('Hold down Ctrl to select multiple items', 'e'); ?>'>
1195 <?php
1196 foreach ($arr_show as $key => $value) {
1197 $title = $value['title'];
1198 if (empty($title) || $key == 'title') {
1199 $title = $value['description'];
1202 echo " <option value='$key'";
1203 if (is_array($form_show) && in_array($key, $form_show)) {
1204 echo " selected";
1207 echo ">$title</option>\n";
1210 </select>
1211 </td>
1212 <td valign='top' class='dehead' nowrap>
1213 <?php xl('Filters', 'e'); ?>:
1214 </td>
1215 <td colspan='2' class='detail' style='border-style:solid;border-width:1px;border-color:#cccccc'>
1216 <table>
1217 <tr>
1218 <td valign='top' class='detail' nowrap>
1219 <?php xl('Sex', 'e'); ?>:
1220 </td>
1221 <td class='detail' valign='top'>
1222 <select name='form_sexes' title='<?php xl('To filter by sex', 'e'); ?>'>
1223 <?php
1224 foreach (array(3 => xl('Men and Women'), 1 => xl('Women Only'), 2 => xl('Men Only')) as $key => $value) {
1225 echo " <option value='$key'";
1226 if ($key == $form_sexes) {
1227 echo " selected";
1230 echo ">$value</option>\n";
1233 </select>
1234 </td>
1235 </tr>
1236 <tr>
1237 <td valign='top' class='detail' nowrap>
1238 <?php xl('Facility', 'e'); ?>:
1239 </td>
1240 <td valign='top' class='detail'>
1241 <?php
1242 // Build a drop-down list of facilities.
1244 $fres = $facilityService->getAll();
1245 echo " <select name='form_facility'>\n";
1246 echo " <option value=''>-- All Facilities --\n";
1247 foreach ($fres as $frow) {
1248 $facid = $frow['id'];
1249 echo " <option value='$facid'";
1250 if ($facid == $_POST['form_facility']) {
1251 echo " selected";
1254 echo ">" . $frow['name'] . "\n";
1257 echo " </select>\n";
1259 </td>
1260 </tr>
1261 <tr>
1262 <td colspan='2' class='detail' nowrap>
1263 <?php xl('From', 'e'); ?>
1264 <input type='text' class='datepicker' name='form_from_date' id='form_from_date' size='10' value='<?php echo $from_date ?>'
1265 title='Start date yyyy-mm-dd'>
1266 <?php xl('To', 'e'); ?>
1267 <input type='text' class='datepicker' name='form_to_date' id='form_to_date' size='10' value='<?php echo $to_date ?>'
1268 title='End date yyyy-mm-dd'>
1269 </td>
1270 </tr>
1271 </table>
1272 </td>
1273 </tr>
1274 <tr>
1275 <td valign='top' class='dehead' nowrap>
1276 <?php xl('To', 'e'); ?>:
1277 </td>
1278 <td colspan='3' valign='top' class='detail' nowrap>
1279 <?php
1280 foreach (array(1 => 'Screen', 2 => 'Printer', 3 => 'Export File') as $key => $value) {
1281 echo " <input type='radio' name='form_output' value='$key'";
1282 if ($key == $form_output) {
1283 echo ' checked';
1286 echo " />$value &nbsp;";
1289 </td>
1290 <td align='right' valign='top' class='detail' nowrap>
1291 <input type='submit' name='form_submit' value='<?php xl('Submit', 'e'); ?>'
1292 title='<?php xl('Click to generate the report', 'e'); ?>' />
1293 </td>
1294 </tr>
1295 <tr>
1296 <td colspan='5' height="1">
1297 </td>
1298 </tr>
1299 </table>
1300 <?php
1301 } // end not export
1303 if ($_POST['form_submit']) {
1304 $pd_fields = '';
1305 foreach ($arr_show as $askey => $asval) {
1306 if (substr($askey, 0, 1) == '.') {
1307 continue;
1310 if ($askey == 'regdate' || $askey == 'sex' || $askey == 'DOB' ||
1311 $askey == 'lname' || $askey == 'fname' || $askey == 'mname' ||
1312 $askey == 'contrastart' || $askey == 'referral_source') {
1313 continue;
1316 $pd_fields .= ', pd.' . $askey;
1319 $sexcond = '';
1320 if ($form_sexes == '1') {
1321 $sexcond = "AND pd.sex NOT LIKE 'Male' ";
1322 } else if ($form_sexes == '2') {
1323 $sexcond = "AND pd.sex LIKE 'Male' ";
1326 // In the case where content is contraceptive product sales, we
1327 // scan product sales at the top level because it is important to
1328 // account for each of them only once. For each sale we determine
1329 // the one and only IPPF code representing the primary related
1330 // contraceptive service, and that might be either a service in
1331 // the Tally Sheet or the IPPF code attached to the product.
1333 if ($form_content == 5) { // sales of contraceptive products
1334 $query = "SELECT " .
1335 "ds.pid, ds.encounter, ds.sale_date, ds.quantity, " .
1336 "d.cyp_factor, d.related_code, " .
1337 "pd.regdate, pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1338 "pd.contrastart, pd.referral_source$pd_fields, " .
1339 "fe.date AS encdate, fe.provider_id " .
1340 "FROM drug_sales AS ds " .
1341 "JOIN drugs AS d ON d.drug_id = ds.drug_id " .
1342 "JOIN patient_data AS pd ON pd.pid = ds.pid $sexcond" .
1343 "LEFT JOIN form_encounter AS fe ON fe.pid = ds.pid AND fe.encounter = ds.encounter " .
1344 "WHERE ds.sale_date >= '$from_date' AND " .
1345 "ds.sale_date <= '$to_date' AND " .
1346 "ds.pid > 0 AND ds.quantity != 0";
1348 if ($form_facility) {
1349 $query .= " AND fe.facility_id = '$form_facility'";
1352 $query .= " ORDER BY ds.pid, ds.encounter, ds.drug_id";
1353 $res = sqlStatement($query);
1355 while ($row = sqlFetchArray($res)) {
1356 $desired = false;
1357 $prodcode = '';
1358 if ($row['cyp_factor'] > 0) {
1359 $desired = true;
1362 $tmp = getRelatedContraceptiveCode($row);
1363 if (!empty($tmp)) {
1364 $desired = true;
1365 $prodcode = $tmp;
1368 if (!$desired) {
1369 continue; // skip if not a contraceptive product
1372 // If there is a visit and it has a contraceptive service use that, else $prodcode.
1373 if (!empty($row['encounter'])) {
1374 $query = "SELECT " .
1375 "b.code_type, b.code, c.related_code " .
1376 "FROM billing AS b " .
1377 "LEFT OUTER JOIN codes AS c ON c.code_type = '12' AND " .
1378 "c.code = b.code AND c.modifier = b.modifier " .
1379 "WHERE b.pid = " . (0 + $row['pid']) . " AND " .
1380 "b.encounter = " . (0 + $row['encounter']) . " AND " .
1381 "b.activity = 1 AND b.code_type = 'MA' " .
1382 "ORDER BY b.code";
1383 $bres = sqlStatement($query);
1384 while ($brow = sqlFetchArray($bres)) {
1385 $tmp = getRelatedContraceptiveCode($brow);
1386 if (!empty($tmp)) {
1387 $prodcode = $tmp;
1388 break;
1393 // At this point $prodcode is the desired IPPF code, or empty if none.
1394 process_ippf_code($row, $prodcode, $row['quantity']);
1398 // Get referrals and related patient data.
1399 if ($form_content != 5 && ($form_by === '9' || $form_by === '10' || $form_by === '20' || $form_by === '1')) {
1400 $exttest = "t.refer_external = '1'";
1401 $datefld = "t.refer_date";
1403 if ($form_by === '9') {
1404 $exttest = "t.refer_external = '0'";
1405 } else if ($form_by === '20') {
1406 $datefld = "t.reply_date";
1409 $query = "SELECT " .
1410 "t.pid, t.refer_related_code, t.reply_related_code, " .
1411 "pd.regdate, pd.referral_source, " .
1412 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1413 "pd.contrastart$pd_fields " .
1414 "FROM transactions AS t " .
1415 "JOIN patient_data AS pd ON pd.pid = t.pid $sexcond" .
1416 "WHERE t.title = 'Referral' AND $datefld IS NOT NULL AND " .
1417 "$datefld >= '$from_date' AND $datefld <= '$to_date' AND $exttest " .
1418 "ORDER BY t.pid, t.id";
1419 $res = sqlStatement($query);
1420 while ($row = sqlFetchArray($res)) {
1421 process_referral($row);
1425 /*****************************************************************
1426 else if ($form_by === '12') {
1427 // We are reporting on a date range, and assume the applicable date is
1428 // the issue start date which is presumably also the date of pre-
1429 // abortion counseling. The issue end date and the surgery date are
1430 // not of interest here.
1431 $query = "SELECT " .
1432 "l.type, l.begdate, l.pid, " .
1433 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, pd.userlist5, " .
1434 "pd.country_code, pd.status, pd.state, pd.occupation, " .
1435 "lg.client_status, lg.ab_location " .
1436 "FROM lists AS l " .
1437 "JOIN patient_data AS pd ON pd.pid = l.pid $sexcond" .
1438 "LEFT OUTER JOIN lists_ippf_gcac AS lg ON l.type = 'ippf_gcac' AND lg.id = l.id " .
1439 // "LEFT OUTER JOIN lists_ippf_con AS lc ON l.type = 'contraceptive' AND lc.id = l.id " .
1440 "WHERE l.begdate >= '$from_date' AND l.begdate <= '$to_date' AND " .
1441 "l.activity = 1 AND l.type = 'ippf_gcac' " .
1442 "ORDER BY l.pid, l.id";
1443 $res = sqlStatement($query);
1444 while ($row = sqlFetchArray($res)) {
1445 process_issue($row);
1448 *****************************************************************/
1450 // else {
1452 /*****************************************************************
1453 if ($form_by === '104' || $form_by === '105') {
1454 $query = "SELECT " .
1455 "d.name, d.related_code, ds.pid, ds.quantity, " .
1456 "pd.regdate, pd.referral_source, " .
1457 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1458 "pd.contrastart$pd_fields " .
1459 "FROM drug_sales AS ds " .
1460 "JOIN drugs AS d ON d.drug_id = ds.drug_id " .
1461 "JOIN patient_data AS pd ON pd.pid = ds.pid $sexcond" .
1462 "WHERE ds.sale_date IS NOT NULL AND ds.pid != 0 AND " .
1463 "ds.sale_date >= '$from_date' AND ds.sale_date <= '$to_date' " .
1464 "ORDER BY ds.pid, ds.sale_id";
1465 $res = sqlStatement($query);
1466 while ($row = sqlFetchArray($res)) {
1467 $key = "(Unspecified)";
1468 if (!empty($row['related_code'])) {
1469 $relcodes = explode(';', $row['related_code']);
1470 foreach ($relcodes as $codestring) {
1471 if ($codestring === '') continue;
1472 list($codetype, $code) = explode(':', $codestring);
1473 if ($codetype !== 'IPPF') continue;
1474 $key = getContraceptiveMethod($code);
1475 if (!empty($key)) break;
1476 $key = "(No Method)";
1479 if ($form_by === '104') $key .= " / " . $row['name'];
1480 loadColumnData($key, $row, $row['quantity']);
1484 if ($form_by !== '9' && $form_by !== '10' && $form_by !== '20' &&
1485 $form_by !== '104' && $form_by !== '105')
1486 *****************************************************************/
1488 if ($form_content != 5 && $form_by !== '9' && $form_by !== '10' && $form_by !== '20') {
1489 // This gets us all MA codes, with encounter and patient
1490 // info attached and grouped by patient and encounter.
1491 $query = "SELECT " .
1492 "fe.pid, fe.encounter, fe.date AS encdate, pd.regdate, " .
1493 "f.user AS provider, " .
1494 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1495 "pd.contrastart, pd.referral_source$pd_fields, " .
1496 "b.code_type, b.code, c.related_code, lo.title AS lo_title " .
1497 "FROM form_encounter AS fe " .
1498 "JOIN forms AS f ON f.pid = fe.pid AND f.encounter = fe.encounter AND " .
1499 "f.formdir = 'newpatient' AND f.form_id = fe.id AND f.deleted = 0 " .
1500 "JOIN patient_data AS pd ON pd.pid = fe.pid $sexcond" .
1501 "LEFT OUTER JOIN billing AS b ON " .
1502 "b.pid = fe.pid AND b.encounter = fe.encounter AND b.activity = 1 " .
1503 "AND b.code_type = 'MA' " .
1504 "LEFT OUTER JOIN codes AS c ON b.code_type = 'MA' AND c.code_type = '12' AND " .
1505 "c.code = b.code AND c.modifier = b.modifier " .
1506 "LEFT OUTER JOIN list_options AS lo ON " .
1507 "lo.list_id = 'superbill' AND lo.option_id = c.superbill " .
1508 "WHERE fe.date >= '$from_date 00:00:00' AND " .
1509 "fe.date <= '$to_date 23:59:59' ";
1511 if ($form_facility) {
1512 $query .= "AND fe.facility_id = '$form_facility' ";
1515 $query .= "ORDER BY fe.pid, fe.encounter, b.code";
1516 $res = sqlStatement($query);
1518 $prev_encounter = 0;
1520 while ($row = sqlFetchArray($res)) {
1521 if ($row['encounter'] != $prev_encounter) {
1522 $prev_encounter = $row['encounter'];
1523 process_visit($row);
1526 if ($row['code_type'] === 'MA') {
1527 process_ma_code($row);
1528 if (!empty($row['related_code'])) {
1529 $relcodes = explode(';', $row['related_code']);
1530 foreach ($relcodes as $codestring) {
1531 if ($codestring === '') {
1532 continue;
1535 list($codetype, $code) = explode(':', $codestring);
1536 if ($codetype !== 'IPPF') {
1537 continue;
1540 process_ippf_code($row, $code);
1544 } // end while
1545 } // end if
1547 // Sort everything by key for reporting.
1548 ksort($areport);
1549 foreach ($arr_titles as $atkey => $dummy) {
1550 ksort($arr_titles[$atkey]);
1553 if ($form_output != 3) {
1554 echo "<table border='0' cellpadding='1' cellspacing='2' width='98%'>\n";
1555 } // end not csv export
1557 // Generate first column headings line, with category titles.
1559 genStartRow("bgcolor='#dddddd'");
1560 // If the key is an MA or IPPF code, then add a column for its description.
1561 if (uses_description($form_by)) {
1562 genHeadCell(array('', ''));
1563 } else {
1564 genHeadCell('');
1567 // Generate headings for values to be shown.
1568 foreach ($form_show as $value) {
1569 if ($value == '.total') { // Total Services
1570 genHeadCell('');
1571 } else if ($value == '.age2') { // Age
1572 genHeadCell($arr_show[$value]['title'], false, 2);
1573 } else if ($value == '.age9') { // Age
1574 genHeadCell($arr_show[$value]['title'], false, 9);
1575 } else if ($arr_show[$value]['list_id']) {
1576 genHeadCell($arr_show[$value]['title'], false, count($arr_titles[$value]));
1577 } else if (!empty($arr_titles[$value])) {
1578 genHeadCell($arr_show[$value]['title'], false, count($arr_titles[$value]));
1582 if ($form_output != 3) {
1583 genHeadCell('');
1586 genEndRow();
1588 // Generate second column headings line, with individual titles.
1590 genStartRow("bgcolor='#dddddd'");
1591 // If the key is an MA or IPPF code, then add a column for its description.
1592 if (uses_description($form_by)) {
1593 genHeadCell(array($arr_by[$form_by], xl('Description')));
1594 } else {
1595 genHeadCell($arr_by[$form_by]);
1598 // Generate headings for values to be shown.
1599 foreach ($form_show as $value) {
1600 if ($value == '.total') { // Total Services
1601 genHeadCell(xl('Total'));
1602 } else if ($value == '.age2') { // Age
1603 genHeadCell(xl('0-24'), true);
1604 genHeadCell(xl('25+'), true);
1605 } else if ($value == '.age9') { // Age
1606 genHeadCell(xl('0-10'), true);
1607 genHeadCell(xl('11-14'), true);
1608 genHeadCell(xl('15-19'), true);
1609 genHeadCell(xl('20-24'), true);
1610 genHeadCell(xl('25-29'), true);
1611 genHeadCell(xl('30-34'), true);
1612 genHeadCell(xl('35-39'), true);
1613 genHeadCell(xl('40-44'), true);
1614 genHeadCell(xl('45+'), true);
1615 } else if ($arr_show[$value]['list_id']) {
1616 foreach ($arr_titles[$value] as $key => $dummy) {
1617 genHeadCell(getListTitle($arr_show[$value]['list_id'], $key), true);
1619 } else if (!empty($arr_titles[$value])) {
1620 foreach ($arr_titles[$value] as $key => $dummy) {
1621 genHeadCell($key, true);
1626 if ($form_output != 3) {
1627 genHeadCell(xl('Total'), true);
1630 genEndRow();
1632 $encount = 0;
1634 foreach ($areport as $key => $varr) {
1635 $bgcolor = (++$encount & 1) ? "#ddddff" : "#ffdddd";
1637 $dispkey = $key;
1639 // If the key is an MA or IPPF code, then add a column for its description.
1640 if (uses_description($form_by)) {
1641 $dispkey = array($key, '');
1642 $type = $form_by === '102' ? 12 : 11; // MA or IPPF
1643 $crow = sqlQuery("SELECT code_text FROM codes WHERE " .
1644 "code_type = '$type' AND code = '$key' ORDER BY id LIMIT 1");
1645 if (!empty($crow['code_text'])) {
1646 $dispkey[1] = $crow['code_text'];
1650 genStartRow("bgcolor='$bgcolor'");
1652 genAnyCell($dispkey, false, 'detail');
1654 // This is the column index for accumulating column totals.
1655 $cnum = 0;
1656 $totalsvcs = $areport[$key]['.wom'] + $areport[$key]['.men'];
1658 // Generate data for this row.
1659 foreach ($form_show as $value) {
1660 // if ($value == '1') { // Total Services
1661 if ($value == '.total') { // Total Services
1662 genNumCell($totalsvcs, $cnum++);
1663 } else if ($value == '.age2') { // Age
1664 for ($i = 0; $i < 2; ++$i) {
1665 genNumCell($areport[$key]['.age2'][$i], $cnum++);
1667 } else if ($value == '.age9') { // Age
1668 for ($i = 0; $i < 9; ++$i) {
1669 genNumCell($areport[$key]['.age9'][$i], $cnum++);
1671 } else if (!empty($arr_titles[$value])) {
1672 foreach ($arr_titles[$value] as $title => $dummy) {
1673 genNumCell($areport[$key][$value][$title], $cnum++);
1678 // Write the Total column data.
1679 if ($form_output != 3) {
1680 $atotals[$cnum] += $totalsvcs;
1681 genAnyCell($totalsvcs, true, 'dehead');
1684 genEndRow();
1685 } // end foreach
1687 if ($form_output != 3) {
1688 // Generate the line of totals.
1689 genStartRow("bgcolor='#dddddd'");
1691 // If the key is an MA or IPPF code, then add a column for its description.
1692 if (uses_description($form_by)) {
1693 genHeadCell(array(xl('Totals'), ''));
1694 } else {
1695 genHeadCell(xl('Totals'));
1698 for ($cnum = 0; $cnum < count($atotals); ++$cnum) {
1699 genHeadCell($atotals[$cnum], true);
1702 genEndRow();
1703 // End of table.
1704 echo "</table>\n";
1706 } // end of if refresh or export
1708 if ($form_output != 3) {
1710 </form>
1711 </center>
1713 <script language='JavaScript'>
1714 selreport();
1715 <?php if ($form_output == 2) { ?>
1716 var win = top.printLogPrint ? top : opener.top;
1717 win.printLogPrint(window);
1718 <?php } ?>
1719 </script>
1721 </body>
1722 </html>
1723 <?php
1724 } // end not export