Add date format cleaner for x12 5010 - tmccormi
[openemr.git] / library / gen_x12_837.inc.php
blob72fb5a5451910a620fedc893b568cb1d261f45a9
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");
10 function stripZipCode($zip)
12 return str_replace('-','',$zip);
14 function gen_x12_837($pid, $encounter, &$log, $encounter_claim=false) {
16 $today = time();
17 $out = '';
18 $claim = new Claim($pid, $encounter);
19 $edicount = 0;
21 // This is true for the 5010 standard, false for 4010.
22 // x12gsversionstring() should be "005010X222A1" or "004010X098A1".
23 $CMS_5010 = strpos($claim->x12gsversionstring(), '5010') !== false;
25 $log .= "Generating claim $pid-$encounter for " .
26 $claim->patientFirstName() . ' ' .
27 $claim->patientMiddleName() . ' ' .
28 $claim->patientLastName() . ' on ' .
29 date('Y-m-d H:i', $today) . ".\n";
31 $out .= "ISA" .
32 "*00" .
33 "* " .
34 "*00" .
35 "* " .
36 "*" . $claim->x12gsisa05() .
37 "*" . $claim->x12gssenderid() .
38 "*" . $claim->x12gsisa07() .
39 "*" . $claim->x12gsreceiverid() .
40 "*030911" .
41 "*1630" .
42 "*" . ($CMS_5010 ? "^" : "U" ) .
43 "*" . ($CMS_5010 ? "00501" : "00401") .
44 "*000000001" .
45 "*" . $claim->x12gsisa14() .
46 "*" . $claim->x12gsisa15() .
47 "*:" .
48 "~\n";
50 $out .= "GS" .
51 "*HC" .
52 "*" . $claim->x12gsgs02() .
53 "*" . trim($claim->x12gs03()) .
54 "*" . date('Ymd', $today) .
55 "*" . date('Hi', $today) .
56 "*1" .
57 "*X" .
58 "*" . $claim->x12gsversionstring() .
59 "~\n";
61 ++$edicount;
62 $out .= "ST" .
63 "*837" .
64 "*0021" .
65 // Spec says the following is optional, so should be able to leave it out.
66 ($CMS_5010 ? ("*" . $claim->x12gsversionstring()) : "") .
67 "~\n";
69 ++$edicount;
70 $out .= "BHT" .
71 "*0019" . // 0019 is required here
72 "*00" . // 00 = original transmission
73 "*0123" . // reference identification
74 "*" . date('Ymd', $today) . // transaction creation date
75 "*" . date('Hi', $today) . // transaction creation time
76 ($encounter_claim ? "*RP" : "*CH") . // RP = reporting, CH = chargeable
77 "~\n";
79 if (!$CMS_5010) {
80 // This segment was deleted for 5010.
81 ++$edicount;
82 $out .= "REF" .
83 "*87" .
84 "*" . $claim->x12gsversionstring() .
85 "~\n";
88 ++$edicount;
89 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
90 $billingFacilityName = substr($claim->billingFacilityName(), 0, $CMS_5010 ? 60 : 35);
91 $out .= "NM1" . // Loop 1000A Submitter
92 "*41" .
93 "*2" .
94 "*" . $billingFacilityName .
95 "*" .
96 "*" .
97 "*" .
98 "*" .
99 "*46";
100 if (trim($claim->x12gsreceiverid()) == '470819582') { // if ECLAIMS EDI
101 $out .= "*" . $claim->clearingHouseETIN();
102 } else {
103 $out .= "*" . $claim->billingFacilityETIN();
105 $out .= "~\n";
107 ++$edicount;
108 $out .= "PER" .
109 "*IC" .
110 "*" . $claim->billingContactName() .
111 "*TE" .
112 "*" . $claim->billingContactPhone();
113 if (!$CMS_5010 && $claim->x12gsper06()) {
114 $out .= "*ED*" . $claim->x12gsper06();
116 $out .= "~\n";
118 ++$edicount;
119 $out .= "NM1" . // Loop 1000B Receiver
120 "*40" .
121 "*2" .
122 "*" . $claim->clearingHouseName() .
123 "*" .
124 "*" .
125 "*" .
126 "*" .
127 "*46" .
128 "*" . $claim->clearingHouseETIN() .
129 "~\n";
131 $HLcount = 1;
133 ++$edicount;
134 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
135 "*$HLcount" .
136 "*" .
137 "*20" .
138 "*1" . // 1 indicates there are child segments
139 "~\n";
141 $HLBillingPayToProvider = $HLcount++;
143 // Situational PRV segment (for provider taxonomy code) omitted here.
144 // Situational CUR segment (foreign currency information) omitted here.
146 ++$edicount;
147 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
148 $billingFacilityName = substr($claim->billingFacilityName(), 0, $CMS_5010 ? 60 : 35);
149 $out .= "NM1" . // Loop 2010AA Billing Provider
150 "*85" .
151 "*2" .
152 "*" . $billingFacilityName .
153 "*" .
154 "*" .
155 "*" .
156 "*";
157 if ($claim->billingFacilityNPI()) {
158 $out .= "*XX*" . $claim->billingFacilityNPI();
160 else {
161 $log .= "*** Billing facility has no NPI.\n";
162 if ($CMS_5010) {
163 $out .= "*XX*";
165 else {
166 $out .= "*24*" . $claim->billingFacilityETIN();
169 $out .= "~\n";
171 ++$edicount;
172 $out .= "N3" .
173 "*" . $claim->billingFacilityStreet() .
174 "~\n";
176 ++$edicount;
177 $out .= "N4" .
178 "*" . $claim->billingFacilityCity() .
179 "*" . $claim->billingFacilityState() .
180 "*" . stripZipCode($claim->billingFacilityZip()) .
181 "~\n";
183 if ($CMS_5010 || ($claim->billingFacilityNPI() && $claim->billingFacilityETIN())) {
184 ++$edicount;
185 $out .= "REF" ;
186 if($claim->federalIdType()){
187 $out .= "*" . $claim->federalIdType();
189 else{
190 $out .= "*EI"; // For dealing with the situation before adding TaxId type In facility.
192 $out .= "*" . $claim->billingFacilityETIN() .
193 "~\n";
196 if ($claim->providerNumberType() && $claim->providerNumber() &&
197 !($CMS_5010 && $claim->billingFacilityNPI()))
199 ++$edicount;
200 $out .= "REF" .
201 "*" . $claim->providerNumberType() .
202 "*" . $claim->providerNumber() .
203 "~\n";
205 else if ($claim->providerNumber() && !$claim->providerNumberType()) {
206 $log .= "*** Payer-specific provider insurance number is present but has no type assigned.\n";
209 // Situational PER*1C segment omitted.
211 // Pay-To Address defaults to billing provider and is no longer required in 5010.
212 if (!$CMS_5010) {
213 ++$edicount;
214 // Field length is limited to 35. See nucc dataset page 63 www.nucc.org
215 $billingFacilityName = substr($claim->billingFacilityName(), 0, $CMS_5010 ? 60 : 35);
216 $out .= "NM1" . // Loop 2010AB Pay-To Provider
217 "*87" .
218 "*2" .
219 "*" . $billingFacilityName .
220 "*" .
221 "*" .
222 "*" .
223 "*";
224 if ($claim->billingFacilityNPI())
225 $out .= "*XX*" . $claim->billingFacilityNPI();
226 else
227 $out .= "*24*" . $claim->billingFacilityETIN();
228 $out .= "~\n";
230 ++$edicount;
231 $out .= "N3" .
232 "*" . $claim->billingFacilityStreet() .
233 "~\n";
235 ++$edicount;
236 $out .= "N4" .
237 "*" . $claim->billingFacilityCity() .
238 "*" . $claim->billingFacilityState() .
239 "*" . stripZipCode($claim->billingFacilityZip()) .
240 "~\n";
242 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
243 ++$edicount;
244 $out .= "REF" .
245 "*EI" .
246 "*" . $claim->billingFacilityETIN() .
247 "~\n";
251 // Loop 2010AC Pay-To Plan Name omitted. Includes:
252 // NM1*PE, N3, N4, REF*2U, REF*EI
254 $PatientHL = $claim->isSelfOfInsured() ? 0 : 1;
255 $HLSubscriber = $HLcount++;
257 ++$edicount;
258 $out .= "HL" . // Loop 2000B Subscriber HL Loop
259 "*$HLSubscriber" .
260 "*$HLBillingPayToProvider" .
261 "*22" .
262 "*$PatientHL" .
263 "~\n";
265 if (!$claim->payerSequence()) {
266 $log .= "*** Error: Insurance information is missing!\n";
269 ++$edicount;
270 $out .= "SBR" . // Subscriber Information
271 "*" . $claim->payerSequence() .
272 "*" . ($claim->isSelfOfInsured() ? '18' : '') .
273 "*" . $claim->groupNumber() .
274 "*" . (($CMS_5010 && $claim->groupNumber()) ? '' : $claim->groupName()) .
275 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
276 "*" .
277 "*" .
278 "*" .
279 "*" . $claim->claimType() . // Zirmed replaces this
280 "~\n";
282 // Segment PAT omitted.
284 ++$edicount;
285 $out .= "NM1" . // Loop 2010BA Subscriber
286 "*IL" .
287 "*1" . // 1 = person, 2 = non-person
288 "*" . $claim->insuredLastName() .
289 "*" . $claim->insuredFirstName() .
290 "*" . $claim->insuredMiddleName() .
291 "*" .
292 "*" . // Name Suffix
293 "*MI" .
294 // "MI" = Member Identification Number
295 // "II" = Standard Unique Health Identifier, "Required if the
296 // HIPAA Individual Patient Identifier is mandated use."
297 // Here we presume that is not true yet.
298 "*" . $claim->policyNumber() .
299 "~\n";
301 // For 5010, further subscriber info is sent only if they are the patient.
302 if (!$CMS_5010 || $claim->isSelfOfInsured()) {
303 ++$edicount;
304 $out .= "N3" .
305 "*" . $claim->insuredStreet() .
306 "~\n";
308 ++$edicount;
309 $out .= "N4" .
310 "*" . $claim->insuredCity() .
311 "*" . $claim->insuredState() .
312 "*" . stripZipCode($claim->insuredZip()) .
313 "~\n";
315 ++$edicount;
316 $out .= "DMG" .
317 "*D8" .
318 "*" . $claim->insuredDOB() .
319 "*" . $claim->insuredSex() .
320 "~\n";
323 // Segment REF*SY (Subscriber Secondary Identification) omitted.
324 // Segment REF*Y4 (Property and Casualty Claim Number) omitted.
325 // Segment PER*IC (Property and Casualty Subscriber Contact Information) omitted.
327 ++$edicount;
328 //Field length is limited to 35. See nucc dataset page 81 www.nucc.org
329 $payerName = substr($claim->payerName(), 0, $CMS_5010 ? 60 : 35);
330 $out .= "NM1" . // Loop 2010BB Payer
331 "*PR" .
332 "*2" .
333 "*" . $payerName .
334 "*" .
335 "*" .
336 "*" .
337 "*" .
338 // The 5010 spec says:
339 // "On or after the mandated implementation date for the HIPAA
340 // National Plan Identifier (National Plan ID), XV must be sent.
341 // Prior to the mandated implementation date and prior to any phase-
342 // in period identified by Federal regulation, PI must be sent."
343 // *************** Anybody know what that date is? ***************
344 "*PI" .
345 // Zirmed ignores this if using payer name matching:
346 "*" . ($encounter_claim ? $claim->payerAltID() : $claim->payerID()) .
347 "~\n";
349 // if (!$claim->payerID()) {
350 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName() . "'.\n";
351 // }
353 if (true) { // !$CMS_5010
354 // The 5010 spec says:
355 // "Required when the payer address is available and the submitter intends
356 // for the claim to be printed on paper at the next EDI location (for example, a
357 // clearinghouse). If not required by this implementation guide, do not send."
359 ++$edicount;
360 $out .= "N3" .
361 "*" . $claim->payerStreet() .
362 "~\n";
364 ++$edicount;
365 $out .= "N4" .
366 "*" . $claim->payerCity() .
367 "*" . $claim->payerState() .
368 "*" . stripZipCode($claim->payerZip()) .
369 "~\n";
372 // Segment REF (Payer Secondary Identification) omitted.
373 // Segment REF (Billing Provider Secondary Identification) omitted.
375 if (! $claim->isSelfOfInsured()) {
376 ++$edicount;
377 $out .= "HL" . // Loop 2000C Patient Information
378 "*$HLcount" .
379 "*$HLSubscriber" .
380 "*23" .
381 "*0" .
382 "~\n";
384 $HLcount++;
386 ++$edicount;
387 $out .= "PAT" .
388 "*" . $claim->insuredRelationship() .
389 "~\n";
391 ++$edicount;
392 $out .= "NM1" . // Loop 2010CA Patient
393 "*QC" .
394 "*1" .
395 "*" . $claim->patientLastName() .
396 "*" . $claim->patientFirstName() .
397 "*" . $claim->patientMiddleName() .
398 "~\n";
400 ++$edicount;
401 $out .= "N3" .
402 "*" . $claim->patientStreet() .
403 "~\n";
405 ++$edicount;
406 $out .= "N4" .
407 "*" . $claim->patientCity() .
408 "*" . $claim->patientState() .
409 "*" . stripZipCode($claim->patientZip()) .
410 "~\n";
412 ++$edicount;
413 $out .= "DMG" .
414 "*D8" .
415 "*" . $claim->patientDOB() .
416 "*" . $claim->patientSex() .
417 "~\n";
419 // Segment REF*Y4 (Property and Casualty Claim Number) omitted.
420 // Segment REF (Property and Casualty Patient Identifier) omitted.
421 // Segment PER (Property and Casualty Patient Contact Information) omitted.
423 } // end of patient different from insured
425 $proccount = $claim->procCount();
427 $clm_total_charges = 0;
428 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
429 $clm_total_charges += $claim->cptCharges($prockey);
432 if (!$clm_total_charges) {
433 $log .= "*** This claim has no charges!\n";
436 ++$edicount;
437 $out .= "CLM" . // Loop 2300 Claim
438 "*$pid-$encounter" .
439 "*" . sprintf("%.2f",$clm_total_charges) . // Zirmed computes and replaces this
440 "*" .
441 "*" .
442 "*" . sprintf('%02d', $claim->facilityPOS()) . ":" .
443 ($CMS_5010 ? "B" : "") . ":" .
444 $claim->frequencyTypeCode() . // Changed to correct single digit output
445 "*Y" .
446 "*A" .
447 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
448 "*Y" .
449 ($CMS_5010 ? "" : "*C") .
450 "~\n";
452 if ($claim->onsetDate() &&
453 ($claim->onsetDate()!== $claim->serviceDate()) &&
454 ($claim->onsetDateValid())
456 ++$edicount;
457 $out .= "DTP" . // Date of Onset
458 "*431" .
459 "*D8" .
460 "*" . $claim->onsetDate() .
461 "~\n";
464 if ($claim->dateInitialTreatment() && ($claim->onsetDateValid())) {
465 ++$edicount;
466 $out .= "DTP" . // Date of Initial Treatment
467 "*454" .
468 "*D8" .
469 "*" . $claim->dateInitialTreatment() .
470 "~\n";
473 // Segment DTP*304 (Last Seen Date) omitted.
474 // Segment DTP*453 (Acute Manifestation Date) omitted.
475 // Segment DTP*439 (Accident Date) omitted.
476 // Segment DTP*484 (Last Menstrual Period Date) omitted.
477 // Segment DTP*455 (Last X-Ray Date) omitted.
478 // Segment DTP*471 (Hearing and Vision Prescription Date) omitted.
479 // Segments DTP (Disability Dates) omitted.
480 // Segment DTP*297 (Last Worked Date) omitted.
481 // Segment DTP*296 (Authorized Return to Work Date) omitted.
483 if (strcmp($claim->facilityPOS(),'21') == 0 && $claim->onsetDateValid() ) {
484 ++$edicount;
485 $out .= "DTP" . // Date of Hospitalization
486 "*435" .
487 "*D8" .
488 "*" . $claim->onsetDate() .
489 "~\n";
492 // Segment DTP*096 (Discharge Date) omitted.
493 // Segments DTP (Assumed and Relinquished Care Dates) omitted.
494 // Segment DTP*444 (Property and Casualty Date of First Contact) omitted.
495 // Segment DTP*050 (Repricer Received Date) omitted.
496 // Segment PWK (Claim Supplemental Information) omitted.
497 // Segment CN1 (Contract Information) omitted.
499 $patientpaid = $claim->patientPaidAmount();
500 if ($patientpaid != 0) {
501 ++$edicount;
502 $out .= "AMT" . // Patient paid amount. Page 190/220.
503 "*F5" .
504 "*" . $patientpaid .
505 "~\n";
508 // Segment REF*4N (Service Authorization Exception Code) omitted.
509 // Segment REF*F5 (Mandatory Medicare Crossover Indicator) omitted.
510 // Segment REF*EW (Mammography Certification Number) omitted.
511 // Segment REF*9F (Referral Number) omitted.
513 if ($claim->priorAuth()) {
514 ++$edicount;
515 $out .= "REF" . // Prior Authorization Number
516 "*G1" .
517 "*" . $claim->priorAuth() .
518 "~\n";
521 // Segment REF*F8 (Payer Claim Control Number) omitted.
523 if ($claim->cliaCode() && ($CMS_5010 || $claim->claimType() === 'MB')) {
524 // Required by Medicare when in-house labs are done.
525 ++$edicount;
526 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
527 "*X4" .
528 "*" . $claim->cliaCode() .
529 "~\n";
532 // Segment REF*9A (Repriced Claim Number) omitted.
533 // Segment REF*9C (Adjusted Repriced Claim Number) omitted.
534 // Segment REF*LX (Investigational Device Exemption Number) omitted.
535 // Segment REF*D9 (Claim Identifier for Transmission Intermediaries) omitted.
536 // Segment REF*EA (Medical Record Number) omitted.
537 // Segment REF*P4 (Demonstration Project Identifier) omitted.
538 // Segment REF*1J (Care Plan Oversight) omitted.
539 // Segment K3 (File Information) omitted.
541 if ($claim->additionalNotes()) {
542 // Claim note.
543 ++$edicount;
544 $out .= "NTE" . // comments box 19
545 "*" . ($CMS_5010 ? "ADD" : "") .
546 "*" . $claim->additionalNotes() .
547 "~\n";
550 // Segment CR1 (Ambulance Transport Information) omitted.
551 // Segment CR2 (Spinal Manipulation Service Information) omitted.
552 // Segment CRC (Ambulance Certification) omitted.
553 // Segment CRC (Patient Condition Information: Vision) omitted.
554 // Segment CRC (Homebound Indicator) omitted.
555 // Segment CRC (EPSDT Referral) omitted.
557 // Diagnoses, up to $max_per_seg per HI segment.
558 $max_per_seg = $CMS_5010 ? 12 : 8;
559 $da = $claim->diagArray();
560 $diag_type_code = 'BK';
561 $tmp = 0;
562 foreach ($da as $diag) {
563 if ($tmp % $max_per_seg == 0) {
564 if ($tmp) $out .= "~\n";
565 ++$edicount;
566 $out .= "HI"; // Health Diagnosis Codes
568 $out .= "*$diag_type_code:" . $diag;
569 $diag_type_code = 'BF';
570 ++$tmp;
572 if ($tmp) $out .= "~\n";
574 // Segment HI*BP (Anesthesia Related Procedure) omitted.
575 // Segment HI*BG (Condition Information) omitted.
576 // Segment HCP (Claim Pricing/Repricing Information) omitted.
578 if ($claim->referrerLastName()) {
579 // Medicare requires referring provider's name and UPIN.
580 ++$edicount;
581 $out .= "NM1" . // Loop 2310A Referring Provider
582 "*DN" .
583 "*1" .
584 "*" . $claim->referrerLastName() .
585 "*" . $claim->referrerFirstName() .
586 "*" . $claim->referrerMiddleName() .
587 "*" .
588 "*";
589 if ($CMS_5010 || $claim->referrerNPI()) { $out .=
590 "*XX" .
591 "*" . $claim->referrerNPI();
592 } else { $out .=
593 "*34" . // not allowed for 5010
594 "*" . $claim->referrerSSN();
596 $out .= "~\n";
598 if (!$CMS_5010 && $claim->referrerTaxonomy()) {
599 ++$edicount;
600 $out .= "PRV" .
601 "*RF" . // ReFerring provider
602 "*ZZ" .
603 "*" . $claim->referrerTaxonomy() .
604 "~\n";
607 if (!CMS_5010 && $claim->referrerUPIN()) {
608 ++$edicount;
609 $out .= "REF" . // Referring Provider Secondary Identification
610 "*1G" .
611 "*" . $claim->referrerUPIN() .
612 "~\n";
616 ++$edicount;
617 $out .= "NM1" . // Loop 2310B Rendering Provider
618 "*82" .
619 "*1" .
620 "*" . $claim->providerLastName() .
621 "*" . $claim->providerFirstName() .
622 "*" . $claim->providerMiddleName() .
623 "*" .
624 "*";
625 if ($CMS_5010 || $claim->providerNPI()) { $out .=
626 "*XX" .
627 "*" . $claim->providerNPI();
628 } else { $out .=
629 "*34" . // not allowed for 5010
630 "*" . $claim->providerSSN();
631 $log .= "*** Rendering provider has no NPI.\n";
633 $out .= "~\n";
635 if ($claim->providerTaxonomy()) {
636 ++$edicount;
637 $out .= "PRV" .
638 "*PE" . // PErforming provider
639 "*" . ($CMS_5010 ? "PXC" : "ZZ") .
640 "*" . $claim->providerTaxonomy() .
641 "~\n";
644 // 4010: REF*1C is required here for the Medicare provider number if NPI was
645 // specified in NM109. Not sure if other payers require anything here.
646 // --- apparently ECLAIMS, INC wants the data in 2010 but NOT in 2310B - tony@mi-squared.com
648 // 5010 spec says nothing here if NPI was specified.
650 if (($CMS_5010 && !$claim->providerNPI() && in_array($claim->providerNumberType(), array('0B','1G','G2','LU')))
651 || (!$CMS_5010 && trim($claim->x12gsreceiverid()) != '470819582')) // if NOT ECLAIMS EDI
653 if ($claim->providerNumber()) {
654 ++$edicount;
655 $out .= "REF" .
656 "*" . $claim->providerNumberType() .
657 "*" . $claim->providerNumber() .
658 "~\n";
662 // Loop 2310D is omitted in the case of home visits (POS=12).
663 if ($claim->facilityPOS() != 12 &&
664 (!$CMS_5010 || $claim->facilityNPI() != $claim->billingFacilityNPI()))
666 ++$edicount;
667 $out .= "NM1" . // Loop 2310D Service Location
668 "*77" .
669 "*2";
670 //Field length is limited to 35. See nucc dataset page 77 www.nucc.org
671 $facilityName = substr($claim->facilityName(), 0, $CMS_5010 ? 60 : 35);
672 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) { $out .=
673 "*" . $facilityName;
675 if ($claim->facilityNPI() || $claim->facilityETIN()) { $out .=
676 "*" .
677 "*" .
678 "*" .
679 "*";
680 if ($CMS_5010 || $claim->facilityNPI()) { $out .=
681 "*XX*" . $claim->facilityNPI();
682 } else { $out .=
683 "*24*" . $claim->facilityETIN();
685 if (!$claim->facilityNPI()) {
686 $log .= "*** Service location has no NPI.\n";
689 $out .= "~\n";
690 if ($claim->facilityStreet()) {
691 ++$edicount;
692 $out .= "N3" .
693 "*" . $claim->facilityStreet() .
694 "~\n";
696 if ($claim->facilityState()) {
697 ++$edicount;
698 $out .= "N4" .
699 "*" . $claim->facilityCity() .
700 "*" . $claim->facilityState() .
701 "*" . stripZipCode($claim->facilityZip()) .
702 "~\n";
706 // Segment REF (Service Facility Location Secondary Identification) omitted.
707 // Segment PER (Service Facility Contact Information) omitted.
709 // Loop 2310E, Supervising Provider
711 if ($claim->supervisorLastName()) {
712 ++$edicount;
713 $out .= "NM1" .
714 "*DQ" . // Supervising Physician
715 "*1" . // Person
716 "*" . $claim->supervisorLastName() .
717 "*" . $claim->supervisorFirstName() .
718 "*" . $claim->supervisorMiddleName() .
719 "*" . // NM106 not used
720 "*"; // Name Suffix
721 if ($CMS_5010 || $claim->supervisorNPI()) { $out .=
722 "*XX" .
723 "*" . $claim->supervisorNPI();
724 } else { $out .=
725 "*34" .
726 "*" . $claim->supervisorSSN();
728 if (!$claim->supervisorNPI()) {
729 $log .= "*** Supervising Provider has no NPI.\n";
731 $out .= "~\n";
733 if ($claim->supervisorNumber()) {
734 ++$edicount;
735 $out .= "REF" .
736 "*" . $claim->supervisorNumberType() .
737 "*" . $claim->supervisorNumber() .
738 "~\n";
742 // Segments NM1*PW, N3, N4 (Ambulance Pick-Up Location) omitted.
743 // Segments NM1*45, N3, N4 (Ambulance Drop-Off Location) omitted.
745 $prev_pt_resp = $clm_total_charges; // for computation below
747 // Loops 2320 and 2330*, other subscriber/payer information.
748 // Remember that insurance index 0 is always for the payer being billed
749 // by this claim, and 1 and above are always for the "other" payers.
751 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
753 $tmp1 = $claim->claimType($ins);
754 $tmp2 = 'C1'; // Here a kludge. See page 321.
755 if ($tmp1 === 'CI') $tmp2 = 'C1';
756 if ($tmp1 === 'AM') $tmp2 = 'AP';
757 if ($tmp1 === 'HM') $tmp2 = 'HM';
758 if ($tmp1 === 'MB') $tmp2 = 'MB';
759 if ($tmp1 === 'MC') $tmp2 = 'MC';
760 if ($tmp1 === '09') $tmp2 = 'PP';
761 ++$edicount;
762 $out .= "SBR" . // Loop 2320, Subscriber Information - page 297/318
763 "*" . $claim->payerSequence($ins) .
764 "*" . $claim->insuredRelationship($ins) .
765 "*" . $claim->groupNumber($ins) .
766 "*" . (($CMS_5010 && $claim->groupNumber($ins)) ? '' : $claim->groupName($ins)) .
767 "*" . ($CMS_5010 ? $claim->insuredTypeCode($ins) : $tmp2) .
768 "*" .
769 "*" .
770 "*" .
771 "*" . $claim->claimType($ins) .
772 "~\n";
774 // Things that apply only to previous payers, not future payers.
776 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
778 // Generate claim-level adjustments.
779 $aarr = $claim->payerAdjustments($ins);
780 foreach ($aarr as $a) {
781 ++$edicount;
782 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 301/323.
783 "*" . $a[1] .
784 "*" . $a[2] .
785 "*" . $a[3] .
786 "~\n";
789 $payerpaid = $claim->payerTotals($ins);
790 ++$edicount;
791 $out .= "AMT" . // Previous payer's paid amount. Page 307/332.
792 "*D" .
793 "*" . $payerpaid[1] .
794 "~\n";
796 // Segment AMT*A8 (COB Total Non-Covered Amount) omitted.
797 // Segment AMT*EAF (Remaining Patient Liability) omitted.
799 if (!$CMS_5010) {
800 // Patient responsibility amount as of this previous payer.
801 $prev_pt_resp -= $payerpaid[1]; // reduce by payments
802 $prev_pt_resp -= $payerpaid[2]; // reduce by adjustments
804 ++$edicount;
805 $out .= "AMT" . // Allowed amount per previous payer. Page 334.
806 "*B6" .
807 "*" . sprintf('%.2f', $payerpaid[1] + $prev_pt_resp) .
808 "~\n";
810 ++$edicount;
811 $out .= "AMT" . // Patient responsibility amount per previous payer. Page 335.
812 "*F2" .
813 "*" . sprintf('%.2f', $prev_pt_resp) .
814 "~\n";
816 } // End of things that apply only to previous payers.
818 if (!$CMS_5010) {
819 ++$edicount;
820 $out .= "DMG" . // Other subscriber demographic information. Page 342.
821 "*D8" .
822 "*" . $claim->insuredDOB($ins) .
823 "*" . $claim->insuredSex($ins) .
824 "~\n";
827 ++$edicount;
828 $out .= "OI" . // Other Insurance Coverage Information. Page 310/344.
829 "*" .
830 "*" .
831 "*" . ($claim->billingFacilityAssignment($ins) ? 'Y' : 'N') .
832 // For this next item, the 5010 example in the spec does not match its
833 // description. So this might be wrong.
834 "*" . ($CMS_5010 ? '' : 'B') .
835 "*" .
836 "*Y" .
837 "~\n";
839 // Segment MOA (Medicare Outpatient Adjudication) omitted.
841 ++$edicount;
842 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 315/350.
843 "*IL" .
844 "*1" .
845 "*" . $claim->insuredLastName($ins) .
846 "*" . $claim->insuredFirstName($ins) .
847 "*" . $claim->insuredMiddleName($ins) .
848 "*" .
849 "*" .
850 "*MI" .
851 "*" . $claim->policyNumber($ins) .
852 "~\n";
854 ++$edicount;
855 $out .= "N3" .
856 "*" . $claim->insuredStreet($ins) .
857 "~\n";
859 ++$edicount;
860 $out .= "N4" .
861 "*" . $claim->insuredCity($ins) .
862 "*" . $claim->insuredState($ins) .
863 "*" . stripZipCode($claim->insuredZip($ins)) .
864 "~\n";
866 // Segment REF (Other Subscriber Secondary Identification) omitted.
868 ++$edicount;
869 //Field length is limited to 35. See nucc dataset page 81 www.nucc.org
870 $payerName = substr($claim->payerName($ins), 0, $CMS_5010 ? 60 : 35);
871 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 322/359.
872 "*PR" .
873 "*2" .
874 "*" . $payerName .
875 "*" .
876 "*" .
877 "*" .
878 "*" .
879 "*PI" .
880 "*" . $claim->payerID($ins) .
881 "~\n";
883 // if (!$claim->payerID($ins)) {
884 // $log .= "*** CMS ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
885 // }
887 // Payer address (N3 and N4) are added below so that Gateway EDI can
888 // auto-generate secondary claims. These do NOT appear in my copy of
889 // the spec! -- Rod 2008-06-12
891 if ($CMS_5010 || trim($claim->x12gsreceiverid()) == '431420764') { // if Gateway EDI
892 ++$edicount;
893 $out .= "N3" .
894 "*" . $claim->payerStreet($ins) .
895 "~\n";
897 ++$edicount;
898 $out .= "N4" .
899 "*" . $claim->payerCity($ins) .
900 "*" . $claim->payerState($ins) .
901 "*" . stripZipCode($claim->payerZip($ins)) .
902 "~\n";
903 } // end Gateway EDI
905 // Segment DTP*573 (Claim Check or Remittance Date) omitted.
906 // Segment REF (Other Payer Secondary Identifier) omitted.
907 // Segment REF*G1 (Other Payer Prior Authorization Number) omitted.
908 // Segment REF*9F (Other Payer Referral Number) omitted.
909 // Segment REF*T4 (Other Payer Claim Adjustment Indicator) omitted.
910 // Segment REF*F8 (Other Payer Claim Control Number) omitted.
911 // Segment NM1 (Other Payer Referring Provider) omitted.
912 // Segment REF (Other Payer Referring Provider Secondary Identification) omitted.
913 // Segment NM1 (Other Payer Rendering Provider) omitted.
914 // Segment REF (Other Payer Rendering Provider Secondary Identification) omitted.
915 // Segment NM1 (Other Payer Service Facility Location) omitted.
916 // Segment REF (Other Payer Service Facility Location Secondary Identification) omitted.
917 // Segment NM1 (Other Payer Supervising Provider) omitted.
918 // Segment REF (Other Payer Supervising Provider Secondary Identification) omitted.
919 // Segment NM1 (Other Payer Billing Provider) omitted.
920 // Segment REF (Other Payer Billing Provider Secondary Identification) omitted.
922 } // End loops 2320/2330*.
924 $loopcount = 0;
926 // Procedure loop starts here.
928 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
929 ++$loopcount;
931 ++$edicount;
932 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
933 "*$loopcount" .
934 "~\n";
936 ++$edicount;
937 $out .= "SV1" . // Professional Service. Page 400.
938 "*HC:" . $claim->cptKey($prockey) .
939 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
940 "*UN" .
941 "*" . $claim->cptUnits($prockey) .
942 "*" .
943 "*" .
944 "*";
945 $dia = $claim->diagIndexArray($prockey);
946 $i = 0;
947 foreach ($dia as $dindex) {
948 if ($i) $out .= ':';
949 $out .= $dindex;
950 if (++$i >= 4) break;
952 $out .= "~\n";
954 if (!$claim->cptCharges($prockey)) {
955 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
958 if (empty($dia)) {
959 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' is not justified!\n";
962 // Segment SV5 (Durable Medical Equipment Service) omitted.
963 // Segment PWK (Line Supplemental Information) omitted.
964 // Segment PWK (Durable Medical Equipment Certificate of Medical Necessity Indicator) omitted.
965 // Segment CR1 (Ambulance Transport Information) omitted.
966 // Segment CR3 (Durable Medical Equipment Certification) omitted.
967 // Segment CRC (Ambulance Certification) omitted.
968 // Segment CRC (Hospice Employee Indicator) omitted.
969 // Segment CRC (Condition Indicator / Durable Medical Equipment) omitted.
971 ++$edicount;
972 $out .= "DTP" . // Date of Service. Page 435.
973 "*472" .
974 "*D8" .
975 "*" . $claim->serviceDate() .
976 "~\n";
978 $testnote = rtrim($claim->cptNotecodes($prockey));
979 if (!empty($testnote)) {
980 ++$edicount;
981 $out .= "NTE" . // Explain Unusual Circumstances.
982 "*ADD" .
983 "*" . $claim->cptNotecodes($prockey) .
984 "~\n";
987 // Segment DTP*471 (Prescription Date) omitted.
988 // Segment DTP*607 (Revision/Recertification Date) omitted.
989 // Segment DTP*463 (Begin Therapy Date) omitted.
990 // Segment DTP*461 (Last Certification Date) omitted.
991 // Segment DTP*304 (Last Seen Date) omitted.
992 // Segment DTP (Test Date) omitted.
993 // Segment DTP*011 (Shipped Date) omitted.
994 // Segment DTP*455 (Last X-Ray Date) omitted.
995 // Segment DTP*454 (Initial Treatment Date) omitted.
996 // Segment QTY (Ambulance Patient Count) omitted.
997 // Segment QTY (Obstetric Anesthesia Additional Units) omitted.
998 // Segment MEA (Test Result) omitted.
999 // Segment CN1 (Contract Information) omitted.
1000 // Segment REF*9B (Repriced Line Item Reference Number) omitted.
1001 // Segment REF*9D (Adjusted Repriced Line Item Reference Number) omitted.
1002 // Segment REF*G1 (Prior Authorization) omitted.
1003 // Segment REF*6R (Line Item Control Number) omitted.
1004 // (Really oughta have this for robust 835 posting!)
1005 // Segment REF*EW (Mammography Certification Number) omitted.
1006 // Segment REF*X4 (CLIA Number) omitted.
1007 // Segment REF*F4 (Referring CLIA Facility Identification) omitted.
1008 // Segment REF*BT (Immunization Batch Number) omitted.
1009 // Segment REF*9F (Referral Number) omitted.
1010 // Segment AMT*T (Sales Tax Amount) omitted.
1011 // Segment AMT*F4 (Postage Claimed Amount) omitted.
1012 // Segment K3 (File Information) omitted.
1013 // Segment NTE (Line Note) omitted.
1014 // Segment NTE (Third Party Organization Notes) omitted.
1015 // Segment PS1 (Purchased Service Information) omitted.
1016 // Segment HCP (Line Pricing/Repricing Information) omitted.
1018 if (!$CMS_5010) {
1019 // This segment was deleted for 5010.
1021 // AMT*AAE segment for Approved Amount from previous payer.
1022 // Medicare secondaries seem to require this.
1024 for ($ins = $claim->payerCount() - 1; $ins > 0; --$ins) {
1025 if ($claim->payerSequence($ins) > $claim->payerSequence())
1026 continue; // payer is future, not previous
1027 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
1028 ++$edicount;
1029 $out .= "AMT" . // Approved amount per previous payer. Page 485.
1030 "*AAE" .
1031 "*" . sprintf('%.2f', $claim->cptCharges($prockey) - $payerpaid[2]) .
1032 "~\n";
1033 break;
1037 // Loop 2410, Drug Information. Medicaid insurers seem to want this
1038 // with HCPCS codes.
1040 $ndc = $claim->cptNDCID($prockey);
1041 if ($ndc) {
1042 ++$edicount;
1043 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
1044 "*" . // Per addendum, LIN01 is not used.
1045 "*N4" .
1046 "*" . $ndc .
1047 "~\n";
1049 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp) && !preg_match('/^\d{11}$/', $ndc)) {
1050 $log .= "*** NDC code '$ndc' has invalid format!\n";
1053 ++$edicount;
1054 $tmpunits = $claim->cptNDCQuantity($prockey) * $claim->cptUnits($prockey);
1055 if (!$tmpunits) $tmpunits = 1;
1056 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
1057 "*" .
1058 "*" .
1059 "*" . ($CMS_5010 ? '' : sprintf('%.2f', $claim->cptCharges($prockey) / $tmpunits)) .
1060 "*" . $claim->cptNDCQuantity($prockey) .
1061 "*" . $claim->cptNDCUOM($prockey) .
1062 // Note: 5010 documents "ME" (Milligrams) as an additional unit of measure.
1063 "~\n";
1066 // Segment REF (Prescription or Compound Drug Association Number) omitted.
1068 // Loop 2420A, Rendering Provider (service-specific).
1069 // Used if the rendering provider for this service line is different
1070 // from that in loop 2310B.
1072 if ($claim->providerNPI() != $claim->providerNPI($prockey)) {
1073 ++$edicount;
1074 $out .= "NM1" . // Loop 2310B Rendering Provider
1075 "*82" .
1076 "*1" .
1077 "*" . $claim->providerLastName($prockey) .
1078 "*" . $claim->providerFirstName($prockey) .
1079 "*" . $claim->providerMiddleName($prockey) .
1080 "*" .
1081 "*";
1082 if ($CMS_5010 || $claim->providerNPI($prockey)) { $out .=
1083 "*XX" .
1084 "*" . $claim->providerNPI($prockey);
1085 } else { $out .=
1086 "*34" . // Not allowed for 5010
1087 "*" . $claim->providerSSN($prockey);
1089 if (!$claim->providerNPI($prockey)) {
1090 $log .= "*** Rendering provider has no NPI.\n";
1092 $out .= "~\n";
1094 if ($claim->providerTaxonomy($prockey)) {
1095 ++$edicount;
1096 $out .= "PRV" .
1097 "*PE" . // PErforming provider
1098 "*" . ($CMS_5010 ? "PXC" : "ZZ") .
1099 "*" . $claim->providerTaxonomy($prockey) .
1100 "~\n";
1103 // Segment PRV*PE (Rendering Provider Specialty Information) omitted.
1104 // Segment REF (Rendering Provider Secondary Identification) omitted.
1105 // Segment NM1 (Purchased Service Provider Name) omitted.
1106 // Segment REF (Purchased Service Provider Secondary Identification) omitted.
1107 // Segment NM1,N3,N4 (Service Facility Location) omitted.
1108 // Segment REF (Service Facility Location Secondary Identification) omitted.
1109 // Segment NM1 (Supervising Provider Name) omitted.
1110 // Segment REF (Supervising Provider Secondary Identification) omitted.
1111 // Segment NM1,N3,N4 (Ordering Provider) omitted.
1112 // Segment REF (Ordering Provider Secondary Identification) omitted.
1113 // Segment PER (Ordering Provider Contact Information) omitted.
1114 // Segment NM1 (Referring Provider Name) omitted.
1115 // Segment REF (Referring Provider Secondary Identification) omitted.
1116 // Segments NM1*PW, N3, N4 (Ambulance Pick-Up Location) omitted.
1117 // Segments NM1*45, N3, N4 (Ambulance Drop-Off Location) omitted.
1119 // REF*1C is required here for the Medicare provider number if NPI was
1120 // specified in NM109. Not sure if other payers require anything here.
1121 if (!$CMS_5010 && $claim->providerNumber($prockey)) {
1122 ++$edicount;
1123 $out .= "REF" .
1124 "*" . $claim->providerNumberType($prockey) .
1125 // Note: 5010 documents that type 1D (Medicaid) is changed to G2.
1126 "*" . $claim->providerNumber($prockey) .
1127 "~\n";
1131 // Loop 2430, adjudication by previous payers.
1133 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
1134 if ($claim->payerSequence($ins) > $claim->payerSequence())
1135 continue; // payer is future, not previous
1137 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
1138 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
1140 if ($payerpaid[1] == 0 && !count($aarr)) {
1141 $log .= "*** Procedure '" . $claim->cptKey($prockey) .
1142 "' has no payments or adjustments from previous payer!\n";
1143 continue;
1146 ++$edicount;
1147 $out .= "SVD" . // Service line adjudication. Page 554.
1148 "*" . $claim->payerID($ins) .
1149 "*" . $payerpaid[1] .
1150 "*HC:" . $claim->cptKey($prockey) .
1151 "*" .
1152 "*" . $claim->cptUnits($prockey) .
1153 "~\n";
1155 $tmpdate = $payerpaid[0];
1156 foreach ($aarr as $a) {
1157 ++$edicount;
1158 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
1159 "*" . $a[1] .
1160 "*" . $a[2] .
1161 "*" . $a[3] .
1162 "~\n";
1163 if (!$tmpdate) $tmpdate = $a[0];
1165 // WTH is this??
1166 /*************************************************************
1167 if ( isset($a[4]) &&
1168 $a[4] != null ) {
1169 $out .= "CAS02" . // Previous payer's adjustment reason
1170 "*" . $a[4] .
1171 "~\n";
1173 *************************************************************/
1176 if ($tmpdate) {
1177 ++$edicount;
1178 $out .= "DTP" . // Previous payer's line adjustment date. Page 493/566.
1179 "*573" .
1180 "*D8" .
1181 "*$tmpdate" .
1182 "~\n";
1185 // Segment AMT*EAF (Remaining Patient Liability) omitted.
1186 // Segment LQ (Form Identification Code) omitted.
1187 // Segment FRM (Supporting Documentation) omitted.
1189 } // end loop 2430
1190 } // end this procedure
1192 ++$edicount;
1193 $out .= "SE" . // SE Trailer
1194 "*$edicount" .
1195 "*0021" .
1196 "~\n";
1198 $out .= "GE" . // GE Trailer
1199 "*1" .
1200 "*1" .
1201 "~\n";
1203 $out .= "IEA" . // IEA Trailer
1204 "*1" .
1205 "*000000001" .
1206 "~\n";
1208 // Remove any trailing empty fields (delimiters) from each segment.
1209 $out = preg_replace('/\*+~/', '~', $out);
1211 $log .= "\n";
1212 return $out;