x12 billing work and Claim class to psr2/4 work (#1004)
[openemr.git] / library / gen_x12_837.inc.php
blob10813e79d3be8b25c8d22f3b36c583591605a734
1 <?php
2 /*
3 * This program creates a 5010 837P file
5 * @package OpenEMR
6 * @author Rod Roark <rod@sunsetsystems.com>
7 * @author Stephen Waite <stephen.waite@cmsvt.com>
8 * @copyright Copyright (c) 2009 Rod Roark <rod@sunsetsystems.com>
9 * @copyright Copyright (c) 2017 Stephen Waite <stephen.waite@cmsvt.com>
10 * @link https://github.com/openemr/openemr/tree/master
11 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
14 require_once(dirname(__FILE__) . "/invoice_summary.inc.php");
16 use OpenEMR\Billing\Claim;
18 function stripZipCode($zip)
20 return preg_replace('/[-\s]*/', '', $zip);
23 function gen_x12_837($pid, $encounter, &$log, $encounter_claim = false)
25 $today = time();
26 $out = '';
27 $claim = new Claim($pid, $encounter);
28 $edicount = 0;
29 $HLcount = 0;
31 $log .= "Generating claim $pid" . "-" . $encounter . " for " .
32 $claim->patientFirstName() . ' ' .
33 $claim->patientMiddleName() . ' ' .
34 $claim->patientLastName() . ' on ' .
35 date('Y-m-d H:i', $today) . ".\n";
37 $out .= "ISA" .
38 "*" . $claim->x12gsisa01() .
39 "*" . $claim->x12gsisa02() .
40 "*" . $claim->x12gsisa03() .
41 "*" . $claim->x12gsisa04() .
42 "*" . $claim->x12gsisa05() .
43 "*" . $claim->x12gssenderid() .
44 "*" . $claim->x12gsisa07() .
45 "*" . $claim->x12gsreceiverid() .
46 "*" . "030911" . // dummy data replace by billing_process.php
47 "*" . "1630" . // ditto
48 "*" . "^" .
49 "*" . "00501" .
50 "*" . "000000001" .
51 "*" . $claim->x12gsisa14() .
52 "*" . $claim->x12gsisa15() .
53 "*:" .
54 "~\n";
56 $out .= "GS" .
57 "*" . "HC" .
58 "*" . $claim->x12gsgs02() .
59 "*" . trim($claim->x12gs03()) .
60 "*" . date('Ymd', $today) .
61 "*" . date('Hi', $today) .
62 "*" . "1" .
63 "*" . "X" .
64 "*" . $claim->x12gsversionstring() .
65 "~\n";
67 ++$edicount;
68 $out .= "ST" .
69 "*" . "837" .
70 "*" . "0021" .
71 "*" . $claim->x12gsversionstring() .
72 "~\n";
74 ++$edicount;
75 $out .= "BHT" .
76 "*" . "0019" . // 0019 is required here
77 "*" . "00" . // 00 = original transmission
78 "*" . "0123" . // reference identification
79 "*" . date('Ymd', $today) . // transaction creation date
80 "*" . date('Hi', $today) . // transaction creation time
81 "*" . ($encounter_claim ? "RP" : "CH") . // RP = reporting, CH = chargeable
82 "~\n";
84 ++$edicount;
85 if ($claim->federalIdType() == "SY") { // check entity type for NM*102 1 == person, 2 == non-person entity
86 $firstName = $claim->providerFirstName();
87 $lastName = $claim->providerLastName();
88 $middleName = $claim->providerMiddleName();
89 $suffixName = $claim->providerSuffixName();
90 $out .= "NM1" . // Loop 1000A Submitter
91 "*" . "41" .
92 "*" . "1" .
93 "*" . $lastName .
94 "*" . $firstName .
95 "*" . $middleName .
96 "*" . // Name Prefix not used
97 "*" . $suffixName .
98 "*" . "46";
99 } else {
100 $billingFacilityName = substr($claim->billingFacilityName(), 0, 60);
101 if ($billingFacilityName == '') {
102 $log .= "*** billing facility name in 1000A loop is empty\n";
104 $out .= "NM1" .
105 "*" . "41" .
106 "*" . "2" .
107 "*" . $billingFacilityName .
108 "*" .
109 "*" .
110 "*" .
111 "*" .
112 "*" . "46";
114 $out .= "*" . $claim->billingFacilityETIN();
115 $out .= "~\n";
117 ++$edicount;
118 $out .= "PER" .
119 "*" . "IC" .
120 "*" . $claim->billingContactName() .
121 "*" . "TE" .
122 "*" . $claim->billingContactPhone() .
123 "*" . "EM" .
124 "*" . $claim->billingContactEmail();
125 $out .= "~\n";
127 ++$edicount;
128 $out .= "NM1" . // Loop 1000B Receiver
129 "*" . "40" .
130 "*" . "2" .
131 "*" . $claim->clearingHouseName() .
132 "*" .
133 "*" .
134 "*" .
135 "*" .
136 "*" . "46" .
137 "*" . $claim->clearingHouseETIN() .
138 "~\n";
140 ++$HLcount;
141 ++$edicount;
142 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
143 "*" . $HLcount .
144 "*" .
145 "*" . "20" .
146 "*" . "1" . // 1 indicates there are child segments
147 "~\n";
149 $HLBillingPayToProvider = $HLcount++;
150 // Situational PRV segment for provider taxonomy code for Medicaid.
151 if ($claim->claimType() == 'MC') {
152 ++$edicount;
153 $out .= "PRV" .
154 "*" . "BI" .
155 "*" . "ZZ" .
156 "*" . $claim->providerTaxonomy() .
157 "~\n";
160 // Situational CUR segment (foreign currency information) omitted here.
161 ++$edicount;
162 if ($claim->federalIdType() == "SY") { // check for entity type like in 1000A
163 $firstName = $claim->providerFirstName();
164 $lastName = $claim->providerLastName();
165 $middleName = $claim->providerMiddleName();
166 $out .= "NM1" .
167 "*" . "85" .
168 "*" . "1" .
169 "*" . $lastName .
170 "*" . $firstName .
171 "*" . $middleName .
172 "*" . // Name Prefix not used
173 "*";
174 } else {
175 $billingFacilityName = substr($claim->billingFacilityName(), 0, 60);
176 if ($billingFacilityName == '') {
177 $log .= "*** billing facility name in 2010A loop is empty\n";
179 $out .= "NM1" . // Loop 2010AA Billing Provider
180 "*" . "85" .
181 "*" . "2" .
182 "*" . $billingFacilityName .
183 "*" .
184 "*" .
185 "*" .
186 "*";
188 if ($claim->billingFacilityNPI()) {
189 $out .= "*XX*" . $claim->billingFacilityNPI();
190 } else {
191 $log .= "*** Billing facility has no NPI.\n";
193 $out .= "~\n";
195 ++$edicount;
196 $out .= "N3" .
197 "*" . $claim->billingFacilityStreet() .
198 "~\n";
200 ++$edicount;
201 $out .= "N4" .
202 "*" . $claim->billingFacilityCity() .
203 "*" . $claim->billingFacilityState() .
204 "*" . stripZipCode($claim->billingFacilityZip()) .
205 "~\n";
207 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
208 ++$edicount;
209 $out .= "REF";
210 if ($claim->federalIdType()) {
211 $out .= "*" . $claim->federalIdType();
212 } else {
213 $out .= "*EI"; // For dealing with the situation before adding TaxId type In facility.
215 $out .= "*" . $claim->billingFacilityETIN() . "~\n";
216 } else {
217 $log .= "*** No billing facility NPI and/or ETIN.\n";
219 if ($claim->providerNumberType() && $claim->providerNumber() && !$claim->billingFacilityNPI()) {
220 ++$edicount;
221 $out .= "REF" .
222 "*" . $claim->providerNumberType() .
223 "*" . $claim->providerNumber() .
224 "~\n";
225 } else if ($claim->providerNumber() && !$claim->providerNumberType()) {
226 $log .= "*** Payer-specific provider insurance number is present but has no type assigned.\n";
229 // Situational PER*1C segment omitted.
231 // Pay-To Address defaults to billing provider and is no longer required in 5010 but may be useful
232 if ($claim->facilityStreet() != $claim->billingFacilityStreet()) {
233 ++$edicount;
234 $billingFacilityName = substr($claim->billingFacilityName(), 0, 60);
235 $out .= "NM1" . // Loop 2010AB Pay-To Provider
236 "*" . "87" .
237 "*" . "2" .
238 "*" . $billingFacilityName .
239 "*" .
240 "*" .
241 "*" .
242 "*";
243 if ($claim->billingFacilityNPI()) {
244 $out .= "*XX*" . $claim->billingFacilityNPI();
246 $out .= "~\n";
248 ++$edicount;
249 $out .= "N3" .
250 "*" . $claim->billingFacilityStreet() .
251 "~\n";
253 ++$edicount;
254 $out .= "N4" .
255 "*" . $claim->billingFacilityCity() .
256 "*" . $claim->billingFacilityState() .
257 "*" . stripZipCode($claim->billingFacilityZip()) .
258 "~\n";
260 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
261 ++$edicount;
262 $out .= "REF" .
263 "*" . "EI" .
264 "*" . $claim->billingFacilityETIN() .
265 "~\n";
269 // Loop 2010AC Pay-To Plan Name omitted. Includes:
270 // NM1*PE, N3, N4, REF*2U, REF*EI
272 $PatientHL = $claim->isSelfOfInsured() ? 0 : 1;
273 $HLSubscriber = $HLcount++;
275 ++$edicount;
276 $out .= "HL" . // Loop 2000B Subscriber HL Loop
277 "*" . $HLSubscriber .
278 "*" . $HLBillingPayToProvider .
279 "*" . "22" .
280 "*" . $PatientHL .
281 "~\n";
283 if (!$claim->payerSequence()) {
284 $log .= "*** Error: Insurance information is missing!\n";
287 ++$edicount;
288 $out .= "SBR" . // Subscriber Information
289 "*" . $claim->payerSequence() .
290 "*" . ($claim->isSelfOfInsured() ? '18' : '') .
291 "*" . $claim->groupNumber() .
292 "*" . $claim->groupName() .
293 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
294 "*" .
295 "*" .
296 "*" .
297 "*" . $claim->claimType() .
298 "~\n";
300 // Segment PAT omitted.
302 ++$edicount;
303 $out .= "NM1" . // Loop 2010BA Subscriber
304 "*" . "IL" .
305 "*" . "1" . // 1 = person, 2 = non-person
306 "*" . $claim->insuredLastName() .
307 "*" . $claim->insuredFirstName() .
308 "*" . $claim->insuredMiddleName() .
309 "*" .
310 "*" . // Name Suffix not used
311 "*" . "MI" .
312 // "MI" = Member Identification Number
313 // "II" = Standard Unique Health Identifier, "Required if the
314 // HIPAA Individual Patient Identifier is mandated use."
315 // Here we presume that is not true yet.
316 "*" . $claim->policyNumber() .
317 "~\n";
319 // For 5010, further subscriber info is sent only if they are the patient.
320 if ($claim->isSelfOfInsured()) {
321 ++$edicount;
322 $out .= "N3" .
323 "*" . $claim->insuredStreet() .
324 "~\n";
326 ++$edicount;
327 $out .= "N4" .
328 "*" . $claim->insuredCity() .
329 "*" . $claim->insuredState() .
330 "*" . stripZipCode($claim->insuredZip()) .
331 "~\n";
333 ++$edicount;
334 $out .= "DMG" .
335 "*" . "D8" .
336 "*" . $claim->insuredDOB() .
337 "*" . $claim->insuredSex() .
338 "~\n";
341 // Segment REF*SY (Subscriber Secondary Identification) omitted.
342 // Segment REF*Y4 (Property and Casualty Claim Number) omitted.
343 // Segment PER*IC (Property and Casualty Subscriber Contact Information) omitted.
345 ++$edicount;
346 $payerName = substr($claim->payerName(), 0, 60);
347 $out .= "NM1" . // Loop 2010BB Payer
348 "*" . "PR" .
349 "*" . "2" .
350 "*" . $payerName .
351 "*" .
352 "*" .
353 "*" .
354 "*" .
355 "*" . "PI" .
356 "*" . ($encounter_claim ? $claim->payerAltID() : $claim->payerID()) .
357 "~\n";
358 if (!$claim->payerID()) {
359 $log .= "*** CMS ID is missing for payer '" . $claim->payerName() . "'.\n";
362 ++$edicount;
363 $out .= "N3" .
364 "*" . $claim->payerStreet() .
365 "~\n";
367 ++$edicount;
368 $out .= "N4" .
369 "*" . $claim->payerCity() .
370 "*" . $claim->payerState() .
371 "*" . stripZipCode($claim->payerZip()) .
372 "~\n";
374 // Segment REF (Payer Secondary Identification) omitted.
375 // Segment REF (Billing Provider Secondary Identification) omitted.
377 if ($claim->isSelfOfInsured()) {
378 ++$edicount;
379 $out .= "HL" . // Loop 2000C Patient Information
380 "*" . $HLcount .
381 "*" . $HLSubscriber .
382 "*" . "23" .
383 "*" . "0" .
384 "~\n";
386 $HLcount++;
387 ++$edicount;
388 $out .= "PAT" .
389 "*" . $claim->insuredRelationship() .
390 "~\n";
392 ++$edicount;
393 $out .= "NM1" . // Loop 2010CA Patient
394 "*" . "QC" .
395 "*" . "1" .
396 "*" . $claim->patientLastName() .
397 "*" . $claim->patientFirstName();
399 if ($claim->patientMiddleName() !== '') {
400 $out .= "*" . $claim->patientMiddleName();
403 $out .= "~\n";
405 ++$edicount;
406 $out .= "N3" .
407 "*" . $claim->patientStreet() .
408 "~\n";
410 ++$edicount;
411 $out .= "N4" .
412 "*" . $claim->patientCity() .
413 "*" . $claim->patientState() .
414 "*" . stripZipCode($claim->patientZip()) .
415 "~\n";
417 ++$edicount;
418 $out .= "DMG" .
419 "*" . "D8" .
420 "*" . $claim->patientDOB() .
421 "*" . $claim->patientSex() .
422 "~\n";
424 // Segment REF*Y4 (Property and Casualty Claim Number) omitted.
425 // Segment REF (Property and Casualty Patient Identifier) omitted.
426 // Segment PER (Property and Casualty Patient Contact Information) omitted.
427 } // end of patient different from insured
429 $proccount = $claim->procCount();
430 $clm_total_charges = 0;
431 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
432 $clm_total_charges += $claim->cptCharges($prockey);
434 if (!$clm_total_charges) {
435 $log .= "*** This claim has no charges!\n";
438 ++$edicount;
439 $out .= "CLM" . // Loop 2300 Claim
440 "*" . $pid . "-" . $encounter .
441 "*" . sprintf("%.2f", $clm_total_charges) .
442 "*" .
443 "*" .
444 "*" . sprintf('%02d', $claim->facilityPOS()) . ":" . "B" . ":" . $claim->frequencyTypeCode() .
445 "*" . "Y" .
446 "*" . "A" .
447 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
448 "*" . "Y" .
449 "~\n";
451 if ($claim->onsetDate() && ($claim->onsetDate() !== $claim->serviceDate()) && ($claim->onsetDateValid())) {
452 ++$edicount;
453 $out .= "DTP" . // Date of Onset
454 "*" . "431" .
455 "*" . "D8" .
456 "*" . $claim->onsetDate() .
457 "~\n";
460 // above is for historical use of encounter onset date, now in misc_billing_options
461 // Segment DTP*431 (Onset of Current Symptoms or Illness)
462 // Segment DTP*484 (Last Menstrual Period Date)
464 if ($claim->miscOnsetDate() && ($claim->box14Qualifier()) && ($claim->miscOnsetDateValid())) {
465 ++$edicount;
466 $out .= "DTP" . // Date Last Seen
467 "*" . $claim->box14Qualifier() .
468 "*" . "D8" .
469 "*" . $claim->miscOnsetDate() .
470 "~\n";
473 // Segment DTP*454 (Initial Treatment Date)
474 // Segment DTP*304 (Last Seen Date)
475 // Segment DTP*453 (Acute Manifestation Date)
476 // Segment DTP*439 (Accident Date)
477 // Segment DTP*455 (Last X-Ray Date)
478 // Segment DTP*471 (Hearing and Vision Prescription Date)
479 // Segment DTP*314 (Disability) omitted.
480 // Segment DTP*360 (Initial Disability Period Start) omitted.
481 // Segment DTP*361 (Initial Disability Period End) omitted.
482 // Segment DTP*297 (Last Worked Date)
483 // Segment DTP*296 (Authorized Return to Work Date)
485 if ($claim->dateInitialTreatment() && ($claim->box15Qualifier()) && ($claim->dateInitialTreatmentValid())) {
486 ++$edicount;
487 $out .= "DTP" . // Date Last Seen
488 "*" . $claim->box15Qualifier() .
489 "*" . "D8" .
490 "*" . $claim->dateInitialTreatment() .
491 "~\n";
494 if (strcmp($claim->facilityPOS(), '21') == 0 && $claim->onsetDateValid()) {
495 ++$edicount;
496 $out .= "DTP" . // Date of Hospitalization
497 "*" . "435" .
498 "*" . "D8" .
499 "*" . $claim->onsetDate() .
500 "~\n";
503 // above is for historical use of encounter onset date, now in misc_billing_options
504 if (strcmp($claim->facilityPOS(), '21') == 0 && $claim->hospitalizedFromDateValid()) {
505 ++$edicount;
506 $out .= "DTP" . // Date of Admission
507 "*" . "435" .
508 "*" . "D8" .
509 "*" . $claim->hospitalizedFrom() .
510 "~\n";
513 // Segment DTP*096 (Discharge Date)
514 if (strcmp($claim->facilityPOS(), '21') == 0 && $claim->hospitalizedToDateValid()) {
515 ++$edicount;
516 $out .= "DTP" . // Date of Discharge
517 "*" . "96" .
518 "*" . "D8" .
519 "*" . $claim->hospitalizedTo() .
520 "~\n";
523 // Segments DTP (Assumed and Relinquished Care Dates) omitted.
524 // Segment DTP*444 (Property and Casualty Date of First Contact) omitted.
525 // Segment DTP*050 (Repricer Received Date) omitted.
526 // Segment PWK (Claim Supplemental Information) omitted.
527 // Segment CN1 (Contract Information) omitted.
529 $patientpaid = $claim->patientPaidAmount();
530 if ($patientpaid != 0) {
531 ++$edicount;
532 $out .= "AMT" . // Patient paid amount. Page 190/220.
533 "*" . "F5" .
534 "*" . $patientpaid .
535 "~\n";
538 // Segment REF*4N (Service Authorization Exception Code) omitted.
539 // Segment REF*F5 (Mandatory Medicare Crossover Indicator) omitted.
540 // Segment REF*EW (Mammography Certification Number) omitted.
541 // Segment REF*9F (Referral Number) omitted.
543 if ($claim->priorAuth()) {
544 ++$edicount;
545 $out .= "REF" . // Prior Authorization Number
546 "*" . "G1" .
547 "*" . $claim->priorAuth() .
548 "~\n";
551 // Segment REF*F8 Payer Claim Control Number for claim re-submission.icn_resubmission_number
552 if (trim($claim->billing_options['icn_resubmission_number']) > 3) {
553 ++$edicount;
554 error_log("Method 1: " . $claim->billing_options['icn_resubmission_number'], 0);
555 $out .= "REF" .
556 "*" . "F8" .
557 "*" . $claim->icnResubmissionNumber() .
558 "~\n";
561 if ($claim->cliaCode() && ($claim->claimType() === 'MB')) {
562 // Required by Medicare when in-house labs are done.
563 ++$edicount;
564 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
565 "*" . "X4" .
566 "*" . $claim->cliaCode() .
567 "~\n";
570 // Segment REF*9A (Repriced Claim Number) omitted.
571 // Segment REF*9C (Adjusted Repriced Claim Number) omitted.
572 // Segment REF*LX (Investigational Device Exemption Number) omitted.
573 // Segment REF*D9 (Claim Identifier for Transmission Intermediaries) omitted.
574 // Segment REF*EA (Medical Record Number) omitted.
575 // Segment REF*P4 (Demonstration Project Identifier) omitted.
576 // Segment REF*1J (Care Plan Oversight) omitted.
577 // Segment K3 (File Information) omitted.
578 if ($claim->additionalNotes()) {
579 // Claim note.
580 ++$edicount;
581 $out .= "NTE" . // comments box 19
582 "*" . "ADD" .
583 "*" . $claim->additionalNotes() .
584 "~\n";
587 // Segment CR1 (Ambulance Transport Information) omitted.
588 // Segment CR2 (Spinal Manipulation Service Information) omitted.
589 // Segment CRC (Ambulance Certification) omitted.
590 // Segment CRC (Patient Condition Information: Vision) omitted.
591 // Segment CRC (Homebound Indicator) omitted.
592 // Segment CRC (EPSDT Referral).
593 if ($claim->epsdtFlag()) {
594 ++$edicount;
595 $out .= "CRC" .
596 "*" . "ZZ" .
597 "*" . "Y" .
598 "*" . $claim->medicaidReferralCode() .
599 "~\n";
602 // Diagnoses, up to $max_per_seg per HI segment.
603 $max_per_seg = 12;
604 $da = $claim->diagArray();
605 if ($claim->diagtype == "ICD9") {
606 $diag_type_code = 'BK';
607 } else {
608 $diag_type_code = 'ABK';
610 $tmp = 0;
611 foreach ($da as $diag) {
612 if ($tmp % $max_per_seg == 0) {
613 if ($tmp) {
614 $out .= "~\n";
616 ++$edicount;
617 $out .= "HI"; // Health Diagnosis Codes
619 $out .= "*" . $diag_type_code . ":" . $diag;
620 if ($claim->diagtype == "ICD9") {
621 $diag_type_code = 'BF';
622 } else {
623 $diag_type_code = 'ABF';
625 ++$tmp;
628 if ($tmp) {
629 $out .= "~\n";
632 // Segment HI*BP (Anesthesia Related Procedure) omitted.
633 // Segment HI*BG (Condition Information) omitted.
634 // Segment HCP (Claim Pricing/Repricing Information) omitted.
635 if ($claim->referrerLastName()) {
636 // Medicare requires referring provider's name and UPIN.
637 ++$edicount;
638 $out .= "NM1" . // Loop 2310A Referring Provider
639 "*" . "DN" .
640 "*" . "1" .
641 "*" . $claim->referrerLastName() .
642 "*" . $claim->referrerFirstName() .
643 "*" . $claim->referrerMiddleName() .
644 "*" .
645 "*";
646 if ($claim->referrerNPI()) {
647 $out .=
648 "*" . "XX" .
649 "*" . $claim->referrerNPI();
650 } else {
651 $log .= "*** Referring provider has no NPI.\n";
653 $out .= "~\n";
656 // Per the implementation guide lines, only include this information if it is different
657 // than the Loop 2010AA information
658 if ($claim->providerNPIValid() && ($claim->billingFacilityNPI() !== $claim->providerNPI())) {
659 ++$edicount;
660 $out .= "NM1" . // Loop 2310B Rendering Provider
661 "*" . "82" .
662 "*" . "1" .
663 "*" . $claim->providerLastName() .
664 "*" . $claim->providerFirstName() .
665 "*" . $claim->providerMiddleName() .
666 "*" .
667 "*";
668 if ($claim->providerNPI()) {
669 $out .=
670 "*" . "XX" .
671 "*" . $claim->providerNPI();
672 } else {
673 $log .= "*** Rendering provider has no NPI.\n";
675 $out .= "~\n";
677 if ($claim->providerTaxonomy()) {
678 ++$edicount;
679 $out .= "PRV" .
680 "*" . "PE" . // Performing provider
681 "*" . ($claim->claimType() != 'MC' ? "PXC" : "ZZ") .
682 "*" . $claim->providerTaxonomy() .
683 "~\n";
684 } else {
685 $log .= "*** Performing provider has no taxonomy code.\n";
687 } else {
688 $log .= "*** Rendering provider is billing under a group.\n";
690 if (!$claim->providerNPIValid()) {
691 // If the loop was skipped because the provider NPI was invalid, generate a warning for the log.
692 $log .= "*** Skipping 2310B because " . $claim->providerLastName() . "," . $claim->providerFirstName() . " has invalid NPI.\n";
695 if (!$claim->providerNPI() && in_array($claim->providerNumberType(), array('0B', '1G', 'G2', 'LU'))) {
696 if ($claim->providerNumber()) {
697 ++$edicount;
698 $out .= "REF" .
699 "*" . $claim->providerNumberType() .
700 "*" . $claim->providerNumber() .
701 "~\n";
704 // End of Loop 2310B
706 // Loop 2310C is omitted in the case of home visits (POS=12).
707 if ($claim->facilityPOS() != 12 && ($claim->facilityNPI() != $claim->billingFacilityNPI())) {
708 ++$edicount;
709 $out .= "NM1" . // Loop 2310C Service Location
710 "*" . "77" .
711 "*" . "2";
712 $facilityName = substr($claim->facilityName(), 0, 60);
713 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) {
714 $out .=
715 "*" . $facilityName;
716 } else {
717 $log .= "*** Check for invalid facility name, NPI, and/or tax id.\n";
719 if ($claim->facilityNPI() || $claim->facilityETIN()) {
720 $out .=
721 "*" .
722 "*" .
723 "*" .
724 "*";
725 if ($claim->facilityNPI()) {
726 $out .=
727 "*" . "XX" . "*" . $claim->facilityNPI();
728 } else {
729 $out .=
730 "*" . "24" . "*" . $claim->facilityETIN();
732 if (!$claim->facilityNPI()) {
733 $log .= "*** Service location has no NPI.\n";
737 $out .= "~\n";
738 if ($claim->facilityStreet()) {
739 ++$edicount;
740 $out .= "N3" .
741 "*" . $claim->facilityStreet() .
742 "~\n";
745 if ($claim->facilityState()) {
746 ++$edicount;
747 $out .= "N4" .
748 "*" . $claim->facilityCity() .
749 "*" . $claim->facilityState() .
750 "*" . stripZipCode($claim->facilityZip()) .
751 "~\n";
754 // Segment REF (Service Facility Location Secondary Identification) omitted.
755 // Segment PER (Service Facility Contact Information) omitted.
757 // Loop 2310E, Supervising Provider
758 if ($claim->supervisorLastName()) {
759 ++$edicount;
760 $out .= "NM1" .
761 "*" . "DQ" . // Supervising Physician
762 "*" . "1" . // Person
763 "*" . $claim->supervisorLastName() .
764 "*" . $claim->supervisorFirstName() .
765 "*" . $claim->supervisorMiddleName() .
766 "*" . // NM106 not used
767 "*"; // Name Suffix not used
768 if ($claim->supervisorNPI()) {
769 $out .=
770 "*" . "XX" .
771 "*" . $claim->supervisorNPI();
772 } else {
773 $log .= "*** Supervising Provider has no NPI.\n";
775 $out .= "~\n";
777 if ($claim->supervisorNumber()) {
778 ++$edicount;
779 $out .= "REF" .
780 "*" . $claim->supervisorNumberType() .
781 "*" . $claim->supervisorNumber() .
782 "~\n";
784 } else {
785 $log .= "*** Supervising provider has invalid last name.\n";
788 // Segments NM1*PW, N3, N4 (Ambulance Pick-Up Location) omitted.
789 // Segments NM1*45, N3, N4 (Ambulance Drop-Off Location) omitted.
791 // Loops 2320 and 2330, other subscriber/payer information.
792 // Remember that insurance index 0 is always for the payer being billed
793 // by this claim, and 1 and above are always for the "other" payers.
795 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
796 $tmp1 = $claim->claimType($ins);
797 $tmp2 = 'C1'; // Here a kludge. See page 321.
798 if ($tmp1 === 'CI') {
799 $tmp2 = 'C1';
801 if ($tmp1 === 'AM') {
802 $tmp2 = 'AP';
804 if ($tmp1 === 'HM') {
805 $tmp2 = 'HM';
807 if ($tmp1 === 'MB') {
808 $tmp2 = 'MB';
810 if ($tmp1 === 'MC') {
811 $tmp2 = 'MC';
813 if ($tmp1 === '09') {
814 $tmp2 = 'PP';
817 ++$edicount;
818 $out .= "SBR" . // Loop 2320, Subscriber Information - page 297/318
819 "*" . $claim->payerSequence($ins) .
820 "*" . $claim->insuredRelationship($ins) .
821 "*" . $claim->groupNumber($ins) .
822 "*" . $claim->groupName($ins) .
823 "*" . $claim->insuredTypeCode($ins) .
824 "*" .
825 "*" .
826 "*" .
827 "*" . $claim->claimType($ins) .
828 "~\n";
830 // Things that apply only to previous payers, not future payers.
831 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
832 // Generate claim-level adjustments.
833 $aarr = $claim->payerAdjustments($ins);
834 foreach ($aarr as $a) {
835 ++$edicount;
836 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 301/323.
837 "*" . $a[1] .
838 "*" . $a[2] .
839 "*" . $a[3] .
840 "~\n";
843 $payerpaid = $claim->payerTotals($ins);
844 ++$edicount;
845 $out .= "AMT" . // Previous payer's paid amount. Page 307/332.
846 "*" . "D" .
847 "*" . $payerpaid[1] .
848 "~\n";
849 // Segment AMT*A8 (COB Total Non-Covered Amount) omitted.
850 // Segment AMT*EAF (Remaining Patient Liability) omitted.
851 } // End of things that apply only to previous payers.
853 ++$edicount;
854 $out .= "OI" . // Other Insurance Coverage Information. Page 310/344.
855 "*" .
856 "*" .
857 "*" . ($claim->billingFacilityAssignment($ins) ? 'Y' : 'N') .
858 // For this next item, the 5010 example in the spec does not match its
859 // description. So this might be wrong.
860 "*" .
861 "*" .
862 "*" .
863 "Y" .
864 "~\n";
866 // Segment MOA (Medicare Outpatient Adjudication) omitted.
867 ++$edicount;
868 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 315/350.
869 "*" . "IL" .
870 "*" . "1" .
871 "*" . $claim->insuredLastName($ins) .
872 "*" . $claim->insuredFirstName($ins) .
873 "*" . $claim->insuredMiddleName($ins) .
874 "*" .
875 "*" .
876 "*" . "MI" .
877 "*" . $claim->policyNumber($ins) .
878 "~\n";
880 ++$edicount;
881 $out .= "N3" .
882 "*" . $claim->insuredStreet($ins) .
883 "~\n";
885 ++$edicount;
886 $out .= "N4" .
887 "*" . $claim->insuredCity($ins) .
888 "*" . $claim->insuredState($ins) .
889 "*" . stripZipCode($claim->insuredZip($ins)) .
890 "~\n";
892 // Segment REF (Other Subscriber Secondary Identification) omitted.
893 ++$edicount;
894 $payerName = substr($claim->payerName($ins), 0, 60);
895 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 322/359.
896 "*" . "PR" .
897 "*" . "2" .
898 "*" . $payerName .
899 "*" .
900 "*" .
901 "*" .
902 "*" .
903 "*" . "PI" .
904 "*" . $claim->payerID($ins) .
905 "~\n";
907 if (!$claim->payerID($ins)) {
908 $log .= "*** CMS ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
911 ++$edicount;
912 $out .= "N3" .
913 "*" . $claim->payerStreet($ins) .
914 "~\n";
916 ++$edicount;
917 $out .= "N4" .
918 "*" . $claim->payerCity($ins) .
919 "*" . $claim->payerState($ins) .
920 "*" . stripZipCode($claim->payerZip($ins)) .
921 "~\n";
922 // Segment DTP*573 (Claim Check or Remittance Date) omitted.
923 // Segment REF (Other Payer Secondary Identifier) omitted.
924 // Segment REF*G1 (Other Payer Prior Authorization Number) omitted.
925 // Segment REF*9F (Other Payer Referral Number) omitted.
926 // Segment REF*T4 (Other Payer Claim Adjustment Indicator) omitted.
927 // Segment REF*F8 (Other Payer Claim Control Number) omitted.
928 // Segment NM1 (Other Payer Referring Provider) omitted.
929 // Segment REF (Other Payer Referring Provider Secondary Identification) omitted.
930 // Segment NM1 (Other Payer Rendering Provider) omitted.
931 // Segment REF (Other Payer Rendering Provider Secondary Identification) omitted.
932 // Segment NM1 (Other Payer Service Facility Location) omitted.
933 // Segment REF (Other Payer Service Facility Location Secondary Identification) omitted.
934 // Segment NM1 (Other Payer Supervising Provider) omitted.
935 // Segment REF (Other Payer Supervising Provider Secondary Identification) omitted.
936 // Segment NM1 (Other Payer Billing Provider) omitted.
937 // Segment REF (Other Payer Billing Provider Secondary Identification) omitted.
938 } // End loops 2320/2330*.
940 $loopcount = 0;
942 // Procedure loop starts here.
943 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
944 ++$loopcount;
945 ++$edicount;
946 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
947 "*" . $loopcount .
948 "~\n";
950 ++$edicount;
951 $out .= "SV1" . // Professional Service. Page 400.
952 "*" . "HC:" . $claim->cptKey($prockey) .
953 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
954 "*" . "UN" .
955 "*" . $claim->cptUnits($prockey) .
956 "*" .
957 "*" .
958 "*";
959 $dia = $claim->diagIndexArray($prockey);
960 $i = 0;
961 foreach ($dia as $dindex) {
962 if ($i) {
963 $out .= ':';
966 $out .= $dindex;
967 if (++$i >= 4) {
968 break;
972 # needed for epstd
973 if ($claim->epsdtFlag()) {
974 $out .= "*" .
975 "*" .
976 "*" .
977 "*" . "Y" .
978 "~\n";
979 } else {
980 $out .= "~\n";
983 if (!$claim->cptCharges($prockey)) {
984 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
987 if (empty($dia)) {
988 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' is not justified!\n";
991 // Segment SV5 (Durable Medical Equipment Service) omitted.
992 // Segment PWK (Line Supplemental Information) omitted.
993 // Segment PWK (Durable Medical Equipment Certificate of Medical Necessity Indicator) omitted.
994 // Segment CR1 (Ambulance Transport Information) omitted.
995 // Segment CR3 (Durable Medical Equipment Certification) omitted.
996 // Segment CRC (Ambulance Certification) omitted.
997 // Segment CRC (Hospice Employee Indicator) omitted.
998 // Segment CRC (Condition Indicator / Durable Medical Equipment) omitted.
1000 ++$edicount;
1001 $out .= "DTP" . // Date of Service. Page 435.
1002 "*" . "472" .
1003 "*" . "D8" .
1004 "*" . $claim->serviceDate() .
1005 "~\n";
1007 $testnote = rtrim($claim->cptNotecodes($prockey));
1008 if (!empty($testnote)) {
1009 ++$edicount;
1010 $out .= "NTE" . // Explain Unusual Circumstances.
1011 "*" . "ADD" .
1012 "*" . $claim->cptNotecodes($prockey) .
1013 "~\n";
1016 // Segment DTP*471 (Prescription Date) omitted.
1017 // Segment DTP*607 (Revision/Recertification Date) omitted.
1018 // Segment DTP*463 (Begin Therapy Date) omitted.
1019 // Segment DTP*461 (Last Certification Date) omitted.
1020 // Segment DTP*304 (Last Seen Date) omitted.
1021 // Segment DTP (Test Date) omitted.
1022 // Segment DTP*011 (Shipped Date) omitted.
1023 // Segment DTP*455 (Last X-Ray Date) omitted.
1024 // Segment DTP*454 (Initial Treatment Date) omitted.
1025 // Segment QTY (Ambulance Patient Count) omitted.
1026 // Segment QTY (Obstetric Anesthesia Additional Units) omitted.
1027 // Segment MEA (Test Result) omitted.
1028 // Segment CN1 (Contract Information) omitted.
1029 // Segment REF*9B (Repriced Line Item Reference Number) omitted.
1030 // Segment REF*9D (Adjusted Repriced Line Item Reference Number) omitted.
1031 // Segment REF*G1 (Prior Authorization) omitted.
1032 // Segment REF*6R (Line Item Control Number) omitted.
1033 // (Really oughta have this for robust 835 posting!)
1034 // Segment REF*EW (Mammography Certification Number) omitted.
1035 // Segment REF*X4 (CLIA Number) omitted.
1036 // Segment REF*F4 (Referring CLIA Facility Identification) omitted.
1037 // Segment REF*BT (Immunization Batch Number) omitted.
1038 // Segment REF*9F (Referral Number) omitted.
1039 // Segment AMT*T (Sales Tax Amount) omitted.
1040 // Segment AMT*F4 (Postage Claimed Amount) omitted.
1041 // Segment K3 (File Information) omitted.
1042 // Segment NTE (Line Note) omitted.
1043 // Segment NTE (Third Party Organization Notes) omitted.
1044 // Segment PS1 (Purchased Service Information) omitted.
1045 // Segment HCP (Line Pricing/Repricing Information) omitted.
1048 // Loop 2410, Drug Information. Medicaid insurers seem to want this
1049 // with HCPCS codes.
1051 $ndc = $claim->cptNDCID($prockey);
1053 if ($ndc) {
1054 ++$edicount;
1056 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
1057 "*" . // Per addendum, LIN01 is not used.
1058 "*" . "N4" .
1059 "*" . $ndc .
1060 "~\n";
1062 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp) && !preg_match('/^\d{11}$/', $ndc)) {
1063 $log .= "*** NDC code '$ndc' has invalid format!\n";
1066 ++$edicount;
1067 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
1068 "*" .
1069 "*" .
1070 "*" .
1071 "*" . $claim->cptNDCQuantity($prockey) .
1072 "*" . $claim->cptNDCUOM($prockey) .
1073 // Note: 5010 documents "ME" (Milligrams) as an additional unit of measure.
1074 "~\n";
1077 // Segment REF (Prescription or Compound Drug Association Number) omitted.
1079 // Loop 2420A, Rendering Provider (service-specific).
1080 // Used if the rendering provider for this service line is different
1081 // from that in loop 2310B.
1083 if ($claim->providerNPI() != $claim->providerNPI($prockey)) {
1084 ++$edicount;
1085 $out .= "NM1" . // Loop 2310B Rendering Provider
1086 "*" . "82" .
1087 "*" . "1" .
1088 "*" . $claim->providerLastName($prockey) .
1089 "*" . $claim->providerFirstName($prockey) .
1090 "*" . $claim->providerMiddleName($prockey) .
1091 "*" .
1092 "*";
1093 if ($claim->providerNPI($prockey)) {
1094 $out .=
1095 "*" . "XX" .
1096 "*" . $claim->providerNPI($prockey);
1097 } else {
1098 $log .= "*** Rendering provider has no NPI.\n";
1100 $out .= "~\n";
1102 if ($claim->providerTaxonomy($prockey)) {
1103 ++$edicount;
1104 $out .= "PRV" .
1105 "*" . "PE" . // PErforming provider
1106 "*" . "PXC" .
1107 "*" . $claim->providerTaxonomy($prockey) .
1108 "~\n";
1111 // Segment PRV*PE (Rendering Provider Specialty Information) omitted.
1112 // Segment REF (Rendering Provider Secondary Identification) omitted.
1113 // Segment NM1 (Purchased Service Provider Name) omitted.
1114 // Segment REF (Purchased Service Provider Secondary Identification) omitted.
1115 // Segment NM1,N3,N4 (Service Facility Location) omitted.
1116 // Segment REF (Service Facility Location Secondary Identification) omitted.
1117 // Segment NM1 (Supervising Provider Name) omitted.
1118 // Segment REF (Supervising Provider Secondary Identification) omitted.
1119 // Segment NM1,N3,N4 (Ordering Provider) omitted.
1120 // Segment REF (Ordering Provider Secondary Identification) omitted.
1121 // Segment PER (Ordering Provider Contact Information) omitted.
1122 // Segment NM1 (Referring Provider Name) omitted.
1123 // Segment REF (Referring Provider Secondary Identification) omitted.
1124 // Segments NM1*PW, N3, N4 (Ambulance Pick-Up Location) omitted.
1125 // Segments NM1*45, N3, N4 (Ambulance Drop-Off Location) omitted.
1127 // REF*1C is required here for the Medicare provider number if NPI was
1128 // specified in NM109. Not sure if other payers require anything here.
1129 ++$edicount;
1130 $out .= "REF" .
1131 "*" . $claim->providerNumberType($prockey) .
1132 // Note: 5010 documents that type 1D (Medicaid) is changed to G2.
1133 "*" . $claim->providerNumber($prockey) .
1134 "~\n";
1136 // Loop 2430, adjudication by previous payers.
1138 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
1139 if ($claim->payerSequence($ins) > $claim->payerSequence()) {
1140 continue; // payer is future, not previous
1143 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
1144 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
1146 if ($payerpaid[1] == 0 && !count($aarr)) {
1147 $log .= "*** Procedure '" . $claim->cptKey($prockey) .
1148 "' has no payments or adjustments from previous payer!\n";
1149 continue;
1152 ++$edicount;
1153 $out .= "SVD" . // Service line adjudication. Page 554.
1154 "*" . $claim->payerID($ins) .
1155 "*" . $payerpaid[1] .
1156 "*" . "HC:" . $claim->cptKey($prockey) .
1157 "*" .
1158 "*" . $claim->cptUnits($prockey) .
1159 "~\n";
1161 $tmpdate = $payerpaid[0];
1162 foreach ($aarr as $a) {
1163 ++$edicount;
1164 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
1165 "*" . $a[1] .
1166 "*" . $a[2] .
1167 "*" . $a[3] .
1168 "~\n";
1169 if (!$tmpdate) {
1170 $tmpdate = $a[0];
1174 if ($tmpdate) {
1175 ++$edicount;
1176 $out .= "DTP" . // Previous payer's line adjustment date. Page 493/566.
1177 "*" . "573" .
1178 "*" . "D8" .
1179 "*" . $tmpdate .
1180 "~\n";
1183 // Segment AMT*EAF (Remaining Patient Liability) omitted.
1184 // Segment LQ (Form Identification Code) omitted.
1185 // Segment FRM (Supporting Documentation) omitted.
1186 } // end loop 2430
1187 } // end this procedure
1189 ++$edicount;
1190 $out .= "SE" . // SE Trailer
1191 "*" . $edicount .
1192 "*" . "0021" .
1193 "~\n";
1195 $out .= "GE" . // GE Trailer
1196 "*" . "1" .
1197 "*" . "1" .
1198 "~\n";
1200 $out .= "IEA" . // IEA Trailer
1201 "*" . "1" .
1202 "*" . "000000001" .
1203 "~\n";
1205 // Remove any trailing empty fields (delimiters) from each segment.
1206 $out = preg_replace('/\*+~/', '~', $out);
1208 $log .= "\n";
1209 return $out;