Fix bug in the careplan list endpoint
[openemr.git] / library / edihistory / edih_segments.php
blob3a98a289f027c4d4ceb92b8dda34613428d7649d
1 <?php
3 /*
4 * edih_segments.php
6 * Copyright 2016 Kevin McCormick <kevin@kt61p>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
23 * @author Kevin McCormick
24 * @link: https://www.open-emr.org
25 * @package OpenEMR
26 * @subpackage ediHistory
30 /**
31 * increment loop values ($lpval is a reference)
33 * @param $lptest the prospective loop value
34 * @param &$lpval the present loop value -- reassigned here
35 * @return integer value from strcmp()
37 function edih_change_loop($lptest, &$lpval)
39 // strcmp($str1,$str2) Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
40 if (strcmp($lptest, $lpval) > 0) {
41 //echo "$lptest greater than $lpval" .PHP_EOL;
42 $lpval = $lptest;
45 return strcmp($lptest, $lpval);
48 /**
49 * format segments for display of x12 edi files
51 * @param array $segments
52 * @param string $delimiter
53 * return string
55 function edih_segments_text($segments, $delimiter)
58 $str_html = '';
60 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
61 // debug
62 csv_edihist_log('edih_generic_text: invalid argument');
63 $str_html = "Invalid arguments for view of x12 file text<br />";
64 return $str_html;
68 $de = $delimiter;
69 $loopid = " -- ";
70 $idx = 0;
72 foreach ($segments as $key => $seg) {
73 $idx++;
75 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
79 return $str_html;
82 /**
83 * identify loops and format segments for display
84 * of 837 (professional claim) type x12 edi files
86 * @param array $segments
87 * @param string $delimiter
88 * return string
90 function edih_837_text($segments, $delimiter, $err_seg = '')
93 $str_html = '';
94 $err_ar = array();
96 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
97 // debug
98 csv_edihist_log('edih_837_text: invalid argument');
99 $str_html .= "Invalid arguments for view of x12 file text<br />";
100 return $str_html;
103 // to highlight identified errors listed in 999/997 ack
104 if ($err_seg) {
105 $er = edih_errseg_parse($err_seg);
106 $erstn = (isset($er['trace'])) ? substr($er['trace'], -4) : '';
107 $erseg = (isset($er['err'])) ? $er['err'] : array();
108 } else {
109 $erstn = '';
110 $erseg = array();
114 $de = $delimiter;
115 $loopid = "0";
116 $idx = 0;
117 $stkey = 0;
118 $segnum = 0;
119 $stsegct = 0;
120 $bterr = 'btseg';
122 foreach ($segments as $key => $seg) {
123 $idx++;
124 $title = '';
125 $stsegct++;
126 $bterr = 'btseg';
128 if ($erstn && ($erstn == $stn)) {
129 $bterr = (in_array($stsegct, $erseg)) ? 'bterr' : 'btseg';
133 if (strncmp('ST' . $de, $seg, 3) === 0) {
134 $loopid = 'Header';
135 $stkey = (int)$key;
136 $stsegct = 1;
137 $stn = explode($de, $seg)[2];
138 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
139 continue;
143 if (strncmp('BHT' . $de, $seg, 4) === 0) {
144 $loopid = 'Begin';
145 $stsegct = 2;
146 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
147 continue;
151 if (strncmp('HL' . $de, $seg, 3) === 0) {
152 $sar = explode($de, $seg);
153 if ($sar[3] == '20') { // level code
154 $loopid = '2000A'; // billing provider (clinic)
155 } elseif ($sar[3] == '22') {
156 $loopid = '2000B'; // subscriber
157 } elseif ($sar[3] == '23' || $sar[3] == 'PT') {
158 $loopid = '2000C'; // dependent
159 $has_eb = false;
160 } else {
161 //debug
162 csv_edihist_log('edih_837_text: HL has no level ' . $seg);
166 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
167 continue;
171 if (strncmp('CLM' . $de, $seg, 4) === 0) {
172 $loopid = '2300';
173 $title = 'Claim';
174 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
175 $title = '';
176 continue;
180 if (strncmp('SBR' . $de, $seg, 4) === 0) {
181 if ($loopid == '2000B') {
182 $title = 'Subscriber';
183 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
184 } else {
185 $title = 'Other Subscriber';
186 $loopid = '2320';
187 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'> -- </td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
190 $title = '';
191 continue;
195 if (strncmp('LX' . $de, $seg, 3) === 0) {
196 $loopid = '2400';
197 $title = 'Svc Line Number';
198 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
199 $title = '';
200 continue;
204 if (strncmp('LIN' . $de, $seg, 4) === 0) {
205 $loopid = '2410';
206 $title = 'Drug ID';
207 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
208 $title = '';
209 continue;
213 if (strncmp('SVD' . $de, $seg, 4) === 0) {
214 $loopid = '2430';
215 $title = 'Line Adjudication';
216 $str_html .= "<tr></tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
217 $title = '';
218 continue;
222 if (strncmp('NM1' . $de, $seg, 4) === 0) {
223 $sar = explode($de, $seg);
224 $nm101 = ( isset($sar[1]) ) ? $sar[1] : '';
225 if ($loopid == 'Begin' || strcmp(substr($loopid, 0, 4), '2320') < 0) {
226 if ($nm101 == '41') {
227 $loopid = '1000A';
228 $title = 'Submitter';
229 } elseif ($nm101 == '40') {
230 $loopid = '1000B';
231 $title = 'Receiver';
232 } elseif ($nm101 == '85') {
233 $loopid = '2010AA';
234 $title = 'Billing';
235 } elseif ($nm101 == '87') {
236 $loopid = '2010AB';
237 $title = 'Pay to';
238 } elseif ($nm101 == 'PE') {
239 $loopid = '2010AC';
240 $title = 'Pay to Plan';
241 } elseif ($nm101 == 'IL') {
242 $loopid = '2010BA';
243 $title = 'Subscriber';
244 } elseif ($nm101 == 'PR') {
245 $loopid = '2010BB';
246 $title = 'Payer';
247 } elseif ($nm101 == 'QC') {
248 $loopid = '2010CA';
249 $title = 'Patient';
250 } elseif ($nm101 == 'DN') {
251 $loopid = '2310A';
252 $title = 'Referring Provider';
253 } elseif ($nm101 == 'P3') {
254 $loopid = '2310A';
255 $title = 'Primary Care Provider';
256 } elseif ($nm101 == '82') {
257 $loopid = '2310B';
258 $title = 'Rendering Provider';
259 } elseif ($nm101 == '77') {
260 $loopid = '2310C';
261 $title = 'Service Facility';
262 } elseif ($nm101 == 'DQ') {
263 $loopid = '2310D';
264 $title = 'Supervising Provider';
265 } elseif ($nm101 == 'PW') {
266 $loopid = '2310E';
267 $title = 'Ambulance pickup';
268 } elseif ($nm101 == '45') {
269 $loopid = '2310F';
270 $title = 'Ambulance dropoff';
272 } elseif (strcmp(substr($loopid, 0, 4), '2400') < 0) {
273 if ($nm101 == 'IL') {
274 $loopid = '2330A';
275 $title = 'Other Subscriber';
276 } elseif ($nm101 == 'PR') {
277 $loopid = '2330B';
278 $title = 'Other Payer';
279 } elseif ($nm101 == 'PR') {
280 $loopid = '2330C';
281 $title = 'Other Referring Provider';
282 } elseif ($nm101 == '82') {
283 $loopid = '2330D';
284 $title = 'Other Rendering Provider';
285 } elseif ($nm101 == '77') {
286 $loopid = '2330E';
287 $title = 'Other Svc Facility';
288 } elseif ($nm101 == 'DQ') {
289 $loopid = '2330F';
290 $title = 'Other Supervising Provider';
291 } elseif ($nm101 == '85') {
292 $loopid = '2330G';
293 $title = 'Other Billing Provider';
295 } else {
296 if ($nm101 == '82') {
297 $loopid = '2420A';
298 $title = 'Rendering Provider';
299 } elseif ($nm101 == 'QB') {
300 $loopid = '2420B';
301 $title = 'Purchased Svc Provider';
302 } elseif ($nm101 == '77') {
303 $loopid = '2420C';
304 $title = 'Service Facility';
305 } elseif ($nm101 == 'DQ') {
306 $loopid = '2420D';
307 $title = 'Supervising Provider';
308 } elseif ($nm101 == 'DK') {
309 $loopid = '2420E';
310 $title = 'Ordering Provider';
311 } elseif ($nm101 == 'DN') {
312 $loopid = '2420F';
313 $title = 'Referring Provider';
314 } elseif ($nm101 == 'P3') {
315 $loopid = '2420F';
316 $title = 'Primary Care Provider';
317 } elseif ($nm101 == 'PW') {
318 $loopid = '2420G';
319 $title = 'Ambulance pickup';
320 } elseif ($nm101 == '45') {
321 $loopid = '2420H';
322 $title = 'Ambulance dropoff';
327 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
328 $title = '';
329 continue;
333 if (strncmp('SE' . $de, $seg, 3) === 0) {
334 $loopid = 'Trailer';
335 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
336 $title = '';
337 continue;
340 // for all the segments that do not begin loops
341 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'> -- </td><td class='btnum' title='" . attr($key) . "'>" . text($stsegct) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
346 return $str_html;
350 * identify loops and format segments for display
351 * of 270/271 (eligibility) type x12 edi files
353 * @param array $segments
354 * @param string $delimiter
355 * return string
357 function edih_271_text($segments, $delimiter, $err_seg = '')
360 $str_html = '';
362 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
363 // debug
364 csv_edihist_log('edih_271_text: invalid argument');
365 $str_html .= "Invalid arguments for view of x12 file text<br />";
366 return $str_html;
370 $de = $delimiter;
371 $prevseg = '';
372 $loopid = "0";
373 $lx_ct = 0;
374 $hasst = false;
375 $idx = 0;
376 $stsegct = 0;
378 // to highlight identified errors listed in 999/997 ack (for 270)
379 if ($err_seg) {
380 $er = edih_errseg_parse($err_seg);
381 $erstn = (isset($er['trace'])) ? substr($er['trace'], -4) : '';
382 $erseg = (isset($er['err'])) ? $er['err'] : array();
383 } else {
384 $erstn = '';
385 $erseg = array();
389 if ($err_seg) {
390 $er = edih_errseg_parse($err_seg);
391 if (is_array($er) && count($er)) {
392 $err_ar = $er;
397 foreach ($segments as $key => $seg) {
398 $sar = array();
399 $idx++;
400 $stsegct++;
401 $bterr = 'btseg';
403 if ($erstn && ($erstn == $stn)) {
404 $bterr = (in_array($stsegct, $erseg)) ? 'bterr' : 'btseg';
408 if (strncmp('ST' . $de, $seg, 3) === 0) {
409 $sar = explode($de, $seg);
410 $loopid = 'Header';
411 $hasst = true;
412 $stsegct = 1;
413 $sttp = (isset($seg[1])) ? $seg[1] : '';
414 $stn = (isset($seg[2])) ? $seg[2] : '';
415 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
416 continue;
420 if (strncmp('BHT' . $de, $seg, 4) === 0) {
421 $loopid = 'Begin';
422 // 2nd seg in transaction, ST may not be included if segments are transaction slice
423 if ($stsegct < 2) {
424 $stsegct = 2;
427 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
428 continue;
432 if (strncmp('HL' . $de, $seg, 3) === 0) {
433 $sar = explode($de, $seg);
434 if ($sar[3] == '20') { // level code
435 $loopid = '2000A'; // info source (payer)
436 } elseif ($sar[3] == '21') {
437 $loopid = '2000B'; // info receiver (clinic)
438 } elseif ($sar[3] == '22') {
439 $loopid = '2000C'; // subscriber
440 $has_eb = false;
441 } elseif ($sar[3] == '23') {
442 $loopid = '2000D'; // dependent
443 $has_eb = false;
444 } else {
445 //debug
446 csv_edihist_log('edih_271_text: HL has no level ' . $seg);
450 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
451 $prevseg = 'HL' . $de;
452 continue;
456 if (strncmp('NM1' . $de, $seg, 4) === 0) {
457 if (strncmp('NM1' . $de, $prevseg, 4) === 0) {
458 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
459 continue;
462 switch ((string)$loopid) {
463 case '2000A':
464 $loopid = '2100A';
465 break; // edih_change_loop($lptest, &$lpval)
466 case '2000B':
467 $loopid = '2100B';
468 break;
469 case '2000C':
470 $loopid = '2100C';
471 break;
472 case '2000D':
473 $loopid = '2100D';
474 break;
475 default:
476 $loopid = $loopid;
479 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
480 $prevseg = 'NM1' . $de;
481 continue;
485 if (strncmp('EB' . $de, $seg, 3) === 0 || strncmp('EQ' . $de, $seg, 3) === 0) {
486 // EB* segment is in 271 type, EQ* is corresponding segment in 270 type
487 if (strncmp($seg, $prevseg, 3) === 0) {
488 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
489 $prevseg = substr($seg, 0, 3);
490 continue;
493 if ($loopid = '2100C' || $loopid = '2115C' || $loopid = '2120C') {
494 $loopid = '2110C';
495 } elseif ($loopid = '2100D' || $loopid = '2115D' || $loopid = '2120D') {
496 $loopid = '2110D';
499 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
500 $prevseg = substr($seg, 0, 3);
501 $has_eb = (strncmp('EB' . $de, $seg, 3) === 0);
502 $has_iii = false;
503 continue;
507 if (strncmp('III' . $de, $seg, 4) === 0 && $has_eb) {
508 // the III segment begins a loop in 271 type, but not in 270
509 if ($loopid = '2110C') {
510 $loopid = '2115C';
513 if ($loopid = '2100D') {
514 $loopid = '2115D';
517 if ($has_iii) {
518 $str_html .= "<tr><td class='btloop'></td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
519 } else {
520 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
521 $has_iii = true;
524 $prevseg = substr($seg, 0, 4);
525 continue;
529 if (strncmp('LS' . $de, $seg, 3) === 0) {
530 if ($loopid = '2110C' || $loopid = '2115C') {
531 $loopid = '2120C';
532 } elseif ($loopid = '2110D' || $loopid = '2115D') {
533 $loopid = '2120D';
536 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
537 continue;
541 if (strncmp('SE' . $de, $seg, 3) === 0) {
542 $str_html .= "<tr><td class='btloop'>Trailer</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
543 $loopid = '0';
544 continue;
547 // for all the segments that do not begin loops
548 $prevseg = substr($seg, 0, strpos($seg, $de) + 1);
549 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
554 return $str_html;
558 function edih_835_text($segments, $delimiter, $err_seg = '')
561 $str_html = '';
562 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
563 //debug
564 csv_edihist_log('edih_835_text: invalid segments');
565 $str_html .= "Invalid arguments for view of x12 file text<br />";
566 return $str_html;
570 $de = $delimiter;
571 $prevseg = '';
572 $loopid = "0";
573 $lx_ct = 0;
574 $idx = 0;
576 foreach ($segments as $key => $seg) {
577 //$idx++;
579 if (strncmp('ST' . $de, $seg, 3) === 0) {
580 $loopid = 'Header';
581 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
582 continue;
586 if (strncmp('N1' . $de, $seg, 3) === 0) {
587 $sar = explode($de, $seg);
588 if ($sar[1] == 'PR') {
589 $loopid = '1000A';
590 } elseif ($sar[1] == 'PE') {
591 $loopid = '1000B';
594 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
595 $prevseg = 'N1' . $de;
596 continue;
600 if (strncmp('LX' . $de, $seg, 3) === 0) {
601 $loopid = '2000';
602 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
603 $prevseg = 'LX' . $de;
604 continue;
608 if (strncmp('TS3' . $de, $seg, 4) === 0) {
609 if ($loopid == '2000') {
610 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
611 } else {
612 $loopid = '2000';
613 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
616 $prevseg = 'TS3' . $de;
617 continue;
621 if (strncmp('CLP' . $de, $seg, 4) === 0) {
622 $loopid = '2100';
623 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
624 $prevseg = 'CLP' . $de;
625 continue;
629 if (strncmp('SVC' . $de, $seg, 4) === 0) {
630 $loopid = '2110';
631 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
632 $prevseg = 'SVC' . $de;
633 continue;
637 if (strncmp('PLB' . $de, $seg, 4) === 0) {
638 $loopid = 'Adjust';
639 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
640 $prevseg = 'PLB' . $de;
641 continue;
645 if (strncmp('SE' . $de, $seg, 3) === 0) {
646 $loopid = 'Trailer';
647 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
648 $prevseg = 'SE' . $de;
649 continue;
652 // for all the segments that do not begin loops
653 $prevseg = substr($seg, 0, 3);
654 $prevseg .= $de;
655 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
660 return $str_html;
665 * identify loops and format segments for display
666 * of 277 (claim status) type x12 edi files
668 * @param array $segments
669 * @param string $delimiter
670 * return string
672 function edih_277_text($segments, $delimiter, $stpos = '')
675 $str_html = '';
676 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
677 //debug
678 csv_edihist_log('edih_277_text: invlid segments');
679 $str_html .= "Invalid arguments for view of x12 file text<br />";
680 return $str_html;
684 // to highlight identified errors listed in 999/997 ack (for 276)
685 //if ($err_seg) {
686 //$er = edih_errseg_parse($err_seg);
687 //$erstn = (isset($er['trace'])) ? substr($er['trace'], -4) : '';
688 //$erseg = (isset($er['err'])) ? $er['err'] : array();
689 //} else {
690 //$erstn = '';
691 //$erseg = array();
694 $de = $delimiter;
695 $prevseg = '';
696 $loopid = "0";
697 $lx_ct = 0;
698 $stsegct = 0;
699 //$idx = 0;
701 foreach ($segments as $idx => $seg) {
702 //$idx++;
703 $stsegct++;
704 $key = ($stpos) ? $idx - $stpos : $idx;
705 // if 276 transactions are parsed, 999 errors may be present
706 //if ($erstn && ($erstn == $stn)) {
707 //$bterr = (in_array($stsegct, $erseg)) ? 'bterr' : 'btseg';
710 if (strncmp('ST' . $de, $seg, 3) === 0) {
711 $loopid = 'Header';
712 $stsegct = 1;
713 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
714 continue;
718 if (strncmp('BHT' . $de, $seg, 4) === 0) {
719 $loopid = 'Begin';
720 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
721 continue;
725 if (strncmp('HL' . $de, $seg, 3) === 0) {
726 $sar = explode($de, $seg);
727 if ($sar[3] == '20') { // level code
728 $loopid = '2000A'; // info source (payer)
729 } elseif ($sar[3] == '21') {
730 $loopid = '2000B'; // info receiver (clinic)
731 } elseif ($sar[3] == '19') {
732 $loopid = '2000C'; // provider
733 } elseif ($sar[3] == '22' || $sar[3] == 'PT') {
734 $loopid = '2000D'; // subscriber
735 } elseif ($sar[3] == '23') {
736 $loopid = '2000E'; // dependent
737 } else {
738 //debug
739 csv_edihist_log('edih_277_text: HL has no level ' . $seg);
743 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
744 $prevseg = 'HL' . $de;
745 continue;
750 if (strncmp('NM1' . $de, $seg, 4) === 0) {
751 if (strncmp('NM1' . $de, $prevseg, 4) === 0) {
752 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
753 continue;
756 switch ((string)$loopid) {
757 case '2000A':
758 $loopid = '2100A';
759 break; // edih_change_loop($lptest, &$lpval)
760 case '2000B':
761 $loopid = '2100B';
762 break;
763 case '2000C':
764 $loopid = '2100C';
765 break;
766 case '2000D':
767 $loopid = '2100D';
768 break;
769 case '2000E':
770 $loopid = '2100E';
771 break;
774 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
775 $prevseg = 'NM1';
776 continue;
780 if (strncmp('TRN' . $de, $seg, 4) === 0) {
781 if (strncmp('TRN' . $de, $prevseg, 4) === 0) {
782 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
783 continue;
786 switch ((string)$loopid) {
787 case '2100A':
788 $loopid = '2200A';
789 break;
790 case '2100B':
791 $loopid = '2200B';
792 break;
793 case '2100C':
794 $loopid = '2200C';
795 break;
796 case '2100D':
797 $loopid = '2200D';
798 break;
799 case '2100E':
800 $loopid = '2200E';
801 break;
804 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
805 $prevseg = 'TRN';
806 continue;
810 if (strncmp('SVC' . $de, $seg, 4) === 0) {
811 if (strncmp('SVC' . $de, $prevseg, 4) === 0) {
812 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
813 continue;
816 switch ((string)$loopid) {
817 case '2200D':
818 $loopid = '2220D';
819 break;
820 case '2200E':
821 $loopid = '2220E';
822 break;
825 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
826 $prevseg = 'SVC';
827 continue;
831 if (strncmp('SE' . $de, $seg, 3) === 0) {
832 $loopid = 'Trailer';
833 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
834 $prevseg = 'SE';
835 continue;
838 // for all the segments that do not begin loops
839 $prevseg = substr($seg, 0, 3);
840 $prevseg .= $de;
841 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
845 return $str_html;
849 * identify loops and format segments for display
850 * of 278 (authorization) type x12 edi files
852 * @param array $segments
853 * @param string $delimiter
854 * return string
856 function edih_278_text($segments, $delimiter, $err_seg = '')
859 $str_html = '';
861 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
862 // debug
863 csv_edihist_log('edih_278_text(): invalid argument');
864 $str_html .= "Invalid arguments for view of x12 file text<br />";
865 return $str_html;
869 $de = $delimiter;
870 $prevseg = '';
871 $loopid = "0";
872 $lx_ct = 0;
873 $hasst = false;
874 $err_ar = array();
875 $idx = 0;
876 $stsegct = 0;
878 // to highlight identified errors listed in 999/997 ack
879 if ($err_seg) {
880 $er = edih_errseg_parse($err_seg);
881 $erstn = (isset($er['trace'])) ? substr($er['trace'], -4) : '';
882 $erseg = (isset($er['err'])) ? $er['err'] : array();
883 } else {
884 $erstn = '';
885 $erseg = array();
889 foreach ($segments as $key => $seg) {
890 $idx++;
891 $stsegct++;
892 $title = '';
893 $bterr = 'btseg';
895 if ($erstn && ($erstn == $stn)) {
896 $bterr = (in_array($stsegct, $erseg)) ? 'bterr' : 'btseg';
900 if (strncmp('ST' . $de, $seg, 3) === 0) {
901 $loopid = 'Header';
902 $hasst = true;
903 $stsegct = 1;
904 $stn = explode($de, $seg)[2];
905 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
906 continue;
910 if (strncmp('BHT' . $de, $seg, 4) === 0) {
911 $loopid = 'Begin';
912 // 2nd seg in transaction, ST may not be included if segments are transaction slice
913 if ($stsegct < 2) {
914 $stsegct = 2;
917 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
918 continue;
922 if (strncmp($seg, 'HL' . $de, 3) === 0) {
923 $sar = explode($de, $seg);
924 $hl = $sar[1];
925 $hlpc = $sar[2]; // parent code
926 $hllc = $sar[3];
927 $hlcc = (isset($sar[4])) ? $sar[4] : ''; // child code
928 if ($sar[3] == '20') { // level code
929 $loopid = '2000A'; // info source (payer)
930 $title = 'Info Source';
931 } elseif ($sar[3] == '21') {
932 $loopid = '2000B'; // info receiver (clinic)
933 $title = 'Info Receiver';
934 } elseif ($sar[3] == '22') {
935 $loopid = '2000C'; // subscriber
936 $title = 'Subscriber';
937 } elseif ($sar[3] == '23') {
938 $loopid = '2000D'; // dependent
939 $title = 'Dependent';
940 } elseif ($sar[3] == 'EV') {
941 $loopid = '2000E'; // patient event
942 $title = 'Patient Event';
943 } elseif ($sar[3] == 'SS') {
944 $loopid = '2000F'; // service
945 $title = 'Service';
946 } else {
947 //debug
948 csv_edihist_log('edih_278_text: HL has no level ' . $seg);
952 $str_html .= "<tr><td class='btloop' title='" . attr($title) . "'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
953 $prevseg = 'HL';
954 continue;
958 if (strncmp($seg, 'NM1' . $de, 4) === 0) {
959 $sar = explode($de, $seg);
960 $nm101 = $sar[1];
961 if ($loopid == '2000A') {
962 $loopid == '2010A'; // Source
963 } elseif ($loopid == '2000B') {
964 $loopid = '2010B'; // Receiver
965 } elseif ($loopid == '2000C') {
966 $loopid = '2010C'; // Subscriber
967 } elseif ($loopid == '2000D') {
968 $loopid = '2010D'; // Dependent
969 } elseif ($loopid == '2000E' || strpos($loopid, '010E')) { // Patient Event
970 $loopid = (strpos('|71|72|73|77|AAJ|DD|DK|DN|FA|G3|P3|QB|QV|SJ', $nm101) ) ? '2010EA' : $loopid;
971 $loopid = (strpos('|45|FS|ND|PW|R3', $nm101) ) ? '2010EB' : $loopid;
972 $loopid = ($nm101 == 'L5') ? '2010EC' : $loopid;
973 } elseif ($loopid == '2000F' || strpos($loopid, '010F')) { // Service
974 $loopid = (strpos('|71|72|73|77|AAJ|DD|DK|DN|FA|G3|P3|QB|QV|SJ', $nm101) ) ? '2010FA' : $loopid;
978 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
979 $prevseg = 'NM1';
980 continue;
984 if (strncmp('SE' . $de, $seg, 3) === 0) {
985 $str_html .= "<tr><td class='btloop'>Trailer</td><td class='btnum'>" . text($key) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
986 $loopid = '0';
987 $prevseg = 'SE';
988 continue;
991 // for all the segments that do not begin loops
992 $prevseg = substr($seg, 0, strpos($seg, $de));
993 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='" . attr($bterr) . "'>" . text($seg) . "</td></tr>" . PHP_EOL;
998 return $str_html;
1002 * identify loops and format segments for display
1003 * of 997/999 (acknowledgement) type x12 edi files
1005 * @param array $segments
1006 * @param string $delimiter
1007 * return string
1009 function edih_997_text($segments, $delimiter)
1012 $str_html = '';
1013 if (!is_array($segments) || !count($segments) || strlen($delimiter) != 1) {
1014 //debug
1015 csv_edihist_log('edih_997_text(): invalid segments');
1016 return $str_html;
1020 $de = $delimiter;
1021 $loopid = "0";
1023 //echo 'edih_997_text() foreach segment count: '.count($segments).PHP_EOL;
1025 foreach ($segments as $key => $seg) {
1027 //echo var_dump($seg).PHP_EOL;
1029 if (strncmp('TA1' . $de, $seg, 4) === 0) {
1030 $sar = explode($de, $seg);
1031 $rspicn = $sar[1];
1032 $loopid = 'ACK'; // not official
1033 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1034 unset($sar);
1035 $loopid = ''; // reset loop for subsequent segments
1036 continue;
1040 if (strncmp('ST' . $de, $seg, 3) === 0) {
1041 $loopid = 'Header';
1042 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1043 continue;
1047 if (strncmp('AK1' . $de, $seg, 4) === 0) {
1048 $sar = explode($de, $seg);
1049 $rsptp = csv_file_type($sar[1]);
1050 if ($rspicn && $rsptp) {
1051 $rspfile = csv_file_by_controlnum($rsptp, $rspicn);
1054 $title = ($rspfile) ? 'response to ' . $rspfile : '';
1055 $loopid = '2000';
1056 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td title='" . attr($title) . "' class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1057 unset($sar);
1058 continue;
1062 if (strncmp('AK2' . $de, $seg, 4) === 0) {
1063 $loopid = 'AK2';
1064 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1065 continue;
1069 if (strncmp('IK3' . $de, $seg, 4) === 0 || strncmp('AK3' . $de, $seg, 4) === 0) {
1070 $loopid = '2100';
1071 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1072 continue;
1076 if (strncmp('IK4' . $de, $seg, 4) === 0 || strncmp('AK4' . $de, $seg, 4) === 0) {
1077 $loopid = '2110';
1078 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1079 continue;
1083 if (strncmp('SE' . $de, $seg, 3) === 0) {
1084 $loopid = 'Trailer';
1085 $str_html .= "<tr><td class='btloop'>" . text($loopid) . "</td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1086 continue;
1089 // for all the segments that do not begin loops ;
1090 $str_html .= "<tr><td class='btloop'> -- </td><td class='btnum'>" . text($key) . "</td><td class='btseg'>" . text($seg) . "</td></tr>" . PHP_EOL;
1094 return $str_html;
1098 * Display of x12 edi transaction listing or all segments in the files.
1099 * When using $err_info, you must use the filepath of the submitted file
1101 * @param string $filepath path to desired file
1102 * @param string $filetype used when filepath is just filename
1103 * @param string optional $claimid CLM01, or BHT03 to identify a transaction or a trace value
1104 * @param bool false: $claimid is pt transaction, true: $claimid is trace from 835 or 999
1105 * @param string optional $err_info the prepared error info from a 997/999 response
1106 * @return string html for display of file segments
1108 function edih_display_text($filepath, $filetype = '', $claimid = '', $trace = false, $err_info = '')
1111 $str_html = '';
1112 $de = '';
1113 $segments = '';
1114 $stsegkey = '';
1115 $ft = ($filetype) ? $filetype : '';
1116 $errs = ( strlen($err_info) ) ? $err_info : '';
1117 $bht03 = '';
1119 // verify x12 file
1120 $x12obj = csv_check_x12_obj($filepath, $ft);
1122 if ($x12obj && 'edih_x12_file' == get_class($x12obj)) {
1123 $ftype = $x12obj->edih_type();
1124 $ft = csv_file_type($ftype);
1125 $delims = $x12obj->edih_delimiters();
1126 $de = $delims['e'];
1127 $fn = $x12obj->edih_filename();
1128 $segs_ar = $x12obj->edih_segments();
1129 $env_ar = $x12obj->edih_envelopes();
1130 if (!$de || strlen($de) != 1) {
1131 // error in object
1132 // debug
1133 $str_html = 'edih_display_text(): error in delimiters<br />' . PHP_EOL;
1134 $str_html .= $x12obj->edih_message() . PHP_EOL;
1135 return $str_html;
1138 if (!is_array($segs_ar) || !count($segs_ar)) {
1139 // unknown error
1140 $str_html = "<p>unknown error retrieving segments for " . text($fn) . "</p>" . PHP_EOL;
1141 $str_html .= $x12obj->edih_message() . PHP_EOL;
1142 return $str_html;
1144 } else {
1145 //debug
1146 csv_edihist_log('edih_transaction_text(): invalid path ' . $filepath);
1147 $str_html = 'edih_display_text(): error accessing file<br />' . PHP_EOL;
1148 return $str_html;
1152 if ($claimid) {
1153 // claimid can be for transaction, payment, or error response
1154 if ($trace && array_key_exists($claimid, $env_ar['ISA'])) {
1155 $arg_ar = array('ISA13' => $claimid, 'keys' => true);
1156 $segments = $x12obj->edih_x12_slice($arg_ar);
1157 } else {
1158 // claimid alone can be clm01 or bht03, if trace=true, expect trn02 for claimid
1159 foreach ($env_ar['ST'] as $st) {
1160 if ($trace && $claimid == $st['trace']) {
1161 $arg_ar = array('ISA13' => $st['icn'], 'GS06' => $st['gsn'], 'trace' => $claimid, 'keys' => true);
1162 $segments = $x12obj->edih_x12_slice($arg_ar);
1163 break;
1164 } elseif (in_array($claimid, $st['acct'])) {
1165 if ($errs) {
1166 $arg_ar = array('ST02' => $st['stn'], 'ISA13' => $st['icn'], 'GS06' => $st['gsn'], 'keys' => true);
1167 $segments = $x12obj->edih_x12_slice($arg_ar);
1168 } else {
1169 // request for individual transaction segments
1170 $segments = $x12obj->edih_x12_transaction($claimid);
1173 break;
1174 } elseif (in_array($claimid, $st['bht03'])) {
1175 // also possible that bht03 number is given for claimid
1176 // this will likely be a 27x
1177 if ($errs) {
1178 $arg_ar = array('ST02' => $st['stn'], 'ISA13' => $st['icn'], 'GS06' => $st['gsn'], 'keys' => true);
1179 $segments = $x12obj->edih_x12_slice($arg_ar);
1180 } else {
1181 $segments = $x12obj->edih_x12_transaction($claimid);
1184 $bht03 = $claimid;
1185 break;
1189 } else {
1190 $segments = $segs_ar;
1194 // now check if we have segments
1195 if (empty($segments) || !count($segments)) {
1196 if ($claimid) {
1197 $str_html = "<p>error: transaction " . text($claimid) . " not found in " . text($fn) . "</p>" . PHP_EOL;
1198 $str_html .= $x12obj->edih_message() . PHP_EOL;
1199 return $str_html;
1200 } else {
1201 // unknown error
1202 $str_html = "<p>unknown error retrieving segments for " . text($fn) . "</p>" . PHP_EOL;
1203 $str_html .= $x12obj->edih_message() . PHP_EOL;
1204 return $str_html;
1208 // if the segments are from a slice or transaction
1209 // a multidimensional array segs[i][j] must be flattened
1210 $ar_sngl = csv_singlerecord_test($segments);
1211 // false when segments are a transaction or trace only
1212 if (!$ar_sngl) {
1214 // append segments to single array
1215 // keys should not duplicate since all segments
1216 // are from the same x12 file
1217 $trnsegs = array();
1218 for ($i = 0; $i < count($segments); $i++) {
1219 $trnsegs = array_merge($trnsegs, $segments[$i]);
1222 $segments = $trnsegs;
1223 unset($trnsegs);
1227 $capstr = '';
1228 $tbl_id = ($claimid) ? $claimid : $fn;
1230 //'HB'=>'271', 'HS'=>'270', 'HR'=>'276', 'HI'=>'278','HN'=>'277', 'HP'=>'835', 'FA'=>'999', 'HC'=>'837');
1231 switch ((string)$ftype) {
1232 case 'HC':
1233 $capstr = "Claim "; //$cls = "txt837";
1234 $trn_html = edih_837_text($segments, $de, $errs);
1235 break;
1236 case 'HP':
1237 $capstr = "Payment "; //$cls = "txt835";
1238 $trn_html = edih_835_text($segments, $de);
1239 break;
1240 case 'HR':
1241 $capstr = "Status Query "; //$cls = "txt276";
1242 $trn_html = edih_277_text($segments, $de, $errs);
1243 break;
1244 case 'HN':
1245 $capstr = "Claim Status "; //$cls = "txt277";
1246 $trn_html = edih_277_text($segments, $de, $stsegkey);
1247 break;
1248 case 'HS':
1249 $capstr = "Eligibility Query "; //$cls = "txt270";
1250 $trn_html = edih_271_text($segments, $de, $errs);
1251 break;
1252 case 'HB':
1253 $capstr = "Eligibility Report "; //$cls = "txt271";
1254 $trn_html = edih_271_text($segments, $de);
1255 break;
1256 case 'HI':
1257 $capstr = "Authorization "; //$cls = "txt278";
1258 $trn_html = edih_278_text($segments, $de, $errs);
1259 break;
1260 case 'FA':
1261 $capstr = "Batch Acknowledgment "; //$cls = "txt997";
1262 $trn_html = edih_997_text($segments, $de);
1263 break;
1264 default:
1265 $capstr = "x12 $ftype "; //$cls = "txt_x12";
1266 $trn_html = edih_segments_text($segments, $de);
1267 break;
1271 $capstr .= ($claimid) ? " <em>ID:</em> " . text($claimid) : "";
1273 $str_html .= "<table id=" . attr($tbl_id) . " cols=3 class='segtxt'><caption>" . text($capstr) . "</caption>" . PHP_EOL;
1274 $str_html .= "<thead>" . PHP_EOL;
1275 $str_html .= "<tr><th class='btloop'>Loop</th><th class='btloop'>Num</th>";
1276 $str_html .= "<th class='segtxt'>Segment (<em>File:</em> " . text($fn) . ")</th></tr>" . PHP_EOL;
1277 $str_html .= "</thead>" . PHP_EOL . "<tbody>" . PHP_EOL;
1279 $str_html .= $trn_html;
1281 $str_html .= "</tbody></table>" . PHP_EOL;
1283 return $str_html;