Fully responsive globals.php with vertical menu (#2460)
[openemr.git] / interface / billing / billing_process.php
blobe128578b809761f487127b59822dc51ffc461bd0
1 <?php
2 /*
3 * Billing process Program
5 * This program processes data for claims generation
7 * @package OpenEMR
8 * @link http://www.open-emr.org
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Terry Hill <terry@lilysystems.com>
11 * @author Jerry Padgett <sjpadgett@gmail.com>
12 * @author Stephen Waite <stephen.waite@cmsvt.com>
13 * @copyright Copyright (c) 2014-2019 Brady Miller <brady.g.miller@gmail.com>
14 * @copyright Copyright (c) 2016 Terry Hill <terry@lillysystems.com>
15 * @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com>
16 * @copyright Copyright (c) 2018-2019 Stephen Waite <stephen.waite@cmsvt.com>
17 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
20 require_once("../globals.php");
21 require_once("$srcdir/patient.inc");
22 require_once("$srcdir/billrep.inc");
24 use OpenEMR\Billing\BillingUtilities;
25 use OpenEMR\Billing\HCFA_1500;
26 use OpenEMR\Billing\X12_5010_837P;
27 use OpenEMR\Common\Crypto\CryptoGen;
29 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
30 csrfNotVerified();
33 if ($GLOBALS['ub04_support']) {
34 require_once("./ub04_dispose.php");
36 $EXPORT_INC = "$webserver_root/custom/BillingExport.php";
37 if (file_exists($EXPORT_INC)) {
38 include_once($EXPORT_INC);
39 $BILLING_EXPORT = true;
42 $bill_info = array();
44 $bat_type = ''; // will be edi or hcfa
45 $bat_sendid = '';
46 $bat_recvid = '';
47 $bat_content = '';
48 $bat_gscount = 0;
49 $bat_stcount = 0;
50 $bat_time = time();
51 $bat_hhmm = date('Hi', $bat_time);
52 $bat_yymmdd = date('ymd', $bat_time);
53 $bat_yyyymmdd = date('Ymd', $bat_time);
54 // Seconds since 1/1/1970 00:00:00 GMT will be our interchange control number
55 // but since limited to 9 char must be without leading 1
56 $bat_icn = substr((string)$bat_time, 1, 9);
57 $bat_filename = date("Y-m-d-Hi", $bat_time) . "-batch.";
58 $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';
59 $template = array();
60 $ub04id = array();
62 if (isset($_POST['bn_process_hcfa']) || isset($_POST['bn_process_hcfa_form'])) {
63 $pdf = new Cezpdf('LETTER');
64 $pdf->ezSetMargins(trim($_POST['top_margin']) + 0, 0, trim($_POST['left_margin']) + 0, 0);
65 $pdf->selectFont('Courier');
68 function append_claim(&$segs)
70 global $bat_content, $bat_sendid, $bat_recvid, $bat_sender, $bat_stcount;
71 global $bat_gscount, $bat_yymmdd, $bat_yyyymmdd, $bat_hhmm, $bat_icn;
73 foreach ($segs as $seg) {
74 if (! $seg) {
75 continue;
77 $elems = explode('*', $seg);
78 if ($elems[0] == 'ISA') {
79 if (! $bat_content) {
80 $bat_sendid = trim($elems[6]);
81 $bat_recvid = trim($elems[8]);
82 $bat_sender = $GS02 ? $GS02 : $bat_sendid;
83 $bat_content = substr($seg, 0, 70) . "$bat_yymmdd*$bat_hhmm*" . $elems[11] . "*" . $elems[12] . "*$bat_icn*" . $elems[14] . "*" . $elems[15] . "*:~";
85 continue;
86 } elseif (! $bat_content) {
87 die("Error:<br>\nInput must begin with 'ISA'; " . "found '" . text($elems[0]) . "' instead");
89 if ($elems[0] == 'GS') {
90 if ($bat_gscount == 0) {
91 ++ $bat_gscount;
92 $bat_content .= "GS*HC*" . $elems[2] . "*" . $elems[3] . "*$bat_yyyymmdd*$bat_hhmm*1*X*" . $elems[8] . "~";
94 continue;
96 if ($elems[0] == 'ST') {
97 ++ $bat_stcount;
98 $bat_st_02 = sprintf("%04d", $bat_stcount);
99 $bat_content .= "ST*837*" . $bat_st_02;
100 if (! empty($elems[3])) {
101 $bat_content .= "*" . $elems[3];
104 $bat_content .= "~";
105 continue;
108 if ($elems[0] == 'BHT') {
109 // needle is set in OpenEMR\Billing\X12_5010_837P
110 $bat_content .= substr_replace($seg, '*'.$bat_icn.$bat_st_02.'*', strpos($seg, '*0123*'), 6);
111 $bat_content .= "~";
112 continue;
115 if ($elems[0] == 'SE') {
116 $bat_content .= sprintf("SE*%d*%04d~", $elems[1], $bat_stcount);
117 continue;
120 if ($elems[0] == 'GE' || $elems[0] == 'IEA') {
121 continue;
124 $bat_content .= $seg . '~';
128 function append_claim_close()
130 global $bat_content, $bat_stcount, $bat_gscount, $bat_icn;
131 if ($bat_gscount) {
132 $bat_content .= "GE*$bat_stcount*1~";
135 $bat_content .= "IEA*$bat_gscount*$bat_icn~";
138 function send_batch()
140 global $bat_content, $bat_filename, $webserver_root;
141 // If a writable edi directory exists, log the batch to it.
142 // I guarantee you'll be glad we did this. :-)
143 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/documents/edi/$bat_filename", 'a');
144 if ($fh) {
145 fwrite($fh, $bat_content);
146 fclose($fh);
148 header("Pragma: public");
149 header("Expires: 0");
150 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
151 header("Content-Type: application/force-download");
152 header("Content-Disposition: attachment; filename=$bat_filename");
153 header("Content-Description: File Transfer");
154 header("Content-Length: " . strlen($bat_content));
155 echo $bat_content;
158 process_form($_POST);
160 function process_form($ar)
162 global $bill_info, $webserver_root, $bat_filename, $pdf, $template;
163 global $ub04id;
165 // Set up crypto object
166 $cryptoGen = new CryptoGen();
168 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'])
169 || isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04']) || isset($ar['bn_ub04_x12'])) {
170 if ($GLOBALS['billing_log_option'] == 1) {
171 $hlog = file_get_contents($GLOBALS['OE_SITE_DIR'] . "/documents/edi/process_bills.log");
172 if ($cryptoGen->cryptCheckStandard($hlog)) {
173 $hlog = $cryptoGen->decryptStandard($hlog, null, 'database');
175 } else { // ($GLOBALS['billing_log_option'] == 2)
176 $hlog = '';
180 if (isset($ar['bn_external'])) {
181 // Open external billing file for output.
182 $be = new BillingExport();
185 if (empty($ar['claims'])) {
186 $ar['claims'] = array();
188 $claim_count = 0;
189 foreach ($ar['claims'] as $claimid => $claim_array) {
190 $ta = explode("-", $claimid);
191 $patient_id = $ta[0];
192 $encounter = $ta[1];
193 $payer_id = substr($claim_array['payer'], 1);
194 $payer_type = substr($claim_array['payer'], 0, 1);
195 $payer_type = $payer_type == 'T' ? 3 : $payer_type == 'S' ? 2 : 1;
197 if (isset($claim_array['bill'])) {
198 if (isset($ar['bn_external'])) {
199 // Write external claim.
200 $be->addClaim($patient_id, $encounter);
201 } else {
202 $sql = "SELECT x.processing_format from x12_partners as x where x.id =?";
203 $result = sqlQuery($sql, [$claim_array['partner']]);
204 $target = "x12";
205 if (!empty($result['processing_format'])) {
206 $target = $result['processing_format'];
210 $tmp = 1;
211 if (isset($ar['HiddenMarkAsCleared']) && $ar['HiddenMarkAsCleared'] == 'yes') {
212 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 2); // $sql .= " billed = 1, ";
214 if (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter'])) {
215 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', $target, $claim_array['partner']);
216 } elseif (isset($ar['bn_ub04_x12'])) {
217 $ub04id = get_ub04_array($patient_id, $encounter);
218 $ub_save = json_encode($ub04id);
219 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', $target, $claim_array['partner'] . '-837I', 0, $ub_save);
220 } elseif (isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04'])) {
221 $ub04id = get_ub04_array($patient_id, $encounter);
222 $ub_save = json_encode($ub04id);
223 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', 'ub04', - 1, 0, $ub_save);
224 } elseif (isset($ar['bn_process_hcfa']) || isset($ar['bn_hcfa_txt_file']) || isset($ar['bn_process_hcfa_form'])) {
225 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 1, '', 'hcfa');
226 } elseif (isset($ar['bn_mark'])) {
227 // $sql .= " billed = 1, ";
228 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 2);
229 } elseif (isset($ar['bn_reopen'])) {
230 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 1, 0);
231 } elseif (isset($ar['bn_external'])) {
232 // $sql .= " billed = 1, ";
233 $tmp = BillingUtilities::updateClaim(true, $patient_id, $encounter, $payer_id, $payer_type, 2);
236 if (! $tmp) {
237 die(xlt("Claim ") . text($claimid) . xlt(" update failed, not in database?"));
238 } else {
239 if (isset($ar['bn_mark'])) {
240 $bill_info[] = xl("Claim ") . $claimid . xl(" was marked as billed only.") . "\n";
241 } elseif (isset($ar['bn_reopen'])) {
242 $bill_info[] = xl("Claim ") . $claimid . xl(" has been re-opened.") . "\n";
243 } elseif (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter'])) {
244 $log = '';
245 $segs = explode("~\n", X12_5010_837P::gen_x12_837($patient_id, $encounter, $log, isset($ar['bn_x12_encounter'])));
246 $hlog .= $log;
247 append_claim($segs);
248 if (! BillingUtilities::updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
249 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
251 } elseif (isset($ar['bn_ub04_x12'])) {
252 $log = '';
253 $segs = explode("~\n", generate_x12_837I($patient_id, $encounter, $log, $ub04id));
254 $hlog .= $log;
255 append_claim($segs);
256 if (! BillingUtilities::updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename, 'X12-837I', - 1, 0, json_encode($ub04id))) {
257 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
259 } elseif (isset($ar['bn_process_hcfa'])) {
260 $log = '';
261 $hcfa = new HCFA_1500();
262 $lines = $hcfa->gen_hcfa_1500($patient_id, $encounter, $log);
263 $hlog .= $log;
264 $alines = explode("\014", $lines); // form feeds may separate pages
265 foreach ($alines as $tmplines) {
266 if ($claim_count ++) {
267 $pdf->ezNewPage();
269 $pdf->ezSetY($pdf->ez['pageHeight'] - $pdf->ez['topMargin']);
270 $pdf->ezText($tmplines, 12, array(
271 'justification' => 'left',
272 'leading' => 12
275 if (! BillingUtilities::updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
276 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
278 } elseif (isset($ar['bn_process_hcfa_form'])) {
279 $log = '';
280 $hcfa = new HCFA_1500();
281 $lines = $hcfa->gen_hcfa_1500($patient_id, $encounter, $log);
282 $hcfa_image = $GLOBALS['images_static_absolute'] . "/cms1500.png";
283 $hlog .= $log;
284 $alines = explode("\014", $lines); // form feeds may separate pages
285 foreach ($alines as $tmplines) {
286 if ($claim_count ++) {
287 $pdf->ezNewPage();
289 $pdf->ezSetY($pdf->ez['pageHeight'] - $pdf->ez['topMargin']);
290 $pdf->addPngFromFile("$hcfa_image", 0, 0, 612, 792);
291 $pdf->ezText($tmplines, 12, array(
292 'justification' => 'left',
293 'leading' => 12
296 if (! BillingUtilities::updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
297 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
299 } elseif (isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04'])) {
300 $claim_count ++;
301 $log = "";
302 $template[] = buildTemplate($patient_id, $encounter, "", "", $log);
303 $hlog .= $log;
304 if (! BillingUtilities::updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename, 'ub04', - 1, 0, json_encode($ub04id))) {
305 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
307 } elseif (isset($ar['bn_hcfa_txt_file'])) {
308 $log = '';
309 $hcfa = new HCFA_1500();
310 $lines = $hcfa->gen_hcfa_1500($patient_id, $encounter, $log);
311 $hlog .= $log;
312 $bat_content .= $lines;
313 if (! BillingUtilities::updateClaim(false, $patient_id, $encounter, - 1, - 1, 2, 2, $bat_filename)) {
314 $bill_info[] = xl("Internal error: claim ") . $claimid . xl(" not found!") . "\n";
316 } else {
317 $bill_info[] = xl("Claim ") . $claimid . xl(" was queued successfully.") . "\n";
320 } // end if this claim has billing
321 } // end foreach
323 if (!empty($hlog)) {
324 if ($GLOBALS['drive_encryption']) {
325 $hlog = $cryptoGen->encryptStandard($hlog, null, 'database');
327 file_put_contents($GLOBALS['OE_SITE_DIR'] . "/documents/edi/process_bills.log", $hlog);
330 if (isset($ar['bn_process_ub04_form']) || isset($ar['bn_process_ub04'])) {
331 if (isset($ar['bn_process_ub04'])) {
332 $action = "noform";
333 } elseif (isset($ar['bn_process_ub04_form'])) {
334 $action = "form";
336 ub04Dispose('download', $template, $bat_filename, $action);
337 exit();
339 if (isset($ar['bn_x12']) || isset($ar['bn_x12_encounter']) || isset($ar['bn_ub04_x12'])) {
340 append_claim_close();
341 send_batch();
342 exit();
345 if (isset($ar['bn_process_hcfa'])) {
346 // If a writable edi directory exists (and it should), write the pdf to it.
347 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/documents/edi/$bat_filename", 'a');
348 if ($fh) {
349 fwrite($fh, $pdf->ezOutput());
350 fclose($fh);
352 // Send the PDF download.
353 $pdf->ezStream(array(
354 'Content-Disposition' => $bat_filename
356 exit();
358 if (isset($ar['bn_process_hcfa_form'])) {
359 // If a writable edi directory exists (and it should), write the pdf to it.
360 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/documents/edi/$bat_filename", 'a');
361 if ($fh) {
362 fwrite($fh, $pdf->ezOutput());
363 fclose($fh);
365 // Send the PDF download.
366 header("Pragma: public");
367 header("Expires: 0");
368 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
369 header("Content-Type: application/force-download");
370 header("Content-Disposition: attachment; filename=$bat_filename");
371 header("Content-Description: File Transfer");
372 // header("Content-Length: " . strlen($bat_content));
373 echo $pdf->ezOutput();
375 exit();
378 if (isset($ar['bn_hcfa_txt_file'])) {
379 $fh = @fopen($GLOBALS['OE_SITE_DIR'] . "/documents/edi/$bat_filename", 'a');
380 if ($fh) {
381 fwrite($fh, $bat_content);
382 fclose($fh);
384 header("Pragma: public");
385 header("Expires: 0");
386 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
387 header("Content-Type: application/force-download");
388 header("Content-Disposition: attachment; filename=$bat_filename");
389 header("Content-Description: File Transfer");
390 header("Content-Length: " . strlen($bat_content));
391 echo $bat_content;
392 exit();
395 if (isset($ar['bn_external'])) {
396 // Close external billing file.
397 $be->close();
401 <html>
402 <head>
404 <link rel="stylesheet" href="<?php echo $css_header;?>" type="text/css">
405 <script type="text/javascript"
406 src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-1-9-1/jquery.min.js"></script>
407 <script>
408 $( function() {
409 $("#close-link").click( function() {
410 window.close();
413 </script>
415 </head>
416 <body class="body_top">
417 <br><p><h3><?php echo xlt('Billing queue results'); ?>:</h3><a href="#" id="close-link"><?php echo xlt('Close'); ?></a><ul>
418 <?php
419 foreach ($bill_info as $infoline) {
420 echo nl2br($infoline);
423 </ul></p>
424 </body>
425 </html>