Merge pull request #1128 from bradymiller/unique-insurance-report-cleanup_1
[openemr.git] / interface / billing / billing_process.php
blob426ba2dca9a1a539c218404f9092a1c66f31d977
1 <?php
2 /*
3 * Billing process Program
5 * This program process data for claims generation
7 * Copyright (C) 2016 Terry Hill <terry@lillysystems.com>
8 * Copyright (C) 2014 Brady Miller <brady.g.miller@gmail.com>
9 * Copyright (C) 2017 Jerry Padgett <sjpadgett@gmail.com>
11 * LICENSE: This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 3
14 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see http://opensource.org/licenses/gpl-license.php.
22 * @package OpenEMR
23 * @author Terry Hill <terry@lilysystems.com>
24 * @author Brady Miller <brady.g.miller@gmail.com>
25 * @author Jerry Padgett <sjpadgett@gmail.com>
26 * @link http://www.open-emr.org
28 include_once("../globals.php");
29 include_once("$srcdir/patient.inc");
30 include_once("$srcdir/billrep.inc");
31 include_once("$srcdir/billing.inc");
32 include_once("$srcdir/gen_x12_837.inc.php");
33 include_once("$srcdir/gen_hcfa_1500.inc.php");
35 if ($GLOBALS['ub04_support']) {
36 require_once("./ub04_dispose.php");
38 $EXPORT_INC = "$webserver_root/custom/BillingExport.php";
39 if (file_exists($EXPORT_INC)) {
40 include_once($EXPORT_INC);
41 $BILLING_EXPORT = true;
44 $bill_info = array();
46 $bat_type = ''; // will be edi or hcfa
47 $bat_sendid = '';
48 $bat_recvid = '';
49 $bat_content = '';
50 $bat_gscount = 0;
51 $bat_stcount = 0;
52 $bat_time = time();
53 $bat_hhmm = date('Hi', $bat_time);
54 $bat_yymmdd = date('ymd', $bat_time);
55 $bat_yyyymmdd = date('Ymd', $bat_time);
56 // Minutes since 1/1/1970 00:00:00 GMT will be our interchange control number:
57 $bat_icn = sprintf('%09.0f', $bat_time / 60);
58 $bat_filename = date("Y-m-d-Hi", $bat_time) . "-batch.";
59 $bat_filename .= (isset($_POST['bn_process_hcfa']) || isset($_POST['bn_process_hcfa_form']) || isset($_POST['bn_process_ub04']) || isset($_POST['bn_process_ub04_form'])) ? 'pdf' : 'txt';
60 $template = array();
61 $ub04id = array();
63 if (isset($_POST['bn_process_hcfa']) || isset($_POST['bn_process_hcfa_form'])) {
64 $pdf = new Cezpdf('LETTER');
65 $pdf->ezSetMargins(trim($_POST['top_margin']) + 0, 0, trim($_POST['left_margin']) + 0, 0);
66 $pdf->selectFont('Courier');
69 function append_claim(&$segs)
71 global $bat_content, $bat_sendid, $bat_recvid, $bat_sender, $bat_stcount;
72 global $bat_gscount, $bat_yymmdd, $bat_yyyymmdd, $bat_hhmm, $bat_icn;
74 foreach ($segs as $seg) {
75 if (! $seg) {
76 continue;
78 $elems = explode('*', $seg);
79 if ($elems[0] == 'ISA') {
80 if (! $bat_content) {
81 $bat_sendid = trim($elems[6]);
82 $bat_recvid = trim($elems[8]);
83 $bat_sender = $GS02 ? $GS02 : $bat_sendid;
84 $bat_content = substr($seg, 0, 70) . "$bat_yymmdd*$bat_hhmm*" . $elems[11] . "*" . $elems[12] . "*$bat_icn*" . $elems[14] . "*" . $elems[15] . "*:~";
86 continue;
87 } elseif (! $bat_content) {
88 die("Error:<br>\nInput must begin with 'ISA'; " . "found '" . htmlentities($elems[0]) . "' instead");
90 if ($elems[0] == 'GS') {
91 if ($bat_gscount == 0) {
92 ++ $bat_gscount;
93 $bat_content .= "GS*HC*" . $elems[2] . "*" . $elems[3] . "*$bat_yyyymmdd*$bat_hhmm*1*X*" . $elems[8] . "~";
95 continue;
97 if ($elems[0] == 'ST') {
98 ++ $bat_stcount;
99 $bat_content .= sprintf("ST*837*%04d", $bat_stcount);
100 if (! empty($elems[3])) {
101 $bat_content .= "*" . $elems[3];
104 $bat_content .= "~";
105 continue;
108 if ($elems[0] == 'SE') {
109 $bat_content .= sprintf("SE*%d*%04d~", $elems[1], $bat_stcount);
110 continue;
113 if ($elems[0] == 'GE' || $elems[0] == 'IEA') {
114 continue;
117 $bat_content .= $seg . '~';
121 function append_claim_close()
123 global $bat_content, $bat_stcount, $bat_gscount, $bat_icn;
124 if ($bat_gscount) {
125 $bat_content .= "GE*$bat_stcount*1~";
128 $bat_content .= "IEA*$bat_gscount*$bat_icn~";
131 function send_batch()
133 global $bat_content, $bat_filename, $webserver_root;
134 // If a writable edi directory exists, log the batch to it.
135 // I guarantee you'll be glad we did this. :-)
136 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/edi/$bat_filename", 'a');
137 if ($fh) {
138 fwrite($fh, $bat_content);
139 fclose($fh);
141 header("Pragma: public");
142 header("Expires: 0");
143 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
144 header("Content-Type: application/force-download");
145 header("Content-Disposition: attachment; filename=$bat_filename");
146 header("Content-Description: File Transfer");
147 header("Content-Length: " . strlen($bat_content));
148 echo $bat_content;
151 process_form($_POST);
153 function process_form($ar)
155 global $bill_info, $webserver_root, $bat_filename, $pdf, $template;
156 global $ub04id;
158 if (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter']) || isset($ar['bn_process_hcfa']) || isset($ar['bn_hcfa_txt_file']) || isset($ar['bn_process_hcfa_form'])
159 || isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04']) || isset($ar['bn_ub04_x12'])) {
160 if ($GLOBALS['billing_log_option'] == 1) {
161 $hlog = fopen($GLOBALS['OE_SITE_DIR'] . "/edi/process_bills.log", 'a');
162 } else { // ($GLOBALS['billing_log_option'] == 2)
163 $hlog = fopen($GLOBALS['OE_SITE_DIR'] . "/edi/process_bills.log", 'w');
167 if (isset($ar['bn_external'])) {
168 // Open external billing file for output.
169 $be = new BillingExport();
172 $db = $GLOBALS['adodb']['db'];
174 if (empty($ar['claims'])) {
175 $ar['claims'] = array();
177 $claim_count = 0;
178 foreach ($ar['claims'] as $claimid => $claim_array) {
179 $ta = explode("-", $claimid);
180 $patient_id = $ta[0];
181 $encounter = $ta[1];
182 $payer_id = substr($claim_array['payer'], 1);
183 $payer_type = substr($claim_array['payer'], 0, 1);
184 $payer_type = $payer_type == 'T' ? 3 : $payer_type == 'S' ? 2 : 1;
186 if (isset($claim_array['bill'])) {
187 if (isset($ar['bn_external'])) {
188 // Write external claim.
189 $be->addClaim($patient_id, $encounter);
190 } else {
191 $sql = "SELECT x.processing_format from x12_partners as x where x.id =" . $db->qstr($claim_array['partner']);
192 $result = $db->Execute($sql);
193 $target = "x12";
194 if ($result && ! $result->EOF) {
195 $target = $result->fields['processing_format'];
199 $tmp = 1;
200 if (isset($ar['HiddenMarkAsCleared']) && $ar['HiddenMarkAsCleared'] == 'yes') {
201 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 2); // $sql .= " billed = 1, ";
203 if (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter'])) {
204 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', $target, $claim_array['partner']);
205 } elseif (isset($ar['bn_ub04_x12'])) {
206 $ub04id = get_ub04_array($patient_id, $encounter);
207 $ub_save = json_encode($ub04id);
208 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', $target, $claim_array['partner'] . '-837I', 0, $ub_save);
209 } elseif (isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04'])) {
210 $ub04id = get_ub04_array($patient_id, $encounter);
211 $ub_save = json_encode($ub04id);
212 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', 'ub04', - 1, 0, $ub_save);
213 } elseif (isset($ar['bn_process_hcfa']) || isset($ar['bn_hcfa_txt_file']) || isset($ar['bn_process_hcfa_form'])) {
214 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', 'hcfa');
215 } elseif (isset($ar['bn_mark'])) {
216 // $sql .= " billed = 1, ";
217 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 2);
218 } elseif (isset($ar['bn_reopen'])) {
219 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 0);
220 } elseif (isset($ar['bn_external'])) {
221 // $sql .= " billed = 1, ";
222 $tmp = updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 2);
225 if (! $tmp) {
226 die(xl("Claim ") . $claimid . xl(" update failed, not in database?"));
227 } else {
228 if (isset($ar['bn_mark'])) {
229 $bill_info[] = xl("Claim ") . $claimid . xl(" was marked as billed only.") . "\n";
230 } elseif (isset($ar['bn_reopen'])) {
231 $bill_info[] = xl("Claim ") . $claimid . xl(" has been re-opened.") . "\n";
232 } elseif (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter'])) {
233 $log = '';
234 $segs = explode("~\n", gen_x12_837($patient_id, $encounter, $log, isset($ar['bn_x12_encounter'])));
235 fwrite($hlog, $log);
236 append_claim($segs);
237 if (! updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
238 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
240 } elseif (isset($ar['bn_ub04_x12'])) {
241 $log = '';
242 $segs = explode("~\n", generate_x12_837I($patient_id, $encounter, $log, $ub04id));
243 fwrite($hlog, $log);
244 append_claim($segs);
245 if (! updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename, 'X12-837I', - 1, 0, json_encode($ub04id))) {
246 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
248 } elseif (isset($ar['bn_process_hcfa'])) {
249 $log = '';
250 $lines = gen_hcfa_1500($patient_id, $encounter, $log);
251 fwrite($hlog, $log);
252 $alines = explode("\014", $lines); // form feeds may separate pages
253 foreach ($alines as $tmplines) {
254 if ($claim_count ++) {
255 $pdf->ezNewPage();
257 $pdf->ezSetY($pdf->ez['pageHeight'] - $pdf->ez['topMargin']);
258 $pdf->ezText($tmplines, 12, array(
259 'justification' => 'left',
260 'leading' => 12
263 if (! updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
264 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
266 } elseif (isset($ar['bn_process_hcfa_form'])) {
267 $log = '';
268 $lines = gen_hcfa_1500($patient_id, $encounter, $log);
269 $hcfa_image = $GLOBALS['images_static_absolute'] . "/cms1500.png";
270 fwrite($hlog, $log);
271 $alines = explode("\014", $lines); // form feeds may separate pages
272 foreach ($alines as $tmplines) {
273 if ($claim_count ++) {
274 $pdf->ezNewPage();
276 $pdf->ezSetY($pdf->ez['pageHeight'] - $pdf->ez['topMargin']);
277 $pdf->addPngFromFile("$hcfa_image", 0, 0, 612, 792);
278 $pdf->ezText($tmplines, 12, array(
279 'justification' => 'left',
280 'leading' => 12
283 if (! updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
284 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
286 } elseif (isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04'])) {
287 $claim_count ++;
288 $log = "";
289 $template[] = buildTemplate($patient_id, $encounter, "", "", $log);
290 fwrite($hlog, $log);
291 if (! updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename, 'ub04', - 1, 0, json_encode($ub04id))) {
292 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
294 } elseif (isset($ar['bn_hcfa_txt_file'])) {
295 $log = '';
296 $lines = gen_hcfa_1500($patient_id, $encounter, $log);
297 fwrite($hlog, $log);
298 $bat_content .= $lines;
299 if (! updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
300 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
302 } else {
303 $bill_info[] = xl("Claim ") . $claimid . xl(" was queued successfully.") . "\n";
306 } // end if this claim has billing
307 } // end foreach
309 if (isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04'])) {
310 if (isset($ar['bn_process_ub04'])) {
311 $action = "noform";
312 } elseif (isset($ar['bn_process_ub04_form'])) {
313 $action = "form";
315 ub04Dispose('download', $template, $bat_filename, $action);
316 exit();
318 if (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter']) || isset($ar['bn_ub04_x12'])) {
319 append_claim_close();
320 fclose($hlog);
321 send_batch();
322 exit();
325 if (isset($ar['bn_process_hcfa'])) {
326 fclose($hlog);
327 // If a writable edi directory exists (and it should), write the pdf to it.
328 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/edi/$bat_filename", 'a');
329 if ($fh) {
330 fwrite($fh, $pdf->ezOutput());
331 fclose($fh);
333 // Send the PDF download.
334 $pdf->ezStream(array(
335 'Content-Disposition' => $bat_filename
337 exit();
339 if (isset($ar['bn_process_hcfa_form'])) {
340 fclose($hlog);
341 // If a writable edi directory exists (and it should), write the pdf to it.
342 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/edi/$bat_filename", 'a');
343 if ($fh) {
344 fwrite($fh, $pdf->ezOutput());
345 fclose($fh);
347 // Send the PDF download.
348 header("Pragma: public");
349 header("Expires: 0");
350 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
351 header("Content-Type: application/force-download");
352 header("Content-Disposition: attachment; filename=$bat_filename");
353 header("Content-Description: File Transfer");
354 // header("Content-Length: " . strlen($bat_content));
355 echo $pdf->ezOutput();
357 exit();
360 if (isset($ar['bn_hcfa_txt_file'])) {
361 fclose($hlog);
362 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/edi/$bat_filename", 'a');
363 if ($fh) {
364 fwrite($fh, $bat_content);
365 fclose($fh);
367 header("Pragma: public");
368 header("Expires: 0");
369 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
370 header("Content-Type: application/force-download");
371 header("Content-Disposition: attachment; filename=$bat_filename");
372 header("Content-Description: File Transfer");
373 header("Content-Length: " . strlen($bat_content));
374 echo $bat_content;
375 exit();
378 if (isset($ar['bn_external'])) {
379 // Close external billing file.
380 $be->close();
384 <html>
385 <head>
386 <?php if (function_exists(html_header_show)) {
387 html_header_show();
390 <link rel="stylesheet" href="<?php echo $css_header;?>" type="text/css">
391 <script type="text/javascript"
392 src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-min-1-9-1/index.js"></script>
393 <script>
394 $(document).ready( function() {
395 $("#close-link").click( function() {
396 window.close();
399 </script>
401 </head>
402 <body class="body_top">
403 <br><p><h3><?php echo xlt('Billing queue results'); ?>:</h3><a href="#" id="close-link"><?php echo xlt('Close'); ?></a><ul>
404 <?php
405 foreach ($bill_info as $infoline) {
406 echo nl2br($infoline);
409 </ul></p>
410 </body>
411 </html>