chore: complete integration of flex-3.20 (alpine 3.20) into ci (#7538)
[openemr.git] / interface / reports / immunization_report.php
blob959860e063d9f30a7c15f3e29501b19a9c1445bd
1 <?php
3 /**
4 * This report lists patient immunizations for a given date range.
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Brady Miller <brady.g.miller@gmail.com>
9 * @author Sherwin Gaddis <sherwingaddis@gmail.com>
10 * @author Stephen Waite <stephen.waite@open-emr.org>
11 * @copyright Copyright (c) 2011 Ensoftek Inc.
12 * @copyright Copyright (c) 2017-2018 Brady Miller <brady.g.miller@gmail.com>
13 * @copyright Copyright (c) 2022 Sherwin Gaddis <sherwingaddis@gmail.com>
14 * @copyright Copyright (c) 2022-2023 Stephen Waite <stephen.waite@open-emr.org>
15 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
18 require_once("../globals.php");
19 require_once("$srcdir/patient.inc.php");
21 use OpenEMR\Common\Acl\AclMain;
22 use OpenEMR\Common\Csrf\CsrfUtils;
23 use OpenEMR\Common\Twig\TwigContainer;
24 use OpenEMR\Core\Header;
26 if (!AclMain::aclCheckCore('patients', 'med')) {
27 echo (
28 new TwigContainer(
29 null,
30 $GLOBALS['kernel']
31 ))->getTwig()->render(
32 'core/unauthorized.html.twig',
33 ['pageTitle' => xl("Immunization Registry")]
35 exit;
38 if (!empty($_POST)) {
39 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
40 CsrfUtils::csrfNotVerified();
44 $form_from_date = (isset($_POST['form_from_date'])) ? DateToYYYYMMDD($_POST['form_from_date']) : '';
45 $form_to_date = (isset($_POST['form_to_date'])) ? DateToYYYYMMDD($_POST['form_to_date']) : '';
47 function tr($a)
49 return (str_replace(' ', '^', $a));
52 function format_cvx_code($cvx_code)
55 if ($cvx_code < 10) {
56 return "0$cvx_code";
59 return $cvx_code;
62 function format_phone($phone)
65 $phone = preg_replace("/[^0-9]/", "", $phone);
66 switch (strlen($phone)) {
67 case 7:
68 return tr(preg_replace("/([0-9]{3})([0-9]{4})/", "000 $1$2", $phone));
69 case 10:
70 return tr(preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1 $2$3", $phone));
71 default:
72 return tr("000 0000000");
76 function format_ethnicity($ethnicity)
79 switch ($ethnicity) {
80 case "hisp_or_latin":
81 return ("H^Hispanic or Latino^HL70189");
82 case "not_hisp_or_latin":
83 return ("N^not Hispanic or Latino^HL70189");
84 default: // Unknown
85 return ("U^Unknown^HL70189");
89 $sqlBindArray = array();
90 $query =
91 "select " .
92 "i.patient_id as patientid, " .
93 "p.language, " .
94 "i.cvx_code , ";
95 if (!empty($_POST['form_get_hl7']) && ($_POST['form_get_hl7'] === 'true')) {
96 $query .=
97 "DATE_FORMAT(p.DOB,'%Y%m%d') as DOB, " .
98 "concat(p.street, '^^', p.city, '^', p.state, '^', p.postal_code) as address, " .
99 "p.country_code, " .
100 "p.phone_home, " .
101 "p.phone_biz, " .
102 "p.status, " .
103 "p.sex, " .
104 "p.ethnoracial, " .
105 "p.race, " .
106 "p.ethnicity, " .
107 "c.code_text, " .
108 "c.code, " .
109 "c.code_type, " .
110 "DATE_FORMAT(i.vis_date,'%Y%m%d') as immunizationdate, " .
111 "DATE_FORMAT(i.administered_date,'%Y%m%d') as administered_date, " .
112 "i.lot_number as lot_number, " .
113 "i.manufacturer as manufacturer, " .
114 "concat(p.fname, '^', p.lname) as patientname, ";
115 } else {
116 $query .= "concat(p.fname, ' ',p.mname,' ', p.lname) as patientname, " .
117 "i.vis_date as immunizationdate, ";
120 $query .=
121 "i.id as immunizationid, c.code_text_short as immunizationtitle " .
122 "from immunizations i, patient_data p, codes c " .
123 "left join code_types ct on c.code_type = ct.ct_id " .
124 "where " .
125 "ct.ct_key='CVX' and ";
127 if (!empty($form_from_date)) {
128 $query .= "i.vis_date >= ? and ";
129 array_push($sqlBindArray, $form_from_date);
132 if (!empty($form_to_date)) {
133 $query .= "i.vis_date <= ? and ";
134 array_push($sqlBindArray, $form_to_date);
137 $form_code = isset($_POST['form_code']) ? $_POST['form_code'] : array();
138 if (empty($form_code)) {
139 $query_codes = '';
140 } else {
141 $query_codes = "c.id in (";
142 $codes = '';
143 foreach ($form_code as $code) {
144 $codes .= '?,';
145 array_push($sqlBindArray, $code);
147 $codes = substr($codes, 0, -1);
148 $query_codes .= $codes . ") and ";
151 $query .= "i.patient_id=p.pid and " .
152 $query_codes .
153 "i.cvx_code = c.code and ";
155 //do not show immunization added erroneously
156 $query .= "i.added_erroneously = 0";
158 $D = "\r";
159 $nowdate = date('Ymd');
160 $now = date('YmdGi');
161 $now1 = date('Y-m-d G:i');
162 $filename = "imm_reg_" . $now . ".hl7";
164 // GENERATE HL7 FILE
165 if (!empty($_POST['form_get_hl7']) && ($_POST['form_get_hl7'] === 'true')) {
166 $content = '';
168 $res = sqlStatement($query, $sqlBindArray);
170 while ($r = sqlFetchArray($res)) {
171 $content .= "MSH|^~\&|OPENEMR||||$nowdate||" .
172 "VXU^V04^VXU_V04|OPENEMR-110316102457117|P|2.5.1" .
173 "$D";
174 if ($r['sex'] === 'Male') {
175 $r['sex'] = 'M';
178 if ($r['sex'] === 'Female') {
179 $r['sex'] = 'F';
182 if ($r['status'] === 'married') {
183 $r['status'] = 'M';
186 if ($r['status'] === 'single') {
187 $r['status'] = 'S';
190 if ($r['status'] === 'divorced') {
191 $r['status'] = 'D';
194 if ($r['status'] === 'widowed') {
195 $r['status'] = 'W';
198 if ($r['status'] === 'separated') {
199 $r['status'] = 'A';
202 if ($r['status'] === 'domestic partner') {
203 $r['status'] = 'P';
206 $content .= "PID|" . // [[ 3.72 ]]
207 "|" . // 1. Set id
208 "|" . // 2. (B)Patient id
209 $r['patientid'] . "^^^MPI&2.16.840.1.113883.19.3.2.1&ISO^MR" . "|" . // 3. (R) Patient identifier list. TODO: Hard-coded the OID from NIST test.
210 "|" . // 4. (B) Alternate PID
211 $r['patientname'] . "|" . // 5.R. Name
212 "|" . // 6. Mather Maiden Name
213 $r['DOB'] . "|" . // 7. Date, time of birth
214 $r['sex'] . "|" . // 8. Sex
215 "|" . // 9.B Patient Alias
216 "2106-3^" . $r['race'] . "^HL70005" . "|" . // 10. Race // Ram change
217 $r['address'] . "^^M" . "|" . // 11. Address. Default to address type Mailing Address(M)
218 "|" . // 12. county code
219 "^PRN^^^^" . format_phone($r['phone_home']) . "|" . // 13. Phone Home. Default to Primary Home Number(PRN)
220 "^WPN^^^^" . format_phone($r['phone_biz']) . "|" . // 14. Phone Work.
221 "|" . // 15. Primary language
222 $r['status'] . "|" . // 16. Marital status
223 "|" . // 17. Religion
224 "|" . // 18. patient Account Number
225 "|" . // 19.B SSN Number
226 "|" . // 20.B Driver license number
227 "|" . // 21. Mathers Identifier
228 format_ethnicity($r['ethnicity']) . "|" . // 22. Ethnic Group
229 "|" . // 23. Birth Plase
230 "|" . // 24. Multiple birth indicator
231 "|" . // 25. Birth order
232 "|" . // 26. Citizenship
233 "|" . // 27. Veteran military status
234 "|" . // 28.B Nationality
235 "|" . // 29. Patient Death Date and Time
236 "|" . // 30. Patient Death Indicator
237 "|" . // 31. Identity Unknown Indicator
238 "|" . // 32. Identity Reliability Code
239 "|" . // 33. Last Update Date/Time
240 "|" . // 34. Last Update Facility
241 "|" . // 35. Species Code
242 "|" . // 36. Breed Code
243 "|" . // 37. Breed Code
244 "|" . // 38. Production Class Code
245 "" . // 39. Tribal Citizenship
246 "$D";
247 $content .= "ORC" . // ORC mandatory for RXA
248 "|" .
249 "RE" .
250 "$D";
251 $content .= "RXA|" .
252 "0|" . // 1. Give Sub-ID Counter
253 "1|" . // 2. Administrattion Sub-ID Counter
254 $r['administered_date'] . "|" . // 3. Date/Time Start of Administration
255 $r['administered_date'] . "|" . // 4. Date/Time End of Administration
256 format_cvx_code($r['code']) . "^" . $r['immunizationtitle'] . "^" . "CVX" . "|" . // 5. Administration Code(CVX)
257 "999|" . // 6. Administered Amount. TODO: Immunization amt currently not captured in database, default to 999(not recorded)
258 "|" . // 7. Administered Units
259 "|" . // 8. Administered Dosage Form
260 "|" . // 9. Administration Notes
261 "|" . // 10. Administering Provider
262 "|" . // 11. Administered-at Location
263 "|" . // 12. Administered Per (Time Unit)
264 "|" . // 13. Administered Strength
265 "|" . // 14. Administered Strength Units
266 $r['lot_number'] . "|" . // 15. Substance Lot Number
267 "|" . // 16. Substance Expiration Date
268 "MSD" . "^" . $r['manufacturer'] . "^" . "HL70227" . "|" . // 17. Substance Manufacturer Name
269 "|" . // 18. Substance/Treatment Refusal Reason
270 "|" . // 19.Indication
271 "|" . // 20.Completion Status
272 "A" . // 21.Action Code - RXA
273 "$D";
276 // send the header here
277 header('Content-type: text/plain');
278 header('Content-Disposition: attachment; filename=' . $filename);
280 // put the content in the file
281 echo($content);
282 exit;
285 <html>
286 <head>
287 <title><?php echo xlt('Immunization Registry'); ?></title>
289 <?php Header::setupHeader(['datetime-picker', 'report-helper']); ?>
291 <script>
292 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
293 function confirmHl7() {
294 let msg = <?php echo js_escape(xlt('This step will generate a file which you have to save for future use.') .
295 '<br />' . xlt('The file cannot be generated again. Do you want to proceed?')); ?>;
296 dialog.confirm(msg).then(returned => {
297 if (returned === true) {
298 $('#form_get_hl7').attr('value', 'true');
299 $('#theform').submit();
300 } else {
301 return false;
306 $(function () {
307 var win = top.printLogSetup ? top : opener.top;
308 win.printLogSetup(document.getElementById('printbutton'));
310 $('.datepicker').datetimepicker({
311 <?php $datetimepicker_timepicker = false; ?>
312 <?php $datetimepicker_showseconds = false; ?>
313 <?php $datetimepicker_formatInput = true; ?>
314 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
315 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
318 </script>
320 <style>
321 /* specifically include & exclude from printing */
322 @media print {
323 #report_parameters {
324 visibility: hidden;
325 display: none;
328 #report_parameters_daterange {
329 visibility: visible;
330 display: inline;
331 margin-bottom: 10px;
334 #report_results table {
335 margin-top: 0px;
339 /* specifically exclude some from the screen */
340 @media screen {
341 #report_parameters_daterange {
342 visibility: hidden;
343 display: none;
346 #report_results {
347 width: 100%;
350 </style>
351 </head>
353 <body class="body_top">
355 <span class='title'><?php echo xlt('Report'); ?> - <?php echo xlt('Immunization Registry'); ?></span>
357 <div id="report_parameters_daterange">
358 <?php echo text(oeFormatShortDate($form_from_date)) . " &nbsp; " . xlt('to{{Range}}') . " &nbsp; " . text(oeFormatShortDate($form_to_date)); ?>
359 </div>
361 <form name='theform' id='theform' method='post' action='immunization_report.php' onsubmit='return top.restoreSession()'>
362 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
363 <div id="report_parameters">
364 <input type='hidden' name='form_refresh' id='form_refresh' value='' />
365 <input type='hidden' name='form_get_hl7' id='form_get_hl7' value='' />
366 <input type="hidden" name="form_export" id="form_export" value="" />
367 <table>
368 <tr>
369 <td class='w-50'>
370 <div style='float:left'>
371 <table class='text'>
372 <tr>
373 <td class='col-form-label'>
374 <?php echo xlt('Codes'); ?>:
375 </td>
376 <td>
377 <?php
378 // Build a drop-down list of codes.
380 $query1 = "select id, concat('CVX:',code) as name from codes " .
381 " left join code_types ct on codes.code_type = ct.ct_id " .
382 " where ct.ct_key='CVX' ORDER BY name";
383 $cres = sqlStatement($query1);
384 echo " <select multiple='multiple' size='3' name='form_code[]' class='form-control'>\n";
385 //echo " <option value=''>-- " . xl('All Codes') . " --\n";
386 while ($crow = sqlFetchArray($cres)) {
387 $codeid = $crow['id'];
388 echo " <option value='" . attr($codeid) . "'";
389 if (in_array($codeid, $form_code)) {
390 echo " selected";
392 echo ">" . text($crow['name']) . "\n";
395 echo " </select>\n";
397 </td>
398 <td class='col-form-label'>
399 <?php echo xlt('From VIS Date'); ?>:
400 </td>
401 <td>
402 <input type='text' name='form_from_date' id="form_from_date"
403 class='datepicker form-control'
404 size='10' value='<?php echo attr(oeFormatShortDate($form_from_date)); ?>' />
405 </td>
406 <td class='col-form-label'>
407 <?php echo xlt('To VIS Date{{Range}}'); ?>:
408 </td>
409 <td>
410 <input type='text' name='form_to_date' id="form_to_date"
411 class='datepicker form-control'
412 size='10' value='<?php echo attr(oeFormatShortDate($form_to_date)); ?>' />
413 </td>
414 </tr>
415 </table>
416 </div>
417 </td>
418 <td class='h-100' valign='middle'>
419 <table class='w-100 h-100' style='border-left:1px solid;'>
420 <tr>
421 <td>
422 <div class="text-center">
423 <div class="btn-group" role="group">
424 <a href='#' class='btn btn-secondary btn-save'
425 onclick='
426 $("#form_refresh").attr("value","true");
427 $("#form_get_hl7").attr("value","false");
428 $("#theform").submit();
430 <?php echo xlt('Refresh'); ?>
431 </a>
432 <?php if (!empty($_POST['form_refresh'])) { ?>
433 <a href='#' class='btn btn-secondary btn-print' id='printbutton'>
434 <?php echo xlt('Print'); ?>
435 </a>
436 <a href='#' class='btn btn-secondary btn-transmit' onclick="confirmHl7()">
437 <?php echo xlt('Get HL7'); ?>
438 </a>
439 <a href='#' type="submit" class='btn btn-secondary btn-sheet'
440 onclick='exportData()'>
441 <?php echo xlt('Export'); ?>
442 </a>
444 <?php } ?>
445 </div>
446 </div>
447 </td>
448 </tr>
449 </table>
450 </td>
451 </tr>
452 </table>
453 </div> <!-- end of parameters -->
455 <?php
456 if (!empty($_POST['form_refresh'])) {
458 <div id="report_results">
459 <table class='table'>
460 <thead class='thead-light'>
461 <tr>
462 <th> <?php echo xlt('Patient ID'); ?> </th>
463 <th> <?php echo xlt('Patient Name'); ?> </th>
464 <th> <?php echo xlt('Immunization Code'); ?> </th>
465 <th> <?php echo xlt('Immunization Title'); ?> </th>
466 <th> <?php echo xlt('Immunization Date'); ?> </th>
467 </tr>
468 </thead>
469 <tbody>
470 <?php
471 $total = 0;
473 $res = sqlStatement($query, $sqlBindArray);
475 while ($row = sqlFetchArray($res)) {
476 $rows[] = $row;
478 <tr>
479 <td>
480 <?php echo text($row['patientid']); ?>
481 </td>
482 <td>
483 <?php echo text($row['patientname']); ?>
484 </td>
485 <td>
486 <?php echo text($row['cvx_code']); ?>
487 </td>
488 <td>
489 <?php echo text($row['immunizationtitle']); ?>
490 </td>
491 <td>
492 <?php echo text($row['immunizationdate']); ?>
493 </td>
494 </tr>
495 <?php
496 ++$total;
499 <tr class="report_totals">
500 <td colspan='9'>
501 <?php echo xlt('Total Number of Immunizations'); ?>
503 <?php echo text($total); ?>
504 </td>
505 </tr>
506 </tbody>
507 </table>
508 </div> <!-- end of results -->
509 <?php } else { ?>
510 <div class='text'>
511 <?php echo xlt('Click Refresh to view all results, or please input search criteria above to view specific results.'); ?>
512 </div>
513 <?php } ?>
514 </form>
515 <script>
517 function exportData() {
518 let data = <?php echo json_encode($rows ?? ''); ?>;
519 let csrf_token = <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>;
520 dlgopen(
521 "../../library/ajax/immunization_export.php?csrf_token_form=" + encodeURIComponent(csrf_token) +
522 "&data=" + encodeURIComponent(data),
523 'Export',
524 'modal-xs',
525 300,
526 false,
527 'Export',
529 buttons: [
530 {text: <?php echo xlj('Close'); ?>, close: true, style: 'default btn-sm'}
534 return false;
536 </script>
537 </body>
538 </html>