Add icd9 and minor fixes to the following:
[openemr.git] / library / gen_x12_837.inc.php
blob4647bcd96d2960007dbcf4de8c9b8a08f7a13b3b
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 $out .= "NM1" . // Loop 1000A Submitter
78 "*41" .
79 "*2" .
80 "*" . $claim->billingFacilityName() .
81 "*" .
82 "*" .
83 "*" .
84 "*" .
85 "*46";
86 if (trim($claim->x12gsreceiverid()) == '470819582') { // if ECLAIMS EDI
87 $out .= "*" . $claim->clearingHouseETIN();
88 } else {
89 $out .= "*" . $claim->billingFacilityETIN();
91 $out .= "~\n";
93 ++$edicount;
94 $out .= "PER" .
95 "*IC" .
96 "*" . $claim->billingContactName() .
97 "*TE" .
98 "*" . $claim->billingContactPhone();
99 if ($claim->x12gsper06()) {
100 $out .= "*ED*" . $claim->x12gsper06();
102 $out .= "~\n";
104 ++$edicount;
105 $out .= "NM1" . // Loop 1000B Receiver
106 "*40" .
107 "*2" .
108 "*" . $claim->clearingHouseName() .
109 "*" .
110 "*" .
111 "*" .
112 "*" .
113 "*46" .
114 "*" . $claim->clearingHouseETIN() .
115 "~\n";
117 $HLcount = 1;
119 ++$edicount;
120 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
121 "*$HLcount" .
122 "*" .
123 "*20" .
124 "*1" .
125 "~\n";
127 $HLBillingPayToProvider = $HLcount++;
129 ++$edicount;
130 $out .= "NM1" . // Loop 2010AA Billing Provider
131 "*85" .
132 "*2" .
133 "*" . $claim->billingFacilityName() .
134 "*" .
135 "*" .
136 "*" .
137 "*";
138 if ($claim->billingFacilityNPI()) {
139 $out .= "*XX*" . $claim->billingFacilityNPI();
140 } else {
141 $log .= "*** Billing facility has no NPI.\n";
142 $out .= "*24*" . $claim->billingFacilityETIN();
144 $out .= "~\n";
146 ++$edicount;
147 $out .= "N3" .
148 "*" . $claim->billingFacilityStreet() .
149 "~\n";
151 ++$edicount;
152 $out .= "N4" .
153 "*" . $claim->billingFacilityCity() .
154 "*" . $claim->billingFacilityState() .
155 "*" . $claim->billingFacilityZip() .
156 "~\n";
158 // Add a REF*EI*<ein> segment if NPI was specified in the NM1 above.
159 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
160 ++$edicount;
161 $out .= "REF" ;
162 if($claim->federalIdType()){
163 $out .= "*" . $claim->federalIdType();
165 else{
166 $out .= "*EI";//For dealing with the situation before adding selection for TaxId type In facility ie default to EIN.
168 $out .= "*" . $claim->billingFacilityETIN() .
169 "~\n";
172 if ($claim->providerNumberType() && $claim->providerNumber()) {
173 ++$edicount;
174 $out .= "REF" .
175 "*" . $claim->providerNumberType() .
176 "*" . $claim->providerNumber() .
177 "~\n";
179 else if ($claim->providerNumber()) {
180 $log .= "*** Payer-specific provider insurance number is present but has no type assigned.\n";
183 ++$edicount;
184 $out .= "NM1" . // Loop 2010AB Pay-To Provider
185 "*87" .
186 "*2" .
187 "*" . $claim->billingFacilityName() .
188 "*" .
189 "*" .
190 "*" .
191 "*";
192 if ($claim->billingFacilityNPI())
193 $out .= "*XX*" . $claim->billingFacilityNPI();
194 else
195 $out .= "*24*" . $claim->billingFacilityETIN();
196 $out .= "~\n";
198 ++$edicount;
199 $out .= "N3" .
200 "*" . $claim->billingFacilityStreet() .
201 "~\n";
203 ++$edicount;
204 $out .= "N4" .
205 "*" . $claim->billingFacilityCity() .
206 "*" . $claim->billingFacilityState() .
207 "*" . $claim->billingFacilityZip() .
208 "~\n";
210 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
211 ++$edicount;
212 $out .= "REF" .
213 "*EI" .
214 "*" . $claim->billingFacilityETIN() .
215 "~\n";
218 $PatientHL = 0;
220 ++$edicount;
221 $out .= "HL" . // Loop 2000B Subscriber HL Loop
222 "*$HLcount" .
223 "*$HLBillingPayToProvider" .
224 "*22" .
225 "*$PatientHL" .
226 "~\n";
228 $HLSubscriber = $HLcount++;
230 if (!$claim->payerSequence()) {
231 $log .= "*** Error: Insurance information is missing!\n";
233 ++$edicount;
234 $out .= "SBR" . // Subscriber Information
235 "*" . $claim->payerSequence() .
236 "*" . $claim->insuredRelationship() .
237 "*" . $claim->groupNumber() .
238 "*" . $claim->groupName() .
239 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
240 "*" .
241 "*" .
242 "*" .
243 "*" . $claim->claimType() . // Zirmed replaces this
244 "~\n";
246 ++$edicount;
247 $out .= "NM1" . // Loop 2010BA Subscriber
248 "*IL" .
249 "*1" .
250 "*" . $claim->insuredLastName() .
251 "*" . $claim->insuredFirstName() .
252 "*" . $claim->insuredMiddleName() .
253 "*" .
254 "*" .
255 "*MI" .
256 "*" . $claim->policyNumber() .
257 "~\n";
259 ++$edicount;
260 $out .= "N3" .
261 "*" . $claim->insuredStreet() .
262 "~\n";
264 ++$edicount;
265 $out .= "N4" .
266 "*" . $claim->insuredCity() .
267 "*" . $claim->insuredState() .
268 "*" . $claim->insuredZip() .
269 "~\n";
271 ++$edicount;
272 $out .= "DMG" .
273 "*D8" .
274 "*" . $claim->insuredDOB() .
275 "*" . $claim->insuredSex() .
276 "~\n";
278 ++$edicount;
279 $out .= "NM1" . // Loop 2010BB Payer
280 "*PR" .
281 "*2" .
282 "*" . $claim->payerName() .
283 "*" .
284 "*" .
285 "*" .
286 "*" .
287 "*PI" .
288 // Zirmed ignores this if using payer name matching:
289 "*" . ($encounter_claim ? $claim->payerAltID() : $claim->payerID()) .
290 "~\n";
292 // if (!$claim->payerID()) {
293 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName() . "'.\n";
294 // }
296 ++$edicount;
297 $out .= "N3" .
298 "*" . $claim->payerStreet() .
299 "~\n";
301 ++$edicount;
302 $out .= "N4" .
303 "*" . $claim->payerCity() .
304 "*" . $claim->payerState() .
305 "*" . $claim->payerZip() .
306 "~\n";
308 if (! $claim->isSelfOfInsured()) {
309 ++$edicount;
310 $out .= "HL" . // Loop 2000C Patient Information
311 "*$HLcount" .
312 "*$HLSubscriber" .
313 "*23" .
314 "*0" .
315 "~\n";
317 $HLcount++;
319 ++$edicount;
320 $out .= "PAT" .
321 "*" . $claim->insuredRelationship() .
322 "~\n";
324 ++$edicount;
325 $out .= "NM1" . // Loop 2010CA Patient
326 "*QC" .
327 "*1" .
328 "*" . $claim->patientLastName() .
329 "*" . $claim->patientFirstName() .
330 "*" . $claim->patientMiddleName() .
331 "~\n";
333 ++$edicount;
334 $out .= "N3" .
335 "*" . $claim->patientStreet() .
336 "~\n";
338 ++$edicount;
339 $out .= "N4" .
340 "*" . $claim->patientCity() .
341 "*" . $claim->patientState() .
342 "*" . $claim->patientZip() .
343 "~\n";
345 ++$edicount;
346 $out .= "DMG" .
347 "*D8" .
348 "*" . $claim->patientDOB() .
349 "*" . $claim->patientSex() .
350 "~\n";
351 } // end of patient different from insured
353 $proccount = $claim->procCount();
355 $clm_total_charges = 0;
356 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
357 $clm_total_charges += $claim->cptCharges($prockey);
360 if (!$clm_total_charges) {
361 $log .= "*** This claim has no charges!\n";
365 ++$edicount;
366 $out .= "CLM" . // Loop 2300 Claim
367 "*$pid-$encounter" .
368 "*" . sprintf("%.2f",$clm_total_charges) . // Zirmed computes and replaces this
369 "*" .
370 "*" .
371 "*" . sprintf('%02d', $claim->facilityPOS()) . "::" . $claim->frequencyTypeCode() . // Changed to correct single digit output
372 "*Y" .
373 "*A" .
374 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
375 "*Y" .
376 "*C" .
377 "~\n";
379 ++$edicount;
380 $out .= "DTP" . // Date of Onset
381 "*431" .
382 "*D8" .
383 "*" . $claim->onsetDate() .
384 "~\n";
386 if (strcmp($claim->facilityPOS(),'21') == 0) {
387 ++$edicount;
388 $out .= "DTP" . // Date of Hospitalization
389 "*435" .
390 "*D8" .
391 "*" . $claim->onsetDate() .
392 "~\n";
395 $patientpaid = $claim->patientPaidAmount();
396 if ($patientpaid != 0) {
397 ++$edicount;
398 $out .= "AMT" . // Patient paid amount. Page 220.
399 "*F5" .
400 "*" . $patientpaid .
401 "~\n";
404 if ($claim->priorAuth()) {
405 ++$edicount;
406 $out .= "REF" . // Prior Authorization Number
407 "*G1" .
408 "*" . $claim->priorAuth() .
409 "~\n";
412 if ($claim->cliaCode() and $claim->claimType() === 'MB') {
413 // Required by Medicare when in-house labs are done.
414 ++$edicount;
415 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
416 "*X4" .
417 "*" . $claim->cliaCode() .
418 "~\n";
421 // Note: This would be the place to implement the NTE segment for loop 2300.
423 // Diagnoses, up to 8 per HI segment.
424 $da = $claim->diagArray();
425 $diag_type_code = 'BK';
426 $tmp = 0;
427 foreach ($da as $diag) {
428 if ($tmp % 8 == 0) {
429 if ($tmp) $out .= "~\n";
430 ++$edicount;
431 $out .= "HI"; // Health Diagnosis Codes
433 $out .= "*$diag_type_code:" . $diag;
434 $diag_type_code = 'BF';
435 ++$tmp;
437 if ($tmp) $out .= "~\n";
439 if ($claim->referrerLastName()) {
440 // Medicare requires referring provider's name and UPIN.
441 ++$edicount;
442 $out .= "NM1" . // Loop 2310A Referring Provider
443 "*DN" .
444 "*1" .
445 "*" . $claim->referrerLastName() .
446 "*" . $claim->referrerFirstName() .
447 "*" . $claim->referrerMiddleName() .
448 "*" .
449 "*";
450 if ($claim->referrerNPI()) { $out .=
451 "*XX" .
452 "*" . $claim->referrerNPI();
453 } else { $out .=
454 "*34" .
455 "*" . $claim->referrerSSN();
457 $out .= "~\n";
459 if ($claim->referrerTaxonomy()) {
460 ++$edicount;
461 $out .= "PRV" .
462 "*RF" . // ReFerring provider
463 "*ZZ" .
464 "*" . $claim->referrerTaxonomy() .
465 "~\n";
468 if ($claim->referrerUPIN()) {
469 ++$edicount;
470 $out .= "REF" . // Referring Provider Secondary Identification
471 "*1G" .
472 "*" . $claim->referrerUPIN() .
473 "~\n";
477 ++$edicount;
478 $out .= "NM1" . // Loop 2310B Rendering Provider
479 "*82" .
480 "*1" .
481 "*" . $claim->providerLastName() .
482 "*" . $claim->providerFirstName() .
483 "*" . $claim->providerMiddleName() .
484 "*" .
485 "*";
486 if ($claim->providerNPI()) { $out .=
487 "*XX" .
488 "*" . $claim->providerNPI();
489 } else { $out .=
490 "*34" .
491 "*" . $claim->providerSSN();
492 $log .= "*** Rendering provider has no NPI.\n";
494 $out .= "~\n";
496 if ($claim->providerTaxonomy()) {
497 ++$edicount;
498 $out .= "PRV" .
499 "*PE" . // PErforming provider
500 "*ZZ" .
501 "*" . $claim->providerTaxonomy() .
502 "~\n";
505 // REF*1C is required here for the Medicare provider number if NPI was
506 // specified in NM109. Not sure if other payers require anything here.
507 // --- apparently ECLAIMS, INC wants the data in 2010 but NOT in 2310B - tony@mi-squared.com
509 if (trim($claim->x12gsreceiverid()) != '470819582') { // if NOT ECLAIMS EDI
510 if ($claim->providerNumber()) {
511 ++$edicount;
512 $out .= "REF" .
513 "*" . $claim->providerNumberType() .
514 "*" . $claim->providerNumber() .
515 "~\n";
519 // Loop 2310D is omitted in the case of home visits (POS=12).
520 if ($claim->facilityPOS() != 12) {
521 ++$edicount;
522 $out .= "NM1" . // Loop 2310D Service Location
523 "*77" .
524 "*2";
525 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) { $out .=
526 "*" . $claim->facilityName();
528 if ($claim->facilityNPI() || $claim->facilityETIN()) { $out .=
529 "*" .
530 "*" .
531 "*" .
532 "*";
533 if ($claim->facilityNPI()) { $out .=
534 "*XX*" . $claim->facilityNPI();
535 } else { $out .=
536 "*24*" . $claim->facilityETIN();
537 $log .= "*** Service location has no NPI.\n";
540 $out .= "~\n";
541 if ($claim->facilityStreet()) {
542 ++$edicount;
543 $out .= "N3" .
544 "*" . $claim->facilityStreet() .
545 "~\n";
547 if ($claim->facilityState()) {
548 ++$edicount;
549 $out .= "N4" .
550 "*" . $claim->facilityCity() .
551 "*" . $claim->facilityState() .
552 "*" . $claim->facilityZip() .
553 "~\n";
557 // Loop 2310E, Supervising Provider
559 if ($claim->supervisorLastName()) {
560 ++$edicount;
561 $out .= "NM1" .
562 "*DQ" . // Supervising Physician
563 "*1" . // Person
564 "*" . $claim->supervisorLastName() .
565 "*" . $claim->supervisorFirstName() .
566 "*" . $claim->supervisorMiddleName() .
567 "*" . // NM106 not used
568 "*"; // Name Suffix
569 if ($claim->supervisorNPI()) { $out .=
570 "*XX" .
571 "*" . $claim->supervisorNPI();
572 } else { $out .=
573 "*34" .
574 "*" . $claim->supervisorSSN();
576 $out .= "~\n";
578 if ($claim->supervisorNumber()) {
579 ++$edicount;
580 $out .= "REF" .
581 "*" . $claim->supervisorNumberType() .
582 "*" . $claim->supervisorNumber() .
583 "~\n";
587 $prev_pt_resp = $clm_total_charges; // for computation below
589 // Loops 2320 and 2330*, other subscriber/payer information.
591 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
593 $tmp1 = $claim->claimType($ins);
594 $tmp2 = 'C1'; // Here a kludge. See page 321.
595 if ($tmp1 === 'CI') $tmp2 = 'C1';
596 if ($tmp1 === 'AM') $tmp2 = 'AP';
597 if ($tmp1 === 'HM') $tmp2 = 'HM';
598 if ($tmp1 === 'MB') $tmp2 = 'MB';
599 if ($tmp1 === 'MC') $tmp2 = 'MC';
600 if ($tmp1 === '09') $tmp2 = 'PP';
601 ++$edicount;
602 $out .= "SBR" . // Loop 2320, Subscriber Information - page 318
603 "*" . $claim->payerSequence($ins) .
604 "*" . $claim->insuredRelationship($ins) .
605 "*" . $claim->groupNumber($ins) .
606 "*" . $claim->groupName($ins) .
607 "*" . $tmp2 .
608 "*" .
609 "*" .
610 "*" .
611 "*" . $claim->claimType($ins) .
612 "~\n";
614 // Things that apply only to previous payers, not future payers.
616 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
618 // Generate claim-level adjustments.
619 $aarr = $claim->payerAdjustments($ins);
620 foreach ($aarr as $a) {
621 ++$edicount;
622 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 323.
623 "*" . $a[1] .
624 "*" . $a[2] .
625 "*" . $a[3] .
626 "~\n";
629 $payerpaid = $claim->payerTotals($ins);
630 ++$edicount;
631 $out .= "AMT" . // Previous payer's paid amount. Page 332.
632 "*D" .
633 "*" . $payerpaid[1] .
634 "~\n";
636 // Patient responsibility amount as of this previous payer.
637 $prev_pt_resp -= $payerpaid[1]; // reduce by payments
638 $prev_pt_resp -= $payerpaid[2]; // reduce by adjustments
640 ++$edicount;
641 $out .= "AMT" . // Allowed amount per previous payer. Page 334.
642 "*B6" .
643 "*" . sprintf('%.2f', $payerpaid[1] + $prev_pt_resp) .
644 "~\n";
646 ++$edicount;
647 $out .= "AMT" . // Patient responsibility amount per previous payer. Page 335.
648 "*F2" .
649 "*" . sprintf('%.2f', $prev_pt_resp) .
650 "~\n";
652 } // End of things that apply only to previous payers.
654 ++$edicount;
655 $out .= "DMG" . // Other subscriber demographic information. Page 342.
656 "*D8" .
657 "*" . $claim->insuredDOB($ins) .
658 "*" . $claim->insuredSex($ins) .
659 "~\n";
661 ++$edicount;
662 $out .= "OI" . // Other Insurance Coverage Information. Page 344.
663 "*" .
664 "*" .
665 "*Y" .
666 "*B" .
667 "*" .
668 "*Y" .
669 "~\n";
671 ++$edicount;
672 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 350.
673 "*IL" .
674 "*1" .
675 "*" . $claim->insuredLastName($ins) .
676 "*" . $claim->insuredFirstName($ins) .
677 "*" . $claim->insuredMiddleName($ins) .
678 "*" .
679 "*" .
680 "*MI" .
681 "*" . $claim->policyNumber($ins) .
682 "~\n";
684 ++$edicount;
685 $out .= "N3" .
686 "*" . $claim->insuredStreet($ins) .
687 "~\n";
689 ++$edicount;
690 $out .= "N4" .
691 "*" . $claim->insuredCity($ins) .
692 "*" . $claim->insuredState($ins) .
693 "*" . $claim->insuredZip($ins) .
694 "~\n";
696 ++$edicount;
697 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 359.
698 "*PR" .
699 "*2" .
700 "*" . $claim->payerName($ins) .
701 "*" .
702 "*" .
703 "*" .
704 "*" .
705 "*PI" .
706 "*" . $claim->payerID($ins) .
707 "~\n";
709 // if (!$claim->payerID($ins)) {
710 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
711 // }
713 // Payer address (N3 and N4) are added below so that Gateway EDI can
714 // auto-generate secondary claims. These do NOT appear in my copy of
715 // the spec! -- Rod 2008-06-12
717 if (trim($claim->x12gsreceiverid()) == '431420764') { // if Gateway EDI
718 ++$edicount;
719 $out .= "N3" .
720 "*" . $claim->payerStreet($ins) .
721 "~\n";
723 ++$edicount;
724 $out .= "N4" .
725 "*" . $claim->payerCity($ins) .
726 "*" . $claim->payerState($ins) .
727 "*" . $claim->payerZip($ins) .
728 "~\n";
729 } // end Gateway EDI
731 } // End loops 2320/2330*.
733 $loopcount = 0;
735 // Procedure loop starts here.
737 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
738 ++$loopcount;
740 ++$edicount;
741 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
742 "*$loopcount" .
743 "~\n";
745 ++$edicount;
746 $out .= "SV1" . // Professional Service. Page 400.
747 "*HC:" . $claim->cptKey($prockey) .
748 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
749 "*UN" .
750 "*" . $claim->cptUnits($prockey) .
751 "*" .
752 "*" .
753 "*";
754 $dia = $claim->diagIndexArray($prockey);
755 $i = 0;
756 foreach ($dia as $dindex) {
757 if ($i) $out .= ':';
758 $out .= $dindex;
759 if (++$i >= 4) break;
761 $out .= "~\n";
763 if (!$claim->cptCharges($prockey)) {
764 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
767 if (empty($dia)) {
768 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' is not justified!\n";
771 ++$edicount;
772 $out .= "DTP" . // Date of Service. Page 435.
773 "*472" .
774 "*D8" .
775 "*" . $claim->serviceDate() .
776 "~\n";
778 // AMT*AAE segment for Approved Amount from previous payer.
779 // Medicare secondaries seem to require this.
781 for ($ins = $claim->payerCount() - 1; $ins > 0; --$ins) {
782 if ($claim->payerSequence($ins) > $claim->payerSequence())
783 continue; // payer is future, not previous
784 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
785 ++$edicount;
786 $out .= "AMT" . // Approved amount per previous payer. Page 485.
787 "*AAE" .
788 "*" . sprintf('%.2f', $claim->cptCharges($prockey) - $payerpaid[2]) .
789 "~\n";
790 break;
793 // Loop 2410, Drug Information. Medicaid insurers seem to want this
794 // with HCPCS codes.
796 $ndc = $claim->cptNDCID($prockey);
797 if ($ndc) {
798 ++$edicount;
799 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
800 "*" . // Per addendum, LIN01 is not used.
801 "*N4" .
802 "*" . $ndc .
803 "~\n";
805 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp)) {
806 $log .= "*** NDC code '$ndc' has invalid format!\n";
809 ++$edicount;
810 $tmpunits = $claim->cptNDCQuantity($prockey) * $claim->cptUnits($prockey);
811 if (!$tmpunits) $tmpunits = 1;
812 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
813 "*" .
814 "*" .
815 "*" . sprintf('%.2f', $claim->cptCharges($prockey) / $tmpunits) .
816 "*" . $claim->cptNDCQuantity($prockey) .
817 "*" . $claim->cptNDCUOM($prockey) .
818 "~\n";
821 // Loop 2420A, Rendering Provider (service-specific).
822 // Used if the rendering provider for this service line is different
823 // from that in loop 2310B.
825 if ($claim->providerNPI() != $claim->providerNPI($prockey)) {
826 ++$edicount;
827 $out .= "NM1" . // Loop 2310B Rendering Provider
828 "*82" .
829 "*1" .
830 "*" . $claim->providerLastName($prockey) .
831 "*" . $claim->providerFirstName($prockey) .
832 "*" . $claim->providerMiddleName($prockey) .
833 "*" .
834 "*";
835 if ($claim->providerNPI($prockey)) { $out .=
836 "*XX" .
837 "*" . $claim->providerNPI($prockey);
838 } else { $out .=
839 "*34" .
840 "*" . $claim->providerSSN($prockey);
841 $log .= "*** Rendering provider has no NPI.\n";
843 $out .= "~\n";
845 if ($claim->providerTaxonomy($prockey)) {
846 ++$edicount;
847 $out .= "PRV" .
848 "*PE" . // PErforming provider
849 "*ZZ" .
850 "*" . $claim->providerTaxonomy($prockey) .
851 "~\n";
854 // REF*1C is required here for the Medicare provider number if NPI was
855 // specified in NM109. Not sure if other payers require anything here.
856 if ($claim->providerNumber($prockey)) {
857 ++$edicount;
858 $out .= "REF" .
859 "*" . $claim->providerNumberType($prockey) .
860 "*" . $claim->providerNumber($prockey) .
861 "~\n";
865 // Loop 2430, adjudication by previous payers.
867 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
868 if ($claim->payerSequence($ins) > $claim->payerSequence())
869 continue; // payer is future, not previous
871 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
872 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
874 if ($payerpaid[1] == 0 && !count($aarr)) {
875 $log .= "*** Procedure '" . $claim->cptKey($prockey) .
876 "' has no payments or adjustments from previous payer!\n";
877 continue;
880 ++$edicount;
881 $out .= "SVD" . // Service line adjudication. Page 554.
882 "*" . $claim->payerID($ins) .
883 "*" . $payerpaid[1] .
884 "*HC:" . $claim->cptKey($prockey) .
885 "*" .
886 "*" . $claim->cptUnits($prockey) .
887 "~\n";
889 $tmpdate = $payerpaid[0];
890 foreach ($aarr as $a) {
891 ++$edicount;
892 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
893 "*" . $a[1] .
894 "*" . $a[2] .
895 "*" . $a[3] .
896 "~\n";
897 if (!$tmpdate) $tmpdate = $a[0];
900 if ($tmpdate) {
901 ++$edicount;
902 $out .= "DTP" . // Previous payer's line adjustment date. Page 566.
903 "*573" .
904 "*D8" .
905 "*$tmpdate" .
906 "~\n";
908 } // end loop 2430
909 } // end this procedure
911 ++$edicount;
912 $out .= "SE" . // SE Trailer
913 "*$edicount" .
914 "*0021" .
915 "~\n";
917 $out .= "GE" . // GE Trailer
918 "*1" .
919 "*1" .
920 "~\n";
922 $out .= "IEA" . // IEA Trailer
923 "*1" .
924 "*000000001" .
925 "~\n";
927 $log .= "\n";
928 return $out;