e3149d99acd1273d3005b8de4bef2ae3f5a3485a
[openemr.git] / library / edihistory / ibr_277_read.php
blobe3149d99acd1273d3005b8de4bef2ae3f5a3485a
1 <?php
2 /**
3 * ibr_277_read.php
4 *
5 * read x12 277 claim status responses, especially the 277CA variety
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 3 or later.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. You should have received
15 * a copy of the GNU General Public License along with this program;
16 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 * <http://opensource.org/licenses/gpl-license.php>
20 * @author Kevin McCormick
21 * @link: http://www.open-emr.org
22 * @package OpenEMR
23 * @subpackage ediHistory
26 // /**
27 // * a security measure to prevent direct web access to this file
28 // */
29 // if (!defined('SITE_IN')) die('Direct access not allowed!');
33 /**
34 * get the segments or array_slice parameters for ISA...IEA in a 277 file
36 * @todo adapt this to general purpose x12 section getter
38 * @uses csv_verify_file()
39 * @uses csv_x12_segments()
40 * @param string $filename name of file
41 * @param string $isa13 the ISA control number
42 * @param bool $slice_params whether to return array_slice() parameters or the segments
43 * @return array
44 */
45 function ibr_277_isa_block($filename, $isa13, $slice_params=false) {
47 $isa_str = '';
48 $srchval = strval($isa13);
49 // get segments
50 $x12seg = csv_x12_segments($filename, 'f277', false);
51 if ( !$x12seg || ! isset($x12seg['segments']) ) {
52 $isa_str .= "ibr_277_isa_block: failed to get segments for ".basename($filename).PHP_EOL;
53 csv_edihist_log("ibr_277_isa_block: failed to get segments for $filename");
54 return $isa_str;
57 $elem_d = $x12seg['delimiters']['e'];
58 $isa277 = array();
59 $isa_slice = array();
60 $isa_pos = 0;
61 $idx = -1;
62 foreach($x12seg['segments'] as $segstr) {
63 $idx++;
64 if (substr($segstr, 0, 4) == 'ISA'.$elem_d) {
65 $seg = explode($elem_d, $segstr);
66 $isfound = (strval($seg[13]) == $srchval);
67 $isa_pos = $idx;
70 if ($isfound && !$slice_params) { $isa277[] = $segstr; }
72 if (substr($segstr, 0, 4) == 'IEA'.$elem_d) {
73 $seg = explode($elem_d, $segstr);
74 if (strval($seg[2]) == $srchval) {
75 $isa_slice['start'] = $isa_pos;
76 $isa_slice['count'] = $idx - $isa_pos + 1;
77 //$isfound = false;
78 break;
83 if ( !count($isa277) && !count($isa_slice) ) {
84 $isa_str .= "ibr_277_isa_block: did not find $isa13 in " . basename($filename).PHP_EOL;
85 csv_edihist_log("ibr_277_isa_block: did not find $isa13 in $filename");
86 return $isa_str;
89 if ($slice_params) {
90 return $isa_slice;
91 } else {
92 return $isa277;
97 /**
98 * Selected values from $ar277['claim'] array for claims_277.csv
100 * these are for initial batch return files, basically saying the claims are accepted
101 * for "adjudication" or rejected due to some error or omission
102 * close match to Availity ebr|ibr files, which are derived from these
103 * This uses an edit to the OpenEMR billing_process.php script to create
104 * a unique BHT03 id number, since that is how the claims are identified
106 * @uses ibr_batch_by_ctln()
107 * @param array $ar_277 the array from {@see ibr_277_parse()}
108 * @return array
110 function ibr_277_csv_claim_data($ar_277_clm) {
112 // the $ar_277_vals [ $ar277['claim'] ] array:
113 // <pre>
114 // $arRSP[$isa_ct]['key']
115 // ['BHT'] ['isa_id']['gs06']['iea02']
117 // $arRSP["claim"][$isa_ct]=>["ISA13"]["GS04"]["GS06"]["IEA02"]
118 // =>['BHT']['bht_ct']['key']
119 // =>['ENV"]=>['BHT01']['BHT02']['BHT03']['BHT04']
120 // ['BHT06']["FILE"]["ISA13"]["ST02"]["SE01"]
121 // =>['A']=>['NM101']["NM102"]["NM103"]["NM104"]["NM105"]
122 // ["NM107"]["NM108"]["NM109"]["TRN01"]["TRN02"]
123 // ["DTP03050"]["DTP03009"]
124 // =>['B']=>['NM101']["NM102"]["NM103"]["NM104"]["NM105"]
125 // ["NM107"]["NM108"]["NM109"]["TRN01"]["TRN02"]
126 // ["STC011"]["STC012"]["STC013"]["STC014"]
127 // ["STC02"]["STC03"]["STC04"]["QTY01"]["QTY02"]
128 // ["AMT01"]["AMT02"]
129 // =>['C']=>['NM101']["NM102"]["NM103"]["NM104"]["NM105"]
130 // ["NM107"]["NM108"]["NM109"]["TRN01"]["TRN02"]
131 // ["REFTJ"]
132 // =>['D']=>['NM101']["NM102"]["NM103"]["NM104"]["NM105"]
133 // ["NM107"]["NM108"]["NM109"]["TRN01"]["TRN02"]
134 // ["REF1K"]["REFD9"]["DTP03FROM"]["DTP03TO"]
135 // =>["STC"][i]=>["STC011"]["STC012"]["STC013"]
136 // ["STC014"]["STC02"]["STC03"]["STC04"]
137 // </pre>
138 if (!is_array($ar_277_clm) || count($ar_277_clm) == 0 ) {
139 return FALSE;
142 $csv_ar = array();
144 foreach($ar_277_clm['BHT'] as $bht) {
145 $status = ""; $message = ""; $bfl = ""; $ctlnum = ""; $stnum = "";
146 // this is the BHT03 value from the batch file
147 $bt_bht03 = strval($bht['B']['TRN02']);
149 $st_277 = $bht['ENV']['ISA13'].'_'.$bht['ENV']['ST02']; // this is to find the response later
150 $file_277 = $bht['ENV']['FILE'];
151 $payer_name = isset($bht['A']['NM103'] ) ? $bht['A']['NM103'] : "Unknown Payer";
152 // if no claim_id, but ['TRN02'], find the pid-encounter with batch file and st02
153 if ( isset($bht['D']['REF1K']) ) {
154 $claim_id = $bht['D']['REF1K'];
155 } elseif (isset($bht['D']['REFD9'])) {
156 $claim_id = $bht['D']['REFD9'];
157 } elseif (isset($bht['D']['REFEA'])) {
158 $claim_id = $bht['D']['REFEA'];
159 } elseif (isset($bht['D']['REFBLT'])) {
160 $claim_id = $bht['D']['REFBLT'];
161 } elseif (isset($bht['D']['REFEJ'])) {
162 $claim_id = $bht['D']['REFEJ'];
163 } elseif (isset($bht['D']['REFXZ'])) {
164 $claim_id = $bht['D']['REFXZ'];
165 } elseif (isset($bht['D']['REFVV'])) {
166 $claim_id = $bht['D']['REFVV'];
167 } else {
168 $claim_id = "NF";
170 $pt_name = $bht['D']['NM103'] . ", " . $bht['D']['NM104'];
171 $date = $bht['D']['DTP03FROM'];
172 $pid = $bht['D']['TRN02']; //$pidenc[0]
173 foreach ($bht['D']['STC'] as $stc) {
175 $status = $stc['STC011'];
177 if ($stc['STC011'] == "A1" ) {
178 $status = "A1 Ack";
179 } elseif ($stc['STC011'] == "A2" ) {
180 $status = "A2 Acpt";
181 } elseif ($stc['STC011'] == "A3" ) {
182 $status = "A3 Rej";
183 } elseif ($stc['STC011'] == "A4" ) {
184 $status = "A4 Nfnd";
185 } elseif ($stc['STC011'] == "A5" ) {
186 $status = "A5 Split";
187 } elseif ($stc['STC011'] == "A6" ) {
188 $status = "A6 Rej";
189 } elseif ($stc['STC011'] == "A7" ) {
190 $status = "A7 Rej";
191 } elseif ($stc['STC011'] == "A8" ) {
192 $status = "A8 Rej";
193 } elseif ($stc['STC011'] == "DO" ) {
194 $status = "DO Fail";
196 if ($stc['STC03'] == "15") { $status .= " Resubmit"; }
198 $message .= isset($stc['STC12']) ? trim($stc['STC12']) . " " : "";
200 // revised csv layout
201 //['f277']['claim'] = array('PtName', 'SvcDate', 'clm01', 'Status', 'st_277', 'File_277', 'payer_name', 'claim_id', 'bht03_837');
202 $csv_ar[] = array('pt_name'=>$pt_name, 'date'=>$date, 'pid'=>$pid, 'status'=>$status,
203 'st_277'=>$st_277, 'file_277'=>$file_277, 'payer_name'=>$payer_name,
204 'claim_id'=>$claim_id, 'bht03_837'=>$bt_bht03, 'message'=>$message);
206 }// end foreach ($ar_277_vals as $isa)
208 return $csv_ar;
213 * write data to csv file
215 * @deprecated
216 * @uses csv_write_record()
217 * @param array $ar_claim_data the data array, either file data or claim data
218 * @param string $type either claim or file, claim if omitted
219 * @return int character count from fputcsv()
221 function ibr_277_write_csv($ar_data, $type = "claim") {
223 $ct = ($type == "claim") ? 'claim' : 'file';
224 $rslt = csv_write_record($ar_data, "f277", $ct);
225 return $rslt;
229 * create an html string for a table to display in a web page
231 * @param $ar_data array produced by function ibr_ebr_data_ar
232 * @param $err_only boolean ignore claim information if no 3e subarray is in the claim data
233 * @return string
235 function ibr_277_html ($ar_data, $err_only=FALSE) {
236 //$ar_hd = $ar_data['head'];
237 //$ar_cd = $ar_data['claims'];
238 $idx = 0;
239 $idf = 0;
240 $has3 = FALSE;
241 $hasclm = FALSE;
242 $clm_html = "";
243 $str_html = "";
245 $dtl = ($err_only) ? "Errors only" : "All included claims";
246 //$ar_col_hdr = array('mtime', 'directory', 'file_name', 'text_name', 'claim_ct', 'reject');
247 // the table heading for files'mtime', 'directory', 'file_name', 'claim_ct', 'amt_accpt','reject', 'amt_rej'
248 $f_hdg = "<table cols=6 class=\"f277\">
249 <caption>277 Files Summary {$dtl} </caption>
250 <thead>
251 <tr>
252 <th>Date</th><th>277 File</th><th>Claims</th><th>Amt Total</th><th>Rejects</th><th>Amt Rej</th>
253 </tr>
254 </thead>
255 <tbody>";
257 // the details table heading'pt_name''date''pid''status''st_277''claim_id''payer_name''message'
258 $clm_hdg = "<table cols=6 class=\"f277\">
259 <thead>
260 <tr>
261 <th>Patient Name</th><th>Date</th><th>PtCtln</th><th>Status</th><th>Payer Name</th><th>Claim No</th>
262 </tr>
263 <tr>
264 <th colspan=6 align=left>Message</th>
265 </tr>
266 </thead>
267 <tbody>";
269 // start with the table heading
270 $str_html .= $f_hdg;
272 foreach ($ar_data as $ardt) {
273 // alternate colors
274 $bgf = ($idf % 2 == 1 ) ? 'fodd' : 'feven';
275 $idf++;
277 $ar_hd = $ardt['file'];
278 $ar_cd = $ardt['claim'];
279 // if any individual claims detail is to be output
280 // a claims table was inserted, so put the files heading in
281 if ($hasclm) { $str_html .= $f_hdg; }
282 // reset variables for whether there are claims
283 $clm_html = "";
284 $has3 = FALSE;
285 $hasclm = FALSE;
287 if (isset($ardt['file'])) {
288 // 'filetime''filename''isa13_277''claim_ct''amt_accpt''claim_rct''amt_rej'
290 $str_html .= "
291 <tr class=\"{$bgf}\">
292 <td>{$ardt['file']['filetime']};</td>
293 <td><a href=\"edi_history_main.php?fvkey={$ardt['file']['filename']}\" target=\"_blank\">{$ardt['file']['filename']}</a></td>
294 <td>{$ardt['file']['claim_ct']}</td>
295 <td>{$ardt['file']['amt_accpt']}</td>
296 <td>{$ardt['file']['claim_rct']}</td>
297 <td>{$ardt['file']['amt_rej']}</td>
298 </tr>";
300 if (isset($ardt['claim']) ) {
301 foreach ($ardt['claim'] as $val) {
302 if ($err_only && $val['message'] == "" ) { continue; }
303 $bgc = ($idx % 2 == 1 ) ? 'odd' : 'even';
304 $hasclm = TRUE;
305 $clm_html .= "<tr class=\"{$bgc}\">
306 <td>{$val['pt_name']}</td>
307 <td>{$val['date']}</td>
308 <td><a class='btclm' target='_blank' href='edi_history_main.php?fvbatch={$val['bht03_837']}&btpid={$val['pid']}'>{$val['pid']}</td>
309 <td><a class='clmstatus' target='_blank' href='edi_history_main.php?rspfile={$val['file_277']}&pidenc={$val['pid']}&rspstnum={$val['st_277']}'>{$val['status']}</td>
310 <td>{$val['payer_name']}</td>
311 <td>{$val['claim_id']}</td>
312 </tr>
313 <tr class=\"{$bgc}\">
314 <td colspan = 7>{$val['message']}</td>
315 </tr>";
316 $idx++;
319 // if there were any claims detailed
320 if ( $hasclm && strlen($clm_html) ) {
321 $str_html .= $clm_hdg.$clm_html.PHP_EOL."</tbody></table>".PHP_EOL;
324 // finish the table
325 $str_html .= "</tbody></table>";
327 return $str_html;
332 * Parse x12 277 file into array
334 * The x12 277 claim status response file contains many fields that are useful for
335 * different purposes, so there is a lot of surplus information depending on your
336 * reason for viewing the file.
338 * <pre>
339 * Return array has keys 'file' and 'claim'
340 * The 'claim' array is detailed here:
341 * $arRSP[$isa_ct]['key']
342 * ['BHT'] ['isa_id']['gs06']['iea02']
344 * $arRSP[$isa_ct]['BHT']['bht_ct']['key']
345 * ['ENV"] ['A'] ['B'] ['C'] ['D']['BHT01']['BHT02']['BHT03']['BHT04']['BHT06']
347 * $arRSP[$isa_ct]['BHT']['bht_ct']['ENV"]
348 * ['ISA13'] ['ST02'] ['SE01'] ['FILE']
350 * $arRSP[$isa_ct]['BHT']['bht_ct']['A'] (sender -- insurance company or clearinghouse)
351 * ['NM103']['NM109']['TRN02']['DTP03050']['DTP03009']['PER01']['PER02']['PER03']['PER04']
353 * $arRSP[$isa_ct]['BHT']['bht_ct']['B'] (receiver -- practice or biller)
354 * ['STC011']['STC012']['STC013']['STC014']['STC02']['STC03']['STC04']['STC05']['STC06']
355 * ['STC07']['STC08'] ['STC09']['QTY01']['QTY02']['AMT01']['AMT02']
357 * $arRSP[$isa_ct]['BHT']['bht_ct']['C'] (provider -- practice or individual)
358 * ['NM103']['NM104']['NM105']['NM107']['NM108']['NM109']['TRN01'] ['TRN02']
359 * ['REF01']['REF02']['QTY01']['QTY02']['AMT01']['AMT02']
361 * $arRSP[$isa_ct]['BHT']['bht_ct']['D'] (patient -- individual)
362 * ['NM102']['NM103']['NM104']['NM105']['NM107']['NM108']['NM109']['TRN01']['TRN02']
363 * ['REF1K']['REFD9']['REFEA']['REFBLT']['REFEJ']['REFXZ']['REFVV']
364 * ['DTP03FROM'] ['DTP03TO']
366 * $arRSP[$isa_ct]['BHT']['bht_ct']['D']['STC'][stccount]['key']
367 * ['STC011']['STC012']['STC013']['STC014']['STC011']['STC012']
368 * ['STC02']['STC03']['STC04']['STC05']['STC06']['STC07']['STC08']['STC09']
369 * ['STC101']['STC102']['STC103']['STC104']
370 * ['STC111']['STC112']['STC113']['STC114']
372 * $arRSP[$isa_ct]['BHT']['bht_ct']['D']['SVC'][svccount]['key']
373 * ['SVC011']['SVC012']['SVC013']['SVC014']['SVC015']['SVC016']['SVC017']
374 * ['SVC02']['SVC03']['SVC04']['SVC05']['SVC06']['SVC07']
375 * ['STC011']['STC012']['STC013']['STC014']
376 * ['STC02']['STC03']['STC04']['STC05']['STC06']['STC07']['STC08']['STC09']
377 * ['STC101']['STC102']['STC103']['STC104']
378 * ['STC111']['STC112']['STC113']['STC114']
379 * ['STC12']
380 * </pre>
382 * @todo refactor array design -- does not account well enough for x12 controls or references
383 * @param array $ar_segments -- from ibr_277_process_new and csv_record_include.php
384 * @return array
386 function ibr_277_parse($ar_segments) {
389 // read each segment and parse for desired data
391 // $ar_vals['hl_prv']
392 // ['prv_name']['prv_id']
393 // $ar_vals['hl_prv']['clm_ct']
395 // ISA*00
396 // GS*HN
397 // - ST*277
398 // 0085 expect - BHT*0085
399 // HL*1 NM1*PR TRN*1 DTP*050 DTP*009 // HL03 NM103 NM109
400 // HL*2 NM1*41 TRN*2 STC*A1 QTY*90*1 AMT*YU //
401 // HL*3 NM1*85 TRN*1 REF*TJ QTY*QA*1 AMT*YU
402 // HL*4 NM1*QC TRN*2 STC*A1 REF*1K REF*D9 DTP*472
403 // - repeat BHT series
404 // - SE*27
405 // GE*26
406 // IEA*1
408 if (is_array($ar_segments) && count($ar_segments['segments']) ) {
409 $fdir = dirname($ar_segments['path']);
410 $fname = basename($ar_segments['path']);
411 $fmtime = date('Ymd', filemtime($ar_segments['path']) );
413 $ar_277_segments = $ar_segments['segments'];
415 $elem_d = $ar_segments['delimiters']['e'];
416 $rep_d = $ar_segments['delimiters']['r'];
417 $sub_d = $ar_segments['delimiters']['s'];
418 } else {
419 csv_edihist_log("ibr_277_parse: error invalid segments array");
420 return FALSE;
423 //$arRSP = array();
424 $ar277 = array();
426 $bct = -1;
427 $ict = -1;
428 $st_ct = 0;
429 $svc_ct = 0;
430 $clm_ct = 0;
431 $rej_ct = 0;
432 $amt_accpt = 0;
433 $amt_rej = 0;
434 // $clm_ct = 0;
435 $hl_id = "";
436 $hl_pyr = "0";
437 $hl_parent = "0";
438 $hl_code = "";
439 $stchlct = ""; // keep track of which HL is operating on the loop 2000D STC
441 $loopid = "0";
443 foreach($ar_277_segments as $segline) {
444 // explode the segment into an array of elements
446 $seg = explode($elem_d, $segline);
447 // set counters, loops, etc. here
448 // count segments to verify ST--SE blocks
449 // $st_seg_ct is set to 1 in "ST"
450 $st_seg_ct = isset($st_seg_ct) ? $st_seg_ct+1 : 0;
452 if ($seg[0] == "ISA") {
453 // I have x12-277 files from Availity with multiple ISA--IEA segment blocks
454 $ict++;
456 $isa13 = $seg[13];
457 $fmtime = '20'.strval($seg[9]);
459 //$ar277[$ict]['claim']['ISA13'] = $seg[13];
460 // reset the ST count and BHT count
461 $st_ct = 0;
462 $st_seg_ct = 0;
463 $bct = -1;
465 $loopid = "0";
466 // paranoia check
467 if ($rep_d != $seg[11] ) {
468 $rep_d = $seg[11];
470 if ($sub_d != $seg[16] ) {
471 $sub_d = $seg[16];
474 continue;
477 if ($seg[0] == "IEA") {
478 //$ar277[$ict]['claim']['IEA02'] = $seg[2];
479 if ($seg[2] != $isa13) {
480 echo "ibr_277_read: ISA Mismatch IEA {$seg[2]} vs ISA $isa13 <br />" . PHP_EOL;
482 // consider indexing file array on ISA -- will increase csv table x2 or x3
483 //$ar_col_hdr = array('mtime', 'directory', 'file_name', 'claim_ct', 'amt_accpt','reject', 'amt_rej');
484 $ar277[$ict]['file']['filetime'] = $fmtime;
485 $ar277[$ict]['file']['filename'] = $fname;
486 $ar277[$ict]['file']['isa13_277'] = $isa13;
487 $ar277[$ict]['file']['claim_ct'] = $clm_ct;
488 $ar277[$ict]['file']['amt_accpt'] = $amt_accpt;
489 $ar277[$ict]['file']['claim_rct'] = $rej_ct;
490 $ar277[$ict]['file']['amt_rej'] = $amt_rej;
492 $amt_accpt = 0; $amt_rej = 0; $clm_ct = 0; $rej_ct =0;
493 $isa13 = ''; $fmtime = '';
494 continue;
497 if ($seg[0] == "GS") {
498 $fmtime = strval($seg[4]);
499 //$ar277[$ict]['claim']['GS04'] = $seg[4]; // File date
500 //$ar277[$ict]['claim']['GS06'] = $seg[6]; // Group Control Number
501 $gs04 = strval($seg[4]);
502 $gs06 = strval($seg[6]);
504 continue;
507 if ($seg[0] == "ST") {
509 $st01 = $seg[1]; //R 277 Transaction Set Identifier Code
510 $st02 = $seg[2]; //R Transaction Set Control Number
511 $st03 = $seg[3]; //R 005010X214 Implementation Convention Reference
513 $st_seg_ct = 1; // the ST segment is included in the segment count
514 $st_ct++;
515 $stc_ct = 0; // STC segments (status) at claim level may repear
517 continue;
520 if ($seg[0] == "SE") {
521 // check segment count
522 $se01 = $seg[1];
523 $se02 = $seg[2];
524 if ($se01 != $st_seg_ct) {
525 echo "ibr_277_read: SE segment count mismatch $se01 $st_seg_ct <br />" . PHP_EOL;
527 if ($se02 != $st02) {
528 echo "ibr_277_read: SE ST id mismatch $se02 $st02 <br />" . PHP_EOL;
530 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['SE01'] = $se01;
532 continue;
535 if ($seg[0] == "BHT") {
536 // There may be many BHT's Begin Hierarchical Transaction
538 $bct++;
539 // define the HL structure of the transaction set
540 // 0010 Information Source, Information Receiver, Provider of Service, Subscriber, Dependent
541 // 0085 (Guess ?? ) Information Source, Information Receiver, Provider of Service, Patient
542 //['BHT02']['BHT03']['BHT04']['BHT06']
543 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['BHT01'] = $seg[1]; //R 0010 0085 Hierarchical Structure Code
544 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['BHT02'] = $seg[2]; //R 08 (status) TRANSACTION SET PURPOSE CODE
545 // issue with the Originator reference is that it apparently is created by Availity
546 // and is not our batch file control number
547 // relating back to our claims will require the encounter number (2000D TRN03)
548 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['BHT03'] = $seg[3]; //R Originater REFERENCE IDENTIFICATION
549 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['BHT04'] = $seg[4]; //R CCYYMMDD Transaction Set Creation Date
550 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['BHT06'] = $seg[6]; //R DG CH TH Transaction Type Code
551 //['ISA13'] ['ST02'] ['SE01'] ['FILE']
552 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['FILE'] = $fname; //basename($fp);
553 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['ISA13'] = $isa13;
554 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['GS04'] = $gs04;
555 $ar277[$ict]['claim']['BHT'][$bct]['ENV']['ST02'] = $st02;
557 continue;
560 if ($seg[0] == "HL") {
561 // loop 2000A, 2000B, 2000C, 2000D ??
562 // set the $ky variable acording to HL level
564 $hl01 = isset($seg[1]) ? $seg[1] : "";; // Hierarchical ID Number
565 $hl02 = isset($seg[2]) ? $seg[2] : "";; // Hierarchical Parent ID Number
566 // 20 Information source Payer loop 2000A
567 $hl03 = isset($seg[3]) ? $seg[3] : "";; // Hierarchical Level Code
568 $hl04 = isset($seg[4]) ? $seg[4] : ""; // 1 Hierarchical Child Code
570 // HL*1**20*1~ HL*1 NM1*PR TRN*1 DTP*050 DTP*009
571 if ($hl03 == "20") {
572 $loopid = "2000A";
573 $ky = 'A';
575 // HL*2*1*21*1~
576 if ($hl03 == "21") {
577 $loopid = "2000B";
578 $ky = 'B';
580 // HL*3*2*19*1~
581 if ($hl03 == "19") {
582 $loopid = "2000C";
583 $ky = 'C';
585 // varying levels in loop 2000D
586 // HL*4*3*PT~ patient
587 // HL*4*3*22*1~ subscriber
588 // HL*5*4*23*0~ dependent
589 if ($hl03 == "PT" || $hl03 == "22" || ($hl03 == "23" && $loopid != "2000D") ) {
590 // expect 277CA, but for 277, there is possibility of loop 2000E
591 if ($hl03 == "23" && $loopid == "2000D") {
592 $loopid = "2000E";
593 $ky = 'E';
595 $loopid = "2000D";
596 $ky = 'D';
598 $lp2100D = FALSE;
599 $lp2200D = FALSE;
600 $lp2220D = FALSE;
602 $stc_ct = 0; // multiple STC segments are possible at the patient level
603 $stchlct = $hl01; // keep track of which HL is operating on the loop 2000D STC
604 $svc_ct = 0; // this is for the unlikely event that multiple 2220D loops appear
607 // debug
608 // check for some things in HL segment
609 if (strpos("|20|21|19|PT|22|23", $hl03) == 0) {
610 echo "ibr_277: unexpected HL03 {$seg[3]} in $segline <br />" . PHP_EOL;
612 if ( strpos("|PT|22|23", $hl03) && $hl04 > 0 ) {
613 echo "ibr_277: child HL segment follows HL level $hl03 in $segline " . basename($fp) . PHP_EOL;
616 // true if the parent matches the preceeding HL ID
617 $same_prv = ($seg[2] == $hl_id);
618 // if HL02 is blank, then we are with a new provider
619 $hl_id = $seg[1];
620 $hl_parent = $seg[2];
621 $hl_code = $seg[3];
623 continue;
625 // testing
626 if ($loopid == "2000A" && $ky != 'A') { echo "HL loop mismatch, $hl_code $loopid $ky $segline $fname<br />" . PHP_EOL; }
627 if ($loopid == "2000B" && $ky != 'B') { echo "HL loop mismatch, $hl_code $loopid $ky $segline $fname<br />" . PHP_EOL; }
628 if ($loopid == "2000C" && $ky != 'C') { echo "HL loop mismatch, $hl_code $loopid $ky $segline $fname<br />" . PHP_EOL; }
629 if ($loopid == "2000D" && $ky != 'D') { echo "HL loop mismatch, $hl_code $loopid $ky $segline $fname<br />" . PHP_EOL; }
632 // payer or clearinghouse level HL*1**20*1~
633 if ($seg[0] == "NM1") {
634 // PR payer name AY clearinghouse
635 // expect payer, but clearinghouse may respond here
636 $q = ($seg[1] == "PR") ? $seg[1] : "unexpected qualifier in NM1 2000A: {$seg[1]}";
638 // if ($loopid == "2000A") { $loopid = "2100A" }
639 // if ($loopid == "2000B") { $loopid = "2100B" }
640 // if ($loopid == "2000C") { $loopid = "2100C" }
641 // if ($loopid == "2000D") { $loopid = "2100D" }
642 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM101'] = $seg[1];
643 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM102'] = $seg[2];
644 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM103'] = $seg[3]; // Last name or company name
645 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM104'] = $seg[4]; // first name or blank
646 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM105'] = $seg[5]; // middle name or blank
647 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM107'] = $seg[7]; // name suffix
648 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM108'] = $seg[8]; // "FI" or "XX"
649 $ar277[$ict]['claim']['BHT'][$bct][$ky]['NM109'] = $seg[9]; // tax id, NPI, payerID
651 continue;
654 if ($seg[0] == "TRN") {
655 // if ($loopid == "2100B") { $loopid = "2200B" }
656 // if ($loopid == "2100C") { $loopid = "2200C" }
657 // if ($loopid == "2100D") { $loopid = "2200D" }
658 $ar277[$ict]['claim']['BHT'][$bct][$ky]['TRN01'] = $seg[1];
659 $ar277[$ict]['claim']['BHT'][$bct][$ky]['TRN02'] = $seg[2]; // at HL 4, TRN02 is pid-encounter ['D']['TRN02']
661 continue;
664 if ($seg[0] == "DTP") {
665 if ($seg[1] == "050") { $ar277[$ict]['claim']['BHT'][$bct][$ky]['DTP03050'] = $seg[3]; }
666 if ($seg[1] == "009") { $ar277[$ict]['claim']['BHT'][$bct][$ky]['DTP03009'] = $seg[3]; }
667 if ($seg[1] == "472") {
668 if ($seg[2] == "RD8") {
669 // service dates
670 $sp = strpos($seg[3], "-");
671 $ar277[$ict]['claim']['BHT'][$bct][$ky]['DTP03FROM'] = ($sp) ? substr($seg[3], 0, $sp) : $seg[3];
672 $ar277[$ict]['claim']['BHT'][$bct][$ky]['DTP03TO'] = ($sp) ? substr($seg[3], $sp+1) : $seg[3];
674 if ($seg[2] == "D8") {
675 $ar277[$ict]['claim']['BHT'][$bct]['D']['DTP03FROM'] = $seg[3];
679 continue;
682 if ($seg[0] == "PER") {
683 $ar277[$ict]['claim']['BHT'][$bct][$ky]['PER01'] = $seg[1]; //R IC Contact Function Code R
684 $ar277[$ict]['claim']['BHT'][$bct][$ky]['PER02'] = $seg[2]; //S Payer Contact Name
685 $ar277[$ict]['claim']['BHT'][$bct][$ky]['PER03'] = $seg[3]; //R ED, EM, TE, FX Communication Number Qualifier
686 $ar277[$ict]['claim']['BHT'][$bct][$ky]['PER04'] = $seg[4]; //R Communication Number
688 continue;
689 } // "PER"
691 if ($seg[0] == "QTY" && $loopid == "2000B") {
692 $ar277[$ict]['claim']['BHT'][$bct]['B']['QTY01'] = $seg[1]; // QTY TOTAL ACCEPTED QUANTITY "90" 2200B QTY TOTAL REJECTED QUANTITY "AA" 2200B
693 $ar277[$ict]['claim']['BHT'][$bct]['B']['QTY02'] = $seg[2]; // count of accepted or rejected items
695 continue;
697 if ($seg[0] == "AMT" && $loopid == "2000B") {
698 $ar277[$ict]['claim']['BHT'][$bct]['B']['AMT01'] = $seg[1]; // AMT TOTAL ACCEPTED AMOUNT "YU" 2200B AMT TOTAL REJECTED AMOUNT "YY"
699 $ar277[$ict]['claim']['BHT'][$bct]['B']['AMT02'] = $seg[2]; // quantity, i.e. dollars, accepted or rejected
701 continue;
704 if ($seg[0] == "STC" && $loopid == "2000B") {
705 //PROVIDER STATUS INFORMATION
706 //STC*A1:20*20120217*WQ*65~
707 if ( strpos($seg[1], $sub_d) ) {
708 $sp = strpos($seg[1], $sub_d);
709 $stc01 = explode($sub_d, $seg[1]); // A1:20 is expected here
710 if ( is_array($stc01) ) {
711 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC011'] = isset($stc01[0]) ? $stc01[0] : ""; //STC01-1 Health Care Claim Status Category Code AN 01/30/12 R D0, E
712 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC012'] = isset($stc01[1]) ? $stc01[1] : ""; //STC01-2 Health Care Claim Status Code AN 01/30/12 R
713 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC013'] = isset($stc01[2]) ? $stc01[2] : ""; //STC01-3 Entity Identifier Code ID 02/03/12 S     1P
714 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC014'] = isset($stc01[3]) ? $stc01[3] : ""; //STC01-4 Code List Qualifier Code ID 01/03/12 N/U  
715 } else {
716 $ar277[$ict]['claim']['BHT'][$bct]['prv_STC011'] = isset($seg[1]) ? $seg[1] : "";
720 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC02'] = isset($seg[2]) ? $seg[2] : ""; //STC02 Status Information Effective Date DT 08/08/12 R     CCYYMMDD
721 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC03'] = isset($seg[3]) ? $seg[3] : ""; //STC03 Action Code ID 01/02/12 N/U
722 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC04'] = isset($seg[4]) ? $seg[4] : ""; //STC04 Monetary Amount R 01/18/12 N/U
723 // no segments beyond STC04 are expected in loop 2200B STC
724 if ( !isset($seg[5]) ) { continue; }
726 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC05'] = isset($seg[5]) ? $seg[5] : ""; //STC05 Monetary Amount R 01/18/12 N/U
727 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC06'] = isset($seg[6]) ? $seg[6] : ""; //STC06 Date DT 08/08/12 N/U  
728 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC07'] = isset($seg[7]) ? $seg[7] : ""; //STC07 Payment Method Code ID 03/03/12 N/U
729 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC08'] = isset($seg[8]) ? $seg[8] : ""; //STC08 Date DT 08/08/12 N/U  
730 $ar277[$ict]['claim']['BHT'][$bct]['B']['STC09'] = isset($seg[9]) ? $seg[9] : ""; //STC09 Check Number AN 01/16/12 N/U
732 continue;
733 } // end if ($seg[0] == "STC") in loop 2200B
735 if ($seg[0] == "STC" && $loopid == "2000D") {
736 // loop 2200D Subscriber / Patient
737 if ( strpos($seg[1], $sub_d) ) {
738 $sp = strpos($seg[1], $sub_d);
739 $stc01 = explode($sub_d, $seg[1]); // 2200D STC01-1 Health Care Claim Status Category Code
741 if ( is_array($stc01) ) { // "A2" Accept , "A3" "A7" Reject, or “R3” Warning 1/30
742 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC011'] = isset($stc01[0]) ? $stc01[0] : ""; //STC01-1 Health Care Claim Status Category Code AN 01/30/12 R D0, E
743 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC012'] = isset($stc01[1]) ? $stc01[1] : ""; //STC01-2 Health Care Claim Status Code AN 01/30/12 R
744 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC013'] = isset($stc01[2]) ? $stc01[2] : ""; //STC01-3 Entity Identifier Code ID 02/03/12 S     1P
745 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC014'] = isset($stc01[3]) ? $stc01[3] : ""; //STC01-4 Code List Qualifier Code ID 01/03/12 N/U  
746 } else {
747 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC011'] = isset($seg[1]) ? $seg[1] : "";
751 // interject some tallys here, for the files array
752 if ($loopid == "2000D" && $stchlct == $hl01) {
753 $clm_ct++;
754 if (strpos("|A1|A2|A5|", $stc01[0]) === FALSE) { $rej_ct++; }
755 $amt_accpt += $seg[4];
756 if ($seg[3] == "U") { $amt_rej += $seg[4]; }
757 $stchlct = "yes";
761 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC02'] = isset($seg[2]) ? $seg[2] : ""; //STC02 Status Information Effective Date DT 08/08/12 R CCYYMMDD
762 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC03'] = isset($seg[3]) ? $seg[3] : ""; //STC03 Action Code ID 01/02/12 N/U 15 Correct and Resubmit Claim
763 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC04'] = isset($seg[4]) ? $seg[4] : ""; //STC04 Monetary Amount R 01/18/12 N/U
765 // cut this off if there are no more elements, often only 5
766 if ( !isset($seg[5]) ) { continue; }
768 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC05'] = isset($seg[5]) ? $seg[5] : ""; //STC05 Monetary Amount R 01/18/12 N/U
769 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC06'] = isset($seg[6]) ? $seg[6] : ""; //STC06 Date DT 08/08/12 N/U
770 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC07'] = isset($seg[7]) ? $seg[7] : ""; //STC07 Payment Method Code ID 03/03/12 N/U  
771 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC08'] = isset($seg[8]) ? $seg[8] : ""; //STC08 Date DT 08/08/12 N/U
772 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC09'] = isset($seg[9]) ? $seg[9] : ""; //STC09 Check Number AN 01/16/12 N/U
774 //STC10 HEALTH CARE CLAIM STATUS     S
775 if ( isset($seg[10]) && strpos($seg[10], $sub_d) ) {
776 $stc10 = explode($sub_d, $seg[10]);
777 if ( is_array($stc01) ) {
778 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC101'] = isset($stc10[0]) ? $stc10[0] : ""; //STC10-1 Health Care Claim Status Category Code AN 01/30/12 R     D0, E
779 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC102'] = isset($stc10[1]) ? $stc10[1] : ""; //STC10-2 Health Care Claim Status Code AN 01/30/12 R
780 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC103'] = isset($stc10[2]) ? $stc10[2] : ""; //STC10-3 Entity Identifier Code ID 02/03/12 S     1P
781 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC104'] = isset($stc10[3]) ? $stc10[3] : ""; //STC10-4 Code List Qualifier Code ID 01/03/12 N/U
782 } else {
783 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC101'] = isset($seg[10]) ? $seg[10] : "";
787 //STC11 HEALTH CARE CLAIM STATUS     S
788 if ( isset($seg[11]) && strpos($seg[11], $sub_d) ) {
789 $stc11 = explode($sub_d, $seg[10]);
790 if ( is_array($stc11) ) {
791 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC111'] = isset($stc11[0]) ? $stc11[0] : ""; //STC11-1 Health Care Claim Status Category Code AN 01/30/12 R     D0, E
792 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC112'] = isset($stc11[1]) ? $stc11[1] : ""; //STC11-2 Health Care Claim Status Code AN 01/30/12 R
793 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC113'] = isset($stc11[2]) ? $stc11[2] : ""; //STC11-3 Entity Identifier Code ID 02/03/12 S     1P
794 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC114'] = isset($stc11[3]) ? $stc11[3] : ""; //STC11-4 Code List Qualifier Code ID 01/03/12 N/U
795 } else {
796 $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC111'] = isset($seg[11]) ? $seg[11] : "";
799 //STC12 Free-Form Message Text AN 01/01/64 N/U      
800 if ( isset($seg[12]) ) { $ar277[$ict]['claim']['BHT'][$bct][$ky]['STC'][$stc_ct]['STC12'] = $seg[12]; }
802 if( $loopid == "2000D" || $loopid == "2000E") { $stc_ct++; }
803 //$lp2220D = TRUE;
806 continue;
807 } // end if ($seg[0] == "STC") in loop 2200C
809 if ($seg[0] == "REF") {
810 if ($ky == "C") {
811 if ($seg[1] == "TJ") { $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFTJ'] = $seg[2]; }
812 } elseif ($ky == "D") {
813 // ref, 1K, EJ, D9 will be expected
814 if ($seg[1] == "1K") {
815 // REF*1K*<<subscriber number >>~REF02 Payer Claim Control Number AN 1-50 R
816 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REF1K'] = $seg[2];
817 } elseif ($seg[1] == "D9") {
818 // REF*D9*NA~ clearinghouse ID
819 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFD9'] = $seg[2];
820 } elseif ($seg[1] == "EA") {
821 // record ID
822 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFEA'] = $seg[2];
823 } elseif ($seg[1] == "BLT") {
824 // institutional ID
825 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFBLT'] = $seg[2];
826 } elseif ($seg[1] == "EJ") {
827 // control ID
828 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFEJ'] = $seg[2];
829 } elseif ($seg[1] == "XZ") {
830 // prescripton ID
831 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFXZ'] = $seg[2];
832 } elseif ($seg[1] == "VV") {
833 // voucher ID
834 $ar277[$ict]['claim']['BHT'][$bct][$ky]['REFVV'] = $seg[2];
837 } else {
838 $refkey = 'REF'.$seg[1];
839 $ar277[$ict]['claim']['BHT'][$bct][$ky][$refkey] = $seg[1] . ":" . $seg[2]; // qualifier:value
842 continue;
845 if ($seg[0] == "SVC") {
846 // loop 2220D
847 // set another loop id
848 $lp2200D = FALSE;
849 $lp2220D = TRUE;
851 // SVC SERVICE LINE INFORMATION   1 S 2220D >1  
852 $sbr_svc01 = $seg[1]; // SVC01 COMPOSITE MEDICAL PROCEDURE INDENTIFIER R
853 $svc01 = explode($sub_d, $seg[1]);
854 //     AD, ER, HC, HP, IV, N4, NU, WK
856 if ( is_array($stc01) ) {
857 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC011'] = isset($svc01[0]) ? $svc01[0] : ""; //SVC01-1 Product/Service ID Qualifier ID 02/02/12 R
858 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC012'] = isset($svc01[1]) ? $svc01[1] : ""; //SVC01-2 Service Identification Code AN 01/01/48 R
859 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC013'] = isset($svc01[2]) ? $svc01[2] : ""; //SVC01-3 Procedure Modifier AN 02/02/12 S
860 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC014'] = isset($svc01[3]) ? $svc01[3] : ""; //SVC01-4 Procedure Modifier AN 02/02/12 S
861 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC015'] = isset($svc01[4]) ? $svc01[4] : ""; //SVC01-5 Procedure Modifier AN 02/02/12 S
862 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC016'] = isset($svc01[5]) ? $svc01[5] : ""; //SVC01-6 Procedure Modifier AN 02/02/12 S
863 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC017'] = isset($svc01[6]) ? $svc01[6] : ""; //SVC01-7 Description AN 01/01/80 N/U  
865 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC02'] = isset($seg[2]) ? $seg[2] : ""; //SVC02 Line Item Charge Amount S9(7)V99 R 01/18/12 R
866 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC03'] = isset($seg[2]) ? $seg[3] : ""; //SVC03 Line Item Payment Amount S9(7)V99 R 01/18/12 R
867 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC04'] = isset($seg[2]) ? $seg[4] : ""; //SVC04 Revenue Code AN 01/01/48 S
868 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC05'] = isset($seg[2]) ? $seg[5] : ""; //SVC05 Quantity R 01/15/12 N/U  
869 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC06'] = isset($seg[2]) ? $seg[6] : ""; //SVC06 COMPOSITE MEDICAL PROCEDURE INDENTIFIER     N/U
870 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['SVC07'] = isset($seg[2]) ? $seg[7] : ""; //SVC07 Units of Service Count S9(3)V9 R 01/15/12 S
872 $svc_ct++;
873 continue;
876 if ($seg[0] == "STC" && $lp2220D ) {
877 // loop 2220D
878 //SUBSCRIBER STATUS INFORMATION
879 //STC*A1:20*20120217*WQ*65~
880 if ( strpos($seg[1], $sub_d) ) {
881 $sp = strpos($sub_d, $seg[1]);
882 $stc_svc_01 = explode($sub_d, $seg[1]); // 2200D STC01-1 Health Care Claim Status Category Code
883 if ( is_array($stc01) ) { // "A2" Accept , "A3" Reject, or “R3” Warning 1/30
884 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC011'] = isset($stc01[0]) ? $stc01[0] : ""; //STC01-1 Health Care Claim Status Category Code AN 01/30/12 R D0, E
885 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC012'] = isset($stc01[1]) ? $stc01[1] : ""; //STC01-2 Health Care Claim Status Code AN 01/30/12 R
886 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC013'] = isset($stc01[1]) ? $stc01[1] : ""; //STC01-3 Entity Identifier Code ID 02/03/12 S     1P
887 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC014'] = isset($stc01[1]) ? $stc01[1] : ""; //STC01-4 Code List Qualifier Code ID 01/03/12 N/U  
888 } else {
889 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC011'] = isset($seg[1]) ? $seg[1] : "";
893 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC02'] = isset($seg[2]) ? $seg[2] : ""; //STC02 Status Information Effective Date DT 08/08/12 R CCYYMMDD
894 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC03'] = isset($seg[3]) ? $seg[3] : ""; //STC03 Action Code ID 01/02/12 N/U
895 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC04'] = isset($seg[4]) ? $seg[4] : ""; //STC04 Monetary Amount R 01/18/12 N/U
896 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC05'] = isset($seg[5]) ? $seg[5] : ""; //STC05 Monetary Amount R 01/18/12 N/U
897 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC06'] = isset($seg[6]) ? $seg[6] : ""; //STC06 Date DT 08/08/12 N/U
898 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC07'] = isset($seg[7]) ? $seg[7] : ""; //STC07 Payment Method Code ID 03/03/12 N/U  
899 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC08'] = isset($seg[8]) ? $seg[8] : ""; //STC08 Date DT 08/08/12 N/U
900 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC09'] = isset($seg[9]) ? $seg[9] : ""; //STC09 Check Number AN 01/16/12 N/U
901 //STC10 HEALTH CARE CLAIM STATUS     S
902 if ( isset($seg[10]) && strpos($seg[10], $sub_d) ) {
903 $stc10 = explode($sub_d, $seg[10]);
904 if ( is_array($stc01) ) {
905 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC101'] = isset($stc10[0]) ? $stc10[0] : ""; //STC10-1 Health Care Claim Status Category Code AN 01/30/12 R     D0, E
906 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC102'] = isset($stc10[1]) ? $stc10[1] : ""; //STC10-2 Health Care Claim Status Code AN 01/30/12 R
907 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC103'] = isset($stc10[2]) ? $stc10[2] : ""; //STC10-3 Entity Identifier Code ID 02/03/12 S     1P
908 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC104'] = isset($stc10[3]) ? $stc10[3] : ""; //STC10-4 Code List Qualifier Code ID 01/03/12 N/U
909 } else {
910 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC101'] = isset($seg[10]) ? $seg[10] : "";
914 //STC11 HEALTH CARE CLAIM STATUS     S
915 if ( isset($seg[11]) && strpos($seg[11], $sub_d) ) {
916 $stc11 = explode($sub_d, $seg[10]);
917 if ( is_array($stc11) ) {
918 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC111'] = isset($stc11[0]) ? $stc11[0] : ""; //STC11-1 Health Care Claim Status Category Code AN 01/30/12 R     D0, E
919 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC112'] = isset($stc11[1]) ? $stc11[1] : ""; //STC11-2 Health Care Claim Status Code AN 01/30/12 R
920 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC113'] = isset($stc11[2]) ? $stc11[2] : ""; //STC11-3 Entity Identifier Code ID 02/03/12 S     1P
921 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC114'] = isset($stc11[3]) ? $stc11[3] : ""; //STC11-4 Code List Qualifier Code ID 01/03/12 N/U
922 } else {
923 $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC111'] = isset($seg[11]) ? $seg[11] : "";
926 //STC12 Free-Form Message Text AN 01/01/64 N/U      
927 if ( isset($seg[12]) ) { $ar277[$ict]['claim']['BHT'][$bct][$ky]['SVC'][$svc_ct]['STC12'] = $seg[12]; }
929 if( $loopid == "2000D" || $loopid == "2000E") { $svc_ct++; }
931 continue;
933 } // end if ($seg[0] == "STC" && $lp2220D ) in loop 2200D
935 } // end foreach ( )
936 // array('mtime', 'file_name', 'claim_ct', 'amt_accpt', 'reject_ct', 'amt_rej');
937 //$ar_col_hdr = array('mtime', 'directory', 'file_name', 'claim_ct', 'amt_accpt','reject', 'amt_rej');
940 //$ar277['file'] = array('filetime' => $fmtime, 'filename' => $fname, 'claim_ct' => $clm_ct,
941 // 'amount' => $amt_accpt, 'reject_ct' => $rej_ct, 'reject_amt' => $amt_rej);
942 // new csv layout
943 //$csv_hd_ar['f277']['file'] = array('date', 'file_name', 'isa13_277', 'claim_ct', 'claim_rct');
944 //$ar277[$ict]['file'] = array('filetime'=>$fmtime, 'filename'=>$fname, 'isa13_277'=>$isa13, 'claim_ct'=>$clm_ct, 'claim_rct' => $rej_ct);
946 //$ar277['claim'] = $arRSP;
947 return $ar277;
952 * Process new files for csv table and html output
954 * @uses csv_newfile_list()
955 * @uses csv_parameters()
956 * @uses csv_x12_segments()
957 * @uses ibr_277_parse()
958 * @uses ibr_277_csv_claim_data()
959 * @uses csv_write_record()
960 * @param bool $html_out -- whether to return html output
961 * @param bool $err_only -- only list claims with errors in output
962 * @param array $files_ar -- list of new files from upload script
963 * @return string
965 function ibr_277_process_new($files_ar = NULL, $html_out = FALSE, $err_only = TRUE) {
967 if ( $files_ar === NULL || !is_array($files_ar) || count($files_ar) == 0) {
968 $ar_files = csv_newfile_list("f277");
969 } else {
970 $ar_files = $files_ar;
971 //$need_dir = FALSE;
974 if ( count($ar_files) == 0 ) {
975 if($html_out) {
976 $html_str .= "<p>ibr_277_process_new: no new f277 files <br />";
977 return $html_str;
980 // we have some new ones, verify and get complete path
981 foreach($ar_files as $fbt) {
982 $fp = csv_verify_file($fbt, 'f277', false);
983 if ($fp) { $ar_277files[] = $fp; }
986 if (!is_array($ar_277files) || count($ar_277files) == 0 ) {
987 $html_str = "ibr_277_process_new: no new f277 files found <br />" . PHP_EOL;
988 return $html_str;
989 } else {
990 $f277count = count($ar_277files);
992 // OK, we have some new files
993 $html_str = "";
994 $idx = 0;
995 $chr_c = 0;
996 $chr_f = 0;
998 foreach ($ar_277files as $file_277) {
999 // since the newfiles routine is updated, the need_dir test is not necessary
1000 //$path_277 = ($need_dir) ? $dir.DIRECTORY_SEPARATOR.$file_277 : $file_277;
1001 $path_277 = $file_277;
1003 $ar_277seg = csv_x12_segments($path_277, "f277", FALSE);
1005 if (is_array($ar_277seg) && count($ar_277seg['segments']) ) {
1006 $ar_277_vals = ibr_277_parse($ar_277seg);
1007 if (!$ar_277_vals) {
1008 $html_str .= "failed to get segments for $file_277 <br />" .PHP_EOL;
1009 continue;
1011 } else {
1012 $html_str .= "failed to get segments for $file_277 <br />" .PHP_EOL;
1013 continue;
1015 // since main array is indexed on isa segment and there may be more
1016 // than one per file, the 'file' csv table has a row for each ISA segment
1017 // and the 'claim' csv table has a row for each BHT segment
1019 foreach($ar_277_vals as $isa) {
1020 $ar_csvf = $isa['file'];
1021 $ar_csvc = ibr_277_csv_claim_data($isa['claim']);
1023 if ($html_out) {
1024 $ar_h[$idx]['file'] = $ar_csvf;
1025 $ar_h[$idx]['claim'] = $ar_csvc;
1026 $idx++;
1028 // still too much in claim csv record, drop the message
1029 //['f277']['claim'] = array('PtName', 'SvcDate', 'clm01', 'Status', 'st_277', 'File_277', 'payer_name', 'claim_id', 'bht03_837');
1030 $ar_csvclm = array();
1031 foreach($ar_csvc as $clm) {
1032 $ar_csvclm[] = array_slice($clm, 0, 8);
1034 $chr_f += csv_write_record($ar_csvf, "f277", "file");
1035 $chr_c += csv_write_record($ar_csvclm, "f277", "claim");
1038 } // end foreach ($ar_files as $file_277)
1040 if ($html_out) {
1041 $html_str .= ibr_277_html($ar_h, $err_only);
1042 } else {
1043 $html_str .= "x12_277 files: processed $f277count x12-277 files <br />". PHP_EOL;
1045 csv_edihist_log("ibr_277_process_new: $chr_f characters written to files_277.csv");
1046 csv_edihist_log("ibr_277_process_new: $chr_c characters written to claims_277.csv");
1049 return $html_str;
1054 * Create html output for a 277 file, same as the process new output
1056 * @uses csv_verify_file()
1057 * @uses csv_x12_segments()
1058 * @uses ibr_277_parse()
1059 * @uses ibr_277_csv_claim_data()
1060 * @uses ibr_277_html()
1061 * @param string $filepath -- filename or full path to file
1062 * @return string
1064 function ibr_277_filetohtml($filepath, $err_only = false) {
1066 // simply create an html output for the file like processing new
1068 $html_str = "";
1070 $fp = csv_verify_file($filepath, "f277");
1071 if ($fp) {
1072 $ar_277_seg = csv_x12_segments($fp, "f277", false);
1073 if (is_array($ar_277_seg) && count($ar_277_seg['segments']) ) {
1074 $ar_277_vals = ibr_277_parse($ar_277_segs);
1075 } else {
1076 $html_str .= "failed to get segments for $fp <br />" .PHP_EOL;
1077 continue;
1079 $idx = 0;
1080 foreach($ar_277_vals as $isa) {
1081 $ar_csvf = $isa['file'];
1082 $ar_csvc = ibr_277_csv_claim_data($isa['claim']);
1084 $ar_h[$idx]['file'] = $ar_csvf;
1085 $ar_h[$idx]['claim'] = $ar_csvc;
1086 $idx++;
1088 $html_str .= ibr_277_html ($ar_h, $err_only);
1089 } else {
1090 csv_edihist_log ("ibr_277_filetohtml: verification failed $filepath");
1091 $html_str .= "ibr_277_filetohtml: Error, validation failed $filepath <br />";
1094 return $html_str;
1098 ////////////////////////////////
1099 // html for claim status -- ties into revision of csv files becasue they
1100 // are too hard to work with with error messages
1101 // csv claims files will be simplified -- no messages
1102 // just status and link to this function
1103 // also x12 csv file record to be modified
1104 ////////////////////////////////
1107 * parse a bht segment group into a multi-dimensonal array
1109 * @param array $segments the ST...SE segments of the response
1110 * @param array $delimiters the delimiters array
1111 * @return array
1113 function ibr_277_bht_array($segments, $delimiters) {
1114 // parse a bht segment group into html output
1115 if (is_array($delimiters) && array_keys($delimiters) == array('t', 'e', 's', 'r')) {
1116 $seg_d = $delimiters['t'];
1117 $elem_d = $delimiters['e'];
1118 $sub_d = $delimiters['s'];
1119 $rep_d = $delimiters['r'];
1120 } else {
1121 csv_edihist_log ("ibr_277_bht_html: invalid delimiters");
1122 return false;
1125 if (!is_array($segments) || count($segments) == 0) {
1126 csv_edihist_log ("ibr_277_bht_html: invalid segments ");
1127 return false;
1130 // open the codes lookup class
1131 $codes277 = new status_code_arrays();
1133 // initialize variables
1134 $bht277_ar = array();
1135 $x12var = '';
1136 $idx = -1;
1137 foreach($segments as $segstr) {
1139 $seg = explode($elem_d, $segstr);
1141 // determine loops
1142 if ($seg[0] == 'ST') { $loopid = '0'; continue; }
1143 if ($seg[0] == 'BHT') { $loopid = '0'; }
1144 if ($seg[0] == 'HL') {
1145 //echo "ibr_277_bht_array HL segment".HP_EOL;
1147 if ($seg[3] == '20') { $loopid = '2000A'; $ky = 'A'; }
1148 if ($seg[3] == '21') { $loopid = '2000B'; $ky = 'B'; }
1149 if ($seg[3] == '19') { $loopid = '2000C'; $ky = 'C'; }
1150 if ($seg[3] == '22') { $loopid = '2000D'; $ky = 'D'; }
1151 if ($seg[3] == 'PT') { $loopid = '2000D'; $ky = 'D'; }
1152 if ($seg[3] == '23') { $loopid = '2000E'; $ky = 'E'; }
1154 if ($seg[0] == 'NM1'){
1155 if ( $loopid == '2000A') { $loopid = '2100A'; $level = 'Source'; }
1156 if ( $loopid == '2000B') { $loopid = '2100B'; $level = 'Receiver'; }
1157 if ( $loopid == '2000C') { $loopid = '2100C'; $level = 'Provider'; }
1158 if ( $loopid == '2000D') { $loopid = '2100D'; $level = 'Subscriber'; }
1159 if ( $loopid == '2000E') { $loopid = '2100E'; $level = 'Dependent'; }
1161 if ($seg[0] == 'TRN'){
1162 if ( $loopid == '2100A') { $loopid = '2200A'; $x12var = 'CA'; }
1163 if ( $loopid == '2100B') { $loopid = '2200B'; $x12var = ''; }
1164 if ( $loopid == '2100C') { $loopid = '2200C'; $x12var = ''; }
1165 if ( $loopid == '2100D') { $loopid = '2200D'; $x12var = ''; }
1167 if ($seg[0] == 'SVC'){
1168 if ( $loopid == '2200C') { $loopid = '2220C'; }
1169 if ( $loopid == '2200D') { $loopid = '2220D'; }
1170 if ( $loopid == '2200E') { $loopid = '2220E'; }
1173 // create $bht277_ar array so values can be organized for output
1174 // this design can work because the segment order is
1175 // NM1* ~TRN* ~STC* ~REF* ~DTP* ~SVC* ~DTP
1176 if ($loopid == '2000A') {
1177 // $ky should be 'A'
1178 $bht277_ar['A'] = array('loop'=>'', 'level'=>'', 'entity'=>'', 'name'=>'', 'id'=>'',
1179 'sourcerefid'=>'', 'pername'=>'', 'percontact'=>'',
1180 'pernumtype'=>'', 'pernumber'=>'', 'perextra'=>'',
1181 'trace'=>'', 'dtrec'=>'', 'dtproc'=>'',
1182 'STC'=>array());
1184 if ($loopid == '2000B') {
1185 $bht277_ar['B'] = array('loop'=>'', 'level'=>'', 'entity'=>'', 'name'=>'', 'id'=>'', 'trace'=>'',
1186 'qtyacc'=>'', 'amtacc'=>'', 'qtyrej'=>'', 'amtrej'=>'',
1187 'STC'=>array(), 'dtsvc'=>'', );
1189 if ($loopid == '2000C') {
1190 $bht277_ar['C'] = array('loop'=>'', 'level'=>'', 'entity'=>'', 'name'=>'', 'id'=>'', 'trace'=>'',
1191 'qtyacc'=>'', 'amtacc'=>'', 'qtyrej'=>'', 'amtrej'=>'',
1192 'STC'=>array(), 'dtsvc'=>'' );
1193 //'stcat'=>'', 'ststat'=>'', 'stentity'=>'', 'stclqual'=>'',
1194 //'stdate'=>'','staction'=>'','stamount'=>'', 'stmessage'=>''
1195 //'stcat2'=>'','ststat2'=>'','stentity2'=>'','stclqual2'
1196 //'stcat3'=>'','ststat3'=>'','stentity3'=>'','stclqual3'
1198 if ($loopid == '2000D') {
1199 $bht277_ar['D'] = array('loop'=>'', 'level'=>'', 'entity'=>'', 'name'=>'', 'id'=>'', 'trace'=>'',
1200 'qtyacc'=>'', 'amtacc'=>'', 'qtyrej'=>'', 'amtrej'=>'',
1201 'STC'=>array(), 'dtsvc'=>'', 'SVC'=>array());
1202 //'stccat'=>'', 'stcstat'=>'', 'stcentity'=>'', 'stcclqual'=>'',
1203 //'stcdate'=>'','stcaction'=>'','stcamount'=>'', 'stcmessage'=>''
1204 //'stccat2'=>'','stcstat2'=>'','stcentity2'=>'','stcclqual2'
1205 //'stccat3'=>'','stcstat3'=>'','stcentity3'=>'','stcclqual3'
1208 if ($loopid == '2000E') {
1209 $bht277_ar['E'] = array('loop'=>'', 'level'=>'', 'entity'=>'', 'name'=>'', 'id'=>'', 'trace'=>'',
1210 'qtyacc'=>'', 'amtacc'=>'', 'qtyrej'=>'', 'amtrej'=>'',
1211 'STC'=>array(), 'dtsvc'=>'', 'SVC'=>array());
1212 //'stccat'=>'', 'stcstat'=>'', 'stcentity'=>'', 'stcclqual'=>'',
1213 //'stcdate'=>'','stcaction'=>'','stcamount'=>'', 'stcmessage'=>''
1214 //'stccat2'=>'','stcstat2'=>'','stcentity2'=>'','stcclqual2'
1215 //'stccat3'=>'','stcstat3'=>'','stcentity3'=>'','stcclqual3'
1219 if ($seg[0] == 'BHT') {
1220 if (isset($seg[3])) { $sourcerefid = $seg[3]; }
1223 if ($seg[0] == 'NM1') {
1224 // get entity type
1225 $entity = $codes277->get_STC_Entity_Code($seg[1]);
1226 //$entity = ($seg[1]) ? : '&nbsp;';
1227 // assemble name last:$seg[3] first:$seg[4] middle:$seg[5]
1228 $name = ($seg[2] == '1') ? $seg[3].', '.$seg[4].' '.$seg[5] : $seg[3];
1230 $id = ($seg[8] == 'PI') ? 'EDI: '.$seg[9] : '';
1231 $id = ($seg[8] == 'XV') ? 'CMS: '.$seg[9] : $id;
1232 $id = ($seg[8] == '46') ? 'ETIN: '.$seg[9] : $id;
1233 $id = ($seg[8] == '24') ? 'EIN: '.$seg[9] : $id;
1234 $id = ($seg[8] == 'II') ? 'UHI: '.$seg[9] : $id;
1235 $id = ($seg[8] == 'MI') ? 'MbrID: '.$seg[9] : $id;
1236 $id = ($seg[8] == 'FI') ? 'TIN: '.$seg[9] : $id;
1237 $id = ($seg[8] == 'SV') ? 'SPN: '.$seg[9] : $id;
1238 $id = ($seg[8] == 'XX') ? 'NPI: '.$seg[9] : $id;
1239 if ($id == '' && isset($seg[8])) { $id = $seg[8].' '.$seg[9]; }
1241 $bht277_ar[$ky]['loop'] = $loopid;
1242 $bht277_ar[$ky]['level'] = $level;
1243 $bht277_ar[$ky]['entity'] = $entity[1];
1244 $bht277_ar[$ky]['name'] = $name;
1245 $bht277_ar[$ky]['id'] = $id;
1249 if ($seg[0] == 'PER') {
1250 // contact information is not sent in the 277CA variety
1251 $bht277_ar[$ky]['percontact'] = $seg[1];
1252 $bht277_ar[$ky]['pernumtype'] = $seg[2];
1253 $bht277_ar[$ky]['pernumber'] = $seg[3];
1254 if ( isset($seg[5]) && isset($seg[6]) ) {
1255 $bht277_ar[$ky]['perextra'] = $seg[5] . ' ' . $seg[6];
1259 if ($seg[0] == 'TRN') {
1260 // transaction reference, but which one?
1261 $trtype = ($seg[1] == '1') ? 'This transaction ' : 'Referenced transaction ' ;
1262 // trace in loop
1263 $trace = ($loopid == '2200A') ? 'Xmit RefID: '.$seg[2] : ''; // ''837 BHT03: '.$seg[2] : '';
1264 // according to CMS Versions 5010 and D.0 & 3.0
1265 // 837 BHT03 is mapped to the 277CA response in the 2200B.TRN02 data element
1266 $trace = ($loopid == '2200B') ? (($x12var == 'CA') ? '276 BHT03: '.$seg[2] : '837 BHT03: '.$seg[2]) : $trace;
1267 $trace = ($loopid == '2200C' && $seg[2]) ? '837 BHT03: '.$seg[2] : $trace;
1268 $trace = ($loopid == '2200D') ? '837 CLM01: '.$seg[2] : $trace;
1269 $trace = ($loopid == '2200E') ? '837 CLM01: '.$seg[2] : $trace;
1270 if ($trace == '' && isset($seg[9])) { $trace = $loopid.' trace '.$seg[9]; }
1272 $bht277_ar[$ky]['trace'] = ($trace) ? $trtype . ' ' . $trace : '';
1273 // from BHT segment
1274 if ($loopid == '2200A') { $bht277_ar[$ky]['sourcerefid'] = 'Reference: ' .$sourcerefid; }
1277 if ($seg[0] == 'DTP') {
1278 if ($seg[2] == 'D8') {
1279 $dt = substr($seg[3],0,4) .'-'. substr($seg[3],4,2) .'-'. substr($seg[3],6,2);
1281 if ($seg[2] == 'D8') {
1282 if ($seg[1] == '050') { $bht277_ar[$ky]['dtrec'] = $dt; }
1283 if ($seg[1] == '009') { $bht277_ar[$ky]['dtproc'] = $dt; }
1284 if ($seg[1] == '472') { $bht277_ar[$ky]['dtsvc'] = $dt; }
1286 if ($seg[2] == 'RD8') {
1287 $dt_ar = preg_split('/\D/', $seg[3]);
1288 $dt1 = substr($dt_ar[0],0,4) .'-'. substr($dt_ar[0],4,2) .'-'. substr($dt_ar[0],6,2);
1289 $dt2 = substr($dt_ar[1],0,4) .'-'. substr($dt_ar[1],4,2) .'-'. substr($dt_ar[1],6,2);
1290 if ($seg[1] == '472') { $bht277_ar[$ky]['dtsvc'] = $dt1 .' to '. $dt2; }
1291 if ($seg[1] == '434') { $bht277_ar[$ky]['dtstmt'] = $dt1 .' to '. $dt2; }
1295 if ($seg[0] == 'QTY') {
1296 // $ky should be B
1297 // debug
1298 //echo "QTY Segment in $loopid $segstr" .PHP_EOL;
1300 if ($seg[1] == '90') { $bht277_ar[$ky]['qtyacc'] = $seg[2]; }
1301 if ($seg[1] == 'AA') { $bht277_ar[$ky]['qtyrej'] = $seg[2]; }
1303 if ($seg[0] == 'AMT') {
1304 // debug
1305 //echo "AMT Segment in $loopid $segstr" .PHP_EOL;
1307 if ($seg[1] == 'YU') { $bht277_ar[$ky]['amtacc'] = sprintf("%0.02f", $seg[2]); }
1308 if ($seg[1] == 'YY') { $bht277_ar[$ky]['amtrej'] = sprintf("%0.02f", $seg[2]); }
1310 //'stcat''ststat''stentity''stclqual''stdate''staction''stamount'
1311 if ($seg[0] == 'STC') {
1312 // since there can be multiple STC segments in a loop
1313 $idx = count($bht277_ar[$ky]['STC']);
1314 // loop identification
1315 $bht277_ar[$ky]['STC'][$idx]['loop'] = $loopid;
1317 if ( strpos($seg[1], $sub_d) ) {
1318 $stc01 = explode($sub_d, $seg[1]);
1319 if ( isset($stc01[0]) ) {
1320 $cat = $codes277->get_STC_Category_Code($stc01[0]);
1321 $bht277_ar[$ky]['STC'][$idx]['stccat'] = $cat[1];
1323 if ( isset($stc01[1]) ) {
1324 $stat = $codes277->get_STC_Status_Code($stc01[1]);
1325 $bht277_ar[$ky]['STC'][$idx]['stcstat'] = $stat[1];
1327 if ( isset($stc01[2]) ) {
1328 $entity = $codes277->get_STC_Entity_Code($stc01[2]);
1329 $bht277_ar[$ky]['STC'][$idx]['stcentity'] = $entity[1];
1331 if ( isset($stc01[3]) ) {
1332 // this seems to be used only in special situations, like a pharmacy claim
1333 $bht277_ar[$ky]['STC'][$idx]['stcclqual'] = $stc01[3];
1337 $bht277_ar[$ky]['STC'][$idx]['stcdate'] = $seg[2];
1339 if ( isset($seg[3]) ) {
1340 if ($seg[3]== 'WQ') { $bht277_ar[$ky]['STC'][$idx]['stcaction'] = $seg[3] . ' Accepted'; }
1341 if ($seg[3]== 'U') { $bht277_ar[$ky]['STC'][$idx]['stcaction'] = $seg[3] . ' Rejected'; }
1343 if ( isset($seg[4]) ) {
1344 $bht277_ar[$ky]['STC'][$idx]['stcamount'] = sprintf("%0.02f", $seg[4]);
1346 if ( isset($seg[10]) ) {
1347 if ( strpos($seg[10], $sub_d) ) {
1348 $stc10 = explode($sub_d, $seg[10]);
1349 if ( isset($stc10[0]) ) {
1350 $cat = $codes277->get_STC_Category_Code($stc10[0]);
1351 $bht277_ar[$ky]['STC'][$idx]['stccat2'] = $cat[1];
1353 if ( isset($stc10[1]) ) {
1354 $stat = $codes277->get_STC_Status_Code($stc10[1]);
1355 $bht277_ar[$ky]['STC'][$idx]['stcstat2'] = $stat[1];
1357 if ( isset($stc10[2]) ) {
1358 $entity = $codes277->get_STC_Entity_Code($stc10[2]);
1359 $bht277_ar[$ky]['STC'][$idx]['stcentity2'] = $entity[1];
1361 if ( isset($stc10[3]) ) {
1362 // this seems to be used only in special situations, like a pharmacy claim
1363 $bht277_ar[$ky]['STC'][$idx]['stcclqual2'] = $stc10[3];
1367 if ( isset($seg[11]) ) {
1368 if ( strpos($seg[11], $sub_d) ) {
1369 $stc11 = explode($sub_d, $seg[10]);
1370 if ( isset($stc11[0]) ) {
1371 $cat = $codes277->get_STC_Category_Code($stc11[0]);
1372 $bht277_ar[$ky]['STC'][$idx]['stccat3'] = $cat[1];
1374 if ( isset($stc11[1]) ) {
1375 $stat = $codes277->get_STC_Status_Code($stc11[1]);
1376 $bht277_ar[$ky]['STC'][$idx]['stcstat3'] = $stat[1];
1378 if ( isset($stc11[2]) ) {
1379 $entity = $codes277->get_STC_Entity_Code($stc11[2]);
1380 $bht277_ar[$ky]['STC'][$idx]['stcentity3'] = $entity[1];
1382 if ( isset($stc11[3]) ) {
1383 // this seems to be used only in special situations, like a pharmacy claim
1384 $bht277_ar[$ky]['STC'][$idx]['stcclqual3'] = $stc11[3];
1388 if ( isset($seg[12]) ) {
1389 $bht277_ar[$ky]['STC'][$idx]['stcmessage'] = $seg[12];
1393 if ($seg[0] == 'REF') {
1394 //'ref1K''refD9''refEA''refBLT''refEJ''refXZ''refVV''refFJ'
1395 $refkey = 'ref' . strtolower($seg[1]);
1396 $refstr = '';
1397 if ($seg[1] == '1K') { $refstr = 'Payer Ctl No '; }
1398 if ($seg[1] == 'BLT') { $refstr = 'Billing Type '; }
1399 if ($seg[1] == 'EJ') { $refstr = 'Pt Acct No '; }
1400 if ($seg[1] == 'XZ') { $refstr = 'Rx No '; }
1401 if ($seg[1] == 'VV') { $refstr = 'Voucher No '; }
1402 if ($seg[1] == 'FJ') { $refstr = 'Svc Item Info '; }
1403 if ($seg[1] == 'D9') { $refstr = 'Clearinghouse ID No '; }
1404 if ($seg[1] == 'TJ') { $refstr = 'Fed Tax ID No '; }
1406 $bht277_ar[$ky][$refkey] = $refstr . $seg[2];
1409 if ($seg[0] == 'SVC') {
1410 // SVC segment only occurs in 2200D or 2200E
1411 if ($ky == 'D' || $ky == 'E') {
1412 $idx = count($bht277_ar[$ky]['SVC']);
1413 // loop identification
1414 $bht277_ar[$ky]['SVC'][$idx]['loop'] = $loopid;
1415 // required elements
1416 $bht277_ar[$ky]['SVC'][$idx]['svccode'] = $seg[1];
1417 $bht277_ar[$ky]['SVC'][$idx]['svcfee'] = $seg[2];
1418 $bht277_ar[$ky]['SVC'][$idx]['svcpmt'] = $seg[3];
1419 // situational elements
1420 if (isset($seg[4])) { $bht277_ar[$ky]['SVC'][$idx]['svcnub'] = $seg[4]; }
1421 if (isset($seg[5])) { $bht277_ar[$ky]['SVC'][$idx]['svcqty'] = $seg[5]; }
1422 if (isset($seg[5])) { $bht277_ar[$ky]['SVC'][$idx]['svcqty'] = $seg[5]; }
1423 if (isset($seg[6])) { $bht277_ar[$ky]['SVC'][$idx]['svccompid'] = $seg[6]; }
1424 // required, but test anyway
1425 if (isset($seg[7])) { $bht277_ar[$ky]['SVC'][$idx]['svcqty'] = $seg[7]; }
1429 // return the array
1430 return $bht277_ar;
1434 * create an html table to display the claim status response
1436 * @param array $bhtarray the multidimesional array from {@see ibr_277_bht_array()}
1437 * @return string
1439 function ibr_277_bhthtml($bhtarray) {
1441 if (is_array($bhtarray)) {
1442 $bar = $bhtarray;
1443 } else {
1444 csv_edihist_log("ibr_277_bhthtml: error, argument not array");
1445 return false;
1447 // derive the caption
1448 $capstr = 'Claim Status: ';
1449 if ($bar['D']['trace']) { $capstr .= $bar['D']['trace']; }
1450 if (isset($bar['D']['ref1k'])) { $capstr .= ' ' . $bar['D']['ref1k']; }
1452 $str_html = "<table class='bht277' cols=5 caption='$capstr'>
1453 <thead>
1454 <tr>
1455 <th>Level</th>
1456 <th colspan='4'>Information</th>
1457 </tr>
1458 </thead>
1459 <tbody>".PHP_EOL;
1461 if (isset($bar['A'])) {
1462 // Source level
1463 $str_html .= "<tr class='leva'>
1464 <td>{$bar['A']['level']}</td>
1465 <td colspan='2'>{$bar['A']['entity']} {$bar['A']['name']}</td>
1466 <td colspan='2'>{$bar['A']['id']}</td>
1467 </tr>
1468 <tr class='leva'>
1469 <td>&nbsp;</td>
1470 <td colspan='2'>{$bar['A']['sourcerefid']}</td>
1471 <td colspan='2'>{$bar['A']['trace']} </td>
1472 </tr>
1473 <tr class='leva'>
1474 <td>&nbsp;</td>
1475 <td colspan='4'>Recieved {$bar['A']['dtrec']} Processed {$bar['A']['dtproc']}</td>
1476 </tr>".PHP_EOL;
1477 if ($bar['A']['percontact']) {
1478 $str_html .= "<tr class='leva'>
1479 <td>&nbsp;</td>
1480 <td colspan='4'>{$bar['A']['pername']} {$bar['A']['percontact']} {$bar['A']['pernumtype']} {$bar['A']['pernumber']} </td>
1481 </tr>".PHP_EOL;
1485 if (isset($bar['B'])) {
1486 // Reciever level
1487 $acp = '';
1488 if ($bar['B']['qtyacc']) { $acp .= ' Accepted ' . $bar['B']['qtyacc'] . ': ' . $bar['B']['amtacc']; }
1489 if ($bar['B']['qtyrej']) { $acp .= ' Rejected ' . $bar['B']['qtyrej'] . ': ' . $bar['B']['amtrej']; }
1490 $str_html .= "<tr class='levb'>
1491 <td>{$bar['B']['level']}</td>
1492 <td colspan='4'>{$bar['B']['entity']} {$bar['B']['name']} {$bar['B']['id']}</td>
1493 </tr>
1494 <tr class='levb'>
1495 <td>&nbsp;</td>
1496 <td colspan='4'>$acp {$bar['B']['trace']} </td>
1497 </tr>".PHP_EOL;
1498 if (count($bar['B']['STC'])) {
1499 foreach($bar['B']['STC'] as $stc) {
1500 $str_html .= "<tr class='levb'>
1501 <td>&nbsp;</td>
1502 <td colspan='4'>{$stc['stcamount']} {$stc['stcaction']} {$stc['stccat']} </td>
1503 </tr>".PHP_EOL;
1508 if (isset($bar['C'])) {
1509 // Reciever level
1510 $acp = ''; $ref = '';
1511 if ($bar['C']['qtyacc']) { $acp .= ' Accepted ' . $bar['C']['qtyacc'] . ': ' . $bar['C']['amtacc']; }
1512 if ($bar['C']['qtyrej']) { $acp .= ' Rejected ' . $bar['C']['qtyrej'] . ': ' . $bar['C']['amtrej']; }
1513 $str_html .= "<tr class='levc'>
1514 <td>{$bar['C']['level']}</td>
1515 <td colspan='4'>{$bar['C']['entity']} {$bar['C']['name']} {$bar['C']['id']}</td>
1516 </tr>".PHP_EOL;
1517 // trace is not really expected in 2000C
1518 if ($bar['C']['trace']) { $ref = $bar['C']['trace']; }
1519 // we expect a reftj (tax id) in 2000C
1520 if (isset($bar['C']['reftj'])) { $ref .= ' ' .$bar['C']['reftj']; }
1521 if ($ref) {
1522 $str_html .= "<tr class='levc'>
1523 <td>&nbsp;</td>
1524 <td colspan='4'>$ref</td>
1525 </tr>".PHP_EOL;
1527 if (count($bar['C']['STC'])) {
1528 foreach($bar['C']['STC'] as $stc) {
1529 $str_html .= "<tr class='levc'>
1530 <td>&nbsp;</td>
1531 <td colspan='4'>{$stc['stcamount']} {$stc['stcaction']} {$stc['stccat']} </td>
1532 </tr>".PHP_EOL;
1537 if (isset($bar['D'])) {
1538 // Subscriber level
1539 // do not expect amounts or quantities in D
1540 $acp = ''; $ref = '';
1541 if ($bar['D']['qtyacc']) { $acp .= ' Accepted ' . $bar['D']['qtyacc'] . ': ' . $bar['D']['amtacc']; }
1542 if ($bar['D']['qtyrej']) { $acp .= ' Rejected ' . $bar['D']['qtyrej'] . ': ' . $bar['D']['amtrej']; }
1543 $str_html .= "<tr class='levd'>
1544 <td>{$bar['D']['level']}</td>
1545 <td colspan='4'>{$bar['D']['entity']} {$bar['D']['name']} {$bar['D']['id']}</td>
1546 </tr>".PHP_EOL;
1547 if ($bar['D']['dtsvc']) {
1548 $str_html .= "<tr class='levd'>
1549 <td>&nbsp;</td>
1550 <td colspan='4'>Service Date: {$bar['D']['dtsvc']}</td>
1551 </tr>".PHP_EOL;
1553 // our pid-encounter and possibly payer claim number and intermediary trace
1554 if (isset($bar['D']['trace'])) { $ref .= $bar['D']['trace']; }
1555 if (isset($bar['D']['ref1k'])) { $ref .= ' ' . $bar['D']['ref1k']; }
1556 if (isset($bar['D']['refvv'])) { $ref .= ' ' . $bar['D']['refvv']; }
1557 if (isset($bar['D']['refd9'])) { $ref .= ' ' . $bar['D']['refd9']; }
1558 if ($ref) {
1559 $str_html .= "<tr class='levd'>
1560 <td>&nbsp;</td>
1561 <td colspan='4'>$ref</td>
1562 </tr>".PHP_EOL;
1565 if (count($bar['D']['STC'])) {
1566 foreach($bar['D']['STC'] as $stc) {
1567 $str_html .= "<tr class='levd'>
1568 <td>&nbsp;</td>
1569 <td colspan='4'>{$stc['stcamount']} {$stc['stcaction']} {$stc['stccat']} </td>
1570 </tr>
1571 <tr class='levd'>
1572 <td>&nbsp;</td>
1573 <td colspan='4'>{$stc['stcmessage']}</td>
1574 </tr>".PHP_EOL;
1578 if (count($bar['D']['SVC'])) {
1579 foreach($bar['D']['SVC'] as $svc) {
1580 $str_html .= "<tr class='levd'>
1581 <td>&nbsp;</td>
1582 <td colspan='4'>{$svc['svccode']} {$svc['svcfee']} {$svc['svcpmt']} {$svc['svcqty']} </td>
1583 </tr>".PHP_EOL;
1588 if (isset($bar['E'])) {
1589 // Subscriber level
1590 // do not expect amounts or quantities
1591 $acp = ''; $ref = '';
1592 if ($bar['E']['qtyacc']) { $acp .= ' Accepted ' . $bar['E']['qtyacc'] . ': ' . $bar['E']['amtacc']; }
1593 if ($bar['E']['qtyrej']) { $rej .= ' Rejected ' . $bar['E']['qtyrej'] . ': ' . $bar['E']['amtrej']; }
1594 $str_html .= "<tr class='leve'>
1595 <td>{$bar['E']['level']}</td>
1596 <td colspan='4'>{$bar['E']['entity']} {$bar['E']['name']} {$bar['E']['id']}</td>
1597 </tr>".PHP_EOL;
1598 if ($bar['E']['dtsvc']) {
1599 $str_html .= "<tr class='leve'>
1600 <td>&nbsp;</td>
1601 <td colspan='4'>Service Date: {$bar['E']['dtsvc']}</td>
1602 </tr>".PHP_EOL;
1604 // our pid-encounter and possibly payer claim number and intermediary trace
1605 if (isset($bar['E']['trace'])) { $ref .= $bar['E']['trace']; }
1606 if (isset($bar['E']['ref1k'])) { $ref .= ' ' . $bar['E']['ref1k']; }
1607 if (isset($bar['D']['refvv'])) { $ref .= ' ' . $bar['D']['refvv']; }
1608 if (isset($bar['E']['refd9'])) { $ref .= ' ' . $bar['E']['refd9']; }
1609 if ($ref) {
1610 $str_html .= "<tr class='leve'>
1611 <td>&nbsp;</td>
1612 <td colspan='4'>$ref</td>
1613 </tr>".PHP_EOL;
1616 if (count($bar['E']['STC'])) {
1617 foreach($bar['E']['STC'] as $stc) {
1618 $str_html .= "<tr class='leve'>
1619 <td>&nbsp;</td>
1620 <td colspan='4'>{$stc['stcamount']} {$stc['stcaction']} {$stc['stccat']} </td>
1621 </tr>
1622 <tr class='leve'>
1623 <td>&nbsp;</td>
1624 <td colspan='4'>{$stc['stcmessage']}</td>
1625 </tr>".PHP_EOL;
1629 if (count($bar['E']['SVC'])) {
1630 foreach($bar['E']['SVC'] as $svc) {
1631 $str_html .= "<tr class='leve'>
1632 <td>&nbsp;</td>
1633 <td colspan='4'>{$svc['svccode']} Fee: {$svc['svcfee']} Pmt: {$svc['svcpmt']} Qty: {$svc['svcqty']} </td>
1634 </tr>".PHP_EOL;
1638 $str_html .= "</tbody>
1639 </table>".PHP_EOL;
1641 return $str_html;
1647 * determine the array_slice parameters for the particular claim status transaction
1649 * parameters to slice ST...SE transaction segments out of the the file segments array
1651 * @param array the segments array of the 277 file
1652 * @param array the delimiters array
1653 * @param string the bht03 value we are looking for in loop 2000C TRN
1654 * @param string the patient control (pid-enc or encounter) from 837 CLM01
1655 * @param string the ST02 number from claims_f277.csv, from 277 file initial processing
1656 * @param string the ISA control number from the envelope wrapping the ST02 number
1657 * @return array the parameters for array_slice (start, count, searchval)
1659 function ibr_277_bhtblock($segments, $delimiters, $clm01 = '', $bht03 = '', $st02 = '') {
1660 // derive the array_slice parameters for the bht segments block
1661 // need to add the isa13 parameter, multiple ISA--IEA in 277 files
1662 $useclm = false;
1663 $useenc = false;
1664 $usebht = false;
1665 $usest = false;
1666 $isfound = false;
1667 $slice_ar = array();
1668 $isanum = '';
1670 $elem_d = $delimiters['e'];
1672 if (!is_array($segments)) {
1673 csv_edihist_log ("ibr_277_bhtblock: segment array error");
1674 // debug
1675 //echo "ibr_277_bhtblock: segment array error".PHP_EOL;
1676 return false;
1678 if (!$clm01 && !$bht03 && !$st02) {
1679 csv_edihist_log ("ibr_277_bhtblock: no specifier arguments given");
1680 return false;
1681 } elseif (($bht03 == '0123' || strlen($bht03) != 13) && !$clm01 && !$st02) {
1682 // OpenEMR presently gives all BHT03 value of '0123' in batch files
1683 //echo "ibr_277_bhtblock: bht03 useless $bht03 with no clm01 or st02".PHP_EOL;
1684 csv_edihist_log ("bht03 useless $bht03 with no isa13 or st02");
1685 return false;
1686 } elseif (strpos($st02, '_')) {
1687 $dpos = strpos($st02, '_');
1688 $srchval = substr($st02, $dpos+1);
1689 $isanum = substr($st02, 0, $dpos);
1690 //$srchval = (strlen($st02) < 4) ? str_pad ($st02, 4, "0", STR_PAD_LEFT) : strval($st02);
1691 $usest = true;
1692 } elseif (strlen($bht03) == 13) {
1693 $srchval = strval($bht03);
1694 $usebht = true;
1695 } elseif (strlen($clm01) && strpos($clm01, '-')) {
1696 $useclm = true;
1697 $srchval = strval($clm01);
1698 } elseif (strlen($clm01) && !strpos($clm01, '-')) {
1699 $useenc = true;
1700 $srchval = strval($clm01);
1703 $isastr = 'ISA'.$elem_d;
1704 $ststr = 'ST'.$elem_d;
1705 $trnstr = 'TRN'.$elem_d.'2'.$elem_d;
1706 $sestr = 'SE'.$elem_d;
1707 $idx = -1;
1709 foreach($segments as $segstr) {
1710 // increment index
1711 $idx++;
1712 // check ISA envelope
1713 if (substr($segstr, 0, 4) == $isastr) {
1714 $seg = explode($elem_d, $segstr);
1715 $isisa = ($seg[13] == $isanum) ? true : false;
1716 continue;
1718 if (substr($segstr, 0, 4) == 'IEA'.$elem_d) {
1719 $isisa = false;
1720 continue;
1722 // get position of ST segment
1723 if (substr($segstr, 0, 3) == $ststr) {
1724 $stpos = $idx;
1725 $isfound = false;
1726 $seg = explode($elem_d, $segstr);
1727 $stnum = strval($seg[2]);
1728 if ($usest && $isisa && ($stnum == $srchval)) {
1729 $isfound = true;
1731 continue;
1734 if (substr($segstr, 0, 6) == $trnstr) {
1735 $seg = explode($elem_d, $segstr);
1736 if ($seg[2] == $srchval) {
1737 $isfound = true;
1738 $slice_ar[0] = $stpos;
1741 if ($useenc) {
1742 if (substr($seg[2], -strlen($srchval)) == $srchval) {
1743 $isfound = true;
1744 $slice_ar[0] = $stpos;
1747 continue;
1750 if ($isfound && (substr($segstr, 0, 3) == $sestr) ) {
1751 $seg = explode($elem_d, $segstr);
1752 if ($stnum == $seg[2]) {
1753 $slice_ar[1] = $seg[1];
1754 $slice_ar[2] = $srchval;
1757 if ($idx - $stpos + 1 != $seg[1]) {
1758 $ct = $idx - $stpos + 1;
1759 csv_edihist_log ("ibr_277_bhtblock: $srchval st count error se02 {$seg[1]} count $ct ");
1762 // we expect only one match in a file
1763 break;
1767 // return the slice or the slice parameters? slice parameters
1768 return $slice_ar;
1772 * create a display for an individual claim status response
1774 * @uses csv_file_by_controlnum()
1775 * @uses csv_x12_segments()
1776 * @uses ibr_277_bhtblock()
1777 * @uses ibr_277_bht_array()
1778 * @uses ibr_277_bhthtml()
1779 * @param string $filename the filename
1780 * @param string $isa13 the isa13 control number for the file
1781 * @param string $bht03 the identifier from the 837 bht segment
1782 * @param string $clm01 the pid-encounter from the 837 clm segment
1783 * @param string $st02 the st number from the 277 file
1784 * @return string either an error message or a table with the information from the response
1786 function ibr_277_response_html($filename = '', $isa13 = '', $bht03 = '', $clm01 = '', $st02 = '' ) {
1787 // create a display for an individual 277 response
1788 $html_str = '';
1790 if (!$filename && !$isa13) {
1791 csv_edihist_log ("ibr_277_response_html: called with no file arguments");
1792 $html_str .= "Error, no file given<br />".PHP_EOL;
1793 return $html_str;
1794 } elseif (!$filename && $isa13) {
1795 $fn = csv_file_by_controlnum('f277', $isa13);
1796 } elseif ($filename) {
1797 $fn = basename($filename);
1800 if ($fn) {
1802 $ar_277_seg = csv_x12_segments($fn, "f277", false);
1805 if ($bht03 || $clm01 || $st02) {
1807 $sliceparams = ibr_277_bhtblock($ar_277_seg['segments'], $ar_277_seg['delimiters'], $clm01, $bht03, $st02);
1808 if ($sliceparams) {
1809 $bhtsegs = array_slice($ar_277_seg['segments'], $sliceparams[0], $sliceparams[1]);
1810 $bht_ar = ibr_277_bht_array($bhtsegs, $ar_277_seg['delimiters']);
1811 $bht_html = ibr_277_bhthtml($bht_ar);
1812 if ($bht_html) {
1813 $html_str .= $bht_html;
1814 } else {
1815 $html_str .= "Error encountered in generating display <br />".PHP_EOL;
1818 } else {
1819 $html_str .= "Did not find status for $bht03 $clm01 $st02 in $fn <br />".PHP_EOL;
1821 } else {
1822 csv_edihist_log ("ibr_277_response_html: called with no claim identifying arguments");
1823 $html_str .= "Error, no claim identification given<br />".PHP_EOL;
1826 return $html_str;