Merge branch 'master' of git://github.com/openemr/openemr
[openemr.git] / interface / billing / sl_eob_invoice.php
blob3c4750822c2d7777cfa48752a4c90e9e5a37d0a0
1 <?php
2 // Copyright (C) 2005-2010 Rod Roark <rod@sunsetsystems.com>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 // This provides for manual posting of EOBs. It is invoked from
10 // sl_eob_search.php. For automated (X12 835) remittance posting
11 // see sl_eob_process.php.
13 require_once("../globals.php");
14 require_once("$srcdir/log.inc");
15 require_once("$srcdir/patient.inc");
16 require_once("$srcdir/forms.inc");
17 require_once("$srcdir/sl_eob.inc.php");
18 require_once("$srcdir/invoice_summary.inc.php");
19 require_once("../../custom/code_types.inc.php");
21 $debug = 0; // set to 1 for debugging mode
23 $INTEGRATED_AR = $GLOBALS['oer_config']['ws_accounting']['enabled'] === 2;
25 // If we permit deletion of transactions. Might change this later.
26 $ALLOW_DELETE = $INTEGRATED_AR;
28 $info_msg = "";
30 // Format money for display.
32 function bucks($amount) {
33 if ($amount)
34 printf("%.2f", $amount);
37 // Delete rows, with logging, for the specified table using the
38 // specified WHERE clause. Borrowed from deleter.php.
40 function row_delete($table, $where) {
41 $tres = sqlStatement("SELECT * FROM $table WHERE $where");
42 $count = 0;
43 while ($trow = sqlFetchArray($tres)) {
44 $logstring = "";
45 foreach ($trow as $key => $value) {
46 if (! $value || $value == '0000-00-00 00:00:00') continue;
47 if ($logstring) $logstring .= " ";
48 $logstring .= $key . "='" . addslashes($value) . "'";
50 newEvent("delete", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "$table: $logstring");
51 ++$count;
53 if ($count) {
54 $query = "DELETE FROM $table WHERE $where";
55 echo $query . "<br>\n";
56 sqlStatement($query);
60 <html>
61 <head>
62 <?php html_header_show(); ?>
63 <link rel=stylesheet href="<?php echo $css_header;?>" type="text/css">
64 <title><?php xl('EOB Posting - Invoice','e')?></title>
65 <script language="JavaScript">
67 // An insurance radio button is selected.
68 function setins(istr) {
69 <?php if (!$INTEGRATED_AR) { ?>
70 var f = document.forms[0];
71 for (var i = 0; i < f.elements.length; ++i) {
72 var ename = f.elements[i].name;
73 if (ename.indexOf('[src]') < 0) continue;
74 var evalue = f.elements[i].value;
75 var tmp = evalue.substring(0, 4).toLowerCase();
76 if (tmp >= 'ins1' && tmp <= 'ins3')
77 evalue = evalue.substring(4);
78 else if (evalue.substring(0, 2).toLowerCase() == 'pt')
79 evalue = evalue.substring(2);
80 while (evalue.substring(0, 1) == '/')
81 evalue = evalue.substring(1);
82 f.elements[i].value = istr + '/' + evalue;
84 <?php } ?>
85 return true;
88 // Compute an adjustment that writes off the balance:
89 function writeoff(code) {
90 var f = document.forms[0];
91 var belement = f['form_line[' + code + '][bal]'];
92 var pelement = f['form_line[' + code + '][pay]'];
93 var aelement = f['form_line[' + code + '][adj]'];
94 var relement = f['form_line[' + code + '][reason]'];
95 var tmp = belement.value - pelement.value;
96 aelement.value = Number(tmp).toFixed(2);
97 if (aelement.value && ! relement.value) relement.selectedIndex = 1;
98 return false;
101 // Onsubmit handler. A good excuse to write some JavaScript.
102 function validate(f) {
103 var delcount = 0;
104 for (var i = 0; i < f.elements.length; ++i) {
105 var ename = f.elements[i].name;
106 // Count deletes.
107 if (ename.substring(0, 9) == 'form_del[') {
108 if (f.elements[i].checked) ++delcount;
109 continue;
111 var pfxlen = ename.indexOf('[pay]');
112 if (pfxlen < 0) continue;
113 var pfx = ename.substring(0, pfxlen);
114 var code = pfx.substring(pfx.indexOf('[')+1, pfxlen-1);
115 if (f[pfx+'[pay]'].value || f[pfx+'[adj]'].value) {
116 <?php if (!$INTEGRATED_AR) { // source validation not appropriate ?>
117 var srcobj = f[pfx+'[src]'];
118 while (srcobj.value.length) {
119 var tmp = srcobj.value.substring(srcobj.value.length - 1);
120 if (tmp > ' ' && tmp != '/') break;
121 srcobj.value = srcobj.value.substring(0, srcobj.value.length - 1);
123 var svalue = srcobj.value;
124 if (! svalue) {
125 alert('<?php xl('Source is missing for code ','e') ?>' + code);
126 return false;
127 } else {
128 var tmp = svalue.substring(0, 4).toLowerCase();
129 if (tmp >= 'ins1' && tmp <= 'ins3') {
130 svalue = svalue.substring(4);
131 } else if (svalue.substring(0, 2).toLowerCase() == 'pt') {
132 svalue = svalue.substring(2);
133 } else {
134 alert('<?php xl('Invalid or missing payer in source for code ','e')?>' + code);
135 return false;
137 if (svalue) {
138 if (svalue.substring(0, 1) != '/') {
139 alert('<?php xl('Missing slash after payer in source for code ','e')?>' + code);
140 return false;
142 if (false) { // Please keep this, Oakland Clinic wants it. -- Rod
143 tmp = svalue.substring(1, 3).toLowerCase();
144 if (tmp != 'nm' && tmp != 'ci' && tmp != 'cp' && tmp != 'ne' &&
145 tmp != 'it' && tmp != 'pf' && tmp != 'pp' && tmp != 'ok')
147 alert('<?php xl('Invalid source designation "','e') ?>' + tmp + '<?php xl('" for code ','e') ?>' + code);
148 return false;
150 } // End of OC code
153 <?php } ?>
154 if (! f[pfx+'[date]'].value) {
155 alert('<?php xl('Date is missing for code ','e')?>' + code);
156 return false;
159 if (f[pfx+'[pay]'].value && isNaN(parseFloat(f[pfx+'[pay]'].value))) {
160 alert('<?php xl('Payment value for code ','e') ?>' + code + '<?php xl(' is not a number','e') ?>');
161 return false;
163 if (f[pfx+'[adj]'].value && isNaN(parseFloat(f[pfx+'[adj]'].value))) {
164 alert('<?php xl('Adjustment value for code ','e') ?>' + code + '<?php xl(' is not a number','e') ?>');
165 return false;
167 if (f[pfx+'[adj]'].value && ! f[pfx+'[reason]'].value) {
168 alert('<?php xl('Please select an adjustment reason for code ','e') ?>' + code);
169 return false;
171 // TBD: validate the date format
173 // Demand confirmation if deleting anything.
174 if (delcount > 0) {
175 if (!confirm('<?php echo xl('Really delete'); ?> ' + delcount +
176 ' <?php echo xl('transactions'); ?>?' +
177 ' <?php echo xl('This action will be logged'); ?>!')
178 ) return false;
180 return true;
183 <!-- Get current date -->
185 function getFormattedToday()
187 var today = new Date();
188 var dd = today.getDate();
189 var mm = today.getMonth()+1; //January is 0!
190 var yyyy = today.getFullYear();
191 if(dd<10){dd='0'+dd}
192 if(mm<10){mm='0'+mm}
194 return (yyyy + '-' + mm + '-' + dd);
197 <!-- Update Payment Fields -->
199 function updateFields(payField, adjField, balField, coPayField, isFirstProcCode)
201 var payAmount = 0.0;
202 var adjAmount = 0.0;
203 var balAmount = 0.0;
204 var coPayAmount = 0.0;
206 // coPayFiled will be null if there is no co-pay entry in the fee sheet
207 if (coPayField)
208 coPayAmount = coPayField.value;
210 // if balance field is 0.00, its value comes back as null, so check for nul-ness first
211 if (balField)
212 balAmount = (balField.value) ? balField.value : 0;
213 if (payField)
214 payAmount = (payField.value) ? payField.value : 0;
216 //alert('balance = >' + balAmount +'< payAmount = ' + payAmount + ' copay = ' + coPayAmount + ' isFirstProcCode = ' + isFirstProcCode);
218 // subtract the co-pay only from the first procedure code
219 if (isFirstProcCode == 1)
220 balAmount = parseFloat(balAmount) + parseFloat(coPayAmount);
222 adjAmount = balAmount - payAmount;
224 // Assign rounded adjustment value back to TextField
225 adjField.value = adjAmount = Math.round(adjAmount*100)/100;
228 </script>
229 </head>
230 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
231 <?php
232 $trans_id = 0 + $_GET['id'];
233 if (! $trans_id) die(xl("You cannot access this page directly."));
235 if ($INTEGRATED_AR) {
236 // In the Integrated A/R case, $trans_id matches form_encounter.id.
237 $ferow = sqlQuery("SELECT e.*, p.fname, p.mname, p.lname " .
238 "FROM form_encounter AS e, patient_data AS p WHERE " .
239 "e.id = '$trans_id' AND p.pid = e.pid");
240 if (empty($ferow)) die("There is no encounter with form_encounter.id = '$trans_id'.");
241 $patient_id = 0 + $ferow['pid'];
242 $encounter_id = 0 + $ferow['encounter'];
243 $svcdate = substr($ferow['date'], 0, 10);
244 $form_payer_id = 0 + $_POST['form_payer_id'];
245 $form_reference = $_POST['form_reference'];
246 $form_check_date = fixDate($_POST['form_check_date'], date('Y-m-d'));
247 $form_deposit_date = fixDate($_POST['form_deposit_date'], $form_check_date);
248 $form_pay_total = 0 + $_POST['form_pay_total'];
250 else {
251 slInitialize();
254 $payer_type = 0;
255 if (preg_match('/^Ins(\d)/i', $_POST['form_insurance'], $matches)) {
256 $payer_type = $matches[1];
259 if ($_POST['form_save'] || $_POST['form_cancel']) {
260 if ($_POST['form_save']) {
261 if ($debug) {
262 echo xl("This module is in test mode. The database will not be changed.",'','<p><b>',"</b><p>\n");
265 if ($INTEGRATED_AR) {
266 $session_id = arGetSession($form_payer_id, $form_reference,
267 $form_check_date, $form_deposit_date, $form_pay_total);
268 // The sl_eob_search page needs its invoice links modified to invoke
269 // javascript to load form parms for all the above and submit.
270 // At the same time that page would be modified to work off the
271 // openemr database exclusively.
272 // And back to the sl_eob_invoice page, I think we may want to move
273 // the source input fields from row level to header level.
275 // Handle deletes. row_delete() is borrowed from deleter.php.
276 if ($ALLOW_DELETE && !$debug) {
277 foreach ($_POST['form_del'] as $arseq => $dummy) {
278 row_delete("ar_activity", "pid = '$patient_id' AND " .
279 "encounter = '$encounter_id' AND sequence_no = '$arseq'");
284 $paytotal = 0;
285 foreach ($_POST['form_line'] as $code => $cdata) {
286 if (!$INTEGRATED_AR) {
287 $thissrc = trim($cdata['src']);
288 $thisdate = trim($cdata['date']);
290 $thispay = trim($cdata['pay']);
291 $thisadj = trim($cdata['adj']);
292 $thisins = trim($cdata['ins']);
293 $reason = trim($cdata['reason']);
294 if (strpos(strtolower($reason), 'ins') !== false)
295 $reason .= ' ' . $_POST['form_insurance'];
296 if (! $thisins) $thisins = 0;
298 if ($thispay) {
299 if ($INTEGRATED_AR) {
300 arPostPayment($patient_id, $encounter_id, $session_id,
301 $thispay, $code, $payer_type, $reason, $debug);
302 } else {
303 slPostPayment($trans_id, $thispay, $thisdate, $thissrc, $code, $thisins, $debug);
305 $paytotal += $thispay;
308 // Be sure to record adjustment reasons even for zero adjustments.
309 if ($thisadj || $reason) {
310 // "To copay" and "To ded'ble" need to become a comment in a zero
311 // adjustment, formatted just like sl_eob_process.php.
312 if (preg_match("/To copay/", $reason)) {
313 $reason = $_POST['form_insurance'] . " coins: $thisadj";
314 $thisadj = 0;
316 else if (preg_match("/To ded'ble/", $reason)) {
317 $reason = $_POST['form_insurance'] . " dedbl: $thisadj";
318 $thisadj = 0;
320 if ($INTEGRATED_AR) {
321 arPostAdjustment($patient_id, $encounter_id, $session_id,
322 $thisadj, $code, $payer_type, $reason, $debug);
323 } else {
324 slPostAdjustment($trans_id, $thisadj, $thisdate, $thissrc, $code, $thisins, $reason, $debug);
329 // Maintain which insurances are marked as finished.
331 if ($INTEGRATED_AR) {
332 $form_done = 0 + $_POST['form_done'];
333 $form_stmt_count = 0 + $_POST['form_stmt_count'];
334 sqlStatement("UPDATE form_encounter " .
335 "SET last_level_closed = $form_done, " .
336 "stmt_count = $form_stmt_count WHERE " .
337 "pid = '$patient_id' AND encounter = '$encounter_id'");
339 else {
340 $form_duedate = fixDate($_POST['form_duedate']);
341 $form_notes = trim($_POST['form_notes']);
342 // We use the "Ship Via" field of the invoice to hold these.
343 $form_eobs = "";
344 foreach (array('Ins1', 'Ins2', 'Ins3') as $value) {
345 if ($_POST["form_done_$value"]) {
346 if ($form_eobs) $form_eobs .= ","; else $form_eobs = "Done: ";
347 $form_eobs .= $value;
350 $query = "UPDATE ar SET duedate = '$form_duedate', notes = '$form_notes', " .
351 "shipvia = '$form_eobs' WHERE id = $trans_id";
352 if ($debug) {
353 echo $query . "<br>\n";
354 } else {
355 SLQuery($query);
356 if ($sl_err) die($sl_err);
360 if ($_POST['form_secondary']) {
361 if ($INTEGRATED_AR) {
362 arSetupSecondary($patient_id, $encounter_id, $debug);
363 } else {
364 slSetupSecondary($trans_id, $debug);
368 echo "<script language='JavaScript'>\n";
369 echo " if (opener.document.forms[0].form_amount) {\n";
370 echo " var tmp = opener.document.forms[0].form_amount.value - $paytotal;\n";
371 echo " opener.document.forms[0].form_amount.value = Number(tmp).toFixed(2);\n";
372 echo " }\n";
373 } else {
374 echo "<script language='JavaScript'>\n";
376 if ($info_msg) echo " alert('$info_msg');\n";
377 if (! $debug) echo " window.close();\n";
378 echo "</script></body></html>\n";
379 if (!$INTEGRATED_AR) SLClose();
380 exit();
383 if ($INTEGRATED_AR) {
384 // Get invoice charge details.
385 $codes = ar_get_invoice_summary($patient_id, $encounter_id, true);
387 else {
388 // Get invoice data into $arrow.
389 $arres = SLQuery("select ar.*, customer.name, employee.name as doctor " .
390 "from ar, customer, employee where ar.id = $trans_id and " .
391 "customer.id = ar.customer_id and employee.id = ar.employee_id");
392 if ($sl_err) die($sl_err);
393 $arrow = SLGetRow($arres, 0);
394 if (! $arrow) die(xl("There is no match for invoice id = ") . $trans_id);
396 // Determine the date of service. An 8-digit encounter number is
397 // presumed to be a date of service imported during conversion.
398 // Otherwise look it up in the form_encounter table.
400 $svcdate = "";
401 list($patient_id, $encounter) = explode(".", $arrow['invnumber']);
402 if (strlen($encounter) == 8) {
403 $svcdate = substr($encounter, 0, 4) . "-" . substr($encounter, 4, 2) .
404 "-" . substr($encounter, 6, 2);
406 else if ($encounter) {
407 $tmp = sqlQuery("SELECT date FROM form_encounter WHERE " .
408 "encounter = $encounter");
409 $svcdate = substr($tmp['date'], 0, 10);
412 // Get invoice charge details.
413 $codes = get_invoice_summary($trans_id, true);
416 $pdrow = sqlQuery("select genericname2, genericval2 " .
417 "from patient_data where pid = '$patient_id' limit 1");
419 <center>
421 <form method='post' action='sl_eob_invoice.php?id=<?php echo $trans_id ?>'
422 onsubmit='return validate(this)'>
424 <table border='0' cellpadding='3'>
425 <tr>
426 <td>
427 <?php xl('Patient:','e')?>
428 </td>
429 <td>
430 <?php
431 if ($INTEGRATED_AR) {
432 echo $ferow['fname'] . ' ' . $ferow['mname'] . ' ' . $ferow['lname'];
434 else {
435 echo $arrow['name'];
438 </td>
439 <td colspan="2" rowspan="3">
440 <?php
441 if ($INTEGRATED_AR) {
442 for ($i = 1; $i <= 3; ++$i) {
443 $payerid = arGetPayerID($patient_id, $svcdate, $i);
444 if ($payerid) {
445 $tmp = sqlQuery("SELECT name FROM insurance_companies WHERE id = $payerid");
446 echo "Ins$i: " . $tmp['name'] . "<br />";
450 else {
451 echo " <textarea name='form_notes' cols='50' style='height:100%'>";
452 echo $arrow['notes'];
453 echo "</textarea>\n";
456 </td>
457 <?php
458 if ($INTEGRATED_AR) {
459 echo "<td rowspan='3' valign='bottom'>\n";
460 echo xl('Statements Sent:');
461 echo "</td>\n";
462 echo "<td rowspan='3' valign='bottom'>\n";
463 echo "<input type='text' name='form_stmt_count' size='10' value='" .
464 (0 + $ferow['stmt_count']) . "' />\n";
465 echo "</td>\n";
468 </tr>
469 <tr>
470 <td>
471 <?php xl('Provider:','e')?>
472 </td>
473 <td>
474 <?php
475 if ($INTEGRATED_AR) {
476 $tmp = sqlQuery("SELECT fname, mname, lname " .
477 "FROM users WHERE id = " . $ferow['provider_id']);
478 echo $tmp['fname'] . ' ' . $tmp['mname'] . ' ' . $tmp['lname'];
479 $tmp = sqlQuery("SELECT bill_date FROM billing WHERE " .
480 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
481 "activity = 1 ORDER BY fee DESC, id ASC LIMIT 1");
482 $billdate = substr(($tmp['bill_date'] . "Not Billed"), 0, 10);
484 else {
485 echo $arrow['doctor'];
488 </td>
489 </tr>
490 <tr>
491 <td>
492 <?php xl('Invoice:','e')?>
493 </td>
494 <td>
495 <?php
496 if ($INTEGRATED_AR) {
497 echo "$patient_id.$encounter_id";
499 else {
500 echo $arrow['invnumber'];
503 </td>
504 </tr>
506 <tr>
507 <td>
508 <?php xl('Svc Date:','e'); ?>
509 </td>
510 <td>
511 <?php
512 echo $svcdate;
514 </td>
515 <td colspan="2">
516 <?php xl('Done with:','e','',"&nbsp")?>;
517 <?php
518 // Write a checkbox for each insurance. It is to be checked when
519 // we no longer expect any payments from that company for the claim.
520 if ($INTEGRATED_AR) {
521 $last_level_closed = 0 + $ferow['last_level_closed'];
522 foreach (array(0 => 'None', 1 => 'Ins1', 2 => 'Ins2', 3 => 'Ins3') as $key => $value) {
523 if ($key && !arGetPayerID($patient_id, $svcdate, $key)) continue;
524 $checked = ($last_level_closed == $key) ? " checked" : "";
525 echo " <input type='radio' name='form_done' value='$key'$checked />$value&nbsp;\n";
528 else {
529 // The information is stored in the 'shipvia' field of the invoice.
530 $insgot = strtolower($arrow['notes']);
531 $insdone = strtolower($arrow['shipvia']);
532 foreach (array('Ins1', 'Ins2', 'Ins3') as $value) {
533 $lcvalue = strtolower($value);
534 $checked = (strpos($insdone, $lcvalue) === false) ? "" : " checked";
535 if (strpos($insgot, $lcvalue) !== false) {
536 echo " <input type='checkbox' name='form_done_$value' value='1'$checked />$value&nbsp;\n";
541 </td>
542 <?php
543 if ($INTEGRATED_AR) {
544 echo "<td>\n";
545 echo xl('Check/EOB No.:');
546 echo "</td>\n";
547 echo "<td>\n";
548 echo "<input type='text' name='form_reference' size='10' value='' />\n";
549 echo "</td>\n";
552 </tr>
554 <tr>
555 <td>
556 <?php xl('Last Bill Date:','e') ?>
557 </td>
558 <td>
559 <?php
560 if ($INTEGRATED_AR) {
561 echo $billdate;
563 else {
564 echo $arrow['transdate'];
567 </td>
568 <td colspan="2">
569 <?php xl('Now posting for:','e','',"&nbsp")?>;
571 <?php
572 // TBD: check the first not-done-with insurance, not always Ins1!
574 <input type='radio' name='form_insurance' value='Ins1' onclick='setins("Ins1")' checked /><?php xl('Ins1','e')?>&nbsp;
575 <input type='radio' name='form_insurance' value='Ins2' onclick='setins("Ins2")' /><?php xl('Ins2','e')?>&nbsp;
576 <input type='radio' name='form_insurance' value='Ins3' onclick='setins("Ins3")' /><?php xl('Ins3','e')?>&nbsp;
577 <input type='radio' name='form_insurance' value='Pt' onclick='setins("Pt")' /><?php xl('Patient','e')?>
579 <?php
580 // TBD: I think the following is unused and can be removed.
582 <input type='hidden' name='form_eobs' value='<?php echo addslashes($arrow['shipvia']) ?>' />
584 </td>
585 <?php
586 if ($INTEGRATED_AR) {
587 echo "<td>\n";
588 echo xl('Check/EOB Date:');
589 echo "</td>\n";
590 echo "<td>\n";
591 echo "<input type='text' name='form_check_date' size='10' value='' />\n";
592 echo "</td>\n";
595 </tr>
596 <tr>
597 <td>
598 <?php
599 if (!$INTEGRATED_AR) xl('Due Date:','e');
601 </td>
602 <td>
604 <?php if (!$INTEGRATED_AR) { ?>
605 <input type='text' name='form_duedate' size='10' value='<?php echo $arrow['duedate'] ?>'
606 title='<?php xl('Due date mm/dd/yyyy or yyyy-mm-dd','e')?>'>
607 <?php } ?>
608 </td>
609 <td colspan="2">
610 <input type="checkbox" name="form_secondary" value="1"> <?php xl('Needs secondary billing','e')?>
611 &nbsp;&nbsp;
612 <input type='submit' name='form_save' value='<?php xl('Save','e')?>'>
613 &nbsp;
614 <input type='button' value='<?php xl('Cancel','e')?>' onclick='window.close()'>
615 </td>
616 <?php
617 if ($INTEGRATED_AR) {
618 echo "<td>\n";
619 echo xl('Deposit Date:');
620 echo "</td>\n";
621 echo "<td>\n";
622 echo "<input type='text' name='form_deposit_date' size='10' value='' />\n";
623 echo "<input type='hidden' name='form_payer_id' value='' />\n";
624 echo "<input type='hidden' name='form_orig_reference' value='' />\n";
625 echo "<input type='hidden' name='form_orig_check_date' value='' />\n";
626 echo "<input type='hidden' name='form_orig_deposit_date' value='' />\n";
627 echo "<input type='hidden' name='form_pay_total' value='' />\n";
628 echo "</td>\n";
631 </tr>
632 <?php if ($pdrow['genericname2'] == 'Billing') { ?>
633 <tr>
634 <td>
635 <?php xl('Billing Note:','e')?>
636 </td>
637 <td colspan='3' style='color:red'>
638 <?php echo $pdrow['genericval2'] ?>
639 </td>
640 </tr>
641 <?php } ?>
642 <tr>
643 <td height="1">
644 </td>
645 </tr>
646 </table>
648 <table border='0' cellpadding='2' cellspacing='0' width='98%'>
650 <tr bgcolor="#cccccc">
651 <td class="dehead">
652 <?php xl('Code','e')?>
653 </td>
654 <td class="dehead" align="right">
655 <?php xl('Charge','e')?>
656 </td>
657 <td class="dehead" align="right">
658 <?php xl('Balance','e')?>&nbsp;
659 </td>
660 <td class="dehead">
661 <?php xl('By/Source','e')?>
662 </td>
663 <td class="dehead">
664 <?php xl('Date','e')?>
665 </td>
666 <td class="dehead">
667 <?php xl('Pay','e')?>
668 </td>
669 <td class="dehead">
670 <?php xl('Adjust','e')?>
671 </td>
672 <td class="dehead">
673 <?php xl('Reason','e')?>
674 </td>
675 <?php if ($ALLOW_DELETE) { ?>
676 <td class="dehead">
677 <?php xl('Del','e')?>
678 </td>
679 <?php } ?>
680 </tr>
681 <?php
682 $firstProcCodeIndex = -1;
683 $encount = 0;
684 foreach ($codes as $code => $cdata) {
685 ++$encount;
686 $bgcolor = "#" . (($encount & 1) ? "ddddff" : "ffdddd");
687 $dispcode = $code;
689 // remember the index of the first entry whose code is not "CO-PAY", i.e. it's a legitimate proc code
690 if ($firstProcCodeIndex == -1 && strcmp($code, "CO-PAY") !=0)
691 $firstProcCodeIndex = $encount;
693 // this sorts the details more or less chronologically:
694 ksort($cdata['dtl']);
695 foreach ($cdata['dtl'] as $dkey => $ddata) {
696 $ddate = substr($dkey, 0, 10);
697 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
698 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
700 $tmpchg = "";
701 $tmpadj = "";
702 /*****************************************************************
703 if ($ddata['chg'] > 0)
704 $tmpchg = $ddata['chg'];
705 else if ($ddata['chg'] < 0)
706 $tmpadj = 0 - $ddata['chg'];
707 *****************************************************************/
708 if ($ddata['chg'] != 0) {
709 if (isset($ddata['rsn'])) $tmpadj = 0 - $ddata['chg'];
710 else $tmpchg = $ddata['chg'];
713 <tr bgcolor='<?php echo $bgcolor ?>'>
714 <td class="detail">
715 <?php echo $dispcode; $dispcode = "" ?>
716 </td>
717 <td class="detail" align="right">
718 <?php bucks($tmpchg) ?>
719 </td>
720 <td class="detail" align="right">
721 &nbsp;
722 </td>
723 <td class="detail">
724 <?php
725 if (isset($ddata['plv'])) {
726 if (!$ddata['plv']) echo 'Pt/';
727 else echo 'Ins' . $ddata['plv'] . '/';
729 echo $ddata['src'];
731 </td>
732 <td class="detail">
733 <?php echo $ddate ?>
734 </td>
735 <td class="detail">
736 <?php bucks($ddata['pmt']) ?>
737 </td>
738 <td class="detail">
739 <?php bucks($tmpadj) ?>
740 </td>
741 <td class="detail">
742 <?php echo $ddata['rsn'] ?>
743 </td>
744 <?php if ($ALLOW_DELETE) { ?>
745 <td class="detail">
746 <?php if (!empty($ddata['arseq'])) { ?>
747 <input type="checkbox" name="form_del[<?php echo $ddata['arseq']; ?>]" />
748 <?php } else { ?>
749 &nbsp;
750 <?php } ?>
751 </td>
752 <?php } ?>
753 </tr>
754 <?php
755 } // end of prior detail line
757 <tr bgcolor='<?php echo $bgcolor ?>'>
758 <td class="detail">
759 <?php echo $dispcode; $dispcode = "" ?>
760 </td>
761 <td class="detail" align="right">
762 &nbsp;
763 </td>
764 <td class="detail" align="right">
765 <input type="hidden" name="form_line[<?php echo $code ?>][bal]" value="<?php bucks($cdata['bal']) ?>">
766 <input type="hidden" name="form_line[<?php echo $code ?>][ins]" value="<?php echo $cdata['ins'] ?>">
767 <?php printf("%.2f", $cdata['bal']) ?>&nbsp;
768 </td>
769 <td class="detail">
771 <?php if (!$INTEGRATED_AR) { ?>
772 <input type="text" name="form_line[<?php echo $code ?>][src]" size="10"
773 style="background-color:<?php echo $bgcolor ?>" />
774 <!-- title="NM=notmet, CI=coins, CP=copay, NE=notelig, IT=insterm, PF=ptfull, PP=ptpart" -->
775 <?php } ?>
777 </td>
778 <td class="detail">
780 <?php if (!$INTEGRATED_AR) { ?>
781 <input type="text" name="form_line[<?php echo $code ?>][date]" size="10"
782 style="background-color:<?php echo $bgcolor ?>" />
783 <?php } ?>
785 </td>
786 <td class="detail">
787 <input type="text" name="form_line[<?php echo $code ?>][pay]" size="10"
788 style="background-color:<?php echo $bgcolor ?>"
789 onKeyUp="updateFields(document.forms[0]['form_line[<?php echo $code ?>][pay]'],
790 document.forms[0]['form_line[<?php echo $code ?>][adj]'],
791 document.forms[0]['form_line[<?php echo $code ?>][bal]'],
792 document.forms[0]['form_line[CO-PAY][bal]'],
793 <?php echo ($firstProcCodeIndex == $encount) ? 1 : 0 ?>)"/>
794 </td>
795 <td class="detail">
796 <input type="text" name="form_line[<?php echo $code ?>][adj]" size="10"
797 value='<?php echo $totalAdjAmount ?>'
798 style="background-color:<?php echo $bgcolor ?>" />
799 &nbsp; <a href="" onclick="return writeoff('<?php echo $code ?>')">W</a>
800 </td>
801 <td class="detail">
802 <select name="form_line[<?php echo $code ?>][reason]"
803 style="background-color:<?php echo $bgcolor ?>">
804 <?php
805 // Adjustment reasons are now taken from the list_options table.
806 echo " <option value=''></option>\n";
807 $ores = sqlStatement("SELECT option_id, title FROM list_options " .
808 "WHERE list_id = 'adjreason' ORDER BY seq, title");
809 while ($orow = sqlFetchArray($ores)) {
810 echo " <option value='" . addslashes($orow['option_id']) . "'";
811 echo ">" . $orow['title'] . "</option>\n";
814 </select>
815 <?php
816 // TBD: Maybe a comment field would be good here, for appending
817 // to the reason.
819 </td>
821 <?php if ($ALLOW_DELETE) { ?>
822 <td class="detail">
823 &nbsp;
824 </td>
825 <?php } ?>
827 </tr>
828 <?php
829 } // end of code
830 if (!$INTEGRATED_AR) SLClose();
833 </table>
834 </form>
835 </center>
836 <script language="JavaScript">
837 var f1 = opener.document.forms[0];
838 var f2 = document.forms[0];
839 if (f1.form_source) {
840 <?php
841 if ($INTEGRATED_AR) {
842 // These support creation and lookup of ar_session table entries:
843 echo " f2.form_reference.value = f1.form_source.value;\n";
844 echo " f2.form_check_date.value = f1.form_paydate.value;\n";
845 echo " //f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
846 echo " if (f1.form_deposit_date.value != '')\n";
847 echo " f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
848 echo " else\n";
849 echo " f2.form_deposit_date.value = getFormattedToday();\n";
850 echo " f2.form_payer_id.value = f1.form_payer_id.value;\n";
851 echo " f2.form_pay_total.value = f1.form_amount.value;\n";
852 echo " f2.form_orig_reference.value = f1.form_source.value;\n";
853 echo " f2.form_orig_check_date.value = f1.form_paydate.value;\n";
854 echo " f2.form_orig_deposit_date.value = f1.form_deposit_date.value;\n";
856 // While I'm thinking about it, some notes about eob sessions.
857 // If they do not have all of the session key fields in the search
858 // page, then show a warning at the top of the invoice page.
859 // Also when they go to save the invoice page and a session key
860 // field has changed, alert them to that and allow a cancel.
862 // Another point... when posting EOBs, the incoming payer ID might
863 // not match the payer ID for the patient's insurance. This is
864 // because the same payer might be entered more than once into the
865 // insurance_companies table. I don't think it matters much.
867 else {
868 foreach ($codes as $code => $cdata) {
869 echo " f2['form_line[$code][src]'].value = f1.form_source.value;\n";
870 echo " f2['form_line[$code][date]'].value = f1.form_paydate.value;\n";
875 setins("Ins1");
876 </script>
877 </body>
878 </html>