Improvements mostly concerning inventory.
[openemr.git] / interface / reports / ippf_statistics.php
blob5979e4463a8b8f8a310e095fa4d801a3bff1b504
1 <?php
3 /**
4 * This module creates statistical reports related to family planning
5 * and sexual and reproductive health.
7 * @package OpenEMR
8 * @link http://www.open-emr.org
9 * @author Rod Roark <rod@sunsetsystems.com>
10 * @author Brady Miller <brady.g.miller@gmail.com>
11 * @copyright Copyright (c) 2008-2015 Rod Roark <rod@sunsetsystems.com>
12 * @copyright Copyright (c) 2017-2018 Brady Miller <brady.g.miller@gmail.com>
13 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
16 require_once("../globals.php");
17 require_once("../../library/patient.inc");
19 use OpenEMR\Common\Acl\AclMain;
20 use OpenEMR\Common\Csrf\CsrfUtils;
21 use OpenEMR\Core\Header;
22 use OpenEMR\Services\FacilityService;
24 if (!empty($_POST)) {
25 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
26 CsrfUtils::csrfNotVerified();
30 // Might want something different here.
32 if (!AclMain::aclCheckCore('acct', 'rep')) {
33 die("Unauthorized access.");
36 $facilityService = new FacilityService();
38 $report_type = empty($_GET['t']) ? 'i' : $_GET['t'];
40 $from_date = (isset($_POST['form_from_date'])) ? DateToYYYYMMDD($_POST['form_from_date']) : '0000-00-00';
41 $to_date = (isset($_POST['form_to_date'])) ? DateToYYYYMMDD($_POST['form_to_date']) : date('Y-m-d');
43 $form_by = $_POST['form_by']; // this is a scalar
44 $form_show = $_POST['form_show']; // this is an array
45 $form_facility = isset($_POST['form_facility']) ? $_POST['form_facility'] : '';
46 $form_sexes = isset($_POST['form_sexes']) ? $_POST['form_sexes'] : '3';
47 $form_content = isset($_POST['form_content']) ? $_POST['form_content'] : '1';
48 $form_output = isset($_POST['form_output']) ? 0 + $_POST['form_output'] : 1;
50 if (empty($form_by)) {
51 $form_by = '1';
54 if (empty($form_show)) {
55 $form_show = array('1');
58 // One of these is chosen as the left column, or Y-axis, of the report.
60 if ($report_type == 'm') {
61 $report_title = xl('Member Association Statistics Report');
62 $arr_by = array(
63 101 => xl('MA Category'),
64 102 => xl('Specific Service'),
65 // 6 => xl('Contraceptive Method'),
66 // 104 => xl('Specific Contraceptive Service');
67 17 => xl('Patient'),
68 9 => xl('Internal Referrals'),
69 10 => xl('External Referrals'),
70 103 => xl('Referral Source'),
71 2 => xl('Total'),
73 $arr_content = array(
74 1 => xl('Services'),
75 2 => xl('Unique Clients'),
76 4 => xl('Unique New Clients'),
77 // 5 => xl('Contraceptive Products'),
79 $arr_report = array(
80 // Items are content|row|column|column|...
81 /*****************************************************************
82 '2|2|3|4|5|8|11' => xl('Client Profile - Unique Clients'),
83 '4|2|3|4|5|8|11' => xl('Client Profile - New Clients'),
84 *****************************************************************/
86 } elseif ($report_type == 'g') {
87 $report_title = xl('GCAC Statistics Report');
88 $arr_by = array(
89 13 => xl('Abortion-Related Categories'),
90 1 => xl('Total SRH & Family Planning'),
91 12 => xl('Pre-Abortion Counseling'),
92 5 => xl('Abortion Method'), // includes surgical and drug-induced
93 8 => xl('Post-Abortion Followup'),
94 7 => xl('Post-Abortion Contraception'),
95 11 => xl('Complications of Abortion'),
96 10 => xl('External Referrals'),
97 20 => xl('External Referral Followups'),
99 $arr_content = array(
100 1 => xl('Services'),
101 2 => xl('Unique Clients'),
102 4 => xl('Unique New Clients'),
104 $arr_report = array(
105 /*****************************************************************
106 '1|11|13' => xl('Complications by Service Provider'),
107 *****************************************************************/
109 } else {
110 $report_title = xl('IPPF Statistics Report');
111 $arr_by = array(
112 3 => xl('General Service Category'),
113 4 => xl('Specific Service'),
114 104 => xl('Specific Contraceptive Service'),
115 6 => xl('Contraceptive Method'),
116 9 => xl('Internal Referrals'),
117 10 => xl('External Referrals'),
119 $arr_content = array(
120 1 => xl('Services'),
121 3 => xl('New Acceptors'),
122 5 => xl('Contraceptive Products'),
124 $arr_report = array(
128 // This will become the array of reportable values.
129 $areport = array();
131 // This accumulates the bottom line totals.
132 $atotals = array();
134 $arr_show = array(
135 '.total' => array('title' => 'Total'),
136 '.age2' => array('title' => 'Age Category (2)'),
137 '.age9' => array('title' => 'Age Category (9)'),
138 ); // info about selectable columns
140 $arr_titles = array(); // will contain column headers
142 // Query layout_options table to generate the $arr_show table.
143 // Table key is the field ID.
144 $lres = sqlStatement("SELECT field_id, title, data_type, list_id, description " .
145 "FROM layout_options WHERE " .
146 "form_id = 'DEM' AND uor > 0 AND field_id NOT LIKE 'em%' " .
147 "ORDER BY group_name, seq, title");
148 while ($lrow = sqlFetchArray($lres)) {
149 $fid = $lrow['field_id'];
150 if ($fid == 'fname' || $fid == 'mname' || $fid == 'lname') {
151 continue;
154 $arr_show[$fid] = $lrow;
155 $arr_titles[$fid] = array();
158 // Compute age in years given a DOB and "as of" date.
160 function getAge($dob, $asof = '')
162 if (empty($asof)) {
163 $asof = date('Y-m-d');
166 $a1 = explode('-', substr($dob, 0, 10));
167 $a2 = explode('-', substr($asof, 0, 10));
168 $age = $a2[0] - $a1[0];
169 if ($a2[1] < $a1[1] || ($a2[1] == $a1[1] && $a2[2] < $a1[2])) {
170 --$age;
173 // echo "<!-- $dob $asof $age -->\n"; // debugging
174 return $age;
177 $cellcount = 0;
179 function genStartRow($att)
181 global $cellcount, $form_output;
182 if ($form_output != 3) {
183 echo " <tr $att>\n";
186 $cellcount = 0;
189 function genEndRow()
191 global $form_output;
192 if ($form_output == 3) {
193 echo "\n";
194 } else {
195 echo " </tr>\n";
199 function getListTitle($list, $option)
201 $row = sqlQuery("SELECT title FROM list_options WHERE " .
202 "list_id = ? AND option_id = ?", array($list, $option));
203 if (empty($row['title'])) {
204 return $option;
207 return $row['title'];
210 // Usually this generates one cell, but allows for two or more.
212 function genAnyCell($data, $right = false, $class = '', $colspan = 1)
214 global $cellcount, $form_output;
215 if (!is_array($data)) {
216 $data = array(0 => $data);
219 foreach ($data as $datum) {
220 if ($form_output == 3) {
221 if ($cellcount) {
222 echo ',';
225 echo '"' . $datum . '"';
226 } else {
227 echo " <td";
228 if ($class) {
229 echo " class='" . attr($class) . "'";
232 if ($colspan > 1) {
233 echo " colspan='" . attr($colspan) . "' align='center'";
234 } elseif ($right) {
235 echo " align='right'";
238 echo ">" . text($datum) . "</td>\n";
241 ++$cellcount;
245 function genHeadCell($data, $right = false, $colspan = 1)
247 genAnyCell($data, $right, 'dehead', $colspan);
250 // Create an HTML table cell containing a numeric value, and track totals.
252 function genNumCell($num, $cnum)
254 global $atotals, $form_output;
255 $atotals[$cnum] += $num;
256 if (empty($num) && $form_output != 3) {
257 $num = '&nbsp;';
260 genAnyCell($num, true, 'detail');
263 // Translate an IPPF code to the corresponding descriptive name of its
264 // contraceptive method, or to an empty string if none applies.
266 function getContraceptiveMethod($code)
268 $key = '';
269 if (preg_match('/^111101/', $code)) {
270 $key = xl('Pills');
271 } elseif (preg_match('/^11111[1-9]/', $code)) {
272 $key = xl('Injectables');
273 } elseif (preg_match('/^11112[1-9]/', $code)) {
274 $key = xl('Implants');
275 } elseif (preg_match('/^111132/', $code)) {
276 $key = xl('Patch');
277 } elseif (preg_match('/^111133/', $code)) {
278 $key = xl('Vaginal Ring');
279 } elseif (preg_match('/^112141/', $code)) {
280 $key = xl('Male Condoms');
281 } elseif (preg_match('/^112142/', $code)) {
282 $key = xl('Female Condoms');
283 } elseif (preg_match('/^11215[1-9]/', $code)) {
284 $key = xl('Diaphragms/Caps');
285 } elseif (preg_match('/^11216[1-9]/', $code)) {
286 $key = xl('Spermicides');
287 } elseif (preg_match('/^11317[1-9]/', $code)) {
288 $key = xl('IUD');
289 } elseif (preg_match('/^145212/', $code)) {
290 $key = xl('Emergency Contraception');
291 } elseif (preg_match('/^121181.13/', $code)) {
292 $key = xl('Female VSC');
293 } elseif (preg_match('/^122182.13/', $code)) {
294 $key = xl('Male VSC');
295 } elseif (preg_match('/^131191.10/', $code)) {
296 $key = xl('Awareness-Based');
299 return $key;
302 // Helper function to find a contraception-related IPPF code from
303 // the related_code element of the given array.
305 function getRelatedContraceptiveCode($row)
307 if (!empty($row['related_code'])) {
308 $relcodes = explode(';', $row['related_code']);
309 foreach ($relcodes as $codestring) {
310 if ($codestring === '') {
311 continue;
314 list($codetype, $code) = explode(':', $codestring);
315 if ($codetype !== 'IPPF') {
316 continue;
319 // Check if the related code concerns contraception.
320 $tmp = getContraceptiveMethod($code);
321 if (!empty($tmp)) {
322 return $code;
327 return '';
330 // Helper function to find an abortion-method IPPF code from
331 // the related_code element of the given array.
333 function getRelatedAbortionMethod($row)
335 if (!empty($row['related_code'])) {
336 $relcodes = explode(';', $row['related_code']);
337 foreach ($relcodes as $codestring) {
338 if ($codestring === '') {
339 continue;
342 list($codetype, $code) = explode(':', $codestring);
343 if ($codetype !== 'IPPF') {
344 continue;
347 // Check if the related code concerns contraception.
348 $tmp = getAbortionMethod($code);
349 if (!empty($tmp)) {
350 return $code;
355 return '';
358 // Translate an IPPF code to the corresponding descriptive name of its
359 // abortion method, or to an empty string if none applies.
361 function getAbortionMethod($code)
363 $key = '';
364 if (preg_match('/^25222[34]/', $code)) {
365 if (preg_match('/^2522231/', $code)) {
366 $key = xl('D&C');
367 } elseif (preg_match('/^2522232/', $code)) {
368 $key = xl('D&E');
369 } elseif (preg_match('/^2522233/', $code)) {
370 $key = xl('MVA');
371 } elseif (preg_match('/^252224/', $code)) {
372 $key = xl('Medical');
373 } else {
374 $key = xl('Other Surgical');
378 return $key;
381 /*********************************************************************
382 // Helper function to look up the GCAC issue associated with a visit.
383 // Ideally this is the one and only GCAC issue linked to the encounter.
384 // However if there are multiple such issues, or if only unlinked issues
385 // are found, then we pick the one with its start date closest to the
386 // encounter date.
388 function getGcacData($row, $what, $morejoins="") {
389 $patient_id = $row['pid'];
390 $encounter_id = $row['encounter'];
391 $encdate = substr($row['encdate'], 0, 10);
392 $query = "SELECT $what " .
393 "FROM lists AS l " .
394 "JOIN lists_ippf_gcac AS lg ON l.type = 'ippf_gcac' AND lg.id = l.id " .
395 "LEFT JOIN issue_encounter AS ie ON ie.pid = '$patient_id' AND " .
396 "ie.encounter = '$encounter_id' AND ie.list_id = l.id " .
397 "$morejoins " .
398 "WHERE l.pid = '$patient_id' AND " .
399 "l.activity = 1 AND l.type = 'ippf_gcac' " .
400 "ORDER BY ie.pid DESC, ABS(DATEDIFF(l.begdate, '$encdate')) ASC " .
401 "LIMIT 1";
402 // Note that reverse-ordering by ie.pid is a trick for sorting
403 // issues linked to the encounter (non-null values) first.
404 return sqlQuery($query);
407 // Get the "client status" field from the related GCAC issue.
409 function getGcacClientStatus($row) {
410 $irow = getGcacData($row, "lo.title", "LEFT JOIN list_options AS lo ON " .
411 "lo.list_id = 'clientstatus' AND lo.option_id = lg.client_status");
412 if (empty($irow['title'])) {
413 $key = xl('Indeterminate');
415 else {
416 // The client status description should be just fine for this.
417 $key = $irow['title'];
419 return $key;
421 *********************************************************************/
423 // Determine if a recent gcac service was performed.
425 function hadRecentAbService($pid, $encdate)
427 $query = "SELECT COUNT(*) AS count " .
428 "FROM form_encounter AS fe, billing AS b, codes AS c WHERE " .
429 "fe.pid = ? AND " .
430 "fe.date <= ? AND " .
431 "DATE_ADD(fe.date, INTERVAL 14 DAY) > ? AND " .
432 "b.pid = fe.pid AND " .
433 "b.encounter = fe.encounter AND " .
434 "b.activity = 1 AND " .
435 "b.code_type = 'MA' AND " .
436 "c.code_type = '12' AND " .
437 "c.code = b.code AND c.modifier = b.modifier AND " .
438 "( c.related_code LIKE '%IPPF:252223%' OR c.related_code LIKE '%IPPF:252224%' )";
439 $tmp = sqlQuery($query, array($pid, $encdate, $encdate));
440 return !empty($tmp['count']);
443 // Get the "client status" as descriptive text.
445 function getGcacClientStatus($row)
447 $pid = $row['pid'];
448 $encdate = $row['encdate'];
450 if (hadRecentAbService($pid, $encdate)) {
451 return xl('MA Client Accepting Abortion');
454 // Check for a GCAC visit form.
455 // This will the most recent GCAC visit form for visits within
456 // the past 2 weeks, although there really should be such a form
457 // attached to the visit associated with $row.
458 $query = "SELECT lo.title " .
459 "FROM forms AS f, form_encounter AS fe, lbf_data AS d, list_options AS lo " .
460 "WHERE f.pid = ? AND " .
461 "f.formdir = 'LBFgcac' AND " .
462 "f.deleted = 0 AND " .
463 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
464 "fe.date <= ? AND " .
465 "DATE_ADD(fe.date, INTERVAL 14 DAY) > ? AND " .
466 "d.form_id = f.form_id AND " .
467 "d.field_id = 'client_status' AND " .
468 "lo.list_id = 'clientstatus' AND " .
469 "lo.option_id = d.field_value " .
470 "ORDER BY d.form_id DESC LIMIT 1";
471 $irow = sqlQuery($query, array($pid, $encdate, $encdate));
472 if (!empty($irow['title'])) {
473 return $irow['title'];
476 // Check for a referred abortion.
478 $query = "SELECT COUNT(*) AS count " .
479 "FROM transactions AS t, codes AS c WHERE " .
480 "t.title = 'Referral' AND " .
481 "t.refer_date IS NOT NULL AND " .
482 "t.refer_date <= '$encdate' AND " .
483 "DATE_ADD(t.refer_date, INTERVAL 14 DAY) > '$encdate' AND " .
484 "t.refer_related_code LIKE 'REF:%' AND " .
485 "c.code_type = '16' AND " .
486 "c.code = SUBSTRING(t.refer_related_code, 5) AND " .
487 "( c.related_code LIKE '%IPPF:252223%' OR c.related_code LIKE '%IPPF:252224%' )";
489 $query = "SELECT COUNT(*) AS count " .
490 "FROM transactions AS t " .
491 "LEFT JOIN codes AS c ON t.refer_related_code LIKE 'REF:%' AND " .
492 "c.code_type = '16' AND " .
493 "c.code = SUBSTRING(t.refer_related_code, 5) " .
494 "WHERE " .
495 "t.title = 'Referral' AND " .
496 "t.refer_date IS NOT NULL AND " .
497 "t.refer_date <= ? AND " .
498 "DATE_ADD(t.refer_date, INTERVAL 14 DAY) > ? AND " .
499 "( t.refer_related_code LIKE '%IPPF:252223%' OR " .
500 "t.refer_related_code LIKE '%IPPF:252224%' OR " .
501 "( c.related_code IS NOT NULL AND " .
502 "( c.related_code LIKE '%IPPF:252223%' OR " .
503 "c.related_code LIKE '%IPPF:252224%' )))";
505 $tmp = sqlQuery($query, array($encdate, $encdate));
506 if (!empty($tmp['count'])) {
507 return xl('Outbound Referral');
510 return xl('Indeterminate');
513 // Helper function called after the reporting key is determined for a row.
515 function loadColumnData($key, $row, $quantity = 1)
517 global $areport, $arr_titles, $form_content, $from_date, $to_date, $arr_show;
519 // If first instance of this key, initialize its arrays.
520 if (empty($areport[$key])) {
521 $areport[$key] = array();
522 $areport[$key]['.prp'] = 0; // previous pid
523 $areport[$key]['.wom'] = 0; // number of services for women
524 $areport[$key]['.men'] = 0; // number of services for men
525 $areport[$key]['.age2'] = array(0,0); // age array
526 $areport[$key]['.age9'] = array(0,0,0,0,0,0,0,0,0); // age array
527 foreach ($arr_show as $askey => $dummy) {
528 if (substr($askey, 0, 1) == '.') {
529 continue;
532 $areport[$key][$askey] = array();
536 // Skip this key if we are counting unique patients and the key
537 // has already seen this patient.
538 if ($form_content == '2' && $row['pid'] == $areport[$key]['.prp']) {
539 return;
542 // If we are counting new acceptors, then require a unique patient
543 // whose contraceptive start date is within the reporting period.
544 if ($form_content == '3') {
545 // if ($row['pid'] == $areport[$key]['prp']) return;
546 if ($row['pid'] == $areport[$key]['.prp']) {
547 return;
550 // Check contraceptive start date.
551 if (
552 !$row['contrastart'] || $row['contrastart'] < $from_date ||
553 $row['contrastart'] > $to_date
555 return;
559 // If we are counting new clients, then require a unique patient
560 // whose registration date is within the reporting period.
561 if ($form_content == '4') {
562 if ($row['pid'] == $areport[$key]['.prp']) {
563 return;
566 // Check registration date.
567 if (
568 !$row['regdate'] || $row['regdate'] < $from_date ||
569 $row['regdate'] > $to_date
571 return;
575 // Flag this patient as having been encountered for this report row.
576 // $areport[$key]['prp'] = $row['pid'];
577 $areport[$key]['.prp'] = $row['pid'];
579 // Increment the correct sex category.
580 if (strcasecmp($row['sex'], 'Male') == 0) {
581 $areport[$key]['.men'] += $quantity;
582 } else {
583 $areport[$key]['.wom'] += $quantity;
586 // Increment the correct age categories.
587 $age = getAge(fixDate($row['DOB']), $row['encdate']);
588 $i = min(intval(($age - 5) / 5), 8);
589 if ($age < 11) {
590 $i = 0;
593 $areport[$key]['.age9'][$i] += $quantity;
594 $i = $age < 25 ? 0 : 1;
595 $areport[$key]['.age2'][$i] += $quantity;
597 foreach ($arr_show as $askey => $dummy) {
598 if (substr($askey, 0, 1) == '.') {
599 continue;
602 $status = empty($row[$askey]) ? 'Unspecified' : $row[$askey];
603 $areport[$key][$askey][$status] += $quantity;
604 $arr_titles[$askey][$status] += $quantity;
608 // This is called for each IPPF service code that is selected.
610 function process_ippf_code($row, $code, $quantity = 1)
612 global $areport, $arr_titles, $form_by, $form_content;
614 $key = 'Unspecified';
616 // SRH including Family Planning
618 if ($form_by === '1') {
619 if (preg_match('/^1/', $code)) {
620 $key = xl('SRH - Family Planning');
621 } elseif (preg_match('/^2/', $code)) {
622 $key = xl('SRH Non Family Planning');
623 } else {
624 if ($form_content != 5) {
625 return;
628 } elseif ($form_by === '3') { // General Service Category
629 if (preg_match('/^1/', $code)) {
630 $key = xl('SRH - Family Planning');
631 } elseif (preg_match('/^2/', $code)) {
632 $key = xl('SRH Non Family Planning');
633 } elseif (preg_match('/^3/', $code)) {
634 $key = xl('Non-SRH Medical');
635 } elseif (preg_match('/^4/', $code)) {
636 $key = xl('Non-SRH Non-Medical');
637 } else {
638 $key = xl('Invalid Service Codes');
640 } elseif ($form_by === '13') { // Abortion-Related Category
641 if (preg_match('/^252221/', $code)) {
642 $key = xl('Pre-Abortion Counseling');
643 } elseif (preg_match('/^252222/', $code)) {
644 $key = xl('Pre-Abortion Consultation');
645 } elseif (preg_match('/^252223/', $code)) {
646 $key = xl('Induced Abortion');
647 } elseif (preg_match('/^252224/', $code)) {
648 $key = xl('Medical Abortion');
649 } elseif (preg_match('/^252225/', $code)) {
650 $key = xl('Incomplete Abortion Treatment');
651 } elseif (preg_match('/^252226/', $code)) {
652 $key = xl('Post-Abortion Care');
653 } elseif (preg_match('/^252227/', $code)) {
654 $key = xl('Post-Abortion Counseling');
655 } elseif (preg_match('/^25222/', $code)) {
656 $key = xl('Other/Generic Abortion-Related');
657 } else {
658 if ($form_content != 5) {
659 return;
662 } elseif ($form_by === '4') { // Specific Services. One row for each IPPF code.
663 $key = $code;
664 } elseif ($form_by === '104') { // Specific Contraceptive Services. One row for each IPPF code.
665 if ($form_content != 5) {
666 // Skip codes not for contraceptive services.
667 $tmp = getContraceptiveMethod($code);
668 if (empty($tmp)) {
669 return;
673 $key = $code;
674 } elseif ($form_by === '5') { // Abortion Method.
675 $key = getAbortionMethod($code);
676 if (empty($key)) {
677 if ($form_content != 5) {
678 return;
681 $key = 'Unspecified';
683 } elseif ($form_by === '6') { // Contraceptive Method.
684 $key = getContraceptiveMethod($code);
685 if (empty($key)) {
686 if ($form_content != 5) {
687 return;
690 $key = 'Unspecified';
693 /*******************************************************************
694 // Contraceptive method for new contraceptive adoption following abortion.
695 // Get it from the IPPF code if an abortion issue is linked to the visit.
696 // Note we are handling this during processing of services rather than
697 // by enumerating issues, because we need the service date.
699 else if ($form_by === '7') {
700 $key = getContraceptiveMethod($code);
701 if (empty($key)) return;
702 $patient_id = $row['pid'];
703 $encounter_id = $row['encounter'];
704 $query = "SELECT COUNT(*) AS count " .
705 "FROM lists AS l " .
706 "JOIN issue_encounter AS ie ON ie.pid = '$patient_id' AND " .
707 "ie.encounter = '$encounter_id' AND ie.list_id = l.id " .
708 "WHERE l.pid = '$patient_id' AND " .
709 "l.activity = 1 AND l.type = 'ippf_gcac'";
710 // echo "<!-- $key: $query -->\n"; // debugging
711 $irow = sqlQuery($query);
712 if (empty($irow['count'])) return;
714 *******************************************************************/
716 // Contraceptive method for new contraceptive adoption following abortion.
717 // Get it from the IPPF code if there is a suitable recent GCAC form.
719 } elseif ($form_by === '7') {
720 $key = getContraceptiveMethod($code);
721 if (empty($key)) {
722 return;
725 $patient_id = $row['pid'];
726 $encdate = $row['encdate'];
727 // Skip this if no recent gcac service nor gcac form with acceptance.
728 if (!hadRecentAbService($patient_id, $encdate)) {
729 $query = "SELECT COUNT(*) AS count " .
730 "FROM forms AS f, form_encounter AS fe, lbf_data AS d " .
731 "WHERE f.pid = ? AND " .
732 "f.formdir = 'LBFgcac' AND " .
733 "f.deleted = 0 AND " .
734 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
735 "fe.date <= ? AND " .
736 "DATE_ADD(fe.date, INTERVAL 14 DAY) > ? AND " .
737 "d.form_id = f.form_id AND " .
738 "d.field_id = 'client_status' AND " .
739 "( d.field_value = 'maaa' OR d.field_value = 'refout' )";
740 $irow = sqlQuery($query, array($patient_id, $encdate, $encdate));
741 if (empty($irow['count'])) {
742 return;
745 } elseif ($form_by === '8') { // Post-Abortion Care and Followup by Source.
746 // Requirements just call for counting sessions, but this way the columns
747 // can be anything - age category, religion, whatever.
748 if (preg_match('/^25222[567]/', $code)) { // care, followup and incomplete abortion treatment
749 $key = getGcacClientStatus($row);
750 } else {
751 return;
754 /*******************************************************************
755 // Complications of abortion by abortion method and complication type.
756 // These may be noted either during recovery or during a followup visit.
757 // Again, driven by services in order to report by service date.
758 // Note: If there are multiple complications, they will all be reported.
760 else if ($form_by === '11') {
761 $compl_type = '';
762 if (preg_match('/^25222[345]/', $code)) { // all abortions including incomplete
763 $compl_type = 'rec_compl';
765 else if (preg_match('/^25222[67]/', $code)) { // all post-abortion care and followup
766 $compl_type = 'fol_compl';
768 else {
769 return;
771 $irow = getGcacData($row, "lg.$compl_type, lo.title",
772 "LEFT JOIN list_options AS lo ON lo.list_id = 'in_ab_proc' AND " .
773 "lo.option_id = lg.in_ab_proc");
774 if (empty($irow)) return; // this should not happen
775 if (empty($irow[$compl_type])) return; // ok, no complications
776 // We have one or more complications.
777 $abtype = empty($irow['title']) ? xl('Indeterminate') : $irow['title'];
778 $acompl = explode('|', $irow[$compl_type]);
779 foreach ($acompl as $compl) {
780 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
781 "list_id = 'complication' AND option_id = '$compl'");
782 $key = "$abtype / " . $crow['title'];
783 loadColumnData($key, $row);
785 return; // because loadColumnData() is already done.
787 *******************************************************************/
789 // Pre-Abortion Counseling. Three possible situations:
790 // Provided abortion in the MA clinics
791 // Referred to other service providers (govt,private clinics)
792 // Decided not to have the abortion
794 } elseif ($form_by === '12') {
795 if (preg_match('/^252221/', $code)) { // all pre-abortion counseling
796 $key = getGcacClientStatus($row);
797 } else {
798 return;
800 } elseif ($form_by === '17') { // Patient Name.
801 $key = $row['lname'] . ', ' . $row['fname'] . ' ' . $row['mname'];
802 } else {
803 return; // no match, so do nothing
806 // OK we now have the reporting key for this issue.
807 loadColumnData($key, $row, $quantity);
808 } // end function process_ippf_code()
810 // This is called for each MA service code that is selected.
812 function process_ma_code($row)
814 global $form_by, $arr_content, $form_content;
816 $key = 'Unspecified';
818 // One row for each service category.
820 if ($form_by === '101') {
821 if (!empty($row['lo_title'])) {
822 $key = xl($row['lo_title']);
824 } elseif ($form_by === '102') { // Specific Services. One row for each MA code.
825 $key = $row['code'];
826 } elseif ($form_by === '103') { // One row for each referral source.
827 $key = $row['referral_source'];
828 } elseif ($form_by === '2') { // Just one row.
829 $key = $arr_content[$form_content];
830 } else {
831 return;
834 loadColumnData($key, $row);
837 function LBFgcac_query($pid, $encounter, $name)
839 $query = "SELECT d.form_id, d.field_value " .
840 "FROM forms AS f, form_encounter AS fe, lbf_data AS d " .
841 "WHERE f.pid = ? AND " .
842 "f.encounter = ? AND " .
843 "f.formdir = 'LBFgcac' AND " .
844 "f.deleted = 0 AND " .
845 "fe.pid = f.pid AND fe.encounter = f.encounter AND " .
846 "d.form_id = f.form_id AND " .
847 "d.field_id = ?";
848 return sqlStatement($query, array($pid, $encounter, $name));
851 function LBFgcac_title($form_id, $field_id, $list_id)
853 $query = "SELECT lo.title " .
854 "FROM lbf_data AS d, list_options AS lo WHERE " .
855 "d.form_id = ? AND " .
856 "d.field_id = ? AND " .
857 "lo.list_id = ? AND " .
858 "lo.option_id = d.field_value " .
859 "LIMIT 1";
860 $row = sqlQuery($query, array($form_id, $field_id, $list_id));
861 return empty($row['title']) ? '' : $row['title'];
864 // This is called for each encounter that is selected.
866 function process_visit($row)
868 global $form_by;
870 if ($form_by !== '7' && $form_by !== '11') {
871 return;
874 // New contraceptive method following abortion. These should only be
875 // present for inbound referrals.
877 if ($form_by === '7') {
878 // We think this case goes away, but not sure yet.
879 /*****************************************************************
880 $dres = LBFgcac_query($row['pid'], $row['encounter'], 'contrameth');
881 while ($drow = sqlFetchArray($dres)) {
882 $a = explode('|', $drow['field_value']);
883 foreach ($a as $methid) {
884 if (empty($methid)) continue;
885 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
886 "list_id = 'contrameth' AND option_id = '$methid'");
887 $key = $crow['title'];
888 if (empty($key)) $key = xl('Indeterminate');
889 loadColumnData($key, $row);
892 *****************************************************************/
893 } elseif ($form_by === '11') { // Complications of abortion by abortion method and complication type.
894 // These may be noted either during recovery or during a followup visit.
895 // Note: If there are multiple complications, they will all be reported.
896 $dres = LBFgcac_query($row['pid'], $row['encounter'], 'complications');
897 while ($drow = sqlFetchArray($dres)) {
898 $a = explode('|', $drow['field_value']);
899 foreach ($a as $complid) {
900 if (empty($complid)) {
901 continue;
904 $crow = sqlQuery("SELECT title FROM list_options WHERE " .
905 "list_id = 'complication' AND option_id = ?", array($complid));
906 $abtype = LBFgcac_title($drow['form_id'], 'in_ab_proc', 'in_ab_proc');
907 if (empty($abtype)) {
908 $abtype = xl('Indeterminate');
911 $key = "$abtype / " . $crow['title'];
912 loadColumnData($key, $row);
917 // loadColumnData() already done as needed.
920 /*********************************************************************
921 // This is called for each issue that is selected.
923 function process_issue($row) {
924 global $form_by;
926 $key = 'Unspecified';
928 // Pre-Abortion Counseling. Three possible rows:
929 // Provided abortion in the MA clinics
930 // Referred to other service providers (govt,private clinics)
931 // Decided not to have the abortion
933 if ($form_by === '12') {
935 // TBD: Assign one of the 3 keys, or just return.
939 // Others TBD
941 else {
942 return;
945 // TBD: Load column data from the issue.
946 // loadColumnData($key, $row);
948 *********************************************************************/
950 // This is called for each selected referral.
951 // Row keys are the first specified MA code, if any.
953 function process_referral($row)
955 global $form_by;
956 $key = 'Unspecified';
958 // For followups we care about the actual service provided, otherwise
959 // the requested service.
960 $related_code = $form_by === '20' ?
961 $row['reply_related_code'] : $row['refer_related_code'];
963 if (!empty($related_code)) {
964 $relcodes = explode(';', $related_code);
965 foreach ($relcodes as $codestring) {
966 if ($codestring === '') {
967 continue;
970 list($codetype, $code) = explode(':', $codestring);
972 if ($codetype == 'REF') {
973 // This is the expected case; a direct IPPF code is obsolete.
974 $rrow = sqlQuery("SELECT related_code FROM codes WHERE " .
975 "code_type = '16' AND code = ? AND active = 1 " .
976 "ORDER BY id LIMIT 1", array($code));
977 if (!empty($rrow['related_code'])) {
978 list($codetype, $code) = explode(':', $rrow['related_code']);
982 if ($codetype !== 'IPPF') {
983 continue;
986 if ($form_by === '1') {
987 if (preg_match('/^[12]/', $code)) {
988 $key = xl('SRH Referrals');
989 loadColumnData($key, $row);
990 break;
992 } else { // $form_by is 9 (internal) or 10 or 20 (external) referrals
993 $key = $code;
994 break;
996 } // end foreach
999 if ($form_by !== '1') {
1000 loadColumnData($key, $row);
1004 function uses_description($form_by)
1006 return ($form_by === '4' || $form_by === '102' || $form_by === '9' ||
1007 $form_by === '10' || $form_by === '20' || $form_by === '104');
1010 // If we are doing the CSV export then generate the needed HTTP headers.
1011 // Otherwise generate HTML.
1013 if ($form_output == 3) {
1014 header("Pragma: public");
1015 header("Expires: 0");
1016 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
1017 header("Content-Type: application/force-download");
1018 header("Content-Disposition: attachment; filename=service_statistics_report.csv");
1019 header("Content-Description: File Transfer");
1020 } else {
1022 <html>
1023 <head>
1024 <title><?php echo text($report_title); ?></title>
1026 <?php Header::setupHeader('datetime-picker'); ?>
1028 <style>
1029 body { font-family:sans-serif; font-size:10pt; font-weight:normal }
1030 .dehead { color:var(--black); font-family:sans-serif; font-size:10pt; font-weight:bold }
1031 .detail { color:var(--black); font-family:sans-serif; font-size:10pt; font-weight:normal }
1032 </style>
1034 <script>
1036 // Begin experimental code
1038 function selectByValue(sel, val) {
1039 for (var i = 0; i < sel.options.length; ++i) {
1040 if (sel.options[i].value == val) sel.options[i].selected = true;
1044 function selreport() {
1045 var f = document.forms[0];
1046 var isdis = 'visible';
1047 var s = f.form_report;
1048 var v = (s.selectedIndex < 0) ? '' : s.options[s.selectedIndex].value;
1049 if (v.length > 0) {
1050 isdis = 'hidden';
1051 var a = v.split("|");
1052 f.form_content.selectedIndex = -1;
1053 f.form_by.selectedIndex = -1;
1054 f['form_show[]'].selectedIndex = -1;
1055 selectByValue(f.form_content, a[0]);
1056 selectByValue(f.form_by, a[1]);
1057 for (var i = 2; i < a.length; ++i) {
1058 selectByValue(f['form_show[]'], a[i]);
1061 f.form_by.style.visibility = isdis;
1062 f.form_content.style.visibility = isdis;
1063 f['form_show[]'].style.visibility = isdis;
1066 // End experimental code
1068 $(function () {
1069 $('.datepicker').datetimepicker({
1070 <?php $datetimepicker_timepicker = false; ?>
1071 <?php $datetimepicker_showseconds = false; ?>
1072 <?php $datetimepicker_formatInput = true; ?>
1073 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
1074 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
1078 </script>
1079 </head>
1081 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
1083 <center>
1085 <h2><?php echo $report_title; ?></h2>
1087 <form name='theform' method='post' action='ippf_statistics.php?t=<?php echo attr_url($report_type); ?>' onsubmit='return top.restoreSession()'>
1088 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
1090 <table border='0' cellspacing='5' cellpadding='1'>
1092 <!-- Begin experimental code -->
1093 <tr<?php echo (empty($arr_report)) ? " style='display:none'" : ""; ?>>
1094 <td valign='top' class='dehead' nowrap>
1095 <?php echo xlt('Report'); ?>:
1096 </td>
1097 <td valign='top' class='detail' colspan='3'>
1098 <select name='form_report' title='Predefined reports' onchange='selreport()'>
1099 <?php
1100 echo " <option value=''>" . xlt('Custom') . "</option>\n";
1101 foreach ($arr_report as $key => $value) {
1102 echo " <option value='" . attr($key) . "'";
1103 if ($key == $form_report) {
1104 echo " selected";
1107 echo ">" . text($value) . "</option>\n";
1110 </select>
1111 </td>
1112 <td valign='top' class='detail'>
1113 &nbsp;
1114 </td>
1115 </tr>
1116 <!-- End experimental code -->
1118 <tr>
1119 <td valign='top' class='dehead' nowrap>
1120 <?php echo xlt('Rows'); ?>:
1121 </td>
1122 <td valign='top' class='detail'>
1123 <select name='form_by' title='Left column of report'>
1124 <?php
1125 foreach ($arr_by as $key => $value) {
1126 echo " <option value='" . attr($key) . "'";
1127 if ($key == $form_by) {
1128 echo " selected";
1131 echo ">" . text($value) . "</option>\n";
1134 </select>
1135 </td>
1136 <td valign='top' class='dehead' nowrap>
1137 <?php echo xlt('Content'); ?>:
1138 </td>
1139 <td valign='top' class='detail'>
1140 <select name='form_content' title='<?php echo xla('What is to be counted?'); ?>'>
1141 <?php
1142 foreach ($arr_content as $key => $value) {
1143 echo " <option value='" . attr($key) . "'";
1144 if ($key == $form_content) {
1145 echo " selected";
1148 echo ">" . text($value) . "</option>\n";
1151 </select>
1152 </td>
1153 <td valign='top' class='detail'>
1154 &nbsp;
1155 </td>
1156 </tr>
1157 <tr>
1158 <td valign='top' class='dehead' nowrap>
1159 <?php echo xlt('Columns'); ?>:
1160 </td>
1161 <td valign='top' class='detail'>
1162 <select name='form_show[]' size='4' multiple
1163 title='<?php echo xla('Hold down Ctrl to select multiple items'); ?>'>
1164 <?php
1165 foreach ($arr_show as $key => $value) {
1166 $title = $value['title'];
1167 if (empty($title) || $key == 'title') {
1168 $title = $value['description'];
1171 echo " <option value='" . attr($key) . "'";
1172 if (is_array($form_show) && in_array($key, $form_show)) {
1173 echo " selected";
1176 echo ">" . text($title) . "</option>\n";
1179 </select>
1180 </td>
1181 <td valign='top' class='dehead' nowrap>
1182 <?php echo xlt('Filters'); ?>:
1183 </td>
1184 <td colspan='2' class='detail' style='border-style:solid;border-width:1px;border-color:#cccccc'>
1185 <table>
1186 <tr>
1187 <td valign='top' class='detail' nowrap>
1188 <?php echo xlt('Sex'); ?>:
1189 </td>
1190 <td class='detail' valign='top'>
1191 <select name='form_sexes' title='<?php echo xla('To filter by sex'); ?>'>
1192 <?php
1193 foreach (array(3 => xl('Men and Women'), 1 => xl('Women Only'), 2 => xl('Men Only')) as $key => $value) {
1194 echo " <option value='" . attr($key) . "'";
1195 if ($key == $form_sexes) {
1196 echo " selected";
1199 echo ">" . text($value) . "</option>\n";
1202 </select>
1203 </td>
1204 </tr>
1205 <tr>
1206 <td valign='top' class='detail' nowrap>
1207 <?php echo xlt('Facility'); ?>:
1208 </td>
1209 <td valign='top' class='detail'>
1210 <?php
1211 // Build a drop-down list of facilities.
1213 $fres = $facilityService->getAllFacility();
1214 echo " <select name='form_facility'>\n";
1215 echo " <option value=''>-- All Facilities --\n";
1216 foreach ($fres as $frow) {
1217 $facid = $frow['id'];
1218 echo " <option value='" . attr($facid) . "'";
1219 if ($facid == $_POST['form_facility']) {
1220 echo " selected";
1223 echo ">" . text($frow['name']) . "\n";
1226 echo " </select>\n";
1228 </td>
1229 </tr>
1230 <tr>
1231 <td colspan='2' class='detail' nowrap>
1232 <?php echo xlt('From'); ?>
1233 <input type='text' class='datepicker' name='form_from_date' id='form_from_date' size='10' value='<?php echo attr(oeFormatShortDate($from_date)); ?>'>
1234 <?php echo xlt('To{{Range}}'); ?>
1235 <input type='text' class='datepicker' name='form_to_date' id='form_to_date' size='10' value='<?php echo attr(oeFormatShortDate($to_date)); ?>'>
1236 </td>
1237 </tr>
1238 </table>
1239 </td>
1240 </tr>
1241 <tr>
1242 <td valign='top' class='dehead' nowrap>
1243 <?php echo xlt('To{{Destination}}'); ?>:
1244 </td>
1245 <td colspan='3' valign='top' class='detail' nowrap>
1246 <?php
1247 foreach (array(1 => 'Screen', 2 => 'Printer', 3 => 'Export File') as $key => $value) {
1248 echo " <input type='radio' name='form_output' value='" . attr($key) . "'";
1249 if ($key == $form_output) {
1250 echo ' checked';
1253 echo " />" . text($value) . " &nbsp;";
1256 </td>
1257 <td align='right' valign='top' class='detail' nowrap>
1258 <input type='submit' name='form_submit' value='<?php echo xla('Submit'); ?>'
1259 title='<?php echo xla('Click to generate the report'); ?>' />
1260 </td>
1261 </tr>
1262 <tr>
1263 <td colspan='5' height="1">
1264 </td>
1265 </tr>
1266 </table>
1267 <?php
1268 } // end not export
1270 if ($_POST['form_submit']) {
1271 $pd_fields = '';
1272 foreach ($arr_show as $askey => $asval) {
1273 if (substr($askey, 0, 1) == '.') {
1274 continue;
1277 if (
1278 $askey == 'regdate' || $askey == 'sex' || $askey == 'DOB' ||
1279 $askey == 'lname' || $askey == 'fname' || $askey == 'mname' ||
1280 $askey == 'contrastart' || $askey == 'referral_source'
1282 continue;
1285 $pd_fields .= ', pd.' . escape_sql_column_name($askey, array('patient_data'));
1288 $sexcond = '';
1289 if ($form_sexes == '1') {
1290 $sexcond = "AND pd.sex NOT LIKE 'Male' ";
1291 } elseif ($form_sexes == '2') {
1292 $sexcond = "AND pd.sex LIKE 'Male' ";
1295 $sqlBindArray = array();
1297 // In the case where content is contraceptive product sales, we
1298 // scan product sales at the top level because it is important to
1299 // account for each of them only once. For each sale we determine
1300 // the one and only IPPF code representing the primary related
1301 // contraceptive service, and that might be either a service in
1302 // the Tally Sheet or the IPPF code attached to the product.
1304 if ($form_content == 5) { // sales of contraceptive products
1305 $query = "SELECT " .
1306 "ds.pid, ds.encounter, ds.sale_date, ds.quantity, " .
1307 "d.cyp_factor, d.related_code, " .
1308 "pd.regdate, pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1309 "pd.contrastart, pd.referral_source$pd_fields, " .
1310 "fe.date AS encdate, fe.provider_id " .
1311 "FROM drug_sales AS ds " .
1312 "JOIN drugs AS d ON d.drug_id = ds.drug_id " .
1313 "JOIN patient_data AS pd ON pd.pid = ds.pid $sexcond" .
1314 "LEFT JOIN form_encounter AS fe ON fe.pid = ds.pid AND fe.encounter = ds.encounter " .
1315 "WHERE ds.sale_date >= ? AND " .
1316 "ds.sale_date <= ? AND " .
1317 "ds.pid > 0 AND ds.quantity != 0";
1318 array_push($sqlBindArray, $from_date, $to_date);
1320 if ($form_facility) {
1321 $query .= " AND fe.facility_id = ?";
1322 array_push($sqlBindArray, $form_facility);
1325 $query .= " ORDER BY ds.pid, ds.encounter, ds.drug_id";
1326 $res = sqlStatement($query, $sqlBindArray);
1328 while ($row = sqlFetchArray($res)) {
1329 $desired = false;
1330 $prodcode = '';
1331 if ($row['cyp_factor'] > 0) {
1332 $desired = true;
1335 $tmp = getRelatedContraceptiveCode($row);
1336 if (!empty($tmp)) {
1337 $desired = true;
1338 $prodcode = $tmp;
1341 if (!$desired) {
1342 continue; // skip if not a contraceptive product
1345 // If there is a visit and it has a contraceptive service use that, else $prodcode.
1346 if (!empty($row['encounter'])) {
1347 $query = "SELECT " .
1348 "b.code_type, b.code, c.related_code " .
1349 "FROM billing AS b " .
1350 "LEFT OUTER JOIN codes AS c ON c.code_type = '12' AND " .
1351 "c.code = b.code AND c.modifier = b.modifier " .
1352 "WHERE b.pid = ? AND " .
1353 "b.encounter = ? AND " .
1354 "b.activity = 1 AND b.code_type = 'MA' " .
1355 "ORDER BY b.code";
1356 $bres = sqlStatement($query, array((0 + $row['pid']), (0 + $row['encounter'])));
1357 while ($brow = sqlFetchArray($bres)) {
1358 $tmp = getRelatedContraceptiveCode($brow);
1359 if (!empty($tmp)) {
1360 $prodcode = $tmp;
1361 break;
1366 // At this point $prodcode is the desired IPPF code, or empty if none.
1367 process_ippf_code($row, $prodcode, $row['quantity']);
1371 // Get referrals and related patient data.
1372 if ($form_content != 5 && ($form_by === '9' || $form_by === '10' || $form_by === '20' || $form_by === '1')) {
1373 $exttest = "t.refer_external = '1'";
1374 $datefld = "t.refer_date";
1376 if ($form_by === '9') {
1377 $exttest = "t.refer_external = '0'";
1378 } elseif ($form_by === '20') {
1379 $datefld = "t.reply_date";
1382 $query = "SELECT " .
1383 "t.pid, t.refer_related_code, t.reply_related_code, " .
1384 "pd.regdate, pd.referral_source, " .
1385 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1386 "pd.contrastart$pd_fields " .
1387 "FROM transactions AS t " .
1388 "JOIN patient_data AS pd ON pd.pid = t.pid $sexcond" .
1389 "WHERE t.title = 'Referral' AND $datefld IS NOT NULL AND " .
1390 "$datefld >= ? AND $datefld <= ? AND $exttest " .
1391 "ORDER BY t.pid, t.id";
1392 $res = sqlStatement($query, array($from_date, $to_date));
1393 while ($row = sqlFetchArray($res)) {
1394 process_referral($row);
1398 /*****************************************************************
1399 else if ($form_by === '12') {
1400 // We are reporting on a date range, and assume the applicable date is
1401 // the issue start date which is presumably also the date of pre-
1402 // abortion counseling. The issue end date and the surgery date are
1403 // not of interest here.
1404 $query = "SELECT " .
1405 "l.type, l.begdate, l.pid, " .
1406 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, pd.userlist5, " .
1407 "pd.country_code, pd.status, pd.state, pd.occupation, " .
1408 "lg.client_status, lg.ab_location " .
1409 "FROM lists AS l " .
1410 "JOIN patient_data AS pd ON pd.pid = l.pid $sexcond" .
1411 "LEFT OUTER JOIN lists_ippf_gcac AS lg ON l.type = 'ippf_gcac' AND lg.id = l.id " .
1412 // "LEFT OUTER JOIN lists_ippf_con AS lc ON l.type = 'contraceptive' AND lc.id = l.id " .
1413 "WHERE l.begdate >= '$from_date' AND l.begdate <= '$to_date' AND " .
1414 "l.activity = 1 AND l.type = 'ippf_gcac' " .
1415 "ORDER BY l.pid, l.id";
1416 $res = sqlStatement($query);
1417 while ($row = sqlFetchArray($res)) {
1418 process_issue($row);
1421 *****************************************************************/
1423 // else {
1425 /*****************************************************************
1426 if ($form_by === '104' || $form_by === '105') {
1427 $query = "SELECT " .
1428 "d.name, d.related_code, ds.pid, ds.quantity, " .
1429 "pd.regdate, pd.referral_source, " .
1430 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1431 "pd.contrastart$pd_fields " .
1432 "FROM drug_sales AS ds " .
1433 "JOIN drugs AS d ON d.drug_id = ds.drug_id " .
1434 "JOIN patient_data AS pd ON pd.pid = ds.pid $sexcond" .
1435 "WHERE ds.sale_date IS NOT NULL AND ds.pid != 0 AND " .
1436 "ds.sale_date >= '$from_date' AND ds.sale_date <= '$to_date' " .
1437 "ORDER BY ds.pid, ds.sale_id";
1438 $res = sqlStatement($query);
1439 while ($row = sqlFetchArray($res)) {
1440 $key = "(Unspecified)";
1441 if (!empty($row['related_code'])) {
1442 $relcodes = explode(';', $row['related_code']);
1443 foreach ($relcodes as $codestring) {
1444 if ($codestring === '') continue;
1445 list($codetype, $code) = explode(':', $codestring);
1446 if ($codetype !== 'IPPF') continue;
1447 $key = getContraceptiveMethod($code);
1448 if (!empty($key)) break;
1449 $key = "(No Method)";
1452 if ($form_by === '104') $key .= " / " . $row['name'];
1453 loadColumnData($key, $row, $row['quantity']);
1457 if ($form_by !== '9' && $form_by !== '10' && $form_by !== '20' &&
1458 $form_by !== '104' && $form_by !== '105')
1459 *****************************************************************/
1461 if ($form_content != 5 && $form_by !== '9' && $form_by !== '10' && $form_by !== '20') {
1462 $sqlBindArray = array();
1464 // This gets us all MA codes, with encounter and patient
1465 // info attached and grouped by patient and encounter.
1466 $query = "SELECT " .
1467 "fe.pid, fe.encounter, fe.date AS encdate, pd.regdate, " .
1468 "f.user AS provider, " .
1469 "pd.sex, pd.DOB, pd.lname, pd.fname, pd.mname, " .
1470 "pd.contrastart, pd.referral_source$pd_fields, " .
1471 "b.code_type, b.code, c.related_code, lo.title AS lo_title " .
1472 "FROM form_encounter AS fe " .
1473 "JOIN forms AS f ON f.pid = fe.pid AND f.encounter = fe.encounter AND " .
1474 "f.formdir = 'newpatient' AND f.form_id = fe.id AND f.deleted = 0 " .
1475 "JOIN patient_data AS pd ON pd.pid = fe.pid $sexcond" .
1476 "LEFT OUTER JOIN billing AS b ON " .
1477 "b.pid = fe.pid AND b.encounter = fe.encounter AND b.activity = 1 " .
1478 "AND b.code_type = 'MA' " .
1479 "LEFT OUTER JOIN codes AS c ON b.code_type = 'MA' AND c.code_type = '12' AND " .
1480 "c.code = b.code AND c.modifier = b.modifier " .
1481 "LEFT OUTER JOIN list_options AS lo ON " .
1482 "lo.list_id = 'superbill' AND lo.option_id = c.superbill " .
1483 "WHERE fe.date >= ? AND " .
1484 "fe.date <= ? ";
1485 array_push($sqlBindArray, $from_date . ' 00:00:00', $to_date . ' 23:59:59');
1487 if ($form_facility) {
1488 $query .= "AND fe.facility_id = '$form_facility' ";
1489 array_push($sqlBindArray, $form_facility);
1492 $query .= "ORDER BY fe.pid, fe.encounter, b.code";
1493 $res = sqlStatement($query, $sqlBindArray);
1495 $prev_encounter = 0;
1497 while ($row = sqlFetchArray($res)) {
1498 if ($row['encounter'] != $prev_encounter) {
1499 $prev_encounter = $row['encounter'];
1500 process_visit($row);
1503 if ($row['code_type'] === 'MA') {
1504 process_ma_code($row);
1505 if (!empty($row['related_code'])) {
1506 $relcodes = explode(';', $row['related_code']);
1507 foreach ($relcodes as $codestring) {
1508 if ($codestring === '') {
1509 continue;
1512 list($codetype, $code) = explode(':', $codestring);
1513 if ($codetype !== 'IPPF') {
1514 continue;
1517 process_ippf_code($row, $code);
1521 } // end while
1522 } // end if
1524 // Sort everything by key for reporting.
1525 ksort($areport);
1526 foreach ($arr_titles as $atkey => $dummy) {
1527 ksort($arr_titles[$atkey]);
1530 if ($form_output != 3) {
1531 echo "<table border='0' cellpadding='1' cellspacing='2' width='98%'>\n";
1532 } // end not csv export
1534 // Generate first column headings line, with category titles.
1536 genStartRow("bgcolor='#dddddd'");
1537 // If the key is an MA or IPPF code, then add a column for its description.
1538 if (uses_description($form_by)) {
1539 genHeadCell(array('', ''));
1540 } else {
1541 genHeadCell('');
1544 // Generate headings for values to be shown.
1545 foreach ($form_show as $value) {
1546 if ($value == '.total') { // Total Services
1547 genHeadCell('');
1548 } elseif ($value == '.age2') { // Age
1549 genHeadCell($arr_show[$value]['title'], false, 2);
1550 } elseif ($value == '.age9') { // Age
1551 genHeadCell($arr_show[$value]['title'], false, 9);
1552 } elseif ($arr_show[$value]['list_id']) {
1553 genHeadCell($arr_show[$value]['title'], false, count($arr_titles[$value]));
1554 } elseif (!empty($arr_titles[$value])) {
1555 genHeadCell($arr_show[$value]['title'], false, count($arr_titles[$value]));
1559 if ($form_output != 3) {
1560 genHeadCell('');
1563 genEndRow();
1565 // Generate second column headings line, with individual titles.
1567 genStartRow("bgcolor='#dddddd'");
1568 // If the key is an MA or IPPF code, then add a column for its description.
1569 if (uses_description($form_by)) {
1570 genHeadCell(array($arr_by[$form_by], xl('Description')));
1571 } else {
1572 genHeadCell($arr_by[$form_by]);
1575 // Generate headings for values to be shown.
1576 foreach ($form_show as $value) {
1577 if ($value == '.total') { // Total Services
1578 genHeadCell(xl('Total'));
1579 } elseif ($value == '.age2') { // Age
1580 genHeadCell(xl('0-24'), true);
1581 genHeadCell(xl('25+'), true);
1582 } elseif ($value == '.age9') { // Age
1583 genHeadCell(xl('0-10'), true);
1584 genHeadCell(xl('11-14'), true);
1585 genHeadCell(xl('15-19'), true);
1586 genHeadCell(xl('20-24'), true);
1587 genHeadCell(xl('25-29'), true);
1588 genHeadCell(xl('30-34'), true);
1589 genHeadCell(xl('35-39'), true);
1590 genHeadCell(xl('40-44'), true);
1591 genHeadCell(xl('45+'), true);
1592 } elseif ($arr_show[$value]['list_id']) {
1593 foreach ($arr_titles[$value] as $key => $dummy) {
1594 genHeadCell(getListTitle($arr_show[$value]['list_id'], $key), true);
1596 } elseif (!empty($arr_titles[$value])) {
1597 foreach ($arr_titles[$value] as $key => $dummy) {
1598 genHeadCell($key, true);
1603 if ($form_output != 3) {
1604 genHeadCell(xl('Total'), true);
1607 genEndRow();
1609 $encount = 0;
1611 foreach ($areport as $key => $varr) {
1612 $bgcolor = (++$encount & 1) ? "#ddddff" : "#ffdddd";
1614 $dispkey = $key;
1616 // If the key is an MA or IPPF code, then add a column for its description.
1617 if (uses_description($form_by)) {
1618 $dispkey = array($key, '');
1619 $type = $form_by === '102' ? 12 : 11; // MA or IPPF
1620 $crow = sqlQuery("SELECT code_text FROM codes WHERE " .
1621 "code_type = ? AND code = ? ORDER BY id LIMIT 1", array($type, $key));
1622 if (!empty($crow['code_text'])) {
1623 $dispkey[1] = $crow['code_text'];
1627 genStartRow("bgcolor='$bgcolor'");
1629 genAnyCell($dispkey, false, 'detail');
1631 // This is the column index for accumulating column totals.
1632 $cnum = 0;
1633 $totalsvcs = $areport[$key]['.wom'] + $areport[$key]['.men'];
1635 // Generate data for this row.
1636 foreach ($form_show as $value) {
1637 // if ($value == '1') { // Total Services
1638 if ($value == '.total') { // Total Services
1639 genNumCell($totalsvcs, $cnum++);
1640 } elseif ($value == '.age2') { // Age
1641 for ($i = 0; $i < 2; ++$i) {
1642 genNumCell($areport[$key]['.age2'][$i], $cnum++);
1644 } elseif ($value == '.age9') { // Age
1645 for ($i = 0; $i < 9; ++$i) {
1646 genNumCell($areport[$key]['.age9'][$i], $cnum++);
1648 } elseif (!empty($arr_titles[$value])) {
1649 foreach ($arr_titles[$value] as $title => $dummy) {
1650 genNumCell($areport[$key][$value][$title], $cnum++);
1655 // Write the Total column data.
1656 if ($form_output != 3) {
1657 $atotals[$cnum] += $totalsvcs;
1658 genAnyCell($totalsvcs, true, 'dehead');
1661 genEndRow();
1662 } // end foreach
1664 if ($form_output != 3) {
1665 // Generate the line of totals.
1666 genStartRow("bgcolor='#dddddd'");
1668 // If the key is an MA or IPPF code, then add a column for its description.
1669 if (uses_description($form_by)) {
1670 genHeadCell(array(xl('Totals'), ''));
1671 } else {
1672 genHeadCell(xl('Totals'));
1675 for ($cnum = 0; $cnum < count($atotals); ++$cnum) {
1676 genHeadCell($atotals[$cnum], true);
1679 genEndRow();
1680 // End of table.
1681 echo "</table>\n";
1683 } // end of if refresh or export
1685 if ($form_output != 3) {
1687 </form>
1688 </center>
1690 <script>
1691 selreport();
1692 <?php if ($form_output == 2) { ?>
1693 var win = top.printLogPrint ? top : opener.top;
1694 win.printLogPrint(window);
1695 <?php } ?>
1696 </script>
1698 </body>
1699 </html>
1700 <?php
1701 } // end not export