NFQ 0024 fixes check for any BMI finding, also any encounter, assume communication...
[openemr.git] / library / gen_x12_837.inc.php
blob5740ea232db183a4b91e5633094aaf4294075758
1 <?php
2 // Copyright (C) 2007-2009 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";
224 $PatientHL = 0;
226 ++$edicount;
227 $out .= "HL" . // Loop 2000B Subscriber HL Loop
228 "*$HLcount" .
229 "*$HLBillingPayToProvider" .
230 "*22" .
231 "*$PatientHL" .
232 "~\n";
234 $HLSubscriber = $HLcount++;
236 if (!$claim->payerSequence()) {
237 $log .= "*** Error: Insurance information is missing!\n";
239 ++$edicount;
240 $out .= "SBR" . // Subscriber Information
241 "*" . $claim->payerSequence() .
242 "*" . $claim->insuredRelationship() .
243 "*" . $claim->groupNumber() .
244 "*" . $claim->groupName() .
245 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
246 "*" .
247 "*" .
248 "*" .
249 "*" . $claim->claimType() . // Zirmed replaces this
250 "~\n";
252 ++$edicount;
253 $out .= "NM1" . // Loop 2010BA Subscriber
254 "*IL" .
255 "*1" .
256 "*" . $claim->insuredLastName() .
257 "*" . $claim->insuredFirstName() .
258 "*" . $claim->insuredMiddleName() .
259 "*" .
260 "*" .
261 "*MI" .
262 "*" . $claim->policyNumber() .
263 "~\n";
265 ++$edicount;
266 $out .= "N3" .
267 "*" . $claim->insuredStreet() .
268 "~\n";
270 ++$edicount;
271 $out .= "N4" .
272 "*" . $claim->insuredCity() .
273 "*" . $claim->insuredState() .
274 "*" . $claim->insuredZip() .
275 "~\n";
277 ++$edicount;
278 $out .= "DMG" .
279 "*D8" .
280 "*" . $claim->insuredDOB() .
281 "*" . $claim->insuredSex() .
282 "~\n";
284 ++$edicount;
285 //Field length is limited to 35. See nucc dataset page 81 www.nucc.org
286 $payerName=substr($claim->payerName(),0,35);
287 $out .= "NM1" . // Loop 2010BB Payer
288 "*PR" .
289 "*2" .
290 "*" . $payerName .
291 "*" .
292 "*" .
293 "*" .
294 "*" .
295 "*PI" .
296 // Zirmed ignores this if using payer name matching:
297 "*" . ($encounter_claim ? $claim->payerAltID() : $claim->payerID()) .
298 "~\n";
300 // if (!$claim->payerID()) {
301 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName() . "'.\n";
302 // }
304 ++$edicount;
305 $out .= "N3" .
306 "*" . $claim->payerStreet() .
307 "~\n";
309 ++$edicount;
310 $out .= "N4" .
311 "*" . $claim->payerCity() .
312 "*" . $claim->payerState() .
313 "*" . $claim->payerZip() .
314 "~\n";
316 if (! $claim->isSelfOfInsured()) {
317 ++$edicount;
318 $out .= "HL" . // Loop 2000C Patient Information
319 "*$HLcount" .
320 "*$HLSubscriber" .
321 "*23" .
322 "*0" .
323 "~\n";
325 $HLcount++;
327 ++$edicount;
328 $out .= "PAT" .
329 "*" . $claim->insuredRelationship() .
330 "~\n";
332 ++$edicount;
333 $out .= "NM1" . // Loop 2010CA Patient
334 "*QC" .
335 "*1" .
336 "*" . $claim->patientLastName() .
337 "*" . $claim->patientFirstName() .
338 "*" . $claim->patientMiddleName() .
339 "~\n";
341 ++$edicount;
342 $out .= "N3" .
343 "*" . $claim->patientStreet() .
344 "~\n";
346 ++$edicount;
347 $out .= "N4" .
348 "*" . $claim->patientCity() .
349 "*" . $claim->patientState() .
350 "*" . $claim->patientZip() .
351 "~\n";
353 ++$edicount;
354 $out .= "DMG" .
355 "*D8" .
356 "*" . $claim->patientDOB() .
357 "*" . $claim->patientSex() .
358 "~\n";
359 } // end of patient different from insured
361 $proccount = $claim->procCount();
363 $clm_total_charges = 0;
364 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
365 $clm_total_charges += $claim->cptCharges($prockey);
368 if (!$clm_total_charges) {
369 $log .= "*** This claim has no charges!\n";
373 ++$edicount;
374 $out .= "CLM" . // Loop 2300 Claim
375 "*$pid-$encounter" .
376 "*" . sprintf("%.2f",$clm_total_charges) . // Zirmed computes and replaces this
377 "*" .
378 "*" .
379 "*" . sprintf('%02d', $claim->facilityPOS()) . "::" . $claim->frequencyTypeCode() . // Changed to correct single digit output
380 "*Y" .
381 "*A" .
382 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
383 "*Y" .
384 "*C" .
385 "~\n";
387 ++$edicount;
388 $out .= "DTP" . // Date of Onset
389 "*431" .
390 "*D8" .
391 "*" . $claim->onsetDate() .
392 "~\n";
394 if (strcmp($claim->facilityPOS(),'21') == 0) {
395 ++$edicount;
396 $out .= "DTP" . // Date of Hospitalization
397 "*435" .
398 "*D8" .
399 "*" . $claim->onsetDate() .
400 "~\n";
403 $patientpaid = $claim->patientPaidAmount();
404 if ($patientpaid != 0) {
405 ++$edicount;
406 $out .= "AMT" . // Patient paid amount. Page 220.
407 "*F5" .
408 "*" . $patientpaid .
409 "~\n";
412 if ($claim->priorAuth()) {
413 ++$edicount;
414 $out .= "REF" . // Prior Authorization Number
415 "*G1" .
416 "*" . $claim->priorAuth() .
417 "~\n";
420 if ($claim->cliaCode() and $claim->claimType() === 'MB') {
421 // Required by Medicare when in-house labs are done.
422 ++$edicount;
423 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
424 "*X4" .
425 "*" . $claim->cliaCode() .
426 "~\n";
429 // Note: This would be the place to implement the NTE segment for loop 2300.
430 if ($claim->additionalNotes()) {
431 // Claim note.
432 ++$edicount;
433 $out .= "NTE" . // comments box 19
434 "*" .
435 "*" . $claim->additionalNotes() .
436 "~\n";
439 // Diagnoses, up to 8 per HI segment.
440 $da = $claim->diagArray();
441 $diag_type_code = 'BK';
442 $tmp = 0;
443 foreach ($da as $diag) {
444 if ($tmp % 8 == 0) {
445 if ($tmp) $out .= "~\n";
446 ++$edicount;
447 $out .= "HI"; // Health Diagnosis Codes
449 $out .= "*$diag_type_code:" . $diag;
450 $diag_type_code = 'BF';
451 ++$tmp;
453 if ($tmp) $out .= "~\n";
455 if ($claim->referrerLastName()) {
456 // Medicare requires referring provider's name and UPIN.
457 ++$edicount;
458 $out .= "NM1" . // Loop 2310A Referring Provider
459 "*DN" .
460 "*1" .
461 "*" . $claim->referrerLastName() .
462 "*" . $claim->referrerFirstName() .
463 "*" . $claim->referrerMiddleName() .
464 "*" .
465 "*";
466 if ($claim->referrerNPI()) { $out .=
467 "*XX" .
468 "*" . $claim->referrerNPI();
469 } else { $out .=
470 "*34" .
471 "*" . $claim->referrerSSN();
473 $out .= "~\n";
475 if ($claim->referrerTaxonomy()) {
476 ++$edicount;
477 $out .= "PRV" .
478 "*RF" . // ReFerring provider
479 "*ZZ" .
480 "*" . $claim->referrerTaxonomy() .
481 "~\n";
484 if ($claim->referrerUPIN()) {
485 ++$edicount;
486 $out .= "REF" . // Referring Provider Secondary Identification
487 "*1G" .
488 "*" . $claim->referrerUPIN() .
489 "~\n";
493 ++$edicount;
494 $out .= "NM1" . // Loop 2310B Rendering Provider
495 "*82" .
496 "*1" .
497 "*" . $claim->providerLastName() .
498 "*" . $claim->providerFirstName() .
499 "*" . $claim->providerMiddleName() .
500 "*" .
501 "*";
502 if ($claim->providerNPI()) { $out .=
503 "*XX" .
504 "*" . $claim->providerNPI();
505 } else { $out .=
506 "*34" .
507 "*" . $claim->providerSSN();
508 $log .= "*** Rendering provider has no NPI.\n";
510 $out .= "~\n";
512 if ($claim->providerTaxonomy()) {
513 ++$edicount;
514 $out .= "PRV" .
515 "*PE" . // PErforming provider
516 "*ZZ" .
517 "*" . $claim->providerTaxonomy() .
518 "~\n";
521 // REF*1C is required here for the Medicare provider number if NPI was
522 // specified in NM109. Not sure if other payers require anything here.
523 // --- apparently ECLAIMS, INC wants the data in 2010 but NOT in 2310B - tony@mi-squared.com
525 if (trim($claim->x12gsreceiverid()) != '470819582') { // if NOT ECLAIMS EDI
526 if ($claim->providerNumber()) {
527 ++$edicount;
528 $out .= "REF" .
529 "*" . $claim->providerNumberType() .
530 "*" . $claim->providerNumber() .
531 "~\n";
535 // Loop 2310D is omitted in the case of home visits (POS=12).
536 if ($claim->facilityPOS() != 12) {
537 ++$edicount;
538 $out .= "NM1" . // Loop 2310D Service Location
539 "*77" .
540 "*2";
541 //Field length is limited to 35. See nucc dataset page 77 www.nucc.org
542 $facilityName=substr($claim->facilityName(),0,35);
543 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) { $out .=
544 "*" . $facilityName;
546 if ($claim->facilityNPI() || $claim->facilityETIN()) { $out .=
547 "*" .
548 "*" .
549 "*" .
550 "*";
551 if ($claim->facilityNPI()) { $out .=
552 "*XX*" . $claim->facilityNPI();
553 } else { $out .=
554 "*24*" . $claim->facilityETIN();
555 $log .= "*** Service location has no NPI.\n";
558 $out .= "~\n";
559 if ($claim->facilityStreet()) {
560 ++$edicount;
561 $out .= "N3" .
562 "*" . $claim->facilityStreet() .
563 "~\n";
565 if ($claim->facilityState()) {
566 ++$edicount;
567 $out .= "N4" .
568 "*" . $claim->facilityCity() .
569 "*" . $claim->facilityState() .
570 "*" . $claim->facilityZip() .
571 "~\n";
575 // Loop 2310E, Supervising Provider
577 if ($claim->supervisorLastName()) {
578 ++$edicount;
579 $out .= "NM1" .
580 "*DQ" . // Supervising Physician
581 "*1" . // Person
582 "*" . $claim->supervisorLastName() .
583 "*" . $claim->supervisorFirstName() .
584 "*" . $claim->supervisorMiddleName() .
585 "*" . // NM106 not used
586 "*"; // Name Suffix
587 if ($claim->supervisorNPI()) { $out .=
588 "*XX" .
589 "*" . $claim->supervisorNPI();
590 } else { $out .=
591 "*34" .
592 "*" . $claim->supervisorSSN();
594 $out .= "~\n";
596 if ($claim->supervisorNumber()) {
597 ++$edicount;
598 $out .= "REF" .
599 "*" . $claim->supervisorNumberType() .
600 "*" . $claim->supervisorNumber() .
601 "~\n";
605 $prev_pt_resp = $clm_total_charges; // for computation below
607 // Loops 2320 and 2330*, other subscriber/payer information.
609 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
611 $tmp1 = $claim->claimType($ins);
612 $tmp2 = 'C1'; // Here a kludge. See page 321.
613 if ($tmp1 === 'CI') $tmp2 = 'C1';
614 if ($tmp1 === 'AM') $tmp2 = 'AP';
615 if ($tmp1 === 'HM') $tmp2 = 'HM';
616 if ($tmp1 === 'MB') $tmp2 = 'MB';
617 if ($tmp1 === 'MC') $tmp2 = 'MC';
618 if ($tmp1 === '09') $tmp2 = 'PP';
619 ++$edicount;
620 $out .= "SBR" . // Loop 2320, Subscriber Information - page 318
621 "*" . $claim->payerSequence($ins) .
622 "*" . $claim->insuredRelationship($ins) .
623 "*" . $claim->groupNumber($ins) .
624 "*" . $claim->groupName($ins) .
625 "*" . $tmp2 .
626 "*" .
627 "*" .
628 "*" .
629 "*" . $claim->claimType($ins) .
630 "~\n";
632 // Things that apply only to previous payers, not future payers.
634 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
636 // Generate claim-level adjustments.
637 $aarr = $claim->payerAdjustments($ins);
638 foreach ($aarr as $a) {
639 ++$edicount;
640 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 323.
641 "*" . $a[1] .
642 "*" . $a[2] .
643 "*" . $a[3] .
644 "~\n";
647 $payerpaid = $claim->payerTotals($ins);
648 ++$edicount;
649 $out .= "AMT" . // Previous payer's paid amount. Page 332.
650 "*D" .
651 "*" . $payerpaid[1] .
652 "~\n";
654 // Patient responsibility amount as of this previous payer.
655 $prev_pt_resp -= $payerpaid[1]; // reduce by payments
656 $prev_pt_resp -= $payerpaid[2]; // reduce by adjustments
658 ++$edicount;
659 $out .= "AMT" . // Allowed amount per previous payer. Page 334.
660 "*B6" .
661 "*" . sprintf('%.2f', $payerpaid[1] + $prev_pt_resp) .
662 "~\n";
664 ++$edicount;
665 $out .= "AMT" . // Patient responsibility amount per previous payer. Page 335.
666 "*F2" .
667 "*" . sprintf('%.2f', $prev_pt_resp) .
668 "~\n";
670 } // End of things that apply only to previous payers.
672 ++$edicount;
673 $out .= "DMG" . // Other subscriber demographic information. Page 342.
674 "*D8" .
675 "*" . $claim->insuredDOB($ins) .
676 "*" . $claim->insuredSex($ins) .
677 "~\n";
679 ++$edicount;
680 $out .= "OI" . // Other Insurance Coverage Information. Page 344.
681 "*" .
682 "*" .
683 "*Y" .
684 "*B" .
685 "*" .
686 "*Y" .
687 "~\n";
689 ++$edicount;
690 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 350.
691 "*IL" .
692 "*1" .
693 "*" . $claim->insuredLastName($ins) .
694 "*" . $claim->insuredFirstName($ins) .
695 "*" . $claim->insuredMiddleName($ins) .
696 "*" .
697 "*" .
698 "*MI" .
699 "*" . $claim->policyNumber($ins) .
700 "~\n";
702 ++$edicount;
703 $out .= "N3" .
704 "*" . $claim->insuredStreet($ins) .
705 "~\n";
707 ++$edicount;
708 $out .= "N4" .
709 "*" . $claim->insuredCity($ins) .
710 "*" . $claim->insuredState($ins) .
711 "*" . $claim->insuredZip($ins) .
712 "~\n";
714 ++$edicount;
715 //Field length is limited to 35. See nucc dataset page 81 www.nucc.org
716 $payerName=substr($claim->payerName($ins),0,35);
717 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 359.
718 "*PR" .
719 "*2" .
720 "*" . $payerName .
721 "*" .
722 "*" .
723 "*" .
724 "*" .
725 "*PI" .
726 "*" . $claim->payerID($ins) .
727 "~\n";
729 // if (!$claim->payerID($ins)) {
730 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
731 // }
733 // Payer address (N3 and N4) are added below so that Gateway EDI can
734 // auto-generate secondary claims. These do NOT appear in my copy of
735 // the spec! -- Rod 2008-06-12
737 if (trim($claim->x12gsreceiverid()) == '431420764') { // if Gateway EDI
738 ++$edicount;
739 $out .= "N3" .
740 "*" . $claim->payerStreet($ins) .
741 "~\n";
743 ++$edicount;
744 $out .= "N4" .
745 "*" . $claim->payerCity($ins) .
746 "*" . $claim->payerState($ins) .
747 "*" . $claim->payerZip($ins) .
748 "~\n";
749 } // end Gateway EDI
751 } // End loops 2320/2330*.
753 $loopcount = 0;
755 // Procedure loop starts here.
757 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
758 ++$loopcount;
760 ++$edicount;
761 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
762 "*$loopcount" .
763 "~\n";
765 ++$edicount;
766 $out .= "SV1" . // Professional Service. Page 400.
767 "*HC:" . $claim->cptKey($prockey) .
768 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
769 "*UN" .
770 "*" . $claim->cptUnits($prockey) .
771 "*" .
772 "*" .
773 "*";
774 $dia = $claim->diagIndexArray($prockey);
775 $i = 0;
776 foreach ($dia as $dindex) {
777 if ($i) $out .= ':';
778 $out .= $dindex;
779 if (++$i >= 4) break;
781 $out .= "~\n";
783 if (!$claim->cptCharges($prockey)) {
784 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
787 if (empty($dia)) {
788 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' is not justified!\n";
791 ++$edicount;
792 $out .= "DTP" . // Date of Service. Page 435.
793 "*472" .
794 "*D8" .
795 "*" . $claim->serviceDate() .
796 "~\n";
798 // AMT*AAE segment for Approved Amount from previous payer.
799 // Medicare secondaries seem to require this.
801 for ($ins = $claim->payerCount() - 1; $ins > 0; --$ins) {
802 if ($claim->payerSequence($ins) > $claim->payerSequence())
803 continue; // payer is future, not previous
804 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
805 ++$edicount;
806 $out .= "AMT" . // Approved amount per previous payer. Page 485.
807 "*AAE" .
808 "*" . sprintf('%.2f', $claim->cptCharges($prockey) - $payerpaid[2]) .
809 "~\n";
810 break;
813 // Loop 2410, Drug Information. Medicaid insurers seem to want this
814 // with HCPCS codes.
816 $ndc = $claim->cptNDCID($prockey);
817 if ($ndc) {
818 ++$edicount;
819 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
820 "*" . // Per addendum, LIN01 is not used.
821 "*N4" .
822 "*" . $ndc .
823 "~\n";
825 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp)) {
826 $log .= "*** NDC code '$ndc' has invalid format!\n";
829 ++$edicount;
830 $tmpunits = $claim->cptNDCQuantity($prockey) * $claim->cptUnits($prockey);
831 if (!$tmpunits) $tmpunits = 1;
832 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
833 "*" .
834 "*" .
835 "*" . sprintf('%.2f', $claim->cptCharges($prockey) / $tmpunits) .
836 "*" . $claim->cptNDCQuantity($prockey) .
837 "*" . $claim->cptNDCUOM($prockey) .
838 "~\n";
841 // Loop 2420A, Rendering Provider (service-specific).
842 // Used if the rendering provider for this service line is different
843 // from that in loop 2310B.
845 if ($claim->providerNPI() != $claim->providerNPI($prockey)) {
846 ++$edicount;
847 $out .= "NM1" . // Loop 2310B Rendering Provider
848 "*82" .
849 "*1" .
850 "*" . $claim->providerLastName($prockey) .
851 "*" . $claim->providerFirstName($prockey) .
852 "*" . $claim->providerMiddleName($prockey) .
853 "*" .
854 "*";
855 if ($claim->providerNPI($prockey)) { $out .=
856 "*XX" .
857 "*" . $claim->providerNPI($prockey);
858 } else { $out .=
859 "*34" .
860 "*" . $claim->providerSSN($prockey);
861 $log .= "*** Rendering provider has no NPI.\n";
863 $out .= "~\n";
865 if ($claim->providerTaxonomy($prockey)) {
866 ++$edicount;
867 $out .= "PRV" .
868 "*PE" . // PErforming provider
869 "*ZZ" .
870 "*" . $claim->providerTaxonomy($prockey) .
871 "~\n";
874 // REF*1C is required here for the Medicare provider number if NPI was
875 // specified in NM109. Not sure if other payers require anything here.
876 if ($claim->providerNumber($prockey)) {
877 ++$edicount;
878 $out .= "REF" .
879 "*" . $claim->providerNumberType($prockey) .
880 "*" . $claim->providerNumber($prockey) .
881 "~\n";
885 // Loop 2430, adjudication by previous payers.
887 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
888 if ($claim->payerSequence($ins) > $claim->payerSequence())
889 continue; // payer is future, not previous
891 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
892 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
894 if ($payerpaid[1] == 0 && !count($aarr)) {
895 $log .= "*** Procedure '" . $claim->cptKey($prockey) .
896 "' has no payments or adjustments from previous payer!\n";
897 continue;
900 ++$edicount;
901 $out .= "SVD" . // Service line adjudication. Page 554.
902 "*" . $claim->payerID($ins) .
903 "*" . $payerpaid[1] .
904 "*HC:" . $claim->cptKey($prockey) .
905 "*" .
906 "*" . $claim->cptUnits($prockey) .
907 "~\n";
909 $tmpdate = $payerpaid[0];
910 foreach ($aarr as $a) {
911 ++$edicount;
912 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
913 "*" . $a[1] .
914 "*" . $a[2] .
915 "*" . $a[3] .
916 "~\n";
917 if (!$tmpdate) $tmpdate = $a[0];
920 if ($tmpdate) {
921 ++$edicount;
922 $out .= "DTP" . // Previous payer's line adjustment date. Page 566.
923 "*573" .
924 "*D8" .
925 "*$tmpdate" .
926 "~\n";
928 } // end loop 2430
929 } // end this procedure
931 ++$edicount;
932 $out .= "SE" . // SE Trailer
933 "*$edicount" .
934 "*0021" .
935 "~\n";
937 $out .= "GE" . // GE Trailer
938 "*1" .
939 "*1" .
940 "~\n";
942 $out .= "IEA" . // IEA Trailer
943 "*1" .
944 "*000000001" .
945 "~\n";
947 $log .= "\n";
948 return $out;