Simplified code to generate img tag rather than iframe.
[openemr.git] / library / gen_x12_837.inc.php
blobe491b88ac675f186f9e4fb12ab27222629ad52f2
1 <?php
2 // Copyright (C) 2007-2008 Rod Roark <rod@sunsetsystems.com>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 require_once("Claim.class.php");
11 function gen_x12_837($pid, $encounter, &$log) {
13 $today = time();
14 $out = '';
15 $claim = new Claim($pid, $encounter);
16 $edicount = 0;
18 $log .= "Generating claim $pid-$encounter for " .
19 $claim->patientFirstName() . ' ' .
20 $claim->patientMiddleName() . ' ' .
21 $claim->patientLastName() . ' on ' .
22 date('Y-m-d H:i', $today) . ".\n";
24 $out .= "ISA" .
25 "*00" .
26 "* " .
27 "*00" .
28 "* " .
29 "*ZZ" .
30 "*" . $claim->x12gssenderid() .
31 "*ZZ" .
32 "*" . $claim->x12gsreceiverid() .
33 "*030911" .
34 "*1630" .
35 "*U" .
36 "*00401" .
37 "*000000001" .
38 "*0" .
39 "*P" .
40 "*:" .
41 "~\n";
43 $out .= "GS" .
44 "*HC" .
45 "*" . $claim->x12gssenderid() .
46 "*" . $claim->x12gsreceiverid() .
47 "*" . date('Ymd', $today) .
48 "*" . date('Hi', $today) .
49 "*1" .
50 "*X" .
51 "*" . $claim->x12gsversionstring() .
52 "~\n";
54 ++$edicount;
55 $out .= "ST" .
56 "*837" .
57 "*0021" .
58 "~\n";
60 ++$edicount;
61 $out .= "BHT" .
62 "*0019" .
63 "*00" .
64 "*0123" .
65 "*" . date('Ymd', $today) .
66 "*1023" .
67 "*CH" .
68 "~\n";
70 ++$edicount;
71 $out .= "REF" .
72 "*87" .
73 "*" . $claim->x12gsversionstring() .
74 "~\n";
76 ++$edicount;
77 $out .= "NM1" . // Loop 1000A Submitter
78 "*41" .
79 "*2" .
80 "*" . $claim->billingFacilityName() .
81 "*" .
82 "*" .
83 "*" .
84 "*" .
85 "*46" .
86 "*" . $claim->billingFacilityETIN() .
87 "~\n";
89 ++$edicount;
90 $out .= "PER" .
91 "*IC" .
92 "*" . $claim->billingContactName() .
93 "*TE" .
94 "*" . $claim->billingContactPhone() .
95 "~\n";
97 ++$edicount;
98 $out .= "NM1" . // Loop 1000B Receiver
99 "*40" .
100 "*2" .
101 "*" . $claim->clearingHouseName() .
102 "*" .
103 "*" .
104 "*" .
105 "*" .
106 "*46" .
107 "*" . $claim->clearingHouseETIN() .
108 "~\n";
110 $HLcount = 1;
112 ++$edicount;
113 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
114 "*$HLcount" .
115 "*" .
116 "*20" .
117 "*1" .
118 "~\n";
120 $HLBillingPayToProvider = $HLcount++;
122 ++$edicount;
123 $out .= "NM1" . // Loop 2010AA Billing Provider
124 "*85" .
125 "*2" .
126 "*" . $claim->billingFacilityName() .
127 "*" .
128 "*" .
129 "*" .
130 "*";
131 if ($claim->billingFacilityNPI()) {
132 $out .= "*XX*" . $claim->billingFacilityNPI();
133 } else {
134 $log .= "*** Billing facility has no NPI.\n";
135 $out .= "*24*" . $claim->billingFacilityETIN();
137 $out .= "~\n";
139 ++$edicount;
140 $out .= "N3" .
141 "*" . $claim->billingFacilityStreet() .
142 "~\n";
144 ++$edicount;
145 $out .= "N4" .
146 "*" . $claim->billingFacilityCity() .
147 "*" . $claim->billingFacilityState() .
148 "*" . $claim->billingFacilityZip() .
149 "~\n";
151 // Add a REF*EI*<ein> segment if NPI was specified in the NM1 above.
152 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
153 ++$edicount;
154 $out .= "REF" .
155 "*EI" .
156 "*" . $claim->billingFacilityETIN() .
157 "~\n";
160 if ($claim->providerNumberType() && $claim->providerNumber()) {
161 ++$edicount;
162 $out .= "REF" .
163 "*" . $claim->providerNumberType() .
164 "*" . $claim->providerNumber() .
165 "~\n";
167 else if ($claim->providerNumber()) {
168 $log .= "*** Payer-specific provider insurance number is present but has no type assigned.\n";
171 ++$edicount;
172 $out .= "NM1" . // Loop 2010AB Pay-To Provider
173 "*87" .
174 "*2" .
175 "*" . $claim->billingFacilityName() .
176 "*" .
177 "*" .
178 "*" .
179 "*";
180 if ($claim->billingFacilityNPI())
181 $out .= "*XX*" . $claim->billingFacilityNPI();
182 else
183 $out .= "*24*" . $claim->billingFacilityETIN();
184 $out .= "~\n";
186 ++$edicount;
187 $out .= "N3" .
188 "*" . $claim->billingFacilityStreet() .
189 "~\n";
191 ++$edicount;
192 $out .= "N4" .
193 "*" . $claim->billingFacilityCity() .
194 "*" . $claim->billingFacilityState() .
195 "*" . $claim->billingFacilityZip() .
196 "~\n";
198 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
199 ++$edicount;
200 $out .= "REF" .
201 "*EI" .
202 "*" . $claim->billingFacilityETIN() .
203 "~\n";
206 $PatientHL = 0;
208 ++$edicount;
209 $out .= "HL" . // Loop 2000B Subscriber HL Loop
210 "*$HLcount" .
211 "*$HLBillingPayToProvider" .
212 "*22" .
213 "*$PatientHL" .
214 "~\n";
216 $HLSubscriber = $HLcount++;
218 if (!$claim->payerSequence()) {
219 $log .= "*** Error: Insurance information is missing!\n";
221 ++$edicount;
222 $out .= "SBR" . // Subscriber Information
223 "*" . $claim->payerSequence() .
224 "*" . $claim->insuredRelationship() .
225 "*" . $claim->groupNumber() .
226 "*" . $claim->groupName() .
227 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
228 "*" .
229 "*" .
230 "*" .
231 "*" . $claim->claimType() . // Zirmed replaces this
232 "~\n";
234 ++$edicount;
235 $out .= "NM1" . // Loop 2010BA Subscriber
236 "*IL" .
237 "*1" .
238 "*" . $claim->insuredLastName() .
239 "*" . $claim->insuredFirstName() .
240 "*" . $claim->insuredMiddleName() .
241 "*" .
242 "*" .
243 "*MI" .
244 "*" . $claim->policyNumber() .
245 "~\n";
247 ++$edicount;
248 $out .= "N3" .
249 "*" . $claim->insuredStreet() .
250 "~\n";
252 ++$edicount;
253 $out .= "N4" .
254 "*" . $claim->insuredCity() .
255 "*" . $claim->insuredState() .
256 "*" . $claim->insuredZip() .
257 "~\n";
259 ++$edicount;
260 $out .= "DMG" .
261 "*D8" .
262 "*" . $claim->insuredDOB() .
263 "*" . $claim->insuredSex() .
264 "~\n";
266 ++$edicount;
267 $out .= "NM1" . // Loop 2010BB Payer
268 "*PR" .
269 "*2" .
270 "*" . $claim->payerName() .
271 "*" .
272 "*" .
273 "*" .
274 "*" .
275 "*PI" .
276 "*" . $claim->payerID() . // Zirmed ignores this if using Payer Name Matching.
277 "~\n";
279 // if (!$claim->payerID()) {
280 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName() . "'.\n";
281 // }
283 ++$edicount;
284 $out .= "N3" .
285 "*" . $claim->payerStreet() .
286 "~\n";
288 ++$edicount;
289 $out .= "N4" .
290 "*" . $claim->payerCity() .
291 "*" . $claim->payerState() .
292 "*" . $claim->payerZip() .
293 "~\n";
295 if (! $claim->isSelfOfInsured()) {
296 ++$edicount;
297 $out .= "HL" . // Loop 2000C Patient Information
298 "*$HLcount" .
299 "*$HLSubscriber" .
300 "*23" .
301 "*0" .
302 "~\n";
304 $HLcount++;
306 ++$edicount;
307 $out .= "PAT" .
308 "*" . $claim->insuredRelationship() .
309 "~\n";
311 ++$edicount;
312 $out .= "NM1" . // Loop 2010CA Patient
313 "*QC" .
314 "*1" .
315 "*" . $claim->patientLastName() .
316 "*" . $claim->patientFirstName() .
317 "*" . $claim->patientMiddleName() .
318 "~\n";
320 ++$edicount;
321 $out .= "N3" .
322 "*" . $claim->patientStreet() .
323 "~\n";
325 ++$edicount;
326 $out .= "N4" .
327 "*" . $claim->patientCity() .
328 "*" . $claim->patientState() .
329 "*" . $claim->patientZip() .
330 "~\n";
332 ++$edicount;
333 $out .= "DMG" .
334 "*D8" .
335 "*" . $claim->patientDOB() .
336 "*" . $claim->patientSex() .
337 "~\n";
338 } // end of patient different from insured
340 $proccount = $claim->procCount();
342 $clm_total_charges = 0;
343 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
344 $clm_total_charges += $claim->cptCharges($prockey);
347 if (!$clm_total_charges) {
348 $log .= "*** This claim has no charges!\n";
351 ++$edicount;
352 $out .= "CLM" . // Loop 2300 Claim
353 "*$pid-$encounter" .
354 "*" . sprintf("%.2f",$clm_total_charges) . // Zirmed computes and replaces this
355 "*" .
356 "*" .
357 "*" . $claim->facilityPOS() . "::" . $claim->frequencyTypeCode() .
358 "*Y" .
359 "*A" .
360 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
361 "*Y" .
362 "*C" .
363 "~\n";
365 ++$edicount;
366 $out .= "DTP" . // Date of Onset
367 "*431" .
368 "*D8" .
369 "*" . $claim->onsetDate() .
370 "~\n";
372 if (strcmp($claim->facilityPOS(),'21') == 0) {
373 ++$edicount;
374 $out .= "DTP" . // Date of Hospitalization
375 "*435" .
376 "*D8" .
377 "*" . $claim->onsetDate() .
378 "~\n";
381 $patientpaid = $claim->patientPaidAmount();
382 if ($patientpaid != 0) {
383 ++$edicount;
384 $out .= "AMT" . // Patient paid amount. Page 220.
385 "*F5" .
386 "*" . $patientpaid .
387 "~\n";
390 if ($claim->priorAuth()) {
391 ++$edicount;
392 $out .= "REF" . // Prior Authorization Number
393 "*G1" .
394 "*" . $claim->priorAuth() .
395 "~\n";
398 if ($claim->cliaCode()) {
399 // Required by Medicare when in-house labs are done.
400 ++$edicount;
401 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
402 "*X4" .
403 "*" . $claim->cliaCode() .
404 "~\n";
407 // Note: This would be the place to implement the NTE segment for loop 2300.
409 $da = $claim->diagArray();
410 ++$edicount;
411 $out .= "HI"; // Health Diagnosis Codes
412 $diag_type_code = 'BK';
413 foreach ($da as $diag) {
414 $out .= "*$diag_type_code:" . $diag;
415 $diag_type_code = 'BF';
417 $out .= "~\n";
419 if ($claim->referrerLastName()) {
420 // Medicare requires referring provider's name and UPIN.
421 ++$edicount;
422 $out .= "NM1" . // Loop 2310A Referring Provider
423 "*DN" .
424 "*1" .
425 "*" . $claim->referrerLastName() .
426 "*" . $claim->referrerFirstName() .
427 "*" . $claim->referrerMiddleName() .
428 "*" .
429 "*";
430 if ($claim->referrerNPI()) { $out .=
431 "*XX" .
432 "*" . $claim->referrerNPI();
433 } else { $out .=
434 "*34" .
435 "*" . $claim->referrerSSN();
437 $out .= "~\n";
439 if ($claim->referrerTaxonomy()) {
440 ++$edicount;
441 $out .= "PRV" .
442 "*RF" . // ReFerring provider
443 "*ZZ" .
444 "*" . $claim->referrerTaxonomy() .
445 "~\n";
448 if ($claim->referrerUPIN()) {
449 ++$edicount;
450 $out .= "REF" . // Referring Provider Secondary Identification
451 "*1G" .
452 "*" . $claim->referrerUPIN() .
453 "~\n";
457 ++$edicount;
458 $out .= "NM1" . // Loop 2310B Rendering Provider
459 "*82" .
460 "*1" .
461 "*" . $claim->providerLastName() .
462 "*" . $claim->providerFirstName() .
463 "*" . $claim->providerMiddleName() .
464 "*" .
465 "*";
466 if ($claim->providerNPI()) { $out .=
467 "*XX" .
468 "*" . $claim->providerNPI();
469 } else { $out .=
470 "*34" .
471 "*" . $claim->providerSSN();
472 $log .= "*** Rendering provider has no NPI.\n";
474 $out .= "~\n";
476 if ($claim->providerTaxonomy()) {
477 ++$edicount;
478 $out .= "PRV" .
479 "*PE" . // PErforming provider
480 "*ZZ" .
481 "*" . $claim->providerTaxonomy() .
482 "~\n";
485 // REF*1C is required here for the Medicare provider number if NPI was
486 // specified in NM109. Not sure if other payers require anything here.
487 if ($claim->providerNumber()) {
488 ++$edicount;
489 $out .= "REF" .
490 "*" . $claim->providerNumberType() .
491 "*" . $claim->providerNumber() .
492 "~\n";
495 // Loop 2310D is omitted in the case of home visits (POS=12).
496 if ($claim->facilityPOS() != 12) {
497 ++$edicount;
498 $out .= "NM1" . // Loop 2310D Service Location
499 "*77" .
500 "*2";
501 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) { $out .=
502 "*" . $claim->facilityName();
504 if ($claim->facilityNPI() || $claim->facilityETIN()) { $out .=
505 "*" .
506 "*" .
507 "*" .
508 "*";
509 if ($claim->facilityNPI()) { $out .=
510 "*XX*" . $claim->facilityNPI();
511 } else { $out .=
512 "*24*" . $claim->facilityETIN();
513 $log .= "*** Service location has no NPI.\n";
516 $out .= "~\n";
517 if ($claim->facilityStreet()) {
518 ++$edicount;
519 $out .= "N3" .
520 "*" . $claim->facilityStreet() .
521 "~\n";
523 if ($claim->facilityState()) {
524 ++$edicount;
525 $out .= "N4" .
526 "*" . $claim->facilityCity() .
527 "*" . $claim->facilityState() .
528 "*" . $claim->facilityZip() .
529 "~\n";
533 $prev_pt_resp = $clm_total_charges; // for computation below
535 // Loops 2320 and 2330*, other subscriber/payer information.
537 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
539 $tmp1 = $claim->claimType($ins);
540 $tmp2 = 'C1'; // Here a kludge. See page 321.
541 if ($tmp1 === 'CI') $tmp2 = 'C1';
542 if ($tmp1 === 'AM') $tmp2 = 'AP';
543 if ($tmp1 === 'HM') $tmp2 = 'HM';
544 if ($tmp1 === 'MB') $tmp2 = 'MB';
545 if ($tmp1 === 'MC') $tmp2 = 'MC';
546 if ($tmp1 === '09') $tmp2 = 'PP';
547 ++$edicount;
548 $out .= "SBR" . // Loop 2320, Subscriber Information - page 318
549 "*" . $claim->payerSequence($ins) .
550 "*" . $claim->insuredRelationship($ins) .
551 "*" . $claim->groupNumber($ins) .
552 "*" . $claim->groupName($ins) .
553 "*" . $tmp2 .
554 "*" .
555 "*" .
556 "*" .
557 "*" . $claim->claimType($ins) .
558 "~\n";
560 // Things that apply only to previous payers, not future payers.
562 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
564 // Generate claim-level adjustments.
565 $aarr = $claim->payerAdjustments($ins);
566 foreach ($aarr as $a) {
567 ++$edicount;
568 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 323.
569 "*" . $a[1] .
570 "*" . $a[2] .
571 "*" . $a[3] .
572 "~\n";
575 $payerpaid = $claim->payerTotals($ins);
576 ++$edicount;
577 $out .= "AMT" . // Previous payer's paid amount. Page 332.
578 "*D" .
579 "*" . $payerpaid[1] .
580 "~\n";
582 // Patient responsibility amount as of this previous payer.
583 $prev_pt_resp -= $payerpaid[1]; // reduce by payments
584 $prev_pt_resp -= $payerpaid[2]; // reduce by adjustments
586 ++$edicount;
587 $out .= "AMT" . // Patient responsibility amount per previous payer. Page 335.
588 "*F2" .
589 "*" . sprintf('%.2f', $prev_pt_resp) .
590 "~\n";
592 } // End of things that apply only to previous payers.
594 ++$edicount;
595 $out .= "DMG" . // Other subscriber demographic information. Page 342.
596 "*D8" .
597 "*" . $claim->insuredDOB($ins) .
598 "*" . $claim->insuredSex($ins) .
599 "~\n";
601 ++$edicount;
602 $out .= "OI" . // Other Insurance Coverage Information. Page 344.
603 "*" .
604 "*" .
605 "*Y" .
606 "*B" .
607 "*" .
608 "*Y" .
609 "~\n";
611 ++$edicount;
612 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 350.
613 "*IL" .
614 "*1" .
615 "*" . $claim->insuredLastName($ins) .
616 "*" . $claim->insuredFirstName($ins) .
617 "*" . $claim->insuredMiddleName($ins) .
618 "*" .
619 "*" .
620 "*MI" .
621 "*" . $claim->policyNumber($ins) .
622 "~\n";
624 ++$edicount;
625 $out .= "N3" .
626 "*" . $claim->insuredStreet($ins) .
627 "~\n";
629 ++$edicount;
630 $out .= "N4" .
631 "*" . $claim->insuredCity($ins) .
632 "*" . $claim->insuredState($ins) .
633 "*" . $claim->insuredZip($ins) .
634 "~\n";
636 ++$edicount;
637 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 359.
638 "*PR" .
639 "*2" .
640 "*" . $claim->payerName($ins) .
641 "*" .
642 "*" .
643 "*" .
644 "*" .
645 "*PI" .
646 "*" . $claim->payerID($ins) .
647 "~\n";
649 // if (!$claim->payerID($ins)) {
650 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
651 // }
653 // Payer address (N3 and N4) are added below so that Gateway EDI can
654 // auto-generate secondary claims. These do NOT appear in my copy of
655 // the spec! -- Rod 2008-06-12
657 if ($claim->x12gsreceiverid() == '431420764') { // if Gateway EDI
658 ++$edicount;
659 $out .= "N3" .
660 "*" . $claim->payerStreet($ins) .
661 "~\n";
663 ++$edicount;
664 $out .= "N4" .
665 "*" . $claim->payerCity($ins) .
666 "*" . $claim->payerState($ins) .
667 "*" . $claim->payerZip($ins) .
668 "~\n";
669 } // end Gateway EDI
671 } // End loops 2320/2330*.
673 $loopcount = 0;
675 // Procedure loop starts here.
677 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
678 ++$loopcount;
680 ++$edicount;
681 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
682 "*$loopcount" .
683 "~\n";
685 ++$edicount;
686 $out .= "SV1" . // Professional Service. Page 400.
687 "*HC:" . $claim->cptKey($prockey) .
688 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
689 "*UN" .
690 "*" . $claim->cptUnits($prockey) .
691 "*" .
692 "*" .
693 "*";
694 $dia = $claim->diagIndexArray($prockey);
695 $separator = '';
696 foreach ($dia as $dindex) {
697 $out .= $separator . $dindex;
698 $separator = ':';
700 $out .= "~\n";
702 if (!$claim->cptCharges($prockey)) {
703 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
706 if (empty($dia)) {
707 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' is not justified!\n";
710 ++$edicount;
711 $out .= "DTP" . // Date of Service. Page 435.
712 "*472" .
713 "*D8" .
714 "*" . $claim->serviceDate() .
715 "~\n";
717 // Loop 2410, Drug Information. Medicaid insurers seem to want this
718 // with HCPCS codes.
720 $ndc = $claim->cptNDCID($prockey);
721 if ($ndc) {
722 ++$edicount;
723 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
724 "*" . // Per addendum, LIN01 is not used.
725 "*N4" .
726 "*" . $ndc .
727 "~\n";
729 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp)) {
730 $log .= "*** NDC code '$ndc' has invalid format!\n";
733 ++$edicount;
734 $tmpunits = $claim->cptNDCQuantity($prockey) * $claim->cptUnits($prockey);
735 if (!$tmpunits) $tmpunits = 1;
736 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
737 "*" .
738 "*" .
739 "*" . sprintf('%.2f', $claim->cptCharges($prockey) / $tmpunits) .
740 "*" . $claim->cptNDCQuantity($prockey) .
741 "*" . $claim->cptNDCUOM($prockey) .
742 "~\n";
745 // Loop 2430, adjudication by previous payers.
747 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
748 if ($claim->payerSequence($ins) > $claim->payerSequence())
749 continue; // payer is future, not previous
751 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
752 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
754 if ($payerpaid[1] == 0 && !count($aarr)) {
755 $log .= "*** Procedure '" . $claim->cptKey($prockey) .
756 "' has no payments or adjustments from previous payer!\n";
757 continue;
760 ++$edicount;
761 $out .= "SVD" . // Service line adjudication. Page 554.
762 "*" . $claim->payerID($ins) .
763 "*" . $payerpaid[1] .
764 "*HC:" . $claim->cptKey($prockey) .
765 "*" .
766 "*" . $claim->cptUnits($prockey) .
767 "~\n";
769 $tmpdate = $payerpaid[0];
770 foreach ($aarr as $a) {
771 ++$edicount;
772 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
773 "*" . $a[1] .
774 "*" . $a[2] .
775 "*" . $a[3] .
776 "~\n";
777 if (!$tmpdate) $tmpdate = $a[0];
780 if ($tmpdate) {
781 ++$edicount;
782 $out .= "DTP" . // Previous payer's line adjustment date. Page 566.
783 "*573" .
784 "*D8" .
785 "*$tmpdate" .
786 "~\n";
788 } // end loop 2430
789 } // end this procedure
791 ++$edicount;
792 $out .= "SE" . // SE Trailer
793 "*$edicount" .
794 "*0021" .
795 "~\n";
797 $out .= "GE" . // GE Trailer
798 "*1" .
799 "*1" .
800 "~\n";
802 $out .= "IEA" . // IEA Trailer
803 "*1" .
804 "*000000001" .
805 "~\n";
807 $log .= "\n";
808 return $out;