Feature custom loading of dutch prescription class.
[openemr.git] / library / gen_x12_837.inc.php
blob41cb72407ee2b67ec28ce36befada3dc8a5b3d14
1 <?php
2 // Copyright (C) 2007 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.
10 // TBD: Write log messages for the "view log" screen.
13 require_once("Claim.class.php");
15 function gen_x12_837($pid, $encounter) {
17 $today = time();
18 $out = '';
19 $claim = new Claim($pid, $encounter);
20 $edicount = 0;
22 $out .= "ISA" .
23 "*00" .
24 "* " .
25 "*00" .
26 "* " .
27 "*ZZ" .
28 "*" . strtoupper($claim->x12gssenderid()) .
29 "*ZZ" .
30 "*" . strtoupper($claim->x12gsreceiverid()) .
31 "*030911" .
32 "*1630" .
33 "*U" .
34 "*00401" .
35 "*000000001" .
36 "*0" .
37 "*T" .
38 "*:" .
39 "~\n";
41 $out .= "GS" .
42 "*HC" .
43 "*" . strtoupper($claim->x12gssenderid()) .
44 "*" . strtoupper($claim->x12gsreceiverid()) .
45 "*" . date('Ymd', $today) .
46 "*" . date('Hi', $today) .
47 "*1" .
48 "*X" .
49 "*" . strtoupper($claim->x12gsversionstring()) .
50 "~\n";
52 ++$edicount;
53 $out .= "ST" .
54 "*837" .
55 "*0021" .
56 "~\n";
58 ++$edicount;
59 $out .= "BHT" .
60 "*0019" .
61 "*00" .
62 "*0123" .
63 "*" . date('Ymd', $today) .
64 "*1023" .
65 "*CH" .
66 "~\n";
68 ++$edicount;
69 $out .= "REF" .
70 "*87" .
71 "*" . strtoupper($claim->x12gsversionstring()) .
72 "~\n";
74 ++$edicount;
75 $out .= "NM1" . // Loop 1000A Submitter
76 "*41" .
77 "*2" .
78 "*" . strtoupper($claim->billingFacilityName()) .
79 "*" .
80 "*" .
81 "*" .
82 "*" .
83 "*46" .
84 "*" . strtoupper($claim->billingFacilityETIN()) .
85 "~\n";
87 ++$edicount;
88 $out .= "PER" .
89 "*IC" .
90 "*" . strtoupper($claim->billingContactName()) .
91 "*TE" .
92 "*" . $claim->billingContactPhone() .
93 "~\n";
95 ++$edicount;
96 $out .= "NM1" . // Loop 1000B Receiver
97 "*40" .
98 "*2" .
99 "*" . strtoupper($claim->clearingHouseName()) .
100 "*" .
101 "*" .
102 "*" .
103 "*" .
104 "*46" .
105 "*" . strtoupper($claim->clearingHouseETIN()) .
106 "~\n";
108 $HLcount = 1;
110 ++$edicount;
111 $out .= "HL" . // Loop 2000A Billing/Pay-To Provider HL Loop
112 "*$HLcount" .
113 "*" .
114 "*20" .
115 "*1" .
116 "~\n";
118 $HLBillingPayToProvider = $HLcount++;
120 ++$edicount;
121 $out .= "NM1" . // Loop 2010AA Billing Provider
122 "*85" .
123 "*2" .
124 "*" . strtoupper($claim->billingFacilityName()) .
125 "*" .
126 "*" .
127 "*" .
128 "*";
129 if ($claim->billingFacilityNPI())
130 $out .= "*XX*" . $claim->billingFacilityNPI();
131 else
132 $out .= "*24*" . $claim->billingFacilityETIN();
133 $out .= "~\n";
135 ++$edicount;
136 $out .= "N3" .
137 "*" . strtoupper($claim->billingFacilityStreet()) .
138 "~\n";
140 ++$edicount;
141 $out .= "N4" .
142 "*" . strtoupper($claim->billingFacilityCity()) .
143 "*" . strtoupper($claim->billingFacilityState()) .
144 "*" . strtoupper($claim->billingFacilityZip()) .
145 "~\n";
147 // Add a REF*EI*<ein> segment if NPI was specified in the NM1 above.
149 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
150 ++$edicount;
151 $out .= "REF" .
152 "*EI" .
153 "*" . $claim->billingFacilityETIN() .
154 "~\n";
157 ++$edicount;
158 $out .= "REF" .
159 "*" . $claim->providerNumberType() .
160 "*" . $claim->providerNumber() .
161 "~\n";
163 ++$edicount;
164 $out .= "NM1" . // Loop 2010AB Pay-To Provider
165 "*87" .
166 "*2" .
167 "*" . strtoupper($claim->billingFacilityName()) .
168 "*" .
169 "*" .
170 "*" .
171 "*";
172 if ($claim->billingFacilityNPI())
173 $out .= "*XX*" . $claim->billingFacilityNPI();
174 else
175 $out .= "*24*" . $claim->billingFacilityETIN();
176 $out .= "~\n";
178 ++$edicount;
179 $out .= "N3" .
180 "*" . strtoupper($claim->billingFacilityStreet()) .
181 "~\n";
183 ++$edicount;
184 $out .= "N4" .
185 "*" . strtoupper($claim->billingFacilityCity()) .
186 "*" . strtoupper($claim->billingFacilityState()) .
187 "*" . strtoupper($claim->billingFacilityZip()) .
188 "~\n";
190 if ($claim->billingFacilityNPI() && $claim->billingFacilityETIN()) {
191 ++$edicount;
192 $out .= "REF" .
193 "*EI" .
194 "*" . $claim->billingFacilityETIN() .
195 "~\n";
198 $PatientHL = 0;
200 ++$edicount;
201 $out .= "HL" . // Loop 2000B Subscriber HL Loop
202 "*$HLcount" .
203 "*$HLBillingPayToProvider" .
204 "*22" .
205 "*$PatientHL" .
206 "~\n";
208 $HLSubscriber = $HLcount++;
210 ++$edicount;
211 $out .= "SBR" . // Subscriber Information
212 "*" . strtoupper($claim->payerSequence()) .
213 "*" . strtoupper($claim->insuredRelationship()) .
214 "*" . strtoupper($claim->groupNumber()) .
215 "*" . strtoupper($claim->groupName()) .
216 "*" .
217 "*" .
218 "*" .
219 "*" .
220 "*" . $claim->claimType() .
221 "~\n";
223 ++$edicount;
224 $out .= "NM1" . // Loop 2010BA Subscriber
225 "*IL" .
226 "*1" .
227 "*" . strtoupper($claim->insuredLastName()) .
228 "*" . strtoupper($claim->insuredFirstName()) .
229 "*" . strtoupper($claim->insuredMiddleName()) .
230 "*" .
231 "*" .
232 "*MI" .
233 "*" . $claim->policyNumber() .
234 "~\n";
236 ++$edicount;
237 $out .= "N3" .
238 "*" . strtoupper($claim->insuredStreet()) .
239 "~\n";
241 ++$edicount;
242 $out .= "N4" .
243 "*" . strtoupper($claim->insuredCity()) .
244 "*" . strtoupper($claim->insuredState()) .
245 "*" . strtoupper($claim->insuredZip()) .
246 "~\n";
248 ++$edicount;
249 $out .= "DMG" .
250 "*D8" .
251 "*" . $claim->insuredDOB() .
252 "*" . $claim->insuredSex() .
253 "~\n";
255 ++$edicount;
256 $out .= "NM1" . // Loop 2010BB Payer
257 "*PR" .
258 "*2" .
259 "*" . strtoupper($claim->payerName()) .
260 "*" .
261 "*" .
262 "*" .
263 "*" .
264 "*PI" .
265 "*" . $claim->payerID() .
266 "~\n";
268 ++$edicount;
269 $out .= "N3" .
270 "*" . strtoupper($claim->payerStreet()) .
271 "~\n";
273 ++$edicount;
274 $out .= "N4" .
275 "*" . strtoupper($claim->payerCity()) .
276 "*" . strtoupper($claim->payerState()) .
277 "*" . strtoupper($claim->payerZip()) .
278 "~\n";
280 if (! $claim->isSelfOfInsured()) {
281 ++$edicount;
282 $out .= "HL" . // Loop 2000C Patient Information
283 "*$HLcount" .
284 "*$HLSubscriber" .
285 "*23" .
286 "*0" .
287 "~\n";
289 $HLcount++;
291 ++$edicount;
292 $out .= "PAT" .
293 "*" . $claim->insuredRelationship() .
294 "~\n";
296 ++$edicount;
297 $out .= "NM1" . // Loop 2010CA Patient
298 "*QC" .
299 "*1" .
300 "*" . strtoupper($claim->patientLastName()) .
301 "*" . strtoupper($claim->patientFirstName()) .
302 "*" . strtoupper($claim->patientMiddleName()) .
303 "~\n";
305 ++$edicount;
306 $out .= "N3" .
307 "*" . strtoupper($claim->patientStreet()) .
308 "~\n";
310 ++$edicount;
311 $out .= "N4" .
312 "*" . strtoupper($claim->patientCity()) .
313 "*" . strtoupper($claim->patientState()) .
314 "*" . strtoupper($claim->patientZip()) .
315 "~\n";
317 ++$edicount;
318 $out .= "DMG" .
319 "*D8" .
320 "*" . $claim->patientDOB() .
321 "*" . $claim->patientSex() .
322 "~\n";
323 } // end of patient different from insured
325 $proccount = $claim->procCount();
327 $clm_total_charges = 0;
328 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
329 $clm_total_charges += $claim->cptCharges($prockey);
332 ++$edicount;
333 $out .= "CLM" . // Loop 2300 Claim
334 "*$pid-$encounter" .
335 "*" . sprintf("%.2f",$clm_total_charges) .
336 "*" .
337 "*" .
338 "*" . $claim->facilityPOS() . "::1" .
339 "*Y" .
340 "*A" .
341 "*Y" .
342 "*Y" .
343 "*C" .
344 "~\n";
346 ++$edicount;
347 $out .= "DTP" . // Date of Onset
348 "*431" .
349 "*D8" .
350 "*" . $claim->onsetDate() .
351 "~\n";
353 if ($claim->facilityPOS() == '21') {
354 ++$edicount;
355 $out .= "DTP" . // Date of Hospitalization
356 "*435" .
357 "*D8" .
358 "*" . $claim->onsetDate() .
359 "~\n";
362 $patientpaid = $claim->patientPaidAmount();
363 if ($patientpaid != 0) {
364 ++$edicount;
365 $out .= "AMT" . // Patient paid amount. Page 220.
366 "*F5" .
367 "*" . $patientpaid .
368 "~\n";
371 if ($claim->priorAuth()) {
372 ++$edicount;
373 $out .= "REF" . // Prior Authorization Number
374 "*G1" .
375 "*" . $claim->priorAuth() .
376 "~\n";
379 if ($claim->cliaCode()) {
380 // Required by Medicare when in-house labs are done.
381 ++$edicount;
382 $out .= "REF" . // Clinical Laboratory Improvement Amendment Number
383 "*X4" .
384 "*" . $claim->cliaCode() .
385 "~\n";
388 $da = $claim->diagArray();
389 ++$edicount;
390 $out .= "HI"; // Health Diagnosis Codes
391 $diag_type_code = 'BK';
392 foreach ($da as $diag) {
393 $out .= "*$diag_type_code:" . $diag;
394 $diag_type_code = 'BF';
396 $out .= "~\n";
398 if ($claim->referrerLastName()) {
399 // Medicare requires referring provider's name and UPIN.
400 ++$edicount;
401 $out .= "NM1" . // Loop 2310A Referring Provider
402 "*DN" .
403 "*1" .
404 "*" . strtoupper($claim->referrerLastName()) .
405 "*" . strtoupper($claim->referrerFirstName()) .
406 "*" . strtoupper($claim->referrerMiddleName()) .
407 "*" .
408 "*";
409 if ($claim->referrerNPI()) { $out .=
410 "*XX" .
411 "*" . $claim->referrerNPI();
412 } else { $out .=
413 "*34" .
414 "*" . $claim->referrerSSN();
416 $out .= "~\n";
418 ++$edicount;
419 $out .= "REF" . // Referring Provider Secondary Identification
420 "*1G" .
421 "*" . strtoupper($claim->referrerUPIN()) .
422 "~\n";
425 ++$edicount;
426 $out .= "NM1" . // Loop 2310B Rendering Provider
427 "*82" .
428 "*1" .
429 "*" . strtoupper($claim->providerLastName()) .
430 "*" . strtoupper($claim->providerFirstName()) .
431 "*" . strtoupper($claim->providerMiddleName()) .
432 "*" .
433 "*";
434 if ($claim->providerNPI()) { $out .=
435 "*XX" .
436 "*" . $claim->providerNPI();
437 } else { $out .=
438 "*34" .
439 "*" . $claim->providerSSN();
441 $out .= "~\n";
443 ++$edicount;
444 $out .= "PRV" . // Rendering Provider Information
445 "*PE" .
446 "*ZZ" .
447 "*207Q00000X" .
448 "~\n";
450 ++$edicount;
451 $out .= "NM1" . // Loop 2310B Service Location
452 "*77" .
453 "*2" .
454 "*" . strtoupper($claim->facilityName()) .
455 "*" .
456 "*" .
457 "*" .
458 "*";
459 if ($claim->facilityNPI()) { $out .=
460 "*XX*" . $claim->facilityNPI();
461 } else { $out .=
462 "*24*" . $claim->facilityETIN();
464 $out .= "~\n";
466 ++$edicount;
467 $out .= "N3" .
468 "*" . strtoupper($claim->facilityStreet()) .
469 "~\n";
471 ++$edicount;
472 $out .= "N4" .
473 "*" . strtoupper($claim->facilityCity()) .
474 "*" . strtoupper($claim->facilityState()) .
475 "*" . strtoupper($claim->facilityZip()) .
476 "~\n";
478 // Loops 2320 and 2330*, other subscriber/payer information.
480 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
482 ++$edicount;
483 $out .= "SBR" . // Loop 2320, Subscriber Information - page 318
484 "*" . strtoupper($claim->payerSequence($ins)) .
485 "*" . strtoupper($claim->insuredRelationship($ins)) .
486 "*" . strtoupper($claim->groupNumber($ins)) .
487 "*" . strtoupper($claim->groupName($ins)) .
488 "*" .
489 "*" .
490 "*" .
491 "*" .
492 "*" . $claim->claimType($ins) .
493 "~\n";
495 // Things that apply only to previous payers, not future payers.
497 if ($claim->payerSequence($ins) < $claim->payerSequence()) {
499 // Generate claim-level adjustments.
500 $aarr = $claim->payerAdjustments($ins);
501 foreach ($aarr as $a) {
502 ++$edicount;
503 $out .= "CAS" . // Previous payer's claim-level adjustments. Page 323.
504 "*" . $a[1] .
505 "*" . $a[2] .
506 "*" . $a[3] .
507 "~\n";
510 $payerpaid = $claim->payerPaidAmount($ins);
511 ++$edicount;
512 $out .= "AMT" . // Previous payer's paid amount. Page 332.
513 "*D" .
514 "*" . $payerpaid .
515 "~\n";
517 ++$edicount;
518 $out .= "AMT" . // Patient responsibility amount per previous payer. Page 335.
519 "*F2" .
520 "*" . sprintf('%.2f', $claim->invoiceTotal() - $payerpaid) .
521 "~\n";
523 } // End of things that apply only to previous payers.
525 ++$edicount;
526 $out .= "OI" . // Other Insurance Coverage Information. Page 344.
527 "*" .
528 "*" .
529 "*Y" .
530 "*B" .
531 "*" .
532 "*Y" .
533 "~\n";
535 ++$edicount;
536 $out .= "NM1" . // Loop 2330A Subscriber info for other insco. Page 350.
537 "*IL" .
538 "*1" .
539 "*" . strtoupper($claim->insuredLastName($ins)) .
540 "*" . strtoupper($claim->insuredFirstName($ins)) .
541 "*" . strtoupper($claim->insuredMiddleName($ins)) .
542 "*" .
543 "*" .
544 "*MI" .
545 "*" . $claim->policyNumber($ins) .
546 "~\n";
548 ++$edicount;
549 $out .= "NM1" . // Loop 2330B Payer info for other insco. Page 359.
550 "*PR" .
551 "*2" .
552 "*" . strtoupper($claim->payerName($ins)) .
553 "*" .
554 "*" .
555 "*" .
556 "*" .
557 "*PI" .
558 "*" . $claim->payerID($ins) .
559 "~\n";
561 } // End loops 2320/2330*.
563 $loopcount = 0;
565 // Procedure loop starts here.
567 for ($prockey = 0; $prockey < $proccount; ++$prockey) {
568 ++$loopcount;
570 ++$edicount;
571 $out .= "LX" . // Loop 2400 LX Service Line. Page 398.
572 "*$loopcount" .
573 "~\n";
575 ++$edicount;
576 $out .= "SV1" . // Professional Service. Page 400.
577 "*HC:" . strtoupper($claim->cptCode($prockey));
578 if ($claim->cptModifier($prockey)) { $out .=
579 ":" . strtoupper($claim->cptModifier($prockey));
581 $out .=
582 "*" . sprintf('%.2f', $claim->cptCharges($prockey)) .
583 "*UN" .
584 "*" . $claim->cptUnits($prockey) .
585 "*" .
586 "*" .
587 "*" . $claim->diagIndex($prockey) .
588 "~\n";
590 ++$edicount;
591 $out .= "DTP" . // Date of Service. Page 435.
592 "*472" .
593 "*D8" .
594 "*" . $claim->serviceDate() .
595 "~\n";
597 // Loop 2410, Drug Information. Medicaid insurers seem to want this
598 // with HCPCS codes.
600 if ($claim->cptNDCID($prockey))
601 ++$edicount;
602 $out .= "LIN" . // Drug Identification. Page 500+ (Addendum pg 71).
603 "*4" .
604 "*N4" .
605 "*" . $claim->cptNDCID($prockey) .
606 "~\n";
608 ++$edicount;
609 $out .= "CTP" . // Drug Pricing. Page 500+ (Addendum pg 74).
610 "*" .
611 "*" .
612 "*0" . // dummy price, required by HIPAA
613 "*" . $claim->cptNDCQuantity($prockey) .
614 "*" . $claim->cptNDCUOM($prockey) .
615 "~\n";
618 // Loop 2430, adjudication by previous payers.
620 for ($ins = 1; $ins < $claim->payerCount(); ++$ins) {
621 if ($claim->payerSequence($ins) > $claim->payerSequence())
622 continue; // payer is future, not previous
624 ++$edicount;
625 $out .= "SVD" . // Service line adjudication. Page 554.
626 "*" . $claim->payerID($ins) .
627 "*" . $claim->payerPaidAmount($ins, $claim->cptCode($prockey)) .
628 "*HC:" . strtoupper($claim->cptCode($prockey));
629 if ($claim->cptModifier($prockey)) $out .=
630 ":" . strtoupper($claim->cptModifier($prockey));
631 $out .=
632 "*" .
633 "*" . $claim->cptUnits($prockey) .
634 "~\n";
636 $aarr = $claim->payerAdjustments($ins, $claim->cptCode($prockey));
637 $tmpdate = '';
638 foreach ($aarr as $a) {
639 ++$edicount;
640 $out .= "CAS" . // Previous payer's line level adjustments. Page 558.
641 "*" . $a[1] .
642 "*" . $a[2] .
643 "*" . $a[3] .
644 "~\n";
645 $tmpdate = $a[0];
648 if ($tmpdate) {
649 ++$edicount;
650 $out .= "DTP" . // Previous payer's line adjustment date. Page 566.
651 "*573" .
652 "*D8" .
653 "*$tmpdate" .
654 "~\n";
656 } // end loop 2430
657 } // end this procedure
659 ++$edicount;
660 $out .= "SE" . // SE Trailer
661 "*$edicount" .
662 "*0021" .
663 "~\n";
665 $out .= "GE" . // GE Trailer
666 "*1" .
667 "*1" .
668 "~\n";
670 $out .= "IEA" . // IEA Trailer
671 "*1" .
672 "*000000001" .
673 "~\n";
675 return $out;