consolidate similar x12 gen 837 function (#5691)
[openemr.git] / src / Billing / X125010837I.php
blob815ae404abd4d0139b2a4246344eed4629e3d9b1
1 <?php
3 /**
4 * X12 837I
6 * @package OpenEMR
7 * @link https://www.open-emr.org
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 namespace OpenEMR\Billing;
15 use OpenEMR\Billing\Claim;
17 class X125010837I
19 public function x12Date($frmdate)
21 return ('20' . substr($frmdate, 4, 2) . substr($frmdate, 0, 2) . substr($frmdate, 2, 2));
24 public $ub04id = array();
26 public function generateX12837I($pid, $encounter, &$log, $ub04id)
28 $today = time();
29 $out = '';
30 $claim = new Claim($pid, $encounter);
31 $edicount = 0;
33 $log .= "Generating 837I claim $pid-$encounter for " .
34 $claim->patientFirstName() . ' ' .
35 $claim->patientMiddleName() . ' ' .
36 $claim->patientLastName() . ' on ' .
37 date('Y-m-d H:i', $today) . ".\n";
38 $out .= "ISA" .
39 "*" . $claim->x12gsisa01() .
40 "*" . $claim->x12gsisa02() .
41 "*" . $claim->x12gsisa03() .
42 "*" . $claim->x12gsisa04() .
43 "*" . $claim->x12gsisa05() .
44 "*" . $claim->x12_sender_id() .
45 "*" . $claim->x12gsisa07() .
46 "*" . $claim->x12gsreceiverid() .
47 // date of transmission "*030911" .
48 "*" . date('Ymd', $today) .
49 //Time of transmission "*1630" .
50 "*" . date('Hi', $today) .
51 "*" . "^" .
52 "*" . "00501" .
53 "*" . "000000001" .
54 "*" . $claim->x12gsisa14() .
55 "*" . $claim->x12gsisa15() .
56 "*:" .
57 "~\n";
58 $out .= "GS" .
59 "*HC" .
60 "*" . $claim->x12gsgs02() .
61 "*" . trim($claim->x12gs03()) .
62 "*" . date('Ymd', $today) .
63 "*" . date('Hi', $today) .
64 "*1" .
65 "*X" .
66 // "*" . $claim->x12gsversionstring() .
67 "*" . "005010X223A2" .
68 "~\n";
69 ++$edicount;
70 $out .= "ST" .
71 "*" . "837" .
72 "*" . "0021" .
73 // "*" . $claim->x12gsversionstring() .
74 "*" . "005010X223A2" .
75 "~\n";
76 ++$edicount;
77 $out .= "BHT" .
78 "*" . "0019" . // 0019 is required here
79 "*" . "00" . // 00 = original transmission
80 "*" . "0123" . // reference identification
81 "*" . date('Ymd', $today) . // transaction creation date
82 "*" . date('Hi', $today) . // transaction creation time
83 ($encounter_claim ? "*RP" : "*CH") . // RP = reporting, CH = chargeable
84 "~\n";
86 ++$edicount;
87 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
88 $billingFacilityName = substr($claim->billingFacilityName(), 0, 60);
89 if ($billingFacilityName == '') {
90 $log .= "*** billing facility name in 1000A loop is empty\n";
92 $out .= "NM1" . // Loop 1000A Submitter stays in the 837I
93 "*" . "41" .
94 "*" . "2" .
95 "*" . $billingFacilityName .
96 "*" .
97 "*" .
98 "*" .
99 "*" .
100 "*" . "46";
102 $out .= "*" . $claim->billingFacilityETIN();
103 $out .= "~\n";
104 ++$edicount;
106 $out .= "PER" .
107 "*IC" .
108 "*" . $claim->billingContactName() .
109 "*TE" .
110 "*" . $claim->billingContactPhone();
111 $out .= "~\n";
113 ++$edicount;
115 $out .= "NM1" . // Loop 1000B Receiver stays in the 837I
116 "*" . "40" .
117 "*" . "2" .
118 "*" . $claim->clearingHouseName() .
119 "*" .
120 "*" .
121 "*" .
122 "*" .
123 "*" . "46" .
124 "*" . $claim->clearingHouseETIN() .
125 "~\n";
126 $HLcount = 1;
127 ++$edicount;
129 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
130 "*" . "$HLcount" .
131 "*" .
132 "*" . "20" .
133 "*" . "1" . // 1 indicates there are child segments
134 "~\n";
135 $HLBillingPayToProvider = $HLcount++;
136 // Situational PRV segment (for provider taxonomy code) omitted here.
137 // Situational CUR segment (foreign currency information) omitted here.
138 ++$edicount;
139 //Field length is limited to 35. See nucc dataset page 63 www.nucc.org
140 $billingFacilityName = substr($claim->billingFacilityName(), 0, 60);
141 $out .= "NM1" . // Loop 2010AA Billing Provider stays in the 837I
142 "*" . "85" .
143 "*" . "2" .
144 "*" . $billingFacilityName .
145 "*" .
146 "*" .
147 "*" .
148 "*";
149 if ($claim->billingFacilityNPI()) {
150 $out .= "*XX*" . $claim->billingFacilityNPI();
151 } else {
152 $log .= "*** Billing facility has no NPI.\n";
153 $out .= "*XX*";
155 $out .= "~\n";
156 ++$edicount;
157 $out .= "N3" .
158 "*" . $claim->billingFacilityStreet() .
159 "~\n";
160 ++$edicount;
161 $out .= "N4" .
162 "*" . $claim->billingFacilityCity() .
163 "*" . $claim->billingFacilityState() .
164 "*" . $claim->x12Zip($claim->billingFacilityZip()) .
165 "~\n";
166 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
167 ++$edicount;
168 $out .= "REF";
169 if ($claim->federalIdType()) {
170 $out .= "*" . $claim->federalIdType();
171 } else {
172 $out .= "*EI"; // For dealing with the situation before adding TaxId type In facility.
174 $out .= "*" . $claim->billingFacilityETIN() . "~\n";
175 } else {
176 $log .= "*** No billing facility NPI and/or ETIN.\n";
178 if ($claim->providerNumberType() && $claim->providerNumber() && !$claim->billingFacilityNPI()) {
179 ++$edicount;
180 $out .= "REF" .
181 "*" . $claim->providerNumberType() .
182 "*" . $claim->providerNumber() .
183 "~\n";
184 } elseif ($claim->providerNumber() && !$claim->providerNumberType()) {
185 $log .= "*** Payer-specific provider insurance number is present but has no type assigned.\n";
187 // Situational PER*1C segment.
188 ++$edicount;
189 $out .= "PER" .
190 "*" . "IC" .
191 "*" . $claim->billingContactName() .
192 "*" . "TE" .
193 "*" . $claim->billingContactPhone();
194 $out .= "~\n";
196 // This is also excluded in the 837I
197 // Loop 2010AC Pay-To Plan Name omitted. Includes:
198 // NM1*PE, N3, N4, REF*2U, REF*EI
199 $PatientHL = $claim->isSelfOfInsured() ? 0 : 1;
200 $HLSubscriber = $HLcount++;
201 ++$edicount;
203 // loop 2000B
204 $out .= "HL" . // Loop 2000B Subscriber HL Loop
205 "*$HLSubscriber" .
206 "*$HLBillingPayToProvider" .
207 "*" . "22" .
208 "*$PatientHL" .
209 "~\n";
210 if (!$claim->payerSequence()) {
211 $log .= "*** Error: Insurance information is missing!\n";
213 ++$edicount;
215 //SBR01 is either a P or S SBR02 for care is always 18 "patient" SBR09 is always MA
216 $out .= "SBR" . // Subscriber Information
217 "*" . $claim->payerSequence() .
218 "*" . ($claim->isSelfOfInsured() ? '18' : '') .
219 "*" . $claim->groupNumber() .
220 "*" . (($claim->groupNumber()) ? '' : $claim->groupName()) .
221 "*" . $claim->insuredTypeCode() . // applies for secondary medicare
222 "*" .
223 "*" .
224 "*" .
225 "*" . $claim->claimType() . // Zirmed replaces this
226 "~\n";
227 // 2000C Segment PAT omitted.
228 ++$edicount;
229 $out .= "NM1" . // Loop 2010BA Subscriber same in 837I
230 "*IL" .
231 "*" . "1" . // 1 = person, 2 = non-person
232 "*" . $claim->insuredLastName() .
233 "*" . $claim->insuredFirstName() .
234 "*" . $claim->insuredMiddleName() .
235 "*" .
236 "*" . // Name Suffix
237 "*MI" .
238 // "MI" = Member Identification Number
239 // "II" = Standard Unique Health Identifier, "Required if the
240 // HIPAA Individual Patient Identifier is mandated use."
241 // Here we presume that is not true yet.
242 "*" . $claim->policyNumber() .
243 "~\n";
244 // For 5010, further subscriber info is sent only if they are the patient.
245 if ($claim->isSelfOfInsured()) {
246 ++$edicount;
247 $out .= "N3" .
248 "*" . $claim->insuredStreet() .
249 "~\n";
250 ++$edicount;
251 $out .= "N4" .
252 "*" . $claim->insuredCity() .
253 "*" . $claim->insuredState() .
254 "*" . $claim->x12Zip($claim->insuredZip()) .
255 "~\n";
256 ++$edicount;
257 $out .= "DMG" .
258 "*D8" .
259 "*" . $claim->insuredDOB() .
260 "*" . $claim->insuredSex() .
261 "~\n";
263 // Segment REF*SY (Subscriber Secondary Identification) omitted.
264 // Segment REF*Y4 (Property and Casualty Claim Number) omitted.
265 // Segment PER*IC (Property and Casualty Subscriber Contact Information) omitted.
266 ++$edicount;
267 $payerName = substr($claim->payerName(), 0, 60);
268 $out .= "NM1" . // Loop 2010BB Payer
269 "*PR" .
270 "*" . "2" .
271 "*" . $payerName .
272 "*" .
273 "*" .
274 "*" .
275 "*" .
276 "*" . "PI" .
277 "*" . ($encounter_claim ? $claim->payerAltID() : $claim->payerID()) .
278 "~\n";
279 if (!$claim->payerID()) {
280 $log .= "*** Payer ID is missing for payer '" . $claim->payerName() . "'.\n";
283 ++$edicount;
284 $out .= "N3" .
285 "*" . $claim->payerStreet() .
286 "~\n";
287 ++$edicount;
288 $out .= "N4" .
289 "*" . $claim->payerCity() .
290 "*" . $claim->payerState() .
291 "*" . $claim->x12Zip($claim->payerZip()) .
292 "~\n";
294 // Segment REF (Payer Secondary Identification) omitted.
295 // Segment REF (Billing Provider Secondary Identification) omitted.
298 if (!$claim->isSelfOfInsured()) {
299 ++$edicount;
300 $out .= "HL" . // Loop 2000C Patient Information
301 "*" . "$HLcount" .
302 "*$HLSubscriber" .
303 "*23" .
304 "*0" .
305 "~\n";
306 $HLcount++;
307 ++$edicount;
308 $out .= "PAT" .
309 "*" . $claim->insuredRelationship() .
310 "~\n";
311 ++$edicount;
312 $out .= "NM1" . // Loop 2010CA Patient may need this elsed in to the loop 2000C
313 "*QC" .
314 "*1" .
315 "*" . $claim->patientLastName() .
316 "*" . $claim->patientFirstName();
317 if ($claim->patientMiddleName() !== '') {
318 $out .= "*" . $claim->patientMiddleName();
320 $out .= "~\n";
321 ++$edicount;
322 $out .= "N3" .
323 "*" . $claim->patientStreet() .
324 "~\n";
325 ++$edicount;
326 $out .= "N4" .
327 "*" . $claim->patientCity() .
328 "*" . $claim->patientState() .
329 "*" . $claim->x12Zip($claim->patientZip()) .
330 "~\n";
331 ++$edicount;
332 $out .= "DMG" .
333 "*D8" .
334 "*" . $claim->patientDOB() .
335 "*" . $claim->patientSex() .
336 "~\n";
337 // Segment REF*Y4 (Property and Casualty Claim Number) omitted.
338 // Segment REF (Property and Casualty Patient Identifier) omitted.
339 // Segment PER (Property and Casualty Patient Contact Information) omitted.
340 } // end of patient different from insured
341 $proccount = $claim->procCount();
342 $clm_total_charges = 0;
343 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
344 $clm_total_charges += $claim->cptCharges($prockey);
346 if (!$clm_total_charges) {
347 $log .= "*** This claim has no charges!\n";
349 ++$edicount;
350 $out .= "CLM" . // Loop 2300 Claim
351 "*" . $pid . "-" . $encounter .
352 "*" . sprintf("%.2f", $clm_total_charges) . // Zirmed computes and replaces this
353 "*" .
354 "*";
355 // Service location this need to be bill type from ub form type_of_bill
356 if (strlen($ub04id[7]) >= 3) {
357 $out .= "*" . substr($ub04id[7], 1, 1) . ":" . substr($ub04id[7], 2, 1) . ":" . substr($ub04id[7], 3, 1);
360 $out .= "*" .
361 "*" . "A" .
362 "*" . ($claim->billingFacilityAssignment() ? 'Y' : 'N') .
363 "*" . "Y" .
364 "~\n";
365 // discharge hour
366 if ($ub04id[29]) {
367 ++$edicount;
368 $out .= "DTP" . // Loop 2300
369 "*" . "096" .
370 "*" . "TM" .
371 "*" . $ub04id[29] .
372 "~\n";
375 // Statment Dates
376 // DTP 434 RD8 (Statment from OR to date)
378 if ($ub04id[13]) {
379 ++$edicount;
381 $tmp = self::x12Date($ub04id[13]);
382 $tmp1 = self::x12Date($ub04id[14]);
383 $out .= "DTP" . // Loop 2300
384 "*434" . "*" . "RD8" . "*" . $tmp . '-' . $tmp1 . "~\n";
387 if ($ub04id[13]) {
388 ++$edicount;
389 $tmp = self::x12Date($ub04id[25]);
390 $out .= "DTP" . // Loop 2300
391 "*435" . "*" . "DT" . "*" . $tmp . $ub04id[26] . "~\n";
394 if (strlen(trim($ub04id[13])) == 0) {
395 $log .= "*** Error: No Admission Date Entered!\n";
398 // Repricer Received Date
399 // DTP 050 D8 (Admission Date and Hour from form)
401 // Institutional Claim Code
402 // CL1 (Admission Type Code) (Admission Source Code) (Patient Status Code)
404 if ($ub04id[27] != "014X") { // Type of bill
405 ++$edicount;
406 $out .= "CL1" . // Loop 2300
407 "*" . $ub04id[27] . "*" . $ub04id[28] . "*" . $ub04id[30] . "~\n";
410 // Segment PWK (Claim Supplemental Information) omitted.
412 // Segment CN1 (Contract Information) omitted.
414 // Patient Estimated Amount Due
415 // Check logic
417 // $patientpaid = $claim->patientPaidAmount();
418 // if ($patientpaid != 0) {
419 // ++$edicount;
420 // $out .= "AMT" . // Patient paid amount. Page 190/220.
421 // "*F5" .
422 // "*" . $patientpaid .
423 // "~\n";
424 // }
426 // Segment REF*4N (Service Authorization Exception Code) omitted.
427 // Segment REF*9F (Referral Number) omitted.
429 // Prior Authorization
431 if ($claim->priorAuth()) {
432 ++$edicount;
433 $out .= "REF" . // Prior Authorization Number
434 "*G1" . "*" . $claim->priorAuth() . "~\n";
437 // Segment REF*F8 (Payer Claim Control Number) omitted.
439 // This may be needed for the UB04 Claim if so change the 'MB' to 'MA'
440 // if ($claim->cliaCode() && ($CMS_5010 || $claim->claimType() === 'MB')) {
441 // Required by Medicare when in-house labs are done.
442 // ++$edicount;
443 // $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
444 // "*X4" .
445 // "*" . $claim->cliaCode() .
446 // "~\n";
447 // }
449 // Segment REF*9A (Repriced Claim Number) omitted.
450 // Segment REF*9C (Adjusted Repriced Claim Number) omitted.
451 // Segment REF*LX (Investigational Device Exemption Number) omitted.
452 // Segment REF*S9 (Claim Identifier for Transmission Intermediaries) omitted.
453 // Segment REF*LU (Auto Accident State) omitted.
454 // Segment REF*EA (Medical Record Number) omitted.
455 // Segment REF*P4 (Demonstration Project Identifier) omitted.
456 // Segment REF*G4 (Peer Review Organization PRO Approval Number) omitted.
457 // Segment K3 (File Information) omitted.
459 if ($claim->additionalNotes()) {
460 // Claim Note
461 // Has a list of valid codes. Required when PROVIDER deems necessary
463 // Billing note.
464 // Check to verify I am getting this information on the ub04 form
466 ++$edicount;
467 $out .= "NTE" . // comments box 19
468 "*" . "ADD" . "*" . $claim->additionalNotes() . "~\n";
471 // Segment CRC (EPSDT Referral) omitted.
472 // Diagnoses, up to $max_per_seg per HI segment. Check this
473 $max_per_seg = 18;
474 $da = $claim->diagArray();
475 $diag_type_code = 'ABK'; // ICD10
476 $tmp = 0;
477 foreach ($da as $diag) {
478 if ($tmp == 1) {
479 continue;
481 if ($tmp % $max_per_seg == 0) {
482 if ($tmp) {
483 $out .= "~\n";
485 ++$edicount;
486 $out .= "HI"; // Health Diagnosis Codes
488 $out .= "*" . $diag_type_code . ":" . $diag;
489 if ($claim->diagtype == "ICD9") {
490 $diag_type_code = 'BF';
491 } else {
492 $diag_type_code = 'ABF';
495 ++$tmp;
497 if ($tmp) {
498 $out .= "~\n";
501 // Segment HI*BI (Occurrence Span Information).
502 // HI BI (Occurrence Span Code 1) RD8 (Occurrence Span Code Associated Date)
503 if ($ub04id[52]) {
504 $max_per_seg = 4;
505 $diag_type_code = 'BI';
506 $tmp = 0;
507 $os = 52;
508 for ($i = 0; $i <= 3;) {
509 if ($tmp % $max_per_seg == 0) {
510 if ($tmp) {
511 $out .= "~\n";
513 ++$edicount;
514 $out .= "HI"; // Health Diagnosis Codes
516 if ($ub04id[$os]) {
517 $out .= "*" . $diag_type_code . ":" . $ub04id[$os++] . ":" . self::x12Date($ub04id[$os++]) . ":" . self::x12Date($ub04id[$os++]);
518 $diag_type_code = 'BI';
520 if ($os >= 57) {
521 $os = 67;
523 ++$tmp;
524 ++$i;
526 if ($tmp) {
527 $out .= "~\n";
531 // Segment HI*BH (Occurrence Information).
532 // HI BH (Occurrence Code 1) D8 (Occurrence Code Associated Date)
534 if ($ub04id[44]) {
535 $max_per_seg = 8;
536 $diag_type_code = 'BH';
537 $tmp = 0;
538 $os = 44;
539 for ($i = 0; $i <= 7;) {
540 if ($tmp % $max_per_seg == 0) {
541 if ($tmp) {
542 $out .= "~\n";
544 ++$edicount;
545 $out .= "HI"; // Health Diagnosis Codes
547 if ($ub04id[$os]) {
548 $out .= "*" . $diag_type_code . ":" . $ub04id[$os] . ":D8" . ":" . self::x12Date($ub04id[$os++]);
549 $diag_type_code = 'BH';
551 if ($os >= 51) {
552 $os = 59;
554 ++$tmp;
555 ++$i;
557 if ($tmp) {
558 $out .= "~\n";
562 // Segment HI*BE (Value Information).
563 // HI BE (Value Code 1) *.* (Value Code Amount)
565 if ($ub04id[74]) {
566 $max_per_seg = 12;
567 $diag_type_code = 'BE';
568 $os = 74;
569 $tmp = 0;
570 for ($i = 0; $i <= 11;) {
571 if ($tmp % $max_per_seg == 0) {
572 if ($tmp) {
573 $out .= "~\n";
575 ++$edicount;
576 $out .= "HI"; // Health Diagnosis Codes
578 if ($ub04id[$os]) {
579 // if ($i=1) {
580 $out .= "*" . $diag_type_code . ":" . $ub04id[$os++] . ":" . ":" . self::x12Date($ub04id[$os++]);
581 $diag_type_code = 'BE';
582 // }
584 ++$tmp;
585 ++$i;
587 if ($tmp) {
588 $out .= "~\n";
592 // Segment HI*BG (Condition Information).
593 // HI BG (Condition Code 1)
595 if ($ub04id[31]) {
596 $max_per_seg = 11;
597 $diag_type_code = 'BG';
598 $os = 31;
599 $tmp = 0;
600 for ($i = 0; $i <= 10;) {
601 if ($tmp % $max_per_seg == 0) {
602 if ($tmp) {
603 $out .= "~\n";
605 ++$edicount;
606 $out .= "HI"; // Health Diagnosis Codes
608 if ($ub04id[$os]) {
609 // if ($i=1) {
610 $out .= "*" . $diag_type_code . ":" . $ub04id[$os++];
611 $diag_type_code = 'BG';
612 // }
615 ++$tmp;
616 ++$i;
618 if ($tmp) {
619 $out .= "~\n";
623 // Segment HI*TC (Treatment Code Information).
624 // HI TC (Treatment Code 1)
625 /* 63a. TREATMENT AUTHORIZATION CODES - PRIMARY PLAN */
626 if ($ub04id[319]) {
627 $max_per_seg = 3;
628 $diag_type_code = 'TC';
629 $tmp = 0;
631 for ($i = 0; $i <= 2;) {
632 if ($tmp % $max_per_seg == 0) {
633 if ($tmp) {
634 $out .= "~\n";
636 ++$edicount;
637 $out .= "HI"; // Health Diagnosis Codes
640 if ($ub04id[319]) {
641 $out .= "*" . $diag_type_code . ":" . $ub04id[319];
642 $diag_type_code = 'TC';
644 if ($i = 1) {
645 if ($ub04id[322]) {
646 $out .= "*" . $diag_type_code . ":" . $ub04id[322];
647 $diag_type_code = 'TC';
650 if ($i = 2) {
651 if ($ub04id[325]) {
652 $out .= "*" . $diag_type_code . ":" . $ub04id[325];
653 $diag_type_code = 'TC';
657 ++$tmp;
658 ++$i;
660 if ($tmp) {
661 $out .= "~\n";
665 // Segment HCP (Claim Pricing/Repricing Information) omitted.
667 // This needs to allow Attending Physician 2310A, Operating Physician Name 2310B, Other Operating Physician Name 2310C
668 // and Rendering Provider Name (Rendering Provider Name is futher down)
670 if ($ub04id[388]) {
671 ++$edicount;
672 // Loop 2310A Attending Physician
673 $out .= "NM1" . "*71" . "*1" . "*" . $ub04id[388] . "*" . $ub04id[389] . "*" . "*";
674 if ($ub04id[379]) { // NPI
675 $out .= "*" . "XX" . "*" . $ub04id[379];
676 } else {
677 $out .= "*" . "*";
678 $log .= "*** Attending Physician has no NPI.\n";
680 $out .= "~\n";
682 if ($ub04id[380]) {
683 ++$edicount;
684 $out .= "REF" . // Attending Physician Secondary Identification
685 "*" . $ub04id[380] . "*" . $ub04id[381] . "~\n";
689 // 2310B
691 if ($ub04id[400]) {
692 ++$edicount;
694 $out .= "NM1" . // Loop 2310B operating Physician
695 "*72" . "*1" . "*" . $ub04id[400] . "*" . $ub04id[400] . "*" . "*";
696 if ($ub04id[390]) {
697 $out .= "*" . "XX" . "*" . $ub04id[390];
698 } else {
699 $out .= "*" . "*";
700 $log .= "*** Operating Physician has no NPI qualifier.\n";
702 $out .= "~\n";
704 if ($ub04id[391]) {
705 ++$edicount;
706 $out .= "REF" . // operating Physician Secondary Identification
707 "*" . $claim->$ub04id[391] . "*" . $ub04id[392] . "~\n";
711 // 2310C
713 if ($ub04id[413]) {
714 ++$edicount;
716 $out .= "NM1" . // Loop 2310C other operating Physician
717 "*73" . "*1" . "*" . $ub04id[413] . "*" . $ub04id[414] . "*" . "*";
718 if ($ub04id[405]) {
719 $out .= "*" . $ub04id[405] . "*" . $ub04id[406];
720 } else {
721 $out .= "*" . "*";
722 $log .= "*** Other Operating Physician has no NPI.\n";
724 $out .= "~\n";
726 if ($ub04id[407]) {
727 ++$edicount;
728 $out .= "REF" . // other operating Physician Secondary Identification
729 "*" . $ub04id[407] . "*" . $ub04id[408] . "~\n";
732 if ($ub04id[427]) {
733 ++$edicount;
735 $out .= "NM1" . // Loop 2310C other operating Physician
736 "*73" . "*1" . "*" . $ub04id[427] . "*" . $ub04id[428] . "*" . "*";
737 if ($ub04id[420]) {
738 $out .= "*" . $ub04id[419] . "*" . $ub04id[420];
739 } else {
740 $out .= "*" . "*";
741 $log .= "*** Other Operating Physician has no NPI.\n";
743 $out .= "~\n";
745 if ($ub04id[422]) {
746 ++$edicount;
747 $out .= "REF" . // other operating Physician Secondary Identification
748 "*" . $ub04id[422] . "*" . $ub04id[421] . "~\n";
752 * Per the implementation guide lines, only include this information if it is different
753 * than the Loop 2010AA information
755 if ($claim->providerNPIValid() && $claim->billingFacilityNPI() !== $claim->providerNPI()) {
756 ++$edicount;
757 $out .= "NM1" . // Loop 2310D Rendering Provider
758 "*82" . "*1" . "*" . $claim->providerLastName() . "*" . $claim->providerFirstName() . "*" . $claim->providerMiddleName() . "*" . "*";
759 if ($claim->providerNPI()) {
760 $out .= "*XX" . "*" . $claim->providerNPI();
761 } else {
762 $log .= "*** Rendering provider has no NPI.\n";
764 $out .= "~\n";
766 // End of Loop 2310D
767 } else {
768 // This loop can only get skipped if we are generating a 5010 claim
769 if (!($claim->providerNPIValid())) {
770 //If the loop was skipped because the provider NPI was invalid, generate a warning for the log.
771 $log .= "*** Skipping 2310B because " . $claim->providerLastName() . "," . $claim->providerFirstName() . " has invalid NPI.\n";
774 * Skipping this segment because the providerNPI and the billingFacilityNPI are identical
775 * is a normal condition, so no need to warn.
779 // 5010 spec says nothing here if NPI was specified.
781 if (!$claim->providerNPI() && in_array($claim->providerNumberType(), array('0B', '1G', 'G2', 'LU'))) {
782 if ($claim->providerNumber()) {
783 ++$edicount;
784 $out .= "REF" . "*" . $claim->providerNumberType() . "*" . $claim->providerNumber() . "~\n";
788 // Loop 2310D is omitted in the case of home visits (POS=12).
789 if ($claim->facilityPOS() != 12 && ($claim->facilityNPI() != $claim->billingFacilityNPI())) {
790 ++$edicount;
792 // Service Facility Name
794 $out .= "NM1" . // Loop 2310E Service Location
795 "*77" . "*2";
796 $facilityName = substr($claim->facilityName(), 0, 60);
797 if ($claim->facilityName() || $claim->facilityNPI() || $claim->facilityETIN()) {
798 $out .= "*" . $facilityName;
800 if ($claim->facilityNPI() || $claim->facilityETIN()) {
801 $out .= "*" . "*" . "*" . "*";
802 if ($claim->facilityNPI()) {
803 $out .= "*XX*" . $claim->facilityNPI();
804 } else {
805 $log .= "*** Service location has no NPI.\n";
808 $out .= "~\n";
809 if ($claim->facilityStreet()) {
810 ++$edicount;
811 $out .= "N3" . "*" . $claim->facilityStreet() . "~\n";
813 if ($claim->facilityState()) {
814 ++$edicount;
815 $out .= "N4" . "*" . $claim->facilityCity() . "*" . $claim->facilityState() . "*" . $claim->x12Zip($claim->facilityZip()) . "~\n";
819 // Segment REF (Service Facility Location Secondary Identification) omitted.
820 // Segment PER (Service Facility Contact Information) omitted.
822 // Loop 2310F Referring Provider
824 if ($claim->referrerLastName()) {
825 // Medicare requires referring provider's name and UPIN.
826 ++$edicount;
828 $out .= "NM1" . // Loop 2310F Referring Provider this needs to change position
829 "*DN" . "*1" . "*" . $claim->referrerLastName() . "*" . $claim->referrerFirstName() . "*" . $claim->referrerMiddleName() . "*" . "*";
830 if ($claim->referrerNPI()) {
831 $out .= "*XX" . "*" . $claim->referrerNPI();
832 } else {
833 $log .= "*** Referrer has no NPI.\n";
835 $out .= "~\n";
838 // Loop 2310E, Supervising Provider
839 // Omitted
841 // Segments NM1*PW, N3, N4 (Ambulance Pick-Up Location) omitted.
842 // Segments NM1*45, N3, N4 (Ambulance Drop-Off Location) omitted.
844 $prev_pt_resp = $clm_total_charges; // for computation below
846 // Loops 2320 and 2330*, other subscriber/payer information.
847 // Remember that insurance index 0 is always for the payer being billed
848 // by this claim, and 1 and above are always for the "other" payers.
850 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
851 $tmp1 = $claim->claimType($ins);
852 $tmp2 = 'C1'; // Here a kludge. See page 321.
853 if ($tmp1 === 'CI') {
854 $tmp2 = 'C1';
856 if ($tmp1 === 'AM') {
857 $tmp2 = 'AP';
859 if ($tmp1 === 'HM') {
860 $tmp2 = 'HM';
862 if ($tmp1 === 'MB') {
863 $tmp2 = 'MB';
865 if ($tmp1 === 'MA') {
866 $tmp2 = 'MA';
868 if ($tmp1 === 'MC') {
869 $tmp2 = 'MC';
871 if ($tmp1 === '09') {
872 $tmp2 = 'PP';
874 ++$edicount;
876 $out .= "SBR" . // Loop 2320, Subscriber Information - page 297/318
877 "*" . $claim->payerSequence($ins) .
878 "*" . $claim->insuredRelationship($ins) .
879 "*" . $claim->groupNumber($ins) .
880 "*" . (($claim->groupNumber($ins)) ? '' : $claim->groupName($ins)) .
881 "*" . ($claim->insuredTypeCode($ins) ? $claim->insuredTypeCode($ins) : $tmp2) .
882 "*" .
883 "*" .
884 "*" .
885 "*" . $claim->claimType($ins) .
886 "~\n";
888 // Things that apply only to previous payers, not future payers.
890 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
891 // Generate claim-level adjustments.
892 $aarr = $claim->payerAdjustments($ins);
893 foreach ($aarr as $a) {
894 ++$edicount;
895 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 301/323.
896 "*" . $a[1] . "*" . $a[2] . "*" . $a[3] . "~\n";
899 $payerpaid = $claim->payerTotals($ins);
900 ++$edicount;
901 $out .= "AMT" . // Previous payer's paid amount. Page 307/332.
902 "*D" . "*" . $payerpaid[1] . "~\n";
904 // Segment AMT*A8 (COB Total Non-Covered Amount) omitted.
905 // Segment AMT*EAF (Remaining Patient Liability) omitted.
906 } // End of things that apply only to previous payers.
908 ++$edicount;
909 $out .= "OI" . // Other Insurance Coverage Information. Page 310/344.
910 "*" . "*" . "*" . ($claim->billingFacilityAssignment($ins) ? 'Y' : 'N') .
911 // For this next item, the 5010 example in the spec does not match its
912 // description. So this might be wrong.
913 "*" .
914 "*" .
915 "*" .
916 "Y" .
917 "~\n";
919 // Segment MOA (Medicare Outpatient Adjudication) omitted.
920 ++$edicount;
921 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 315/350.
922 "*" . "IL" .
923 "*" . "1" .
924 "*" . $claim->insuredLastName($ins) .
925 "*" . $claim->insuredFirstName($ins) .
926 "*" . $claim->insuredMiddleName($ins) .
927 "*" .
928 "*" .
929 "*" . "MI" .
930 "*" . $claim->policyNumber($ins) .
931 "~\n";
933 ++$edicount;
934 $out .= "N3" .
935 "*" . $claim->insuredStreet($ins) .
936 "~\n";
938 ++$edicount;
939 $out .= "N4" .
940 "*" . $claim->insuredCity($ins) .
941 "*" . $claim->insuredState($ins) .
942 "*" . $claim->x12Zip($claim->insuredZip($ins)) .
943 "~\n";
945 // Segment REF (Other Subscriber Secondary Identification) omitted.
946 ++$edicount;
947 $payerName = substr($claim->payerName($ins), 0, 60);
948 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 322/359.
949 "*" . "PR" .
950 "*" . "2" .
951 "*" . $payerName .
952 "*" .
953 "*" .
954 "*" .
955 "*" .
956 "*" . "PI" .
957 "*" . $claim->payerID($ins) .
958 "~\n";
960 if (!$claim->payerID($ins)) {
961 $log .= "*** Payer ID is missing for payer '" . $claim->payerName($ins) . "'.\n";
964 ++$edicount;
965 $out .= "N3" .
966 "*" . $claim->payerStreet($ins) .
967 "~\n";
969 ++$edicount;
970 $out .= "N4" .
971 "*" . $claim->payerCity($ins) .
972 "*" . $claim->payerState($ins) .
973 "*" . $claim->x12Zip($claim->payerZip($ins)) .
974 "~\n";
976 // Segment DTP*573 (Claim Check or Remittance Date) omitted.
977 // Segment REF (Other Payer Secondary Identifier) omitted.
978 // Segment REF*G1 (Other Payer Prior Authorization Number) omitted.
979 // Segment REF*9F (Other Payer Referral Number) omitted.
980 // Segment REF*T4 (Other Payer Claim Adjustment Indicator) omitted.
981 // Segment REF*F8 (Other Payer Claim Control Number) omitted.
982 // 2330C-I loops Omitted
983 } // End loops 2320/2330*.
985 $loopcount = 0;
987 // Procedure loop starts here.
990 for ($tlh = 0; $tlh < $proccount; ++$tlh) {
991 $tmp = $claim->procs[$tlh][code_text];
993 if ($claim->procs[$tlh][code_type] == 'HCPCS') {
994 $tmpcode = '3';
995 } else {
996 $tmpcode = '1';
998 $getrevcd = $claim->cptCode($tlh);
999 $sql = "SELECT * FROM codes WHERE code_type = ? and code = ? ORDER BY revenue_code DESC";
1000 $revcode[$tlh] = sqlQuery($sql, array(
1001 $tmpcode,
1002 $getrevcd
1007 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
1008 $os = 99 + ($loopcount * 8); // Form revenue code offset
1009 $dosos = 102 + ($loopcount * 8); // Procedure date of service form start offset-add 8 for loop
1010 ++$loopcount;
1012 ++$edicount;
1013 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
1014 "*" . "$loopcount" . "~\n";
1016 ++$edicount;
1018 // Revenue code from form
1020 $tmp = $ub04id[$os]; //$revcode[$prockey][revenue_code];
1021 if (empty($tmp)) {
1022 $log .= "*** Error: Missing Revenue Code for " . $claim->cptKey($prockey) . "!\n";
1024 // Institutional Service Line.
1026 $out .= "SV2" . "*" . $tmp . // revenue code
1028 "*" . "HC:" . $claim->cptKey($prockey) . "*" . sprintf('%.2f', $claim->cptCharges($prockey)) . "*UN" . "*" . $claim->cptUnits($prockey) . "*" . "*" . "*";
1030 $out .= "~\n";
1032 if (!$claim->cptCharges($prockey)) {
1033 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no charges!\n";
1036 // Segment SV5 (Durable Medical Equipment Service) omitted.
1037 // Segment PWK (Line Supplemental Information) omitted.
1038 // Segment PWK (Durable Medical Equipment Certificate of Medical Necessity Indicator) omitted.
1039 // Segment CR1 (Ambulance Transport Information) omitted.
1040 // Segment CR3 (Durable Medical Equipment Certification) omitted.
1041 // Segment CRC (Ambulance Certification) omitted.
1042 // Segment CRC (Hospice Employee Indicator) omitted.
1043 // Segment CRC (Condition Indicator / Durable Medical Equipment) omitted.
1045 ++$edicount;
1047 $out .= "DTP" . // Date of Service. Needs to be when service preformed.
1048 "*" . "472" . "*" . "D8" . "*" . $ub04id[$dosos] . "~\n"; //$claim->serviceDate()
1050 $testnote = rtrim($claim->cptNotecodes($prockey));
1051 if (!empty($testnote)) {
1052 ++$edicount;
1053 $out .= "NTE" . // Explain Unusual Circumstances.
1054 "*ADD" . "*" . $claim->cptNotecodes($prockey) . "~\n";
1057 // Segment DTP*471 (Prescription Date) omitted.
1058 // Segment DTP*607 (Revision/Recertification Date) omitted.
1059 // Segment DTP*463 (Begin Therapy Date) omitted.
1060 // Segment DTP*461 (Last Certification Date) omitted.
1061 // Segment DTP*304 (Last Seen Date) omitted.
1062 // Segment DTP (Test Date) omitted.
1063 // Segment DTP*011 (Shipped Date) omitted.
1064 // Segment DTP*455 (Last X-Ray Date) omitted.
1065 // Segment DTP*454 (Initial Treatment Date) omitted.
1066 // Segment QTY (Ambulance Patient Count) omitted.
1067 // Segment QTY (Obstetric Anesthesia Additional Units) omitted.
1068 // Segment MEA (Test Result) omitted.
1069 // Segment CN1 (Contract Information) omitted.
1070 // Segment REF*9B (Repriced Line Item Reference Number) omitted.
1071 // Segment REF*9D (Adjusted Repriced Line Item Reference Number) omitted.
1072 // Segment REF*G1 (Prior Authorization) omitted.
1073 // Segment REF*6R (Line Item Control Number) omitted.
1074 // (Really oughta have this for robust 835 posting!)
1075 // Segment REF*EW (Mammography Certification Number) omitted.
1076 // Segment REF*X4 (CLIA Number) omitted.
1077 // Segment REF*F4 (Referring CLIA Facility Identification) omitted.
1078 // Segment REF*BT (Immunization Batch Number) omitted.
1079 // Segment REF*9F (Referral Number) omitted.
1080 // Segment AMT*GT (Sales Tax Amount) omitted.
1081 // Segment AMT*F4 (Postage Claimed Amount) omitted.
1082 // Segment K3 (File Information) omitted.
1083 // Segment NTE (Line Note) omitted.
1084 // Segment NTE (Third Party Organization Notes) omitted.
1085 // Segment PS1 (Purchased Service Information) omitted.
1086 // Segment HCP (Line Pricing/Repricing Information) omitted.
1088 // Loop 2410, Drug Information. Medicaid insurers seem to want this
1089 // with HCPCS codes.
1091 $ndc = $claim->cptNDCID($prockey);
1093 if ($ndc) {
1094 ++$edicount;
1095 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
1096 "*" . // Per addendum, LIN01 is not used.
1097 "*" . "N4" .
1098 "*" . $ndc .
1099 "~\n";
1101 if (!preg_match('/^\d\d\d\d\d-\d\d\d\d-\d\d$/', $ndc, $tmp) && !preg_match('/^\d{11}$/', $ndc)) {
1102 $log .= "*** NDC code '$ndc' has invalid format!\n";
1105 ++$edicount;
1106 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
1107 "*" .
1108 "*" .
1109 "*" .
1110 "*" . $claim->cptNDCQuantity($prockey) .
1111 "*" . $claim->cptNDCUOM($prockey) .
1112 // Note: 5010 documents "ME" (Milligrams) as an additional unit of measure.
1113 "~\n";
1116 // Segment REF (Prescription or Compound Drug Association Number) omitted.
1118 // Loop 2420A, Rendering Provider (service-specific). (Operating Physician Name for 837I)
1119 // Used if the rendering provider for this service line is different
1120 // from that in loop 2310B.
1122 if ($claim->providerNPI() != $claim->providerNPI($prockey)) {
1123 ++$edicount;
1124 $out .= "NM1" . // Loop 2310B Rendering Provider
1125 "*" . "82" .
1126 "*" . "1" .
1127 "*" . $claim->providerLastName($prockey) .
1128 "*" . $claim->providerFirstName($prockey) .
1129 "*" . $claim->providerMiddleName($prockey) .
1130 "*" .
1131 "*";
1132 if ($claim->providerNPI($prockey)) {
1133 $out .=
1134 "*" . "XX" .
1135 "*" . $claim->providerNPI($prockey);
1136 } else {
1137 $log .= "*** Rendering provider has no NPI.\n";
1139 $out .= "~\n";
1141 if ($claim->providerTaxonomy($prockey)) {
1142 ++$edicount;
1143 $out .= "PRV" .
1144 "*" . "PE" . // PErforming provider
1145 "*" . "PXC" .
1146 "*" . $claim->providerTaxonomy($prockey) .
1147 "~\n";
1150 // Segment PRV*PE (Rendering Provider Specialty Information) omitted.
1151 // Segment REF (Rendering Provider Secondary Identification) omitted.
1152 // Segment NM1 (Purchased Service Provider Name) omitted.
1153 // Segment REF (Purchased Service Provider Secondary Identification) omitted.
1154 // Segment NM1,N3,N4 (Service Facility Location) omitted.
1155 // Segment REF (Service Facility Location Secondary Identification) omitted.
1156 // Segment NM1 (Supervising Provider Name) omitted.
1157 // Segment REF (Supervising Provider Secondary Identification) omitted.
1158 // Segment NM1,N3,N4 (Ordering Provider) omitted.
1159 // Segment REF (Ordering Provider Secondary Identification) omitted.
1160 // Segment PER (Ordering Provider Contact Information) omitted.
1161 // Segment NM1 (Referring Provider Name) omitted.
1162 // Segment REF (Referring Provider Secondary Identification) omitted.
1163 // Segments NM1*PW, N3, N4 (Ambulance Pick-Up Location) omitted.
1164 // Segments NM1*45, N3, N4 (Ambulance Drop-Off Location) omitted.
1166 // REF*1C is required here for the Medicare provider number if NPI was
1167 // specified in NM109. Not sure if other payers require anything here.
1168 if ($claim->providerNumberType($prockey) == "G2") {
1169 ++$edicount;
1170 $out .= "REF" . "*" . $claim->providerNumberType($prockey) .
1171 "*" . $claim->providerNumber($prockey) . "~\n";
1173 } // provider exception
1175 // Loop 2430, adjudication by previous payers.
1177 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
1178 if ($claim->payerSequence($ins) > $claim->payerSequence()) {
1179 continue; // payer is future, not previous
1182 $payerpaid = $claim->payerTotals($ins, $claim->cptKey($prockey));
1183 $aarr = $claim->payerAdjustments($ins, $claim->cptKey($prockey));
1185 if ($payerpaid[1] == 0 && !count($aarr)) {
1186 $log .= "*** Procedure '" . $claim->cptKey($prockey) . "' has no payments or adjustments from previous payer!\n";
1187 continue;
1190 ++$edicount;
1191 $out .= "SVD" . // Service line adjudication. Page 554.
1192 "*" . $claim->payerID($ins) . "*" . $payerpaid[1] . "*HC:" . $claim->cptKey($prockey) . "*" . "*" . $claim->cptUnits($prockey) . "~\n";
1194 $tmpdate = $payerpaid[0];
1195 foreach ($aarr as $a) {
1196 ++$edicount;
1197 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
1198 "*" . $a[1] . "*" . $a[2] . "*" . $a[3] . "~\n";
1199 if (!$tmpdate) {
1200 $tmpdate = $a[0];
1204 if ($tmpdate) {
1205 ++$edicount;
1206 $out .= "DTP" . // Previous payer's line adjustment date. Page 493/566.
1207 "*573" . "*D8" . "*$tmpdate" . "~\n";
1210 // Segment AMT*EAF (Remaining Patient Liability) omitted.
1211 // Segment LQ (Form Identification Code) omitted.
1212 // Segment FRM (Supporting Documentation) omitted.
1213 } // end loop 2430
1214 } // end this procedure
1216 ++$edicount;
1217 $out .= "SE" . // SE Trailer
1218 "*$edicount" . "*0021" . "~\n";
1220 $out .= "GE" . // GE Trailer
1221 "*1" . "*1" . "~\n";
1223 $out .= "IEA" . // IEA Trailer
1224 "*1" . "*000000001" . "~\n";
1226 // Remove any trailing empty fields (delimiters) from each segment.
1227 $out = preg_replace('/\*+~/', '~', $out);
1229 $log .= "\n";
1230 return $out;