Addressing SQL syntax issue in messages.php
[openemr.git] / library / gen_x12_837.inc.php
blob32d77c809b0d8d7730344c3d45c68f124fbe698b
1 <?php
2 // Copyright (C) 2007-2011 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, $encounter_claim=false) {
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 "*" . $claim->x12gsisa05() .
30 "*" . $claim->x12gssenderid() .
31 "*" . $claim->x12gsisa07() .
32 "*" . $claim->x12gsreceiverid() .
33 "*030911" .
34 "*1630" .
35 "*U" .
36 "*00401" .
37 "*000000001" .
38 "*" . $claim->x12gsisa14() .
39 "*" . $claim->x12gsisa15() .
40 "*:" .
41 "~\n";
43 $out .= "GS" .
44 "*HC" .
45 "*" . $claim->x12gsgs02() .
46 "*" . trim($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 ($encounter_claim ? "*RP" : "*CH") .
68 "~\n";
70 ++$edicount;
71 $out .= "REF" .
72 "*87" .
73 "*" . $claim->x12gsversionstring() .
74 "~\n";
76 ++$edicount;
77 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
78 $billingFacilityName=substr($claim->billingFacilityName(),0,35);
79 $out .= "NM1" . // Loop 1000A Submitter
80 "*41" .
81 "*2" .
82 "*" . $billingFacilityName .
83 "*" .
84 "*" .
85 "*" .
86 "*" .
87 "*46";
88 if (trim($claim->x12gsreceiverid()) == '470819582') { // if ECLAIMS EDI
89 $out .= "*" . $claim->clearingHouseETIN();
90 } else {
91 $out .= "*" . $claim->billingFacilityETIN();
93 $out .= "~\n";
95 ++$edicount;
96 $out .= "PER" .
97 "*IC" .
98 "*" . $claim->billingContactName() .
99 "*TE" .
100 "*" . $claim->billingContactPhone();
101 if ($claim->x12gsper06()) {
102 $out .= "*ED*" . $claim->x12gsper06();
104 $out .= "~\n";
106 ++$edicount;
107 $out .= "NM1" . // Loop 1000B Receiver
108 "*40" .
109 "*2" .
110 "*" . $claim->clearingHouseName() .
111 "*" .
112 "*" .
113 "*" .
114 "*" .
115 "*46" .
116 "*" . $claim->clearingHouseETIN() .
117 "~\n";
119 $HLcount = 1;
121 ++$edicount;
122 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
123 "*$HLcount" .
124 "*" .
125 "*20" .
126 "*1" .
127 "~\n";
129 $HLBillingPayToProvider = $HLcount++;
131 ++$edicount;
132 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
133 $billingFacilityName=substr($claim->billingFacilityName(),0,35);
134 $out .= "NM1" . // Loop 2010AA Billing Provider
135 "*85" .
136 "*2" .
137 "*" . $billingFacilityName .
138 "*" .
139 "*" .
140 "*" .
141 "*";
142 if ($claim->billingFacilityNPI()) {
143 $out .= "*XX*" . $claim->billingFacilityNPI();
144 } else {
145 $log .= "*** Billing facility has no NPI.\n";
146 $out .= "*24*" . $claim->billingFacilityETIN();
148 $out .= "~\n";
150 ++$edicount;
151 $out .= "N3" .
152 "*" . $claim->billingFacilityStreet() .
153 "~\n";
155 ++$edicount;
156 $out .= "N4" .
157 "*" . $claim->billingFacilityCity() .
158 "*" . $claim->billingFacilityState() .
159 "*" . $claim->billingFacilityZip() .
160 "~\n";
162 // Add a REF*EI*<ein> segment if NPI was specified in the NM1 above.
163 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
164 ++$edicount;
165 $out .= "REF" ;
166 if($claim->federalIdType()){
167 $out .= "*" . $claim->federalIdType();
169 else{
170 $out .= "*EI";//For dealing with the situation before adding selection for TaxId type In facility ie default to EIN.
172 $out .= "*" . $claim->billingFacilityETIN() .
173 "~\n";
176 if ($claim->providerNumberType() && $claim->providerNumber()) {
177 ++$edicount;
178 $out .= "REF" .
179 "*" . $claim->providerNumberType() .
180 "*" . $claim->providerNumber() .
181 "~\n";
183 else if ($claim->providerNumber()) {
184 $log .= "*** Payer-specific provider insurance number is present but has no type assigned.\n";
187 ++$edicount;
188 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
189 $billingFacilityName=substr($claim->billingFacilityName(),0,35);
190 $out .= "NM1" . // Loop 2010AB Pay-To Provider
191 "*87" .
192 "*2" .
193 "*" . $billingFacilityName .
194 "*" .
195 "*" .
196 "*" .
197 "*";
198 if ($claim->billingFacilityNPI())
199 $out .= "*XX*" . $claim->billingFacilityNPI();
200 else
201 $out .= "*24*" . $claim->billingFacilityETIN();
202 $out .= "~\n";
204 ++$edicount;
205 $out .= "N3" .
206 "*" . $claim->billingFacilityStreet() .
207 "~\n";
209 ++$edicount;
210 $out .= "N4" .
211 "*" . $claim->billingFacilityCity() .
212 "*" . $claim->billingFacilityState() .
213 "*" . $claim->billingFacilityZip() .
214 "~\n";
216 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
217 ++$edicount;
218 $out .= "REF" .
219 "*EI" .
220 "*" . $claim->billingFacilityETIN() .
221 "~\n";
223 if($claim->isSelfOfInsured()){
224 $PatientHL = 0;
226 else{
227 $PatientHL = 1;
230 ++$edicount;
231 $out .= "HL" . // Loop 2000B Subscriber HL Loop
232 "*$HLcount" .
233 "*$HLBillingPayToProvider" .
234 "*22" .
235 "*$PatientHL" .
236 "~\n";
238 $HLSubscriber = $HLcount++;
240 if (!$claim->payerSequence()) {
241 $log .= "*** Error: Insurance information is missing!\n";
243 ++$edicount;
244 $x="";
245 if($claim->isSelfOfInsured()){
246 $x=18;
248 $out .= "SBR" . // Subscriber Information
249 "*" . $claim->payerSequence() .
250 "*" . $x .
251 "*" . $claim->groupNumber() .
252 "*" . $claim->groupName() .
253 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
254 "*" .
255 "*" .
256 "*" .
257 "*" . $claim->claimType() . // Zirmed replaces this
258 "~\n";
260 ++$edicount;
261 $out .= "NM1" . // Loop 2010BA Subscriber
262 "*IL" .
263 "*1" .
264 "*" . $claim->insuredLastName() .
265 "*" . $claim->insuredFirstName() .
266 "*" . $claim->insuredMiddleName() .
267 "*" .
268 "*" .
269 "*MI" .
270 "*" . $claim->policyNumber() .
271 "~\n";
273 ++$edicount;
274 $out .= "N3" .
275 "*" . $claim->insuredStreet() .
276 "~\n";
278 ++$edicount;
279 $out .= "N4" .
280 "*" . $claim->insuredCity() .
281 "*" . $claim->insuredState() .
282 "*" . $claim->insuredZip() .
283 "~\n";
285 ++$edicount;
286 $out .= "DMG" .
287 "*D8" .
288 "*" . $claim->insuredDOB() .
289 "*" . $claim->insuredSex() .
290 "~\n";
292 ++$edicount;
293 //Field length is limited to 35. See nucc dataset page 81 www.nucc.org
294 $payerName=substr($claim->payerName(),0,35);
295 $out .= "NM1" . // Loop 2010BB Payer
296 "*PR" .
297 "*2" .
298 "*" . $payerName .
299 "*" .
300 "*" .
301 "*" .
302 "*" .
303 "*PI" .
304 // Zirmed ignores this if using payer name matching:
305 "*" . ($encounter_claim ? $claim->payerAltID() : $claim->payerID()) .
306 "~\n";
308 // if (!$claim->payerID()) {
309 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName() . "'.\n";
310 // }
312 ++$edicount;
313 $out .= "N3" .
314 "*" . $claim->payerStreet() .
315 "~\n";
317 ++$edicount;
318 $out .= "N4" .
319 "*" . $claim->payerCity() .
320 "*" . $claim->payerState() .
321 "*" . $claim->payerZip() .
322 "~\n";
324 if (! $claim->isSelfOfInsured()) {
325 ++$edicount;
326 $out .= "HL" . // Loop 2000C Patient Information
327 "*$HLcount" .
328 "*$HLSubscriber" .
329 "*23" .
330 "*0" .
331 "~\n";
333 $HLcount++;
335 ++$edicount;
336 $out .= "PAT" .
337 "*" . $claim->insuredRelationship() .
338 "~\n";
340 ++$edicount;
341 $out .= "NM1" . // Loop 2010CA Patient
342 "*QC" .
343 "*1" .
344 "*" . $claim->patientLastName() .
345 "*" . $claim->patientFirstName() .
346 "*" . $claim->patientMiddleName() .
347 "~\n";
349 ++$edicount;
350 $out .= "N3" .
351 "*" . $claim->patientStreet() .
352 "~\n";
354 ++$edicount;
355 $out .= "N4" .
356 "*" . $claim->patientCity() .
357 "*" . $claim->patientState() .
358 "*" . $claim->patientZip() .
359 "~\n";
361 ++$edicount;
362 $out .= "DMG" .
363 "*D8" .
364 "*" . $claim->patientDOB() .
365 "*" . $claim->patientSex() .
366 "~\n";
367 } // end of patient different from insured
369 $proccount = $claim->procCount();
371 $clm_total_charges = 0;
372 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
373 $clm_total_charges += $claim->cptCharges($prockey);
376 if (!$clm_total_charges) {
377 $log .= "*** This claim has no charges!\n";
381 ++$edicount;
382 $out .= "CLM" . // Loop 2300 Claim
383 "*$pid-$encounter" .
384 "*" . sprintf("%.2f",$clm_total_charges) . // Zirmed computes and replaces this
385 "*" .
386 "*" .
387 "*" . sprintf('%02d', $claim->facilityPOS()) . "::" . $claim->frequencyTypeCode() . // Changed to correct single digit output
388 "*Y" .
389 "*A" .
390 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
391 "*Y" .
392 "*C" .
393 "~\n";
395 if ($claim->dateInitialTreatment()) {
396 ++$edicount;
397 $out .= "DTP" . // Date of Initial Treatment
398 "*454" .
399 "*D8" .
400 "*" . $claim->dateInitialTreatment() .
401 "~\n";
404 ++$edicount;
405 $out .= "DTP" . // Date of Onset
406 "*431" .
407 "*D8" .
408 "*" . $claim->onsetDate() .
409 "~\n";
411 if (strcmp($claim->facilityPOS(),'21') == 0) {
412 ++$edicount;
413 $out .= "DTP" . // Date of Hospitalization
414 "*435" .
415 "*D8" .
416 "*" . $claim->onsetDate() .
417 "~\n";
420 $patientpaid = $claim->patientPaidAmount();
421 if ($patientpaid != 0) {
422 ++$edicount;
423 $out .= "AMT" . // Patient paid amount. Page 220.
424 "*F5" .
425 "*" . $patientpaid .
426 "~\n";
429 if ($claim->priorAuth()) {
430 ++$edicount;
431 $out .= "REF" . // Prior Authorization Number
432 "*G1" .
433 "*" . $claim->priorAuth() .
434 "~\n";
437 if ($claim->cliaCode() and $claim->claimType() === 'MB') {
438 // Required by Medicare when in-house labs are done.
439 ++$edicount;
440 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
441 "*X4" .
442 "*" . $claim->cliaCode() .
443 "~\n";
446 // Note: This would be the place to implement the NTE segment for loop 2300.
447 if ($claim->additionalNotes()) {
448 // Claim note.
449 ++$edicount;
450 $out .= "NTE" . // comments box 19
451 "*" .
452 "*" . $claim->additionalNotes() .
453 "~\n";
456 // Diagnoses, up to 8 per HI segment.
457 $da = $claim->diagArray();
458 $diag_type_code = 'BK';
459 $tmp = 0;
460 foreach ($da as $diag) {
461 if ($tmp % 8 == 0) {
462 if ($tmp) $out .= "~\n";
463 ++$edicount;
464 $out .= "HI"; // Health Diagnosis Codes
466 $out .= "*$diag_type_code:" . $diag;
467 $diag_type_code = 'BF';
468 ++$tmp;
470 if ($tmp) $out .= "~\n";
472 if ($claim->referrerLastName()) {
473 // Medicare requires referring provider's name and UPIN.
474 ++$edicount;
475 $out .= "NM1" . // Loop 2310A Referring Provider
476 "*DN" .
477 "*1" .
478 "*" . $claim->referrerLastName() .
479 "*" . $claim->referrerFirstName() .
480 "*" . $claim->referrerMiddleName() .
481 "*" .
482 "*";
483 if ($claim->referrerNPI()) { $out .=
484 "*XX" .
485 "*" . $claim->referrerNPI();
486 } else { $out .=
487 "*34" .
488 "*" . $claim->referrerSSN();
490 $out .= "~\n";
492 if ($claim->referrerTaxonomy()) {
493 ++$edicount;
494 $out .= "PRV" .
495 "*RF" . // ReFerring provider
496 "*ZZ" .
497 "*" . $claim->referrerTaxonomy() .
498 "~\n";
501 if ($claim->referrerUPIN()) {
502 ++$edicount;
503 $out .= "REF" . // Referring Provider Secondary Identification
504 "*1G" .
505 "*" . $claim->referrerUPIN() .
506 "~\n";
510 ++$edicount;
511 $out .= "NM1" . // Loop 2310B Rendering Provider
512 "*82" .
513 "*1" .
514 "*" . $claim->providerLastName() .
515 "*" . $claim->providerFirstName() .
516 "*" . $claim->providerMiddleName() .
517 "*" .
518 "*";
519 if ($claim->providerNPI()) { $out .=
520 "*XX" .
521 "*" . $claim->providerNPI();
522 } else { $out .=
523 "*34" .
524 "*" . $claim->providerSSN();
525 $log .= "*** Rendering provider has no NPI.\n";
527 $out .= "~\n";
529 if ($claim->providerTaxonomy()) {
530 ++$edicount;
531 $out .= "PRV" .
532 "*PE" . // PErforming provider
533 "*ZZ" .
534 "*" . $claim->providerTaxonomy() .
535 "~\n";
538 // REF*1C is required here for the Medicare provider number if NPI was
539 // specified in NM109. Not sure if other payers require anything here.
540 // --- apparently ECLAIMS, INC wants the data in 2010 but NOT in 2310B - tony@mi-squared.com
542 if (trim($claim->x12gsreceiverid()) != '470819582') { // if NOT ECLAIMS EDI
543 if ($claim->providerNumber()) {
544 ++$edicount;
545 $out .= "REF" .
546 "*" . $claim->providerNumberType() .
547 "*" . $claim->providerNumber() .
548 "~\n";
552 // Loop 2310D is omitted in the case of home visits (POS=12).
553 if ($claim->facilityPOS() != 12) {
554 ++$edicount;
555 $out .= "NM1" . // Loop 2310D Service Location
556 "*77" .
557 "*2";
558 //Field length is limited to 35. See nucc dataset page 77 www.nucc.org
559 $facilityName=substr($claim->facilityName(),0,35);
560 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) { $out .=
561 "*" . $facilityName;
563 if ($claim->facilityNPI() || $claim->facilityETIN()) { $out .=
564 "*" .
565 "*" .
566 "*" .
567 "*";
568 if ($claim->facilityNPI()) { $out .=
569 "*XX*" . $claim->facilityNPI();
570 } else { $out .=
571 "*24*" . $claim->facilityETIN();
572 $log .= "*** Service location has no NPI.\n";
575 $out .= "~\n";
576 if ($claim->facilityStreet()) {
577 ++$edicount;
578 $out .= "N3" .
579 "*" . $claim->facilityStreet() .
580 "~\n";
582 if ($claim->facilityState()) {
583 ++$edicount;
584 $out .= "N4" .
585 "*" . $claim->facilityCity() .
586 "*" . $claim->facilityState() .
587 "*" . $claim->facilityZip() .
588 "~\n";
592 // Loop 2310E, Supervising Provider
594 if ($claim->supervisorLastName()) {
595 ++$edicount;
596 $out .= "NM1" .
597 "*DQ" . // Supervising Physician
598 "*1" . // Person
599 "*" . $claim->supervisorLastName() .
600 "*" . $claim->supervisorFirstName() .
601 "*" . $claim->supervisorMiddleName() .
602 "*" . // NM106 not used
603 "*"; // Name Suffix
604 if ($claim->supervisorNPI()) { $out .=
605 "*XX" .
606 "*" . $claim->supervisorNPI();
607 } else { $out .=
608 "*34" .
609 "*" . $claim->supervisorSSN();
611 $out .= "~\n";
613 if ($claim->supervisorNumber()) {
614 ++$edicount;
615 $out .= "REF" .
616 "*" . $claim->supervisorNumberType() .
617 "*" . $claim->supervisorNumber() .
618 "~\n";
622 $prev_pt_resp = $clm_total_charges; // for computation below
624 // Loops 2320 and 2330*, other subscriber/payer information.
626 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
628 $tmp1 = $claim->claimType($ins);
629 $tmp2 = 'C1'; // Here a kludge. See page 321.
630 if ($tmp1 === 'CI') $tmp2 = 'C1';
631 if ($tmp1 === 'AM') $tmp2 = 'AP';
632 if ($tmp1 === 'HM') $tmp2 = 'HM';
633 if ($tmp1 === 'MB') $tmp2 = 'MB';
634 if ($tmp1 === 'MC') $tmp2 = 'MC';
635 if ($tmp1 === '09') $tmp2 = 'PP';
636 ++$edicount;
637 $out .= "SBR" . // Loop 2320, Subscriber Information - page 318
638 "*" . $claim->payerSequence($ins) .
639 "*" . $claim->insuredRelationship($ins) .
640 "*" . $claim->groupNumber($ins) .
641 "*" . $claim->groupName($ins) .
642 "*" . $tmp2 .
643 "*" .
644 "*" .
645 "*" .
646 "*" . $claim->claimType($ins) .
647 "~\n";
649 // Things that apply only to previous payers, not future payers.
651 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
653 // Generate claim-level adjustments.
654 $aarr = $claim->payerAdjustments($ins);
655 foreach ($aarr as $a) {
656 ++$edicount;
657 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 323.
658 "*" . $a[1] .
659 "*" . $a[2] .
660 "*" . $a[3] .
661 "~\n";
664 $payerpaid = $claim->payerTotals($ins);
665 ++$edicount;
666 $out .= "AMT" . // Previous payer's paid amount. Page 332.
667 "*D" .
668 "*" . $payerpaid[1] .
669 "~\n";
671 // Patient responsibility amount as of this previous payer.
672 $prev_pt_resp -= $payerpaid[1]; // reduce by payments
673 $prev_pt_resp -= $payerpaid[2]; // reduce by adjustments
675 ++$edicount;
676 $out .= "AMT" . // Allowed amount per previous payer. Page 334.
677 "*B6" .
678 "*" . sprintf('%.2f', $payerpaid[1] + $prev_pt_resp) .
679 "~\n";
681 ++$edicount;
682 $out .= "AMT" . // Patient responsibility amount per previous payer. Page 335.
683 "*F2" .
684 "*" . sprintf('%.2f', $prev_pt_resp) .
685 "~\n";
687 } // End of things that apply only to previous payers.
689 ++$edicount;
690 $out .= "DMG" . // Other subscriber demographic information. Page 342.
691 "*D8" .
692 "*" . $claim->insuredDOB($ins) .
693 "*" . $claim->insuredSex($ins) .
694 "~\n";
696 ++$edicount;
697 $out .= "OI" . // Other Insurance Coverage Information. Page 344.
698 "*" .
699 "*" .
700 "*Y" .
701 "*B" .
702 "*" .
703 "*Y" .
704 "~\n";
706 ++$edicount;
707 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 350.
708 "*IL" .
709 "*1" .
710 "*" . $claim->insuredLastName($ins) .
711 "*" . $claim->insuredFirstName($ins) .
712 "*" . $claim->insuredMiddleName($ins) .
713 "*" .
714 "*" .
715 "*MI" .
716 "*" . $claim->policyNumber($ins) .
717 "~\n";
719 ++$edicount;
720 $out .= "N3" .
721 "*" . $claim->insuredStreet($ins) .
722 "~\n";
724 ++$edicount;
725 $out .= "N4" .
726 "*" . $claim->insuredCity($ins) .
727 "*" . $claim->insuredState($ins) .
728 "*" . $claim->insuredZip($ins) .
729 "~\n";
731 ++$edicount;
732 //Field length is limited to 35. See nucc dataset page 81 www.nucc.org
733 $payerName=substr($claim->payerName($ins),0,35);
734 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 359.
735 "*PR" .
736 "*2" .
737 "*" . $payerName .
738 "*" .
739 "*" .
740 "*" .
741 "*" .
742 "*PI" .
743 "*" . $claim->payerID($ins) .
744 "~\n";
746 // if (!$claim->payerID($ins)) {
747 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
748 // }
750 // Payer address (N3 and N4) are added below so that Gateway EDI can
751 // auto-generate secondary claims. These do NOT appear in my copy of
752 // the spec! -- Rod 2008-06-12
754 if (trim($claim->x12gsreceiverid()) == '431420764') { // if Gateway EDI
755 ++$edicount;
756 $out .= "N3" .
757 "*" . $claim->payerStreet($ins) .
758 "~\n";
760 ++$edicount;
761 $out .= "N4" .
762 "*" . $claim->payerCity($ins) .
763 "*" . $claim->payerState($ins) .
764 "*" . $claim->payerZip($ins) .
765 "~\n";
766 } // end Gateway EDI
768 } // End loops 2320/2330*.
770 $loopcount = 0;
772 // Procedure loop starts here.
774 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
775 ++$loopcount;
777 ++$edicount;
778 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
779 "*$loopcount" .
780 "~\n";
782 ++$edicount;
783 $out .= "SV1" . // Professional Service. Page 400.
784 "*HC:" . $claim->cptKey($prockey) .
785 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
786 "*UN" .
787 "*" . $claim->cptUnits($prockey) .
788 "*" .
789 "*" .
790 "*";
791 $dia = $claim->diagIndexArray($prockey);
792 $i = 0;
793 foreach ($dia as $dindex) {
794 if ($i) $out .= ':';
795 $out .= $dindex;
796 if (++$i >= 4) break;
798 $out .= "~\n";
800 if (!$claim->cptCharges($prockey)) {
801 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
804 if (empty($dia)) {
805 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' is not justified!\n";
808 ++$edicount;
809 $out .= "DTP" . // Date of Service. Page 435.
810 "*472" .
811 "*D8" .
812 "*" . $claim->serviceDate() .
813 "~\n";
815 // AMT*AAE segment for Approved Amount from previous payer.
816 // Medicare secondaries seem to require this.
818 for ($ins = $claim->payerCount() - 1; $ins > 0; --$ins) {
819 if ($claim->payerSequence($ins) > $claim->payerSequence())
820 continue; // payer is future, not previous
821 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
822 ++$edicount;
823 $out .= "AMT" . // Approved amount per previous payer. Page 485.
824 "*AAE" .
825 "*" . sprintf('%.2f', $claim->cptCharges($prockey) - $payerpaid[2]) .
826 "~\n";
827 break;
830 // Loop 2410, Drug Information. Medicaid insurers seem to want this
831 // with HCPCS codes.
833 $ndc = $claim->cptNDCID($prockey);
834 if ($ndc) {
835 ++$edicount;
836 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
837 "*" . // Per addendum, LIN01 is not used.
838 "*N4" .
839 "*" . $ndc .
840 "~\n";
842 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp) && !preg_match('/^\d{11}$/', $ndc)) {
843 $log .= "*** NDC code '$ndc' has invalid format!\n";
846 ++$edicount;
847 $tmpunits = $claim->cptNDCQuantity($prockey) * $claim->cptUnits($prockey);
848 if (!$tmpunits) $tmpunits = 1;
849 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
850 "*" .
851 "*" .
852 "*" . sprintf('%.2f', $claim->cptCharges($prockey) / $tmpunits) .
853 "*" . $claim->cptNDCQuantity($prockey) .
854 "*" . $claim->cptNDCUOM($prockey) .
855 "~\n";
858 // Loop 2420A, Rendering Provider (service-specific).
859 // Used if the rendering provider for this service line is different
860 // from that in loop 2310B.
862 if ($claim->providerNPI() != $claim->providerNPI($prockey)) {
863 ++$edicount;
864 $out .= "NM1" . // Loop 2310B Rendering Provider
865 "*82" .
866 "*1" .
867 "*" . $claim->providerLastName($prockey) .
868 "*" . $claim->providerFirstName($prockey) .
869 "*" . $claim->providerMiddleName($prockey) .
870 "*" .
871 "*";
872 if ($claim->providerNPI($prockey)) { $out .=
873 "*XX" .
874 "*" . $claim->providerNPI($prockey);
875 } else { $out .=
876 "*34" .
877 "*" . $claim->providerSSN($prockey);
878 $log .= "*** Rendering provider has no NPI.\n";
880 $out .= "~\n";
882 if ($claim->providerTaxonomy($prockey)) {
883 ++$edicount;
884 $out .= "PRV" .
885 "*PE" . // PErforming provider
886 "*ZZ" .
887 "*" . $claim->providerTaxonomy($prockey) .
888 "~\n";
891 // REF*1C is required here for the Medicare provider number if NPI was
892 // specified in NM109. Not sure if other payers require anything here.
893 if ($claim->providerNumber($prockey)) {
894 ++$edicount;
895 $out .= "REF" .
896 "*" . $claim->providerNumberType($prockey) .
897 "*" . $claim->providerNumber($prockey) .
898 "~\n";
902 // Loop 2430, adjudication by previous payers.
904 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
905 if ($claim->payerSequence($ins) > $claim->payerSequence())
906 continue; // payer is future, not previous
908 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
909 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
911 if ($payerpaid[1] == 0 && !count($aarr)) {
912 $log .= "*** Procedure '" . $claim->cptKey($prockey) .
913 "' has no payments or adjustments from previous payer!\n";
914 continue;
917 ++$edicount;
918 $out .= "SVD" . // Service line adjudication. Page 554.
919 "*" . $claim->payerID($ins) .
920 "*" . $payerpaid[1] .
921 "*HC:" . $claim->cptKey($prockey) .
922 "*" .
923 "*" . $claim->cptUnits($prockey) .
924 "~\n";
926 $tmpdate = $payerpaid[0];
927 foreach ($aarr as $a) {
928 ++$edicount;
929 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
930 "*" . $a[1] .
931 "*" . $a[2] .
932 "*" . $a[3] .
933 "~\n";
934 if (!$tmpdate) $tmpdate = $a[0];
935 if ( isset($a[4]) &&
936 $a[4] != null ) {
937 $out .= "CAS02" . // Previous payer's adjustment reason
938 "*" . $a[4] .
939 "~\n";
943 if ($tmpdate) {
944 ++$edicount;
945 $out .= "DTP" . // Previous payer's line adjustment date. Page 566.
946 "*573" .
947 "*D8" .
948 "*$tmpdate" .
949 "~\n";
951 } // end loop 2430
952 } // end this procedure
954 ++$edicount;
955 $out .= "SE" . // SE Trailer
956 "*$edicount" .
957 "*0021" .
958 "~\n";
960 $out .= "GE" . // GE Trailer
961 "*1" .
962 "*1" .
963 "~\n";
965 $out .= "IEA" . // IEA Trailer
966 "*1" .
967 "*000000001" .
968 "~\n";
970 $log .= "\n";
971 return $out;