Fully responsive globals.php with vertical menu (#2460)
[openemr.git] / interface / billing / sl_eob_process.php
blob79bfcbbfe9d5777614150bf06b8ddf930f694a1e
1 <?php
2 /**
3 * This processes X12 835 remittances and produces a report.
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Rod Roark <rod@sunsetsystems.com>
8 * @author Brady Miller <brady.g.miller@gmail.com>
9 * @author Stephen Waite <stephen.waite@cmsvt.com>
10 * @copyright Copyright (c) 2006-2010 Rod Roark <rod@sunsetsystems.com>
11 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
12 * @copyright Copyright (c) 2019 Stephen Waite <stephen.waite@cmsvt.com>
13 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
16 // Buffer all output so we can archive it to a file.
17 ob_start();
19 require_once("../globals.php");
20 require_once("$srcdir/invoice_summary.inc.php");
22 use OpenEMR\Billing\BillingUtilities;
23 use OpenEMR\Billing\ParseERA;
24 use OpenEMR\Billing\SLEOB;
25 use OpenEMR\Services\InsuranceService;
27 $debug = $_GET['debug'] ? 1 : 0; // set to 1 for debugging mode
28 $paydate = parse_date($_GET['paydate']);
29 $encount = 0;
31 $last_ptname = '';
32 $last_invnumber = '';
33 $last_code = '';
34 $invoice_total = 0.00;
35 $InsertionId; // last inserted ID of
37 ///////////////////////// Assorted Functions /////////////////////////
39 function parse_date($date)
41 $date = substr(trim($date), 0, 10);
42 if (preg_match('/^(\d\d\d\d)\D*(\d\d)\D*(\d\d)$/', $date, $matches)) {
43 return $matches[1] . '-' . $matches[2] . '-' . $matches[3];
46 return '';
49 function writeMessageLine($bgcolor, $class, $description, $nl2br_process = "false")
51 $dline =
52 " <tr bgcolor='" . attr($bgcolor) . "'>\n" .
53 " <td class='" . attr($class) . "' colspan='4'>&nbsp;</td>\n";
54 if ($nl2br_process) {
55 $dline .= " <td class='" . attr($class) . "'>" . nl2br(text($description)) . "</td>\n";
56 } else {
57 $dline .= " <td class='" . attr($class) . "'>" . text($description) . "</td>\n";
59 $dline .=
60 " <td class='" . attr($class) . "' colspan='2'>&nbsp;</td>\n" .
61 " </tr>\n";
62 echo $dline;
65 function writeDetailLine(
66 $bgcolor,
67 $class,
68 $ptname,
69 $invnumber,
70 $code,
71 $date,
72 $description,
73 $amount,
74 $balance
75 ) {
77 global $last_ptname, $last_invnumber, $last_code;
78 if ($ptname == $last_ptname) {
79 $ptname = '&nbsp;';
80 } else {
81 $last_ptname = $ptname;
84 if ($invnumber == $last_invnumber) {
85 $invnumber = '&nbsp;';
86 } else {
87 $last_invnumber = $invnumber;
90 if ($code == $last_code) {
91 $code = '&nbsp;';
92 } else {
93 $last_code = $code;
96 if ($amount) {
97 $amount = sprintf("%.2f", $amount);
100 if ($balance) {
101 $balance = sprintf("%.2f", $balance);
104 $dline =
105 " <tr bgcolor='" . attr($bgcolor) . "'>\n" .
106 " <td class='" . attr($class) . "'>" . text($ptname) . "</td>\n" .
107 " <td class='" . attr($class) . "'>" . text($invnumber) . "</td>\n" .
108 " <td class='" . attr($class) . "'>" . text($code) . "</td>\n" .
109 " <td class='" . attr($class) . "'>" . text(oeFormatShortDate($date)) . "</td>\n" .
110 " <td class='" . attr($class) . "'>" . text($description) . "</td>\n" .
111 " <td class='" . attr($class) . "' align='right'>" . text(oeFormatMoney($amount)) . "</td>\n" .
112 " <td class='" . attr($class) . "' align='right'>" . text(oeFormatMoney($balance)) . "</td>\n" .
113 " </tr>\n";
114 echo $dline;
117 // This writes detail lines that were already in SQL-Ledger for a given
118 // charge item.
120 function writeOldDetail(&$prev, $ptname, $invnumber, $dos, $code, $bgcolor)
122 global $invoice_total;
123 // $prev['total'] = 0.00; // to accumulate total charges
124 ksort($prev['dtl']);
125 foreach ($prev['dtl'] as $dkey => $ddata) {
126 $ddate = substr($dkey, 0, 10);
127 $description = $ddata['src'] . $ddata['rsn'];
128 if ($ddate == ' ') { // this is the service item
129 $ddate = $dos;
130 $description = 'Service Item';
133 $amount = sprintf("%.2f", $ddata['chg'] - $ddata['pmt']);
134 $invoice_total = sprintf("%.2f", $invoice_total + $amount);
135 writeDetailLine(
136 $bgcolor,
137 'olddetail',
138 $ptname,
139 $invnumber,
140 $code,
141 $ddate,
142 $description,
143 $amount,
144 $invoice_total
149 // This is called back by ParseERA::parse_era() once per claim.
151 function era_callback_check(&$out)
153 global $InsertionId;//last inserted ID of
154 global $StringToEcho,$debug;
156 if ($_GET['original']=='original') {
157 $StringToEcho="<br/><br/><br/><br/><br/><br/>";
158 $StringToEcho.="<table border='1' cellpadding='0' cellspacing='0' width='750'>";
159 $StringToEcho.="<tr bgcolor='#cccccc'><td width='50'></td><td class='dehead' width='150' align='center'>" . xlt('Check Number') . "</td><td class='dehead' width='400' align='center'>" . xlt('Payee Name') . "</td><td class='dehead' width='150' align='center'>" . xlt('Check Amount') . "</td></tr>";
160 $WarningFlag=false;
161 for ($check_count=1; $check_count<=$out['check_count']; $check_count++) {
162 if ($check_count%2==1) {
163 $bgcolor='#ddddff';
164 } else {
165 $bgcolor='#ffdddd';
168 $rs=sqlQ("select reference from ar_session where reference=?", array($out['check_number'.$check_count]));
169 if (sqlNumRows($rs)>0) {
170 $bgcolor='#ff0000';
171 $WarningFlag=true;
174 $StringToEcho.="<tr bgcolor='" . attr($bgcolor) . "'>";
175 $StringToEcho.="<td><input type='checkbox' name='chk" . attr($out['check_number'.$check_count]) . "' value='" . attr($out['check_number'.$check_count]) . "'/></td>";
176 $StringToEcho.="<td>" . text($out['check_number'.$check_count]) . "</td>";
177 $StringToEcho.="<td>" . text($out['payee_name'.$check_count]) . "</td>";
178 $StringToEcho.="<td align='right'>" . text(number_format($out['check_amount'.$check_count], 2)) . "</td>";
179 $StringToEcho.="</tr>";
182 $StringToEcho.="<tr bgcolor='#cccccc'><td colspan='4' align='center'><input type='submit' name='CheckSubmit' value='Submit'/></td></tr>";
183 if ($WarningFlag==true) {
184 $StringToEcho.="<tr bgcolor='#ff0000'><td colspan='4' align='center'>" . xlt('Warning, Check Number already exist in the database') . "</td></tr>";
187 $StringToEcho.="</table>";
188 } else {
189 for ($check_count=1; $check_count<=$out['check_count']; $check_count++) {
190 $chk_num=$out['check_number'.$check_count];
191 $chk_num=str_replace(' ', '_', $chk_num);
192 if (isset($_REQUEST['chk'.$chk_num])) {
193 $check_date=$out['check_date'.$check_count]?$out['check_date'.$check_count]:$_REQUEST['paydate'];
194 $post_to_date=$_REQUEST['post_to_date']!=''?$_REQUEST['post_to_date']:date('Y-m-d');
195 $deposit_date=$_REQUEST['deposit_date']!=''?$_REQUEST['deposit_date']:date('Y-m-d');
196 $InsertionId[$out['check_number'.$check_count]]=SLEOB::arPostSession($_REQUEST['InsId'], $out['check_number'.$check_count], $out['check_date'.$check_count], $out['check_amount'.$check_count], $post_to_date, $deposit_date, $debug);
201 function era_callback(&$out)
203 global $encount, $debug;
204 global $invoice_total, $last_code, $paydate;
205 global $InsertionId;//last inserted ID of
208 // Some heading information.
209 $chk_123=$out['check_number'];
210 $chk_123=str_replace(' ', '_', $chk_123);
211 if (isset($_REQUEST['chk'.$chk_123])) {
212 if ($encount == 0) {
213 writeMessageLine(
214 '#ffffff',
215 'infdetail',
216 "Payer: " . $out['payer_name']
218 if ($debug) {
219 writeMessageLine(
220 '#ffffff',
221 'infdetail',
222 "WITHOUT UPDATE is selected; no changes will be applied."
227 $last_code = '';
228 $invoice_total = 0.00;
229 $bgcolor = (++$encount & 1) ? "#ddddff" : "#ffdddd";
230 list($pid, $encounter, $invnumber) = SLEOB::slInvoiceNumber($out);
232 // Get details, if we have them, for the invoice.
233 $inverror = true;
234 $codes = array();
235 if ($pid && $encounter) {
236 // Get invoice data into $arrow or $ferow.
237 $ferow = sqlQuery("SELECT e.*, p.fname, p.mname, p.lname " .
238 "FROM form_encounter AS e, patient_data AS p WHERE " .
239 "e.pid = ? AND e.encounter = ? AND ".
240 "p.pid = e.pid", array($pid, $encounter));
241 if (empty($ferow)) {
242 $pid = $encounter = 0;
243 $invnumber = $out['our_claim_id'];
244 } else {
245 $inverror = false;
246 $codes = ar_get_invoice_summary($pid, $encounter, true);
247 // $svcdate = substr($ferow['date'], 0, 10);
251 // Show the claim status.
252 $csc = $out['claim_status_code'];
253 $inslabel = 'Ins1';
254 if ($csc == '1' || $csc == '19') {
255 $inslabel = 'Ins1';
258 if ($csc == '2' || $csc == '20') {
259 $inslabel = 'Ins2';
262 if ($csc == '3' || $csc == '21') {
263 $inslabel = 'Ins3';
266 $primary = ($inslabel == 'Ins1');
267 writeMessageLine(
268 $bgcolor,
269 'infdetail',
270 "Claim status $csc: " . BillingUtilities::claim_status_codes_CLP02[$csc]
273 // Show an error message if the claim is missing or already posted.
274 if ($inverror) {
275 writeMessageLine(
276 $bgcolor,
277 'errdetail',
278 "The following claim is not in our database"
280 } else {
281 // Skip this test. Claims can get multiple CLPs from the same payer!
283 // $insdone = strtolower($arrow['shipvia']);
284 // if (strpos($insdone, 'ins1') !== false) {
285 // $inverror = true;
286 // writeMessageLine($bgcolor, 'errdetail',
287 // "Primary insurance EOB was already posted for the following claim");
288 // }
291 if ($csc == '4') {//Denial case, code is stored in the claims table for display in the billing manager screen with reason explained.
292 $inverror = true;
293 if (!$debug) {
294 if ($pid && $encounter) {
295 $code_value = '';
296 foreach ($out['svc'] as $svc) {
297 foreach ($svc['adj'] as $adj) {//Per code and modifier the reason will be showed in the billing manager.
298 $code_value .= $svc['code'].'_'.$svc['mod'].'_'.$adj['group_code'].'_'.$adj['reason_code'].',';
302 $code_value = substr($code_value, 0, -1);
303 //We store the reason code to display it with description in the billing manager screen.
304 //process_file is used as for the denial case file name will not be there, and extra field(to store reason) can be avoided.
305 BillingUtilities::updateClaim(true, $pid, $encounter, $_REQUEST['InsId'], substr($inslabel, 3), 7, 0, $code_value);
309 writeMessageLine(
310 $bgcolor,
311 'errdetail',
312 "Not posting adjustments for denied claims, please follow up manually!"
314 } else if ($csc == '22') {
315 $inverror = true;
316 writeMessageLine(
317 $bgcolor,
318 'errdetail',
319 "Payment reversals are not automated, please enter manually!"
323 if ($out['warnings']) {
324 writeMessageLine($bgcolor, 'infdetail', rtrim($out['warnings']), true);
327 // Simplify some claim attributes for cleaner code.
328 $service_date = parse_date($out['dos']);
329 $check_date = $paydate ? $paydate : parse_date($out['check_date']);
330 $production_date = $paydate ? $paydate : parse_date($out['production_date']);
332 $insurance_id = SLEOB::arGetPayerID($pid, $service_date, substr($inslabel, 3));
333 if (empty($ferow['lname'])) {
334 $patient_name = $out['patient_fname'] . ' ' . $out['patient_lname'];
335 } else {
336 $patient_name = $ferow['fname'] . ' ' . $ferow['lname'];
339 $error = $inverror;
341 // This loops once for each service item in this claim.
342 foreach ($out['svc'] as $svc) {
343 // Treat a modifier in the remit data as part of the procedure key.
344 // This key will then make its way into SQL-Ledger.
345 $codekey = $svc['code'];
346 if ($svc['mod']) {
347 $codekey .= ':' . $svc['mod'];
350 $prev = $codes[$codekey];
351 $codetype = ''; //will hold code type, if exists
353 // This reports detail lines already on file for this service item.
354 if ($prev) {
355 $codetype = $codes[$codekey]['code_type']; //store code type
356 writeOldDetail($prev, $patient_name, $invnumber, $service_date, $codekey, $bgcolor);
357 // Check for sanity in amount charged.
358 $prevchg = sprintf("%.2f", $prev['chg'] + $prev['adj']);
359 if ($prevchg != abs($svc['chg'])) {
360 writeMessageLine(
361 $bgcolor,
362 'errdetail',
363 "EOB charge amount " . $svc['chg'] . " for this code does not match our invoice"
365 $error = true;
368 // Check for already-existing primary remittance activity.
369 // Removed this check because it was not allowing for copays manually
370 // entered into the invoice under a non-copay billing code.
371 /****
372 if ((sprintf("%.2f",$prev['chg']) != sprintf("%.2f",$prev['bal']) ||
373 $prev['adj'] != 0) && $primary)
375 writeMessageLine($bgcolor, 'errdetail',
376 "This service item already has primary payments and/or adjustments!");
377 $error = true;
379 ****/
381 unset($codes[$codekey]);
382 } // If the service item is not in our database...
383 else {
384 // This is not an error. If we are not in error mode and not debugging,
385 // insert the service item into SL. Then display it (in green if it
386 // was inserted, or in red if we are in error mode).
387 $description = "CPT4:$codekey Added by $inslabel $production_date";
388 if (!$error && !$debug) {
389 SLEOB::arPostCharge(
390 $pid,
391 $encounter,
393 $svc['chg'],
395 $service_date,
396 $codekey,
397 $description,
398 $debug,
400 $codetype
402 $invoice_total += $svc['chg'];
405 $class = $error ? 'errdetail' : 'newdetail';
406 writeDetailLine(
407 $bgcolor,
408 $class,
409 $patient_name,
410 $invnumber,
411 $codekey,
412 $production_date,
413 $description,
414 $svc['chg'],
415 ($error ? '' : $invoice_total)
419 $class = $error ? 'errdetail' : 'newdetail';
421 // Report Allowed Amount.
422 if ($svc['allowed']) {
423 // A problem here is that some payers will include an adjustment
424 // reflecting the allowed amount, others not. So here we need to
425 // check if the adjustment exists, and if not then create it. We
426 // assume that any nonzero CO (Contractual Obligation) or PI
427 // (Payer Initiated) adjustment is good enough.
428 $contract_adj = sprintf("%.2f", $svc['chg'] - $svc['allowed']);
429 foreach ($svc['adj'] as $adj) {
430 if (($adj['group_code'] == 'CO' || $adj['group_code'] == 'PI') && $adj['amount'] != 0) {
431 $contract_adj = 0;
435 if ($contract_adj > 0) {
436 $svc['adj'][] = array('group_code' => 'CO', 'reason_code' => 'A2',
437 'amount' => $contract_adj);
440 writeMessageLine(
441 $bgcolor,
442 'infdetail',
443 'Allowed amount is ' . sprintf("%.2f", $svc['allowed'])
447 // Report miscellaneous remarks.
448 if ($svc['remark']) {
449 $rmk = $svc['remark'];
450 writeMessageLine($bgcolor, 'infdetail', "$rmk: " .
451 BillingUtilities::remittance_advice_remark_codes[$rmk]);
454 // Post and report the payment for this service item from the ERA.
455 // By the way a 'Claim' level payment is probably going to be negative,
456 // i.e. a payment reversal.
457 if ($svc['paid']) {
458 if (!$error && !$debug) {
459 SLEOB::arPostPayment(
460 $pid,
461 $encounter,
462 $InsertionId[$out['check_number']],
463 $svc['paid'], //$InsertionId[$out['check_number']] gives the session id
464 $codekey,
465 substr($inslabel, 3),
466 $out['check_number'],
467 $debug,
469 $codetype
471 $invoice_total -= $svc['paid'];
474 $description = "$inslabel/" . $out['check_number'] . ' payment';
475 if ($svc['paid'] < 0) {
476 $description .= ' reversal';
479 writeDetailLine(
480 $bgcolor,
481 $class,
482 $patient_name,
483 $invnumber,
484 $codekey,
485 $check_date,
486 $description,
487 0 - $svc['paid'],
488 ($error ? '' : $invoice_total)
492 // Post and report adjustments from this ERA. Posted adjustment reasons
493 // must be 25 characters or less in order to fit on patient statements.
494 foreach ($svc['adj'] as $adj) {
495 $description = $adj['reason_code'] . ': ' .
496 BillingUtilities::claim_adjustment_reason_codes[$adj['reason_code']];
497 if ($adj['group_code'] == 'PR' || !$primary) {
498 // Group code PR is Patient Responsibility. Enter these as zero
499 // adjustments to retain the note without crediting the claim.
500 if ($primary) {
501 /****
502 $reason = 'Pt resp: '; // Reasons should be 25 chars or less.
503 if ($adj['reason_code'] == '1') $reason = 'To deductible: ';
504 else if ($adj['reason_code'] == '2') $reason = 'Coinsurance: ';
505 else if ($adj['reason_code'] == '3') $reason = 'Co-pay: ';
506 ****/
507 $reason = "$inslabel ptresp: "; // Reasons should be 25 chars or less.
508 if ($adj['reason_code'] == '1') {
509 $reason = "$inslabel dedbl: ";
510 } else if ($adj['reason_code'] == '2') {
511 $reason = "$inslabel coins: ";
512 } else if ($adj['reason_code'] == '3') {
513 $reason = "$inslabel copay: ";
515 } // Non-primary insurance adjustments are garbage, either repeating
516 // the primary or are not adjustments at all. Report them as notes
517 // but do not post any amounts.
518 else {
519 $reason = "$inslabel note " . $adj['reason_code'] . ': ';
520 /****
521 $reason .= sprintf("%.2f", $adj['amount']);
522 ****/
525 $reason .= sprintf("%.2f", $adj['amount']);
526 // Post a zero-dollar adjustment just to save it as a comment.
527 if (!$error && !$debug) {
528 SLEOB::arPostAdjustment(
529 $pid,
530 $encounter,
531 $InsertionId[$out['check_number']],
533 $codekey, //$InsertionId[$out['check_number']] gives the session id
534 substr($inslabel, 3),
535 $reason,
536 $debug,
538 $codetype
542 writeMessageLine($bgcolor, $class, $description . ' ' .
543 sprintf("%.2f", $adj['amount']));
544 } // Other group codes for primary insurance are real adjustments.
545 else {
546 if (!$error && !$debug) {
547 SLEOB::arPostAdjustment(
548 $pid,
549 $encounter,
550 $InsertionId[$out['check_number']],
551 $adj['amount'], //$InsertionId[$out['check_number']] gives the session id
552 $codekey,
553 substr($inslabel, 3),
554 "Adjust code " . $adj['reason_code'],
555 $debug,
557 $codetype
559 $invoice_total -= $adj['amount'];
562 writeDetailLine(
563 $bgcolor,
564 $class,
565 $patient_name,
566 $invnumber,
567 $codekey,
568 $production_date,
569 $description,
570 0 - $adj['amount'],
571 ($error ? '' : $invoice_total)
575 } // End of service item
577 // Report any existing service items not mentioned in the ERA, and
578 // determine if any of them are still missing an insurance response
579 // (if so, then insurance is not yet done with the claim).
580 $insurance_done = true;
581 foreach ($codes as $code => $prev) {
582 // writeOldDetail($prev, $arrow['name'], $invnumber, $service_date, $code, $bgcolor);
583 writeOldDetail($prev, $patient_name, $invnumber, $service_date, $code, $bgcolor);
584 $got_response = false;
585 foreach ($prev['dtl'] as $ddata) {
586 if ($ddata['pmt'] || $ddata['rsn']) {
587 $got_response = true;
591 if (!$got_response) {
592 $insurance_done = false;
596 // Cleanup: If all is well, mark Ins<x> done and check for secondary billing.
597 if (!$error && !$debug && $insurance_done) {
598 $level_done = 0 + substr($inslabel, 3);
600 if ($out['crossover']==1) {//Automatic forward case.So need not again bill from the billing manager screen.
601 sqlStatement("UPDATE form_encounter " .
602 "SET last_level_closed = ?,last_level_billed=? WHERE " .
603 "pid = ? AND encounter = ?", array($level_done, $level_done, $pid, $encounter));
604 writeMessageLine(
605 $bgcolor,
606 'infdetail',
607 'This claim is processed by Insurance '.$level_done.' and automatically forwarded to Insurance '.($level_done+1) .' for processing. '
609 } else {
610 sqlStatement("UPDATE form_encounter " .
611 "SET last_level_closed = ? WHERE " .
612 "pid = ? AND encounter = ?", array($level_done, $pid, $encounter));
615 // Check for secondary insurance.
616 if ($primary && SLEOB::arGetPayerID($pid, $service_date, 2)) {
617 SLEOB::arSetupSecondary($pid, $encounter, $debug, $out['crossover']);
619 if ($out['crossover']<>1) {
620 writeMessageLine(
621 $bgcolor,
622 'infdetail',
623 'This claim is now re-queued for secondary paper billing'
628 if ($out['corrected'] == '1') {
629 if ($GLOBALS['update_mbi']) {
630 if ($primary && (substr($inslabel, 3) == 1)) {
631 $updated_ins = InsuranceService::getOne($pid, "primary");
632 $updated_ins['provider'] = $insurance_id;
633 $updated_ins['policy_number'] = $out['corrected_mbi'];
634 InsuranceService::update($pid, "primary", $updated_ins);
635 } else { // tbd secondary medicare
636 // InsuranceService::update($pid, "secondary", array($insurance_id, '', $out['corrected_mbi']));
637 // will need to add method to insurance service to return policy type
640 writeMessageLine(
641 $bgcolor,
642 'infdetail',
643 "The policy number has been updated to " . $out['corrected_mbi']
645 } else {
646 writeMessageLine(
647 $bgcolor,
648 'infdetail',
649 "The policy number could be updated to " . $out['corrected_mbi'] . " if you enable it in globals"
657 /////////////////////////// End Functions ////////////////////////////
659 $info_msg = "";
661 if (!verifyCsrfToken($_GET["csrf_token_form"])) {
662 csrfNotVerified();
665 $eraname = $_GET['eraname'];
667 if (! $eraname) {
668 die(xlt("You cannot access this page directly."));
671 // Open the output file early so that in case it fails, we do not post a
672 // bunch of stuff without saving the report. Also be sure to retain any old
673 // report files. Do not save the report if this is a no-update situation.
675 if (!$debug) {
676 $nameprefix = $GLOBALS['OE_SITE_DIR'] . "/documents/era/$eraname";
677 $namesuffix = '';
678 for ($i = 1; is_file("$nameprefix$namesuffix.html"); ++$i) {
679 $namesuffix = "_$i";
682 $fnreport = "$nameprefix$namesuffix.html";
683 $fhreport = fopen($fnreport, 'w');
684 if (!$fhreport) {
685 die(xlt("Cannot create") . " '" . text($fnreport) . "'");
690 <html>
691 <head>
692 <link rel=stylesheet href="<?php echo $css_header;?>" type="text/css">
693 <style type="text/css">
694 body { font-family:sans-serif; font-size:8pt; font-weight:normal }
695 .dehead { color:#000000; font-family:sans-serif; font-size:9pt; font-weight:bold }
696 .olddetail { color:#000000; font-family:sans-serif; font-size:9pt; font-weight:normal }
697 .newdetail { color:#00dd00; font-family:sans-serif; font-size:9pt; font-weight:normal }
698 .errdetail { color:#dd0000; font-family:sans-serif; font-size:9pt; font-weight:normal }
699 .infdetail { color:#0000ff; font-family:sans-serif; font-size:9pt; font-weight:normal }
700 </style>
701 <title><?php echo xlt('EOB Posting - Electronic Remittances')?></title>
702 </head>
703 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
704 <form action="sl_eob_process.php" method="get" >
705 <input type="hidden" name="csrf_token_form" value="<?php echo attr(collectCsrfToken()); ?>" />
707 <center>
708 <?php
709 if ($_GET['original']=='original') {
710 $alertmsg = ParseERA::parse_era_for_check($GLOBALS['OE_SITE_DIR'] . "/documents/era/$eraname.edi", 'era_callback');
711 echo $StringToEcho;
712 } else {
714 <table border='0' cellpadding='2' cellspacing='0' width='100%'>
716 <tr bgcolor="#cccccc">
717 <td class="dehead">
718 <?php echo xlt('Patient'); ?>
719 </td>
720 <td class="dehead">
721 <?php echo xlt('Invoice'); ?>
722 </td>
723 <td class="dehead">
724 <?php echo xlt('Code'); ?>
725 </td>
726 <td class="dehead">
727 <?php echo xlt('Date'); ?>
728 </td>
729 <td class="dehead">
730 <?php echo xlt('Description'); ?>
731 </td>
732 <td class="dehead" align="right">
733 <?php echo xlt('Amount'); ?>&nbsp;
734 </td>
735 <td class="dehead" align="right">
736 <?php echo xl('Balance'); ?>&nbsp;
737 </td>
738 </tr>
740 <?php
741 global $InsertionId;
743 $eraname=$_REQUEST['eraname'];
744 $alertmsg = ParseERA::parse_era_for_check($GLOBALS['OE_SITE_DIR'] . "/documents/era/$eraname.edi");
745 $alertmsg = ParseERA::parse_era($GLOBALS['OE_SITE_DIR'] . "/documents/era/$eraname.edi", 'era_callback');
746 if (!$debug) {
747 $StringIssue=xl("Total Distribution for following check number is not full").': ';
748 $StringPrint='No';
749 foreach ($InsertionId as $key => $value) {
750 $rs= sqlQ("select pay_total from ar_session where session_id=?", array($value));
751 $row=sqlFetchArray($rs);
752 $pay_total=$row['pay_total'];
753 $rs= sqlQ("select sum(pay_amount) sum_pay_amount from ar_activity where session_id=?", array($value));
754 $row=sqlFetchArray($rs);
755 $pay_amount=$row['sum_pay_amount'];
757 if (($pay_total-$pay_amount)<>0) {
758 $StringIssue.=$key.' ';
759 $StringPrint='Yes';
763 if ($StringPrint=='Yes') {
764 echo "<script>alert(" . js_escape($StringIssue) . ")</script>";
770 </table>
771 <?php
774 </center>
775 <script language="JavaScript">
776 <?php
777 if ($alertmsg) {
778 echo " alert(" . js_escape($alertmsg) . ");\n";
781 </script>
782 <input type="hidden" name="paydate" value="<?php echo attr(DateToYYYYMMDD($_REQUEST['paydate'])); ?>" />
783 <input type="hidden" name="post_to_date" value="<?php echo attr(DateToYYYYMMDD($_REQUEST['post_to_date'])); ?>" />
784 <input type="hidden" name="deposit_date" value="<?php echo attr(DateToYYYYMMDD($_REQUEST['deposit_date'])); ?>" />
785 <input type="hidden" name="debug" value="<?php echo attr($_REQUEST['debug']); ?>" />
786 <input type="hidden" name="InsId" value="<?php echo attr($_REQUEST['InsId']); ?>" />
787 <input type="hidden" name="eraname" value="<?php echo attr($eraname); ?>" />
788 </form>
789 </body>
790 </html>
791 <?php
792 // Save all of this script's output to a report file.
793 if (!$debug) {
794 fwrite($fhreport, ob_get_contents());
795 fclose($fhreport);
798 ob_end_flush();