/** * Parse a batch file for data for the csv record * * The array returned has a key 'file' which is for the files_batch.csv * and a key 'claim' with a subarray for each claim * * @see csv_files_header() for values * @uses csv_x12_segments() * @param string $batch_file name of x12-837 batch file * @return array */ function ibr_batch_csv_data($batch_file_path) { // // read the file and transform it into an array of segment arrays // then loop through the segment arrays and copy desired items // to a data array for writing to the csv_file and csv_claims files // // get the segments from csv_record_include function csv_x12_segments $ar_batch = csv_x12_segments($batch_file_path, 'batch', $seg_array = FALSE); // debug //var_dump(array_keys($ar_batch) ) .PHP_EOL; // if (is_array($ar_batch)) { $batch_file = basename($ar_batch['path']); $elem_d = $ar_batch['delimiters']['e']; // } else { csv_edihist_log("ibr_batch_csv_data did not get segments for {$batch_file}"); return FALSE; } // $ar_data = array(); $st_ct = -1; $seg_ct = 0; // foreach ($ar_batch['segments'] as $segtxt) { // debug //echo "$segtxt <br />" .PHP_EOL; // $seg = explode($elem_d, $segtxt); // increment segment count for testing $seg_ct++; // these values will occur once per file // $fname = $batch_file; // $ar_data[$st_ct][8] = $batch_file if ($seg[0] == "ISA") { $x12partner = $seg[6]; $f_mtime = '20' . $seg[9]; $x12version = $seg[12]; $ctrl_num = strval($seg[13]); // $ar_data[$st_ct][10] = $ctrl_num // continue; } if ($seg[0] == 'GS') { $f_mtime = $seg[4]; continue; } // get GE segment for files data claim count if ($seg[0] == "GE") { $clm_ct = $seg[1]; continue; } // now we need to create a sub array for each ST block if ($seg[0] == "ST") { $st_ct++; // OpenEMR 837 places each claim in an ST block $ln_st = $seg_ct; $st_num = strval($seg[2]); // $ar_data[$st_ct][9] = $st_num; continue; } if ($seg[0] == "BHT") { $bht03 = $seg[3]; $ins_pos = ''; // since this is '0123' and not useful, we will construct it // below with $ctrl_num.$st_num continue; } if ($seg[0] == "HL") { $hlevel = strval($seg[3]); continue; } if ($seg[0] == "SBR") { if (($hlevel == '22' || $hlevel == '23') && !$ins_pos) { $ins_pos = $seg[1]; } //$ins_pos = $seg[1]; continue; } if ($seg[0] == "CAS") { // on theory that CAS will only appear on secondary claims if ($ins_pos == 'P') { $ins_pos = 'S'; } } if ($seg[0] == "NM1" && $seg[1] == "PR") { if ($ins_pos == "P") { $ins_primary = $seg[3]; // $ar_data[$st_ct][7] = $ins_primary; } if ($ins_pos == "S") { $ins_secondary = $seg[3]; // $ar_data[$st_ct][8] = $ins_secondary; } continue; } if ($seg[0] == "NM1" && strpos("|IL|QC", $seg[1])) { // The NM1*QC segment is in the batch file if the patient is not // the subscriber, and it comes after the NM1*IL segment, // so get something in either case, but errors can leave blanks $pt_lname = $pt_lname ? $pt_lname : $seg[3]; // $ar_data[$st_ct][0] = $pt_lname $pt_fname = $pt_fname ? $pt_fname : $seg[4]; // $ar_data[$st_ct][1] = $pt_fname continue; } if ($seg[0] == "NM1" && $seg[1] == '82') { $providerid = $seg[9]; continue; } if ($seg[0] == "CLM") { $inv_split = preg_split('/\\D/', $seg[1], 2, PREG_SPLIT_NO_EMPTY); $pid = $inv_split[0]; // $ar_data[$st_ct][2] = $pid $enctr = $inv_split[1]; // $ar_data[$st_ct][3] = $enctr $clm01 = $seg[1]; $fee = $seg[2]; // $ar_data[$st_ct][5] = $fee continue; } if ($seg[0] == "DTP" && $seg[1] == "472") { $svc_date = $seg[3]; // $ar_data[$st_ct][4] = $svc_date continue; } if ($seg[0] == "AMT" && $seg[1] == "F5") { $pt_paid = $seg[2]; // $ar_data[$st_ct][6] = $pt_paid continue; } if ($seg[0] == "SE") { // end of ST block, get claim array and go back // debug count lines $ln_ct = $seg[1]; // $ln_test = $seg_ct - $ln_st + 1; if ($ln_test != $ln_ct) { csv_edihist_log("ibr_batch_csv_data: ST segment count error {$ln_test} {$ln_ct}"); } //['batch']['claim'] = array('PtName', 'SvcDate', 'clm01', 'InsLevel', 'Ctn_837', 'File_837', 'Fee', 'PtPaid', 'Provider' ); // now put ar_data in order // $ar_data['claim'][$st_ct][0] = $pt_lname . ", " . $pt_fname; $ar_data['claim'][$st_ct][1] = $svc_date; $ar_data['claim'][$st_ct][2] = $clm01; $ar_data['claim'][$st_ct][3] = $ins_pos; $ar_data['claim'][$st_ct][4] = $ctrl_num . $st_num; $ar_data['claim'][$st_ct][5] = $batch_file; $ar_data['claim'][$st_ct][6] = $fee; $ar_data['claim'][$st_ct][7] = isset($pt_paid) ? $pt_paid : "0"; $ar_data['claim'][$st_ct][8] = $providerid; // reset variables so there is no carryover // do not reset $batch_file or $ctrl_num $pt_lname = ""; $pt_fname = ""; $pid = ""; $enctr = ""; $svc_date = ""; $fee = ""; $pt_paid = ""; $ins_primary = ""; $ins_secondary = ""; $st_num = ""; $bht03 = ""; $ins_pos = ""; $providerid = ""; $clm01 = ""; // continue; } // } // end foreach( $ar_batch as $seg) // // put the file data array together //$csv_hd_ar['batch']['file'] = array('Date', 'FileName', 'Ctn_837', 'claim_ct', 'x12_partner'); $ar_data['file'][0] = $f_mtime; $ar_data['file'][1] = $batch_file; $ar_data['file'][2] = $ctrl_num; $ar_data['file'][3] = $clm_ct; $ar_data['file'][4] = $x12partner; //$ar_data['file'][5] = $x12version; return $ar_data; }
/** * Process new x12 835 files so data is written to csv tables and html output is created * * This is a multi-operational function, calling other functions in this script and in * csv_record_include.php to list newly uploaded files, parse them for csv data, write * to the csv data files, and generate html output. * * @uses csv_newfile_list() * @uses csv_x12_segments() * @uses ibr_era_csv_file_data() * @uses ibr_era_csv_write_data() * @uses ibr_era_csv_files_html() * * @param array $file_array not required, array of new filenames, generated by csv_newfile_list() * @param boolean $html_out whether to generate html files summary table * @param boolean $err_only whether to generate html for denied claims * @return string html output */ function ibr_era_process_new($file_array = NULL, $html_out = TRUE, $err_only = TRUE) { // // get new files from directory and write data to the .csv files // // create html table if $html_out is true // 'mtime', 'dirname', 'fname', 'trace' 'payer' 'claims' $html_str = ""; $ar_csv_data = array(); // $err_ref = ""; // if (is_array($file_array) && count($file_array)) { $ar_newfiles = $file_array; } else { $ar_newfiles = csv_newfile_list("era"); } // cut it off if there are no new files if (count($ar_newfiles) == 0) { // no new files if ($html_out) { // return a message $html_str = "<p>ibr_era_process_new: No new ERA 835 files found</p>"; return $html_str; } else { return FALSE; } } else { $fcount = count($ar_newfiles); } // we have new files foreach ($ar_newfiles as $f_era) { // $era_segments = csv_x12_segments($f_era, "era", FALSE); // if (is_array($era_segments) && count($era_segments['segments']) > 0) { $ar_csv_data[] = ibr_era_csv_file_data($era_segments); // } else { csv_edihist_log("ibr_era_process_new: did not get segments for " . basename($full_path)); $htm_hdrc .= "<p>did not get segments for {$f_era} </p>" . PHP_EOL; continue; } } // now send the data to be written to csv table and html output foreach ($ar_csv_data as $eradata) { $chars = ibr_era_csv_write_data($eradata, $err_ref); //$html_out $html_str .= isset($htm_hdrc) ? $htm_hdrc : ""; // if (is_array($chars)) { if ($chars[0]) { csv_edihist_log("ibr_era_process_new: {$chars[0]} characters written to files_era.csv"); } else { csv_edihist_log("ibr_era_process_new: error writing csv data for files: " . PHP_EOL . $err_ref); $html_str .= "<p>ibr_era_process_new: error writing csv data</p>"; } if ($chars[1]) { csv_edihist_log("ibr_era_process_new: {$chars[1]} characters written to claims_era.csv"); } else { csv_edihist_log("ibr_era_process_new: error writing csv data for claims "); $html_str .= "<p>ibr_era_process_new: error writing csv data</p>"; } } } // if ($html_out) { $html_str .= ibr_era_csv_files_html($ar_csv_data, $err_only); } elseif ($chars[0] && $chars[1]) { $html_str .= "x12_835 ERA files: processed {$fcount} ERA files <br />" . PHP_EOL; } else { $html_str .= "x12_835 ERA: error writing csv data <br />"; } return $html_str; }
/** * Produce an html rendition of one of our files * * this function accepts a file name array from uploads.php, one file only, * or a string file path as the filepath argument * * @uses csv_check_filepath() * @uses csv_parameters() * @uses csv_x12_segments() * @param mixed $filepath string or array path to or name of one of our files * @return string html formatted */ function csv_filetohtml($filepath) { // if (is_array($filepath) && count($filepath) > 0) { $ftkey = array_keys($filepath); $type = $ftkey[0]; $ftestpath = $filepath[$type][0]; $bn = basename($ftestpath); } else { $bn = basename($filepath); $params = csv_parameters("ALL"); // foreach ($params as $ky => $val) { if (!$params[$ky]['regex']) { continue; } if (!preg_match($params[$ky]['regex'], $bn)) { continue; } else { $type = $params[$ky]['type']; //$ftestpath = dirname(__FILE__) . $params[$ky]['directory'].DIRECTORY_SEPARATOR.$bn; $ftestpath = $params[$ky]['directory'] . DIRECTORY_SEPARATOR . $bn; break; } } // } // if (!isset($type)) { csv_edihist_log("csv_filetohtml: failed to type {$bn}"); $out_str = "csv_filetohtml: failed to classify {$bn} <br />" . PHP_EOL; return $out_str; } // $fp = csv_check_filepath($ftestpath, $type); if (!$fp) { csv_edihist_log("csv_filetohtml: could not get good path for {$bn}"); $out_str = "csv_filetohtml: could not get good path for {$bn} <br />" . PHP_EOL; return $out_str; } // different file types if (strpos("|batch|era|f277|f997|999|837|835|ta1", (string) $type)) { // x12 file types $seg_ar = csv_x12_segments($fp, $type); if (is_array($seg_ar) && count($seg_ar['segments'])) { $txt_ar = $seg_ar['segments']; $seg_d = $seg_ar['delimiters']['t']; $fltp = 'x12'; } else { csv_edihist_log("csv_filetohtml: did not get segments for {$bn}"); $out_str = "csv_filetohtml: did not get segments for {$bn} <br />" . PHP_EOL; return $out_str; } } elseif (strpos("|ibr|ebr|dpr|ack", $type)) { // clearinghouse file types (newlines) $fh = fopen($fp, 'r'); if ($fh) { while (($buffer = fgets($fh, 1024)) !== false) { $txt_ar[] = $buffer; } if (!feof($fh)) { csv_edihist_log("csv_filetohtml: failed to open {$bn} <br />"); } fclose($fh); $fltp = 'ibr'; } else { csv_edihist_log("csv_filetohtml: did not get lines for {$bn}"); $out_str = "csv_filetohtml: did not get lines for {$bn} <br />" . PHP_EOL; return $out_str; } } elseif (strpos("|text", $type)) { // clearinghouse readable versions $txt_ar = file_get_contents($fp); $fltp = 'text'; if (!$txt_ar) { csv_edihist_log("csv_filetohtml: did not get contents for {$bn}"); $out_str = "csv_filetohtml: did not get contents for {$bn} <br />" . PHP_EOL; return $out_str; } } else { csv_edihist_log("csv_filetohtml: {$type} was not matched for {$bn}"); $out_str = "csv_filetohtml: {$type} was not matched for {$bn} <br />" . PHP_EOL; return $out_str; } // we have navigated our checks and read the file $out_str = ""; // // now prepare the html page $out_str = ''; // use an ordered list format for x12 and ebr/ibr, regular text for text type if ($fltp == "text") { $out_str .= "<h4>{$bn}</h4>\n\t\t\t<div class=\"filetext\">\n\t\t\t<pre>\n\t\t "; $out_str .= $txt_ar; $out_str .= "\n\t\t </pre>"; } elseif ($fltp == 'x12') { $out_str .= "<h4>{$bn}</h4>\n\t\t\t<div class=\"filetext\">\n\t\t\t<ol>\n\t\t\t"; foreach ($txt_ar as $line) { $out_str .= "\n\t\t\t <li>\n\t\t\t <p>\n\t\t\t {$line}{$seg_d}\n\t\t\t </p>\n\t\t\t </li>\n\t\t\t "; } $out_str .= "</ol>\n\t\t "; } else { $out_str .= "<h4>{$bn}</h4>\n\t\t\t<div class=\"filetext\">\n\t\t\t<ol>\n\t\t\t"; foreach ($txt_ar as $line) { $out_str .= "\n\t\t\t <li>\n\t\t\t <p>\n\t\t\t {$line}\n\t\t\t </p>\n\t\t\t </li>\n\t\t\t "; } $out_str .= "</ol>\n\t\t "; } // $out_str .= "\n\t </div>\n\t </body>\n\t </html>"; // return $out_str; }
/** * create a display for an individual claim status response * * @uses csv_file_by_controlnum() * @uses csv_x12_segments() * @uses ibr_277_bhtblock() * @uses ibr_277_bht_array() * @uses ibr_277_bhthtml() * @param string $filename the filename * @param string $isa13 the isa13 control number for the file * @param string $bht03 the identifier from the 837 bht segment * @param string $clm01 the pid-encounter from the 837 clm segment * @param string $st02 the st number from the 277 file * @return string either an error message or a table with the information from the response */ function ibr_277_response_html($filename = '', $isa13 = '', $bht03 = '', $clm01 = '', $st02 = '') { // create a display for an individual 277 response $html_str = ''; // if (!$filename && !$isa13) { csv_edihist_log("ibr_277_response_html: called with no file arguments"); $html_str .= "Error, no file given<br />" . PHP_EOL; return $html_str; } elseif (!$filename && $isa13) { $fn = csv_file_by_controlnum('f277', $isa13); } elseif ($filename) { $fn = basename($filename); } if ($fn) { // $ar_277_seg = csv_x12_segments($fn, "f277", false); if (!is_array($ar_277_seg)) { $html_str .= "Error in file name or file parsing <br />" . PHP_EOL; return $html_str; } } // if ($bht03 || $clm01 || $st02) { // $sliceparams = ibr_277_bhtblock($ar_277_seg['segments'], $ar_277_seg['delimiters'], $clm01, $bht03, $st02); if ($sliceparams) { $bhtsegs = array_slice($ar_277_seg['segments'], $sliceparams[0], $sliceparams[1]); $bht_ar = ibr_277_bht_array($bhtsegs, $ar_277_seg['delimiters']); $bht_html = ibr_277_bhthtml($bht_ar); if ($bht_html) { $html_str .= $bht_html; } else { $html_str .= "Error encountered in generating display <br />" . PHP_EOL; } } else { $html_str .= "Did not find status for {$bht03} {$clm01} {$st02} in {$fn} <br />" . PHP_EOL; } } else { csv_edihist_log("ibr_277_response_html: called with no claim identifying arguments"); $html_str .= "Error, no claim identification given<br />" . PHP_EOL; } // return $html_str; }
/** * process new 997/999 files * * @uses csv_newfile_list() * @uses csv_verify_file() * @uses csv_parameters() * @param array $file_array -- optional, this array is sent from the ibr_io.php script * @param bool $html_out -- whether to produce and return html output * @param bool $err_only -- whether to generate claim information only for errors (ignored) * @return string */ function ibr_997_process_new($file_array = NULL, $html_out = TRUE, $err_only = TRUE) { // $ret_str = ""; $chr_ct1 = 0; $chr_ct2 = 0; $new_997 = array(); $need_dir = TRUE; // if (is_null($file_array) || empty($file_array)) { // directory will need to be prepended to name $new_997 = csv_newfile_list('f997'); } elseif (is_array($file_array) && count($file_array)) { // files that are not verified will just be ignored foreach ($file_array as $finp) { $fp = csv_verify_file($finp, 'f997'); if ($fp) { $new_997[] = $fp; } } $need_dir = FALSE; } // if (count($new_997) == 0) { $ret_str = "<p>ibr_997_process_new: no new 997/999 files. </p>"; return $ret_str; } else { $f997count = count($new_997); } // $ar_htm = array(); // $params = csv_parameters("f997"); $tdir = dirname(__FILE__) . $params['directory']; // // get batch files parameters, we need the batch_dir $bp = csv_parameters("batch"); $batch_dir = dirname(__FILE__) . $bp['directory']; // foreach ($new_997 as $f997) { // make the file path $fpath = $need_dir ? $tdir . DIRECTORY_SEPARATOR . $f997 : $f997; // get file m-time //$ftime = date('Ymd:His', filemtime($fpath)); // read file into string $f_str = file_get_contents($fpath); if ($f_str) { // transform file contents into segment arrays $ar_seg = csv_x12_segments($fpath, "f997", FALSE); // if (!$ar_seg) { // file was rejected csv_edihist_log("ibr_997_process_new: failed to get segments for {$fpath}"); $ret_str .= "ibr_997_process_new: failed to get segments for {$fpath}</p>" . PHP_EOL; continue; } // parse arrays into data arrays $ar_data = ibr_997_parse($ar_seg); // $ar_data = array("file" => $ar_997file, "rejects" => $ar_reject); // $csv_claims = ibr_997_data_csv($ar_data['file'], 'file'); if ($csv_claims) { $chr_ct1 += csv_write_record($csv_claims, "f997", "file"); } else { csv_edihist_log("ibr_997_process_new: error with files csv array"); } // if (isset($ar_data['claims']) && count($ar_data['claims'])) { // only add to claims_997.csv if there are rejected claims $csv_claims = ibr_997_data_csv($ar_data['claims'], 'claim'); if ($csv_claims) { $chr_ct2 += csv_write_record($csv_claims, "f997", "claim"); } else { csv_edihist_log("ibr_997_process_new: error with claims csv array"); } // } // // save all the ar_datas for html output if ($html_out) { $ar_htm[] = $ar_data; } // } else { $ret_str .= "<p>ibr_997_process_new: failed to read {$fpath} </p>" . PHP_EOL; } } // csv_edihist_log("ibr_997_process_new: {$chr_ct1} characters written to files_997.csv"); csv_edihist_log("ibr_997_process_new: {$chr_ct2} characters written to claims_997.csv"); // if ($html_out) { // generate html output and return that $ret_str .= ibr_997_file_data_html($ar_htm, $err_only); } else { $ret_str .= "x12_999 files: processed {$f997count} x12-999 files <br />"; } // return $ret_str; }
/** * process TA1 acknowledgment files * * @return array */ function ibr_process_ta1($filepath) { // $ar_ackfile = array(); // $seg_ar = csv_x12_segments($filepath, 'ta1', false); if (is_array($seg_ar) && isset($seg_ar['segments'])) { $ar_ta1_segments = $seg_ar['segments']; $ack_mtime = date('Ymd', filemtime($seg_ar['path'])); $elem_d = $seg_ar['delimiters']['e']; $sub_d = $seg_ar['delimiters']['s']; $rep_d = $seg_ar['delimiters']['r']; // $ack_fname = basename($seg_ar['path']); $ack_txt = str_replace('.TA1', '.TAT', $ack_fname); } else { // error getting segments csv_edihist_log("ibr_process_ta1: error getting segments for {$filepath}"); return false; } // $batch_file = ''; $ack_msg = ''; // foreach ($ar_ta1_segments as $segstr) { $seg = explode($elem_d, $segstr); if ($seg[0] == 'ISA') { $ack_mtime = $seg[9]; if (strlen($seg[9]) == 6) { $ack_mtime = '20' . $seg[9]; } $ack_isa13 = strval($seg[13]); } if ($seg[0] == 'TA1') { $ack_ctlnum = strval($seg[1]); $ack_date = '20' . $seg[2]; // date is 6 digits, prepend century $ack_status = $seg[4]; $ack_code = $seg[5]; $ack_msg = $ack_code ? $seg[5] . ": " . ibr_ta1_code($seg[5]) : ''; } } if (isset($ack_ctlnum) && strlen($ack_ctlnum)) { $batch_file = csv_file_by_controlnum('batch', $ack_ctlnum); } // $ar_ackfile["ack_time"] = isset($ack_mtime) ? $ack_mtime : ""; //"date" $ar_ackfile["ack_file"] = isset($ack_fname) ? $ack_fname : ""; //"file" $ar_ackfile["ack_isa13"] = isset($ack_isa13) ? $ack_isa13 : ""; // $ta1 isa13 $ar_ackfile["ack_ctrl"] = isset($ack_ctlnum) ? $ack_ctlnum : ""; //"batch_ctrl" $ar_ackfile["ack_code"] = isset($ack_code) ? $ack_code : ""; // error code $ar_ackfile["ack_msg"] = isset($ack_msg) ? $ack_msg : ""; $ar_ackfile["ack_batch"] = $batch_file ? $batch_file : "batch not identified"; $ar_ackfile["ack_ftxt"] = $ack_txt ? $ack_txt : ""; // return $ar_ackfile; }