another billing class and moved reports to billing (#2683)
[openemr.git] / interface / billing / edi_270.php
blob566c5bfe267851280d73ee88b8caae172f741a6b
1 <?php
2 /**
3 * main file for the 270 batch creation.
4 * This report is the batch report required for batch eligibility verification.
6 * This program creates the batch for the x12 270 eligibility file
8 * @package OpenEMR
9 * @link http://www.open-emr.org
10 * @author Terry Hill <terry@lilysystems.com>
11 * @author Brady Miller <brady.g.miller@gmail.com>
12 * @author Jerry Padgett <sjpadgett@gmail.com>
13 * @author Stephen Waite <stephen.waite@cmsvt.com>
14 * @copyright Copyright (c) 2010 MMF Systems, Inc
15 * @copyright Copyright (c) 2016 Terry Hill <terry@lillysystems.com>
16 * @copyright Copyright (c) 2017 Brady Miller <brady.g.miller@gmail.com>
17 * @copyright Copyright (c) 2019 Jerry Padgett <sjpadgett@gmail.com>
18 * @copyright Copyright (c) 2019 Stephen Waite <stephen.waite@cmsvt.com>
19 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
23 require_once("../globals.php");
24 require_once("$srcdir/forms.inc");
25 require_once("$srcdir/patient.inc");
26 require_once "$srcdir/options.inc.php";
27 require_once("$srcdir/calendar.inc");
28 require_once("$srcdir/appointments.inc.php");
30 use OpenEMR\Billing\EDI_270;
31 use OpenEMR\Common\Csrf\CsrfUtils;
32 use OpenEMR\Core\Header;
34 if (!empty($_POST)) {
35 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
36 CsrfUtils::csrfNotVerified();
40 // Element data seperator
41 $eleDataSep = "*";
42 // Segment Terminator
43 $segTer = "~";
44 // Component Element seperator
45 $compEleSep = ":";
47 // filter conditions for the report and batch creation
49 $from_date = (isset($_POST['form_from_date'])) ? DateToYYYYMMDD($_POST['form_from_date']) : date('Y-m-d');
50 $to_date = (isset($_POST['form_to_date'])) ? DateToYYYYMMDD($_POST['form_to_date']) : date('Y-m-d');
51 $form_facility = $_POST['form_facility'] ? $_POST['form_facility'] : '';
52 $form_provider = $_POST['form_users'] ? $_POST['form_users'] : '';
53 $exclude_policy = $_POST['removedrows'] ? $_POST['removedrows'] : '';
54 $x12_partner = $_POST['form_x12'] ? $_POST['form_x12'] : '';
55 $X12info = EDI_270::getX12Partner($x12_partner);
57 // grab appointments, sort by date and make unique to first upcoming appt by pid.
58 $appts = fetchAppointments($from_date, $to_date);
59 $appts = sortAppointments($appts);
60 $appts = unique_by_key($appts, 'pid');
61 $ids = [];
62 foreach ($appts as $eid) {
63 $ids[] = $eid['pc_eid'];
65 //Set up the sql variable binding array (this prevents sql-injection attacks)
66 $sqlBindArray = array();
68 $ids = count($ids) > 0 ? implode(',', $ids) : "'0'";
69 $where = "e.pc_eid in($ids) ";
71 if ($form_facility != "") {
72 $where .= " AND f.id = ? ";
73 array_push($sqlBindArray, $form_facility);
76 if ($form_provider != "") {
77 $where .= " AND d.id = ? ";
78 array_push($sqlBindArray, $form_provider);
81 if ($exclude_policy != "") {
82 $arrayExplode = explode(",", $exclude_policy);
83 array_walk($arrayExplode, 'OpenEMR\Billing\EDI_270::arrFormated');
84 $exclude_policy = implode(",", $arrayExplode);
85 $where .= " AND i.policy_number NOT IN ($exclude_policy)";
87 $where .= " AND (i.policy_number is NOT NULL AND i.policy_number != '')";
88 $where .= " GROUP BY p.pid ORDER BY c.name";
89 $query = sprintf("SELECT e.pc_facility,
90 e.pc_eid,
91 p.lname,
92 p.fname,
93 p.mname,
94 DATE_FORMAT(p.dob, '%%Y%%m%%d') as dob,
95 p.ss,
96 p.sex,
97 p.pid,
98 p.pubpid,
99 i.subscriber_ss,
100 i.policy_number,
101 i.provider as payer_id,
102 i.subscriber_relationship,
103 i.subscriber_lname,
104 i.subscriber_fname,
105 i.subscriber_mname,
106 DATE_FORMAT(i.subscriber_dob, '%%Y%%m%%d') as subscriber_dob,
107 i.policy_number,
108 i.subscriber_sex,
109 DATE_FORMAT(i.date,'%%Y%%m%%d') as date,
110 d.lname as provider_lname,
111 d.fname as provider_fname,
112 d.npi as provider_npi,
113 d.upin as provider_pin,
114 f.federal_ein as federal_ein,
115 f.facility_npi as facility_npi,
116 f.name as facility_name,
117 c.cms_id as cms_id,
118 c.eligibility_id as eligibility_id,
119 c.name as payer_name
120 FROM openemr_postcalendar_events AS e
121 LEFT JOIN users AS d on (e.pc_aid is not null and e.pc_aid = d.id)
122 LEFT JOIN facility AS f on (f.id = e.pc_facility)
123 LEFT JOIN patient_data AS p ON p.pid = e.pc_pid
124 LEFT JOIN insurance_data AS i ON (i.id =(SELECT id FROM insurance_data AS i WHERE pid = p.pid AND type = 'primary' ORDER BY date DESC LIMIT 1))
125 LEFT JOIN insurance_companies as c ON (c.id = i.provider)
126 WHERE %s ", $where);
128 // Run the query
129 $rslt = sqlStatement($query, $sqlBindArray);
130 $res = [];
131 while ($row = sqlFetchArray($rslt)) {
132 foreach ($appts as $tmp) {
133 if ((int)$tmp['pc_eid'] === (int)$row['pc_eid']) {
134 $row['pc_eventDate'] = date("Ymd", strtotime($tmp['pc_eventDate']));
137 $res[] = $row;
139 // Get the facilities information
140 $facilities = getUserFacilities($_SESSION['authId']);
142 // Get the Providers information
143 $providers = EDI_270::getUsernames();
145 //Get the x12 partners information
146 $clearinghouses = EDI_270::getX12Partner();
148 if (isset($_POST['form_xmit']) && !empty($_POST['form_xmit']) && $res) {
149 $eFlag = !$GLOBALS['disable_eligibility_log'];
150 // make the batch request
151 $log = EDI_270::requestRealTimeEligible($res, $X12info, $segTer, $compEleSep, $eFlag);
152 $e = strpos($log, "Error:");
153 if ($e !== false) {
154 $log = text(xlt("One or more transactions failed") .
155 "\n" . $log . "\n");
157 if ($eFlag) {
158 $fn = sprintf(
159 'elig-log_%s_%s.txt',
160 strtolower(str_replace(' ', '', $X12info['name'])),
161 date("Y-m-d:H:i:s")
163 $log = str_replace('~', "~\r", $log);
164 while (@ob_end_flush()) {
166 header('Content-Type: text/plain');
167 header("Content-Length: " . strlen($log));
168 header('Content-Disposition: attachment; filename="' . $fn . '"');
169 ob_start();
170 echo $log;
171 exit();
175 if (isset($_POST['form_savefile']) && !empty($_POST['form_savefile']) && $res) {
176 header('Content-Type: text/plain');
177 header(sprintf(
178 'Content-Disposition: attachment; filename="batch-elig-270.%s.%s.txt"',
179 strtolower(str_replace(' ', '', $X12info['name'])),
180 date("Y-m-d:H:i:s")
182 EDI_270::print_elig($res, $X12info, $segTer, $compEleSep);
183 exit;
186 // unique multidimensional array by key
187 function unique_by_key($source, $key)
189 $i = 0;
190 $rtn_array = array();
191 $key_array = array();
193 foreach ($source as $val) {
194 if (!in_array($val[$key], $key_array)) {
195 $key_array[$i] = $val[$key];
196 $rtn_array[$i] = $val;
198 $i++;
200 return $rtn_array;
204 <html>
206 <head>
208 <title><?php echo xlt('Eligibility 270 Inquiry Batch'); ?></title>
210 <?php Header::setupHeader('datetime-picker'); ?>
212 <style type="text/css">
214 /* specifically include & exclude from printing */
215 @media print {
216 #report_parameters {
217 visibility: hidden;
218 display: none;
220 #report_parameters_daterange {
221 visibility: visible;
222 display: inline;
224 #report_results table {
225 margin-top: 0px;
229 /* specifically exclude some from the screen */
230 @media screen {
231 #report_parameters_daterange {
232 visibility: hidden;
233 display: none;
237 </style>
239 <script type="text/javascript">
241 var stringDelete = <?php echo xlj('Do you want to remove this record?'); ?>;
242 var stringBatch = <?php echo xlj('Please select X12 partner, required to create the 270 batch'); ?>;
244 // for form refresh
246 function refreshme() {
247 document.forms[0].submit();
250 // To delete the row from the reports section
251 function deletetherow(id){
252 var suredelete = confirm(stringDelete);
253 if(suredelete == true){
254 document.getElementById('PR'+id).style.display="none";
255 if(document.getElementById('removedrows').value == ""){
256 document.getElementById('removedrows').value = "'" + id + "'";
257 }else{
258 document.getElementById('removedrows').value = document.getElementById('removedrows').value + ",'" + id + "'";
265 // To validate the batch file generation - for the required field [clearing house/x12 partner]
266 function validate_batch(eFlag) {
267 if (document.getElementById('form_x12').value == '') {
268 alert(stringBatch);
269 return false;
271 else {
272 if (eFlag === true) {
273 document.getElementById('form_xmit').value = "true";
274 } else {
275 document.getElementById('form_savefile').value = "true";
278 document.theform.submit();
282 // To Clear the hidden input field
284 function validate_policy()
286 document.getElementById('removedrows').value = "";
287 document.getElementById('form_savefile').value = "";
288 document.getElementById('form_xmit').value = "";
289 return true;
292 // To toggle the clearing house empty validation message
293 function toggleMessage(id,x12){
295 var spanstyle = String();
297 spanstyle = document.getElementById(id).style.visibility;
298 selectoption = document.getElementById(x12).value;
300 if(selectoption != '')
302 document.getElementById(id).style.visibility = "hidden";
304 else
306 document.getElementById(id).style.visibility = "visible";
307 document.getElementById(id).style.display = "inline";
309 return true;
313 $(function() {
314 $('.datepicker').datetimepicker({
315 <?php $datetimepicker_timepicker = false; ?>
316 <?php $datetimepicker_showseconds = false; ?>
317 <?php $datetimepicker_formatInput = true; ?>
318 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
319 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
323 </script>
325 </head>
326 <body class="body_top">
328 <!-- Required for the popup date selectors -->
329 <div id="overDiv" style="position:absolute; visibility:hidden; z-index:1000;"></div>
331 <span class='title'><?php echo xlt('Report'); ?> - <?php echo xlt('Eligibility 270 Inquiry Batch'); ?></span>
333 <div id="report_parameters_daterange">
334 <?php echo text(oeFormatShortDate($form_from_date)) . " &nbsp; " . xlt('to{{Range}}') . "&nbsp; ". text(oeFormatShortDate($form_to_date)); ?>
335 </div>
337 <form method='post' name='theform' id='theform' action='edi_270.php' onsubmit="return top.restoreSession()">
338 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
339 <input type="hidden" name="removedrows" id="removedrows" value="">
340 <div id="report_parameters">
341 <table>
342 <tr>
343 <td width='550px'>
344 <div style='float:left'>
345 <table class='text'>
346 <tr>
347 <td class='control-label'>
348 <?php echo xlt('From'); ?>:
349 </td>
350 <td>
351 <input type='text' class='datepicker form-control' name='form_from_date' id="form_from_date" size='10' value='<?php echo attr(oeFormatShortDate($from_date)); ?>'>
352 </td>
353 <td class='control-label'>
354 <?php echo xlt('To{{Range}}'); ?>:
355 </td>
356 <td>
357 <input type='text' class='datepicker form-control' name='form_to_date' id="form_to_date" size='10' value='<?php echo attr(oeFormatShortDate($to_date)); ?>'>
358 </td>
359 <td>&nbsp;</td>
360 </tr>
362 <tr>
363 <td class='control-label'>
364 <?php echo xlt('Facility'); ?>:
365 </td>
366 <td>
367 <?php dropdown_facility($form_facility, 'form_facility', false); ?>
368 </td>
369 <td class='control-label'>
370 <?php echo xlt('Provider'); ?>:
371 </td>
372 <td>
373 <select name='form_users' class='form-control' onchange='form.submit();'>
374 <option value=''>-- <?php echo xlt('All'); ?> --</option>
375 <?php foreach ($providers as $user) : ?>
376 <option value='<?php echo attr($user['id']); ?>'
377 <?php echo $form_provider == $user['id'] ? " selected " : null; ?>
378 ><?php echo text($user['fname']." ".$user['lname']); ?></option>
379 <?php endforeach; ?>
380 </select>
381 </td>
382 <td>&nbsp;
383 </td>
384 </tr>
386 <tr>
387 <td class='control-label'>
388 <?php echo xlt('X12 Partner'); ?>:
389 </td>
390 <td colspan='5'>
391 <select name='form_x12' id='form_x12' class='form-control' onchange='return toggleMessage("emptyVald","form_x12");'>
392 <option value=''>--<?php echo xlt('select'); ?>--</option>
393 <?php
394 if (isset($clearinghouses) && !empty($clearinghouses)) {
395 foreach ($clearinghouses as $clearinghouse) {
396 echo "<option value='" . attr($clearinghouse['id']) . "'" .
397 ($clearinghouse['id'] == $X12info['id'] ? " selected " : '') . ">" . text($clearinghouse['name']) . "</option>";
401 </select>
402 <span id='emptyVald' style='color:red;font-size:12px;visibility: <?php echo $X12info['id'] ? "hidden" : ""; ?>'> *
403 <?php echo xlt('Clearing house info required for EDI 270 batch creation.'); ?></span>
404 </td>
405 </tr>
406 </table>
407 </div>
408 </td>
409 <td align='left' valign='middle' height="100%">
410 <table style='border-left:1px solid; width:100%; height:100%' >
411 <tr>
412 <td>
413 <div class="text-center">
414 <div class="btn-group" role="group">
415 <a href='#' class='btn btn-default btn-refresh' onclick='validate_policy(); $("#theform").submit();'>
416 <?php echo xlt('Refresh'); ?>
417 </a>
418 <a href='#' class='btn btn-default btn-transmit' onclick='return validate_batch(false);'>
419 <?php echo xlt('Create batch'); ?>
420 <input type='hidden' name='form_savefile' id='form_savefile' value=''></input>
422 <?php if ($GLOBALS['enable_oa']) {
423 echo "<a href='#' class='btn btn-default btn-transmit' onclick='return validate_batch(true);'>" . xlt('Request Eligibility') . "</a>\n";
426 <input type='hidden' name='form_xmit' id='form_xmit' value=''></input>
427 </a>
428 </div>
429 </div>
430 </td>
431 </tr>
432 </table>
433 </td>
434 </tr>
435 </table>
436 </div>
437 <div class='text'>
438 <?php echo xlt('Please choose date range criteria above, and click Refresh to view results.'); ?>
439 </div>
441 </form>
443 <?php
444 if ($res) {
445 EDI_270::show_elig($res, $X12info, $segTer, $compEleSep);
448 </body>
450 <script language='JavaScript'>
451 <?php
452 if ($alertmsg) {
453 echo " alert(" . js_escape($alertmsg) . ");\n";
454 } ?>
455 </script>
457 </html>