Added a code_type column and support for it to the ar_activity sql table, take 4.
[openemr.git] / interface / billing / sl_eob_invoice.php
blob013f32be5bf8cda224a3247d9bd12a65bb6e6e23
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");
20 require_once("$srcdir/formdata.inc.php");
22 $debug = 0; // set to 1 for debugging mode
24 $INTEGRATED_AR = $GLOBALS['oer_config']['ws_accounting']['enabled'] === 2;
26 // If we permit deletion of transactions. Might change this later.
27 $ALLOW_DELETE = $INTEGRATED_AR;
29 $info_msg = "";
31 // Format money for display.
33 function bucks($amount) {
34 if ($amount)
35 printf("%.2f", $amount);
38 // Delete rows, with logging, for the specified table using the
39 // specified WHERE clause. Borrowed from deleter.php.
41 function row_delete($table, $where) {
42 $tres = sqlStatement("SELECT * FROM $table WHERE $where");
43 $count = 0;
44 while ($trow = sqlFetchArray($tres)) {
45 $logstring = "";
46 foreach ($trow as $key => $value) {
47 if (! $value || $value == '0000-00-00 00:00:00') continue;
48 if ($logstring) $logstring .= " ";
49 $logstring .= $key . "='" . addslashes($value) . "'";
51 newEvent("delete", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "$table: $logstring");
52 ++$count;
54 if ($count) {
55 $query = "DELETE FROM $table WHERE $where";
56 echo $query . "<br>\n";
57 sqlStatement($query);
61 <html>
62 <head>
63 <?php html_header_show(); ?>
64 <link rel=stylesheet href="<?php echo $css_header;?>" type="text/css">
65 <title><?php xl('EOB Posting - Invoice','e')?></title>
66 <script language="JavaScript">
68 // An insurance radio button is selected.
69 function setins(istr) {
70 <?php if (!$INTEGRATED_AR) { ?>
71 var f = document.forms[0];
72 for (var i = 0; i < f.elements.length; ++i) {
73 var ename = f.elements[i].name;
74 if (ename.indexOf('[src]') < 0) continue;
75 var evalue = f.elements[i].value;
76 var tmp = evalue.substring(0, 4).toLowerCase();
77 if (tmp >= 'ins1' && tmp <= 'ins3')
78 evalue = evalue.substring(4);
79 else if (evalue.substring(0, 2).toLowerCase() == 'pt')
80 evalue = evalue.substring(2);
81 while (evalue.substring(0, 1) == '/')
82 evalue = evalue.substring(1);
83 f.elements[i].value = istr + '/' + evalue;
85 <?php } ?>
86 return true;
89 // Compute an adjustment that writes off the balance:
90 function writeoff(code) {
91 var f = document.forms[0];
92 var belement = f['form_line[' + code + '][bal]'];
93 var pelement = f['form_line[' + code + '][pay]'];
94 var aelement = f['form_line[' + code + '][adj]'];
95 var relement = f['form_line[' + code + '][reason]'];
96 var tmp = belement.value - pelement.value;
97 aelement.value = Number(tmp).toFixed(2);
98 if (aelement.value && ! relement.value) relement.selectedIndex = 1;
99 return false;
102 // Onsubmit handler. A good excuse to write some JavaScript.
103 function validate(f) {
104 var delcount = 0;
105 for (var i = 0; i < f.elements.length; ++i) {
106 var ename = f.elements[i].name;
107 // Count deletes.
108 if (ename.substring(0, 9) == 'form_del[') {
109 if (f.elements[i].checked) ++delcount;
110 continue;
112 var pfxlen = ename.indexOf('[pay]');
113 if (pfxlen < 0) continue;
114 var pfx = ename.substring(0, pfxlen);
115 var code = pfx.substring(pfx.indexOf('[')+1, pfxlen-1);
116 if (f[pfx+'[pay]'].value || f[pfx+'[adj]'].value) {
117 <?php if (!$INTEGRATED_AR) { // source validation not appropriate ?>
118 var srcobj = f[pfx+'[src]'];
119 while (srcobj.value.length) {
120 var tmp = srcobj.value.substring(srcobj.value.length - 1);
121 if (tmp > ' ' && tmp != '/') break;
122 srcobj.value = srcobj.value.substring(0, srcobj.value.length - 1);
124 var svalue = srcobj.value;
125 if (! svalue) {
126 alert('<?php xl('Source is missing for code ','e') ?>' + code);
127 return false;
128 } else {
129 var tmp = svalue.substring(0, 4).toLowerCase();
130 if (tmp >= 'ins1' && tmp <= 'ins3') {
131 svalue = svalue.substring(4);
132 } else if (svalue.substring(0, 2).toLowerCase() == 'pt') {
133 svalue = svalue.substring(2);
134 } else {
135 alert('<?php xl('Invalid or missing payer in source for code ','e')?>' + code);
136 return false;
138 if (svalue) {
139 if (svalue.substring(0, 1) != '/') {
140 alert('<?php xl('Missing slash after payer in source for code ','e')?>' + code);
141 return false;
143 if (false) { // Please keep this, Oakland Clinic wants it. -- Rod
144 tmp = svalue.substring(1, 3).toLowerCase();
145 if (tmp != 'nm' && tmp != 'ci' && tmp != 'cp' && tmp != 'ne' &&
146 tmp != 'it' && tmp != 'pf' && tmp != 'pp' && tmp != 'ok')
148 alert('<?php xl('Invalid source designation "','e') ?>' + tmp + '<?php xl('" for code ','e') ?>' + code);
149 return false;
151 } // End of OC code
154 <?php } ?>
155 if (! f[pfx+'[date]'].value) {
156 alert('<?php xl('Date is missing for code ','e')?>' + code);
157 return false;
160 if (f[pfx+'[pay]'].value && isNaN(parseFloat(f[pfx+'[pay]'].value))) {
161 alert('<?php xl('Payment value for code ','e') ?>' + code + '<?php xl(' is not a number','e') ?>');
162 return false;
164 if (f[pfx+'[adj]'].value && isNaN(parseFloat(f[pfx+'[adj]'].value))) {
165 alert('<?php xl('Adjustment value for code ','e') ?>' + code + '<?php xl(' is not a number','e') ?>');
166 return false;
168 if (f[pfx+'[adj]'].value && ! f[pfx+'[reason]'].value) {
169 alert('<?php xl('Please select an adjustment reason for code ','e') ?>' + code);
170 return false;
172 // TBD: validate the date format
174 // Demand confirmation if deleting anything.
175 if (delcount > 0) {
176 if (!confirm('<?php echo xl('Really delete'); ?> ' + delcount +
177 ' <?php echo xl('transactions'); ?>?' +
178 ' <?php echo xl('This action will be logged'); ?>!')
179 ) return false;
181 return true;
184 <!-- Get current date -->
186 function getFormattedToday()
188 var today = new Date();
189 var dd = today.getDate();
190 var mm = today.getMonth()+1; //January is 0!
191 var yyyy = today.getFullYear();
192 if(dd<10){dd='0'+dd}
193 if(mm<10){mm='0'+mm}
195 return (yyyy + '-' + mm + '-' + dd);
198 <!-- Update Payment Fields -->
200 function updateFields(payField, adjField, balField, coPayField, isFirstProcCode)
202 var payAmount = 0.0;
203 var adjAmount = 0.0;
204 var balAmount = 0.0;
205 var coPayAmount = 0.0;
207 // coPayFiled will be null if there is no co-pay entry in the fee sheet
208 if (coPayField)
209 coPayAmount = coPayField.value;
211 // if balance field is 0.00, its value comes back as null, so check for nul-ness first
212 if (balField)
213 balAmount = (balField.value) ? balField.value : 0;
214 if (payField)
215 payAmount = (payField.value) ? payField.value : 0;
217 //alert('balance = >' + balAmount +'< payAmount = ' + payAmount + ' copay = ' + coPayAmount + ' isFirstProcCode = ' + isFirstProcCode);
219 // subtract the co-pay only from the first procedure code
220 if (isFirstProcCode == 1)
221 balAmount = parseFloat(balAmount) + parseFloat(coPayAmount);
223 adjAmount = balAmount - payAmount;
225 // Assign rounded adjustment value back to TextField
226 adjField.value = adjAmount = Math.round(adjAmount*100)/100;
229 </script>
230 </head>
231 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
232 <?php
233 $trans_id = 0 + $_GET['id'];
234 if (! $trans_id) die(xl("You cannot access this page directly."));
236 if ($INTEGRATED_AR) {
237 // In the Integrated A/R case, $trans_id matches form_encounter.id.
238 $ferow = sqlQuery("SELECT e.*, p.fname, p.mname, p.lname " .
239 "FROM form_encounter AS e, patient_data AS p WHERE " .
240 "e.id = '$trans_id' AND p.pid = e.pid");
241 if (empty($ferow)) die("There is no encounter with form_encounter.id = '$trans_id'.");
242 $patient_id = 0 + $ferow['pid'];
243 $encounter_id = 0 + $ferow['encounter'];
244 $svcdate = substr($ferow['date'], 0, 10);
245 $form_payer_id = 0 + $_POST['form_payer_id'];
246 $form_reference = $_POST['form_reference'];
247 $form_check_date = fixDate($_POST['form_check_date'], date('Y-m-d'));
248 $form_deposit_date = fixDate($_POST['form_deposit_date'], $form_check_date);
249 $form_pay_total = 0 + $_POST['form_pay_total'];
251 else {
252 slInitialize();
255 $payer_type = 0;
256 if (preg_match('/^Ins(\d)/i', $_POST['form_insurance'], $matches)) {
257 $payer_type = $matches[1];
260 if ($_POST['form_save'] || $_POST['form_cancel']) {
261 if ($_POST['form_save']) {
262 if ($debug) {
263 echo xl("This module is in test mode. The database will not be changed.",'','<p><b>',"</b><p>\n");
266 if ($INTEGRATED_AR) {
267 $session_id = arGetSession($form_payer_id, $form_reference,
268 $form_check_date, $form_deposit_date, $form_pay_total);
269 // The sl_eob_search page needs its invoice links modified to invoke
270 // javascript to load form parms for all the above and submit.
271 // At the same time that page would be modified to work off the
272 // openemr database exclusively.
273 // And back to the sl_eob_invoice page, I think we may want to move
274 // the source input fields from row level to header level.
276 // Handle deletes. row_delete() is borrowed from deleter.php.
277 if ($ALLOW_DELETE && !$debug) {
278 foreach ($_POST['form_del'] as $arseq => $dummy) {
279 row_delete("ar_activity", "pid = '$patient_id' AND " .
280 "encounter = '$encounter_id' AND sequence_no = '$arseq'");
285 $paytotal = 0;
286 foreach ($_POST['form_line'] as $code => $cdata) {
287 if (!$INTEGRATED_AR) {
288 $thissrc = trim($cdata['src']);
289 $thisdate = trim($cdata['date']);
291 $thispay = trim($cdata['pay']);
292 $thisadj = trim($cdata['adj']);
293 $thisins = trim($cdata['ins']);
294 $thiscodetype = trim($cdata['code_type']);
295 $reason = strip_escape_custom($cdata['reason']);
297 // Get the adjustment reason type. Possible values are:
298 // 1 = Charge adjustment
299 // 2 = Coinsurance
300 // 3 = Deductible
301 // 4 = Other pt resp
302 // 5 = Comment
303 $reason_type = '1';
304 if ($reason) {
305 $tmp = sqlQuery("SELECT option_value FROM list_options WHERE " .
306 "list_id = 'adjreason' AND " .
307 "option_id = '" . add_escape_custom($reason) . "'");
308 if (empty($tmp['option_value'])) {
309 // This should not happen but if it does, apply old logic.
310 if (preg_match("/To copay/", $reason)) {
311 $reason_type = 2;
313 else if (preg_match("/To ded'ble/", $reason)) {
314 $reason_type = 3;
316 $info_msg .= xl("No adjustment reason type found for") . " \"$reason\". ";
318 else {
319 $reason_type = $tmp['option_value'];
323 if (! $thisins) $thisins = 0;
325 if ($thispay) {
326 if ($INTEGRATED_AR) {
327 arPostPayment($patient_id, $encounter_id, $session_id,
328 $thispay, $code, $payer_type, '', $debug, '', $thiscodetype);
329 } else {
330 slPostPayment($trans_id, $thispay, $thisdate, $thissrc, $code, $thisins, $debug);
332 $paytotal += $thispay;
335 // Be sure to record adjustment reasons, even for zero adjustments if
336 // they happen to be comments.
337 if ($thisadj || ($reason && $reason_type == 5)) {
338 // "To copay" and "To ded'ble" need to become a comment in a zero
339 // adjustment, formatted just like sl_eob_process.php.
340 if ($reason_type == '2') {
341 $reason = $_POST['form_insurance'] . " coins: $thisadj";
342 $thisadj = 0;
344 else if ($reason_type == '3') {
345 $reason = $_POST['form_insurance'] . " dedbl: $thisadj";
346 $thisadj = 0;
348 else if ($reason_type == '4') {
349 $reason = $_POST['form_insurance'] . " ptresp: $thisadj $reason";
350 $thisadj = 0;
352 else if ($reason_type == '5') {
353 $reason = $_POST['form_insurance'] . " note: $thisadj $reason";
354 $thisadj = 0;
356 else {
357 // An adjustment reason including "Ins" is assumed to be assigned by
358 // insurance, and in that case we identify which one by appending
359 // Ins1, Ins2 or Ins3.
360 if (strpos(strtolower($reason), 'ins') !== false)
361 $reason .= ' ' . $_POST['form_insurance'];
363 if ($INTEGRATED_AR) {
364 arPostAdjustment($patient_id, $encounter_id, $session_id,
365 $thisadj, $code, $payer_type, $reason, $debug, '', $thiscodetype);
366 } else {
367 slPostAdjustment($trans_id, $thisadj, $thisdate, $thissrc, $code, $thisins, $reason, $debug);
372 // Maintain which insurances are marked as finished.
374 if ($INTEGRATED_AR) {
375 $form_done = 0 + $_POST['form_done'];
376 $form_stmt_count = 0 + $_POST['form_stmt_count'];
377 sqlStatement("UPDATE form_encounter " .
378 "SET last_level_closed = $form_done, " .
379 "stmt_count = $form_stmt_count WHERE " .
380 "pid = '$patient_id' AND encounter = '$encounter_id'");
382 else {
383 $form_duedate = fixDate($_POST['form_duedate']);
384 $form_notes = trim($_POST['form_notes']);
385 // We use the "Ship Via" field of the invoice to hold these.
386 $form_eobs = "";
387 foreach (array('Ins1', 'Ins2', 'Ins3') as $value) {
388 if ($_POST["form_done_$value"]) {
389 if ($form_eobs) $form_eobs .= ","; else $form_eobs = "Done: ";
390 $form_eobs .= $value;
393 $query = "UPDATE ar SET duedate = '$form_duedate', notes = '$form_notes', " .
394 "shipvia = '$form_eobs' WHERE id = $trans_id";
395 if ($debug) {
396 echo $query . "<br>\n";
397 } else {
398 SLQuery($query);
399 if ($sl_err) die($sl_err);
403 if ($_POST['form_secondary']) {
404 if ($INTEGRATED_AR) {
405 arSetupSecondary($patient_id, $encounter_id, $debug);
406 } else {
407 slSetupSecondary($trans_id, $debug);
411 echo "<script language='JavaScript'>\n";
412 echo " if (opener.document.forms[0].form_amount) {\n";
413 echo " var tmp = opener.document.forms[0].form_amount.value - $paytotal;\n";
414 echo " opener.document.forms[0].form_amount.value = Number(tmp).toFixed(2);\n";
415 echo " }\n";
416 } else {
417 echo "<script language='JavaScript'>\n";
419 if ($info_msg) echo " alert('" . addslashes($info_msg) . "');\n";
420 if (! $debug) echo " window.close();\n";
421 echo "</script></body></html>\n";
422 if (!$INTEGRATED_AR) SLClose();
423 exit();
426 if ($INTEGRATED_AR) {
427 // Get invoice charge details.
428 $codes = ar_get_invoice_summary($patient_id, $encounter_id, true);
430 else {
431 // Get invoice data into $arrow.
432 $arres = SLQuery("select ar.*, customer.name, employee.name as doctor " .
433 "from ar, customer, employee where ar.id = $trans_id and " .
434 "customer.id = ar.customer_id and employee.id = ar.employee_id");
435 if ($sl_err) die($sl_err);
436 $arrow = SLGetRow($arres, 0);
437 if (! $arrow) die(xl("There is no match for invoice id = ") . $trans_id);
439 // Determine the date of service. An 8-digit encounter number is
440 // presumed to be a date of service imported during conversion.
441 // Otherwise look it up in the form_encounter table.
443 $svcdate = "";
444 list($patient_id, $encounter) = explode(".", $arrow['invnumber']);
445 if (strlen($encounter) == 8) {
446 $svcdate = substr($encounter, 0, 4) . "-" . substr($encounter, 4, 2) .
447 "-" . substr($encounter, 6, 2);
449 else if ($encounter) {
450 $tmp = sqlQuery("SELECT date FROM form_encounter WHERE " .
451 "encounter = $encounter");
452 $svcdate = substr($tmp['date'], 0, 10);
455 // Get invoice charge details.
456 $codes = get_invoice_summary($trans_id, true);
459 $pdrow = sqlQuery("select genericname2, genericval2 " .
460 "from patient_data where pid = '$patient_id' limit 1");
462 <center>
464 <form method='post' action='sl_eob_invoice.php?id=<?php echo $trans_id ?>'
465 onsubmit='return validate(this)'>
467 <table border='0' cellpadding='3'>
468 <tr>
469 <td>
470 <?php xl('Patient:','e')?>
471 </td>
472 <td>
473 <?php
474 if ($INTEGRATED_AR) {
475 echo $ferow['fname'] . ' ' . $ferow['mname'] . ' ' . $ferow['lname'];
477 else {
478 echo $arrow['name'];
481 </td>
482 <td colspan="2" rowspan="3">
483 <?php
484 if ($INTEGRATED_AR) {
485 for ($i = 1; $i <= 3; ++$i) {
486 $payerid = arGetPayerID($patient_id, $svcdate, $i);
487 if ($payerid) {
488 $tmp = sqlQuery("SELECT name FROM insurance_companies WHERE id = $payerid");
489 echo "Ins$i: " . $tmp['name'] . "<br />";
493 else {
494 echo " <textarea name='form_notes' cols='50' style='height:100%'>";
495 echo $arrow['notes'];
496 echo "</textarea>\n";
499 </td>
500 <?php
501 if ($INTEGRATED_AR) {
502 echo "<td rowspan='3' valign='bottom'>\n";
503 echo xl('Statements Sent:');
504 echo "</td>\n";
505 echo "<td rowspan='3' valign='bottom'>\n";
506 echo "<input type='text' name='form_stmt_count' size='10' value='" .
507 (0 + $ferow['stmt_count']) . "' />\n";
508 echo "</td>\n";
511 </tr>
512 <tr>
513 <td>
514 <?php xl('Provider:','e')?>
515 </td>
516 <td>
517 <?php
518 if ($INTEGRATED_AR) {
519 $tmp = sqlQuery("SELECT fname, mname, lname " .
520 "FROM users WHERE id = " . $ferow['provider_id']);
521 echo $tmp['fname'] . ' ' . $tmp['mname'] . ' ' . $tmp['lname'];
522 $tmp = sqlQuery("SELECT bill_date FROM billing WHERE " .
523 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
524 "activity = 1 ORDER BY fee DESC, id ASC LIMIT 1");
525 $billdate = substr(($tmp['bill_date'] . "Not Billed"), 0, 10);
527 else {
528 echo $arrow['doctor'];
531 </td>
532 </tr>
533 <tr>
534 <td>
535 <?php xl('Invoice:','e')?>
536 </td>
537 <td>
538 <?php
539 if ($INTEGRATED_AR) {
540 echo "$patient_id.$encounter_id";
542 else {
543 echo $arrow['invnumber'];
546 </td>
547 </tr>
549 <tr>
550 <td>
551 <?php xl('Svc Date:','e'); ?>
552 </td>
553 <td>
554 <?php
555 echo $svcdate;
557 </td>
558 <td colspan="2">
559 <?php xl('Done with:','e','',"&nbsp")?>;
560 <?php
561 // Write a checkbox for each insurance. It is to be checked when
562 // we no longer expect any payments from that company for the claim.
563 if ($INTEGRATED_AR) {
564 $last_level_closed = 0 + $ferow['last_level_closed'];
565 foreach (array(0 => 'None', 1 => 'Ins1', 2 => 'Ins2', 3 => 'Ins3') as $key => $value) {
566 if ($key && !arGetPayerID($patient_id, $svcdate, $key)) continue;
567 $checked = ($last_level_closed == $key) ? " checked" : "";
568 echo " <input type='radio' name='form_done' value='$key'$checked />$value&nbsp;\n";
571 else {
572 // The information is stored in the 'shipvia' field of the invoice.
573 $insgot = strtolower($arrow['notes']);
574 $insdone = strtolower($arrow['shipvia']);
575 foreach (array('Ins1', 'Ins2', 'Ins3') as $value) {
576 $lcvalue = strtolower($value);
577 $checked = (strpos($insdone, $lcvalue) === false) ? "" : " checked";
578 if (strpos($insgot, $lcvalue) !== false) {
579 echo " <input type='checkbox' name='form_done_$value' value='1'$checked />$value&nbsp;\n";
584 </td>
585 <?php
586 if ($INTEGRATED_AR) {
587 echo "<td>\n";
588 echo xl('Check/EOB No.:');
589 echo "</td>\n";
590 echo "<td>\n";
591 echo "<input type='text' name='form_reference' size='10' value='' />\n";
592 echo "</td>\n";
595 </tr>
597 <tr>
598 <td>
599 <?php xl('Last Bill Date:','e') ?>
600 </td>
601 <td>
602 <?php
603 if ($INTEGRATED_AR) {
604 echo $billdate;
606 else {
607 echo $arrow['transdate'];
610 </td>
611 <td colspan="2">
612 <?php xl('Now posting for:','e','',"&nbsp")?>;
614 <?php
615 // TBD: check the first not-done-with insurance, not always Ins1!
617 <input type='radio' name='form_insurance' value='Ins1' onclick='setins("Ins1")' checked /><?php xl('Ins1','e')?>&nbsp;
618 <input type='radio' name='form_insurance' value='Ins2' onclick='setins("Ins2")' /><?php xl('Ins2','e')?>&nbsp;
619 <input type='radio' name='form_insurance' value='Ins3' onclick='setins("Ins3")' /><?php xl('Ins3','e')?>&nbsp;
620 <input type='radio' name='form_insurance' value='Pt' onclick='setins("Pt")' /><?php xl('Patient','e')?>
622 <?php
623 // TBD: I think the following is unused and can be removed.
625 <input type='hidden' name='form_eobs' value='<?php echo addslashes($arrow['shipvia']) ?>' />
627 </td>
628 <?php
629 if ($INTEGRATED_AR) {
630 echo "<td>\n";
631 echo xl('Check/EOB Date:');
632 echo "</td>\n";
633 echo "<td>\n";
634 echo "<input type='text' name='form_check_date' size='10' value='' />\n";
635 echo "</td>\n";
638 </tr>
639 <tr>
640 <td>
641 <?php
642 if (!$INTEGRATED_AR) xl('Due Date:','e');
644 </td>
645 <td>
647 <?php if (!$INTEGRATED_AR) { ?>
648 <input type='text' name='form_duedate' size='10' value='<?php echo $arrow['duedate'] ?>'
649 title='<?php xl('Due date mm/dd/yyyy or yyyy-mm-dd','e')?>'>
650 <?php } ?>
651 </td>
652 <td colspan="2">
653 <input type="checkbox" name="form_secondary" value="1"> <?php xl('Needs secondary billing','e')?>
654 &nbsp;&nbsp;
655 <input type='submit' name='form_save' value='<?php xl('Save','e')?>'>
656 &nbsp;
657 <input type='button' value='<?php xl('Cancel','e')?>' onclick='window.close()'>
658 </td>
659 <?php
660 if ($INTEGRATED_AR) {
661 echo "<td>\n";
662 echo xl('Deposit Date:');
663 echo "</td>\n";
664 echo "<td>\n";
665 echo "<input type='text' name='form_deposit_date' size='10' value='' />\n";
666 echo "<input type='hidden' name='form_payer_id' value='' />\n";
667 echo "<input type='hidden' name='form_orig_reference' value='' />\n";
668 echo "<input type='hidden' name='form_orig_check_date' value='' />\n";
669 echo "<input type='hidden' name='form_orig_deposit_date' value='' />\n";
670 echo "<input type='hidden' name='form_pay_total' value='' />\n";
671 echo "</td>\n";
674 </tr>
675 <?php if ($pdrow['genericname2'] == 'Billing') { ?>
676 <tr>
677 <td>
678 <?php xl('Billing Note:','e')?>
679 </td>
680 <td colspan='3' style='color:red'>
681 <?php echo $pdrow['genericval2'] ?>
682 </td>
683 </tr>
684 <?php } ?>
685 <tr>
686 <td height="1">
687 </td>
688 </tr>
689 </table>
691 <table border='0' cellpadding='2' cellspacing='0' width='98%'>
693 <tr bgcolor="#cccccc">
694 <td class="dehead">
695 <?php xl('Code','e')?>
696 </td>
697 <td class="dehead" align="right">
698 <?php xl('Charge','e')?>
699 </td>
700 <td class="dehead" align="right">
701 <?php xl('Balance','e')?>&nbsp;
702 </td>
703 <td class="dehead">
704 <?php xl('By/Source','e')?>
705 </td>
706 <td class="dehead">
707 <?php xl('Date','e')?>
708 </td>
709 <td class="dehead">
710 <?php xl('Pay','e')?>
711 </td>
712 <td class="dehead">
713 <?php xl('Adjust','e')?>
714 </td>
715 <td class="dehead">
716 <?php xl('Reason','e')?>
717 </td>
718 <?php if ($ALLOW_DELETE) { ?>
719 <td class="dehead">
720 <?php xl('Del','e')?>
721 </td>
722 <?php } ?>
723 </tr>
724 <?php
725 $firstProcCodeIndex = -1;
726 $encount = 0;
727 foreach ($codes as $code => $cdata) {
728 ++$encount;
729 $bgcolor = "#" . (($encount & 1) ? "ddddff" : "ffdddd");
730 $dispcode = $code;
732 // remember the index of the first entry whose code is not "CO-PAY", i.e. it's a legitimate proc code
733 if ($firstProcCodeIndex == -1 && strcmp($code, "CO-PAY") !=0)
734 $firstProcCodeIndex = $encount;
736 // this sorts the details more or less chronologically:
737 ksort($cdata['dtl']);
738 foreach ($cdata['dtl'] as $dkey => $ddata) {
739 $ddate = substr($dkey, 0, 10);
740 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
741 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
743 $tmpchg = "";
744 $tmpadj = "";
745 /*****************************************************************
746 if ($ddata['chg'] > 0)
747 $tmpchg = $ddata['chg'];
748 else if ($ddata['chg'] < 0)
749 $tmpadj = 0 - $ddata['chg'];
750 *****************************************************************/
751 if ($ddata['chg'] != 0) {
752 if (isset($ddata['rsn'])) $tmpadj = 0 - $ddata['chg'];
753 else $tmpchg = $ddata['chg'];
756 <tr bgcolor='<?php echo $bgcolor ?>'>
757 <td class="detail">
758 <?php echo $dispcode; $dispcode = "" ?>
759 </td>
760 <td class="detail" align="right">
761 <?php bucks($tmpchg) ?>
762 </td>
763 <td class="detail" align="right">
764 &nbsp;
765 </td>
766 <td class="detail">
767 <?php
768 if (isset($ddata['plv'])) {
769 if (!$ddata['plv']) echo 'Pt/';
770 else echo 'Ins' . $ddata['plv'] . '/';
772 echo $ddata['src'];
774 </td>
775 <td class="detail">
776 <?php echo $ddate ?>
777 </td>
778 <td class="detail">
779 <?php bucks($ddata['pmt']) ?>
780 </td>
781 <td class="detail">
782 <?php bucks($tmpadj) ?>
783 </td>
784 <td class="detail">
785 <?php echo $ddata['rsn'] ?>
786 </td>
787 <?php if ($ALLOW_DELETE) { ?>
788 <td class="detail">
789 <?php if (!empty($ddata['arseq'])) { ?>
790 <input type="checkbox" name="form_del[<?php echo $ddata['arseq']; ?>]" />
791 <?php } else { ?>
792 &nbsp;
793 <?php } ?>
794 </td>
795 <?php } ?>
796 </tr>
797 <?php
798 } // end of prior detail line
800 <tr bgcolor='<?php echo $bgcolor ?>'>
801 <td class="detail">
802 <?php echo $dispcode; $dispcode = "" ?>
803 </td>
804 <td class="detail" align="right">
805 &nbsp;
806 </td>
807 <td class="detail" align="right">
808 <input type="hidden" name="form_line[<?php echo $code ?>][bal]" value="<?php bucks($cdata['bal']) ?>">
809 <input type="hidden" name="form_line[<?php echo $code ?>][ins]" value="<?php echo $cdata['ins'] ?>">
810 <input type="hidden" name="form_line[<?php echo $code ?>][code_type]" value="<?php echo $cdata['code_type'] ?>">
811 <?php printf("%.2f", $cdata['bal']) ?>&nbsp;
812 </td>
813 <td class="detail">
815 <?php if (!$INTEGRATED_AR) { ?>
816 <input type="text" name="form_line[<?php echo $code ?>][src]" size="10"
817 style="background-color:<?php echo $bgcolor ?>" />
818 <!-- title="NM=notmet, CI=coins, CP=copay, NE=notelig, IT=insterm, PF=ptfull, PP=ptpart" -->
819 <?php } ?>
821 </td>
822 <td class="detail">
824 <?php if (!$INTEGRATED_AR) { ?>
825 <input type="text" name="form_line[<?php echo $code ?>][date]" size="10"
826 style="background-color:<?php echo $bgcolor ?>" />
827 <?php } ?>
829 </td>
830 <td class="detail">
831 <input type="text" name="form_line[<?php echo $code ?>][pay]" size="10"
832 style="background-color:<?php echo $bgcolor ?>"
833 onKeyUp="updateFields(document.forms[0]['form_line[<?php echo $code ?>][pay]'],
834 document.forms[0]['form_line[<?php echo $code ?>][adj]'],
835 document.forms[0]['form_line[<?php echo $code ?>][bal]'],
836 document.forms[0]['form_line[CO-PAY][bal]'],
837 <?php echo ($firstProcCodeIndex == $encount) ? 1 : 0 ?>)"/>
838 </td>
839 <td class="detail">
840 <input type="text" name="form_line[<?php echo $code ?>][adj]" size="10"
841 value='<?php echo $totalAdjAmount ?>'
842 style="background-color:<?php echo $bgcolor ?>" />
843 &nbsp; <a href="" onclick="return writeoff('<?php echo $code ?>')">W</a>
844 </td>
845 <td class="detail">
846 <select name="form_line[<?php echo $code ?>][reason]"
847 style="background-color:<?php echo $bgcolor ?>">
848 <?php
849 // Adjustment reasons are now taken from the list_options table.
850 echo " <option value=''></option>\n";
851 $ores = sqlStatement("SELECT option_id, title, is_default FROM list_options " .
852 "WHERE list_id = 'adjreason' ORDER BY seq, title");
853 while ($orow = sqlFetchArray($ores)) {
854 echo " <option value='" . htmlspecialchars($orow['option_id'], ENT_QUOTES) . "'";
855 if ($orow['is_default']) echo " selected";
856 echo ">" . htmlspecialchars($orow['title']) . "</option>\n";
860 </select>
861 <?php
862 // TBD: Maybe a comment field would be good here, for appending
863 // to the reason.
865 </td>
867 <?php if ($ALLOW_DELETE) { ?>
868 <td class="detail">
869 &nbsp;
870 </td>
871 <?php } ?>
873 </tr>
874 <?php
875 } // end of code
876 if (!$INTEGRATED_AR) SLClose();
879 </table>
880 </form>
881 </center>
882 <script language="JavaScript">
883 var f1 = opener.document.forms[0];
884 var f2 = document.forms[0];
885 if (f1.form_source) {
886 <?php
887 if ($INTEGRATED_AR) {
888 // These support creation and lookup of ar_session table entries:
889 echo " f2.form_reference.value = f1.form_source.value;\n";
890 echo " f2.form_check_date.value = f1.form_paydate.value;\n";
891 echo " //f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
892 echo " if (f1.form_deposit_date.value != '')\n";
893 echo " f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
894 echo " else\n";
895 echo " f2.form_deposit_date.value = getFormattedToday();\n";
896 echo " f2.form_payer_id.value = f1.form_payer_id.value;\n";
897 echo " f2.form_pay_total.value = f1.form_amount.value;\n";
898 echo " f2.form_orig_reference.value = f1.form_source.value;\n";
899 echo " f2.form_orig_check_date.value = f1.form_paydate.value;\n";
900 echo " f2.form_orig_deposit_date.value = f1.form_deposit_date.value;\n";
902 // While I'm thinking about it, some notes about eob sessions.
903 // If they do not have all of the session key fields in the search
904 // page, then show a warning at the top of the invoice page.
905 // Also when they go to save the invoice page and a session key
906 // field has changed, alert them to that and allow a cancel.
908 // Another point... when posting EOBs, the incoming payer ID might
909 // not match the payer ID for the patient's insurance. This is
910 // because the same payer might be entered more than once into the
911 // insurance_companies table. I don't think it matters much.
913 else {
914 foreach ($codes as $code => $cdata) {
915 echo " f2['form_line[$code][src]'].value = f1.form_source.value;\n";
916 echo " f2['form_line[$code][date]'].value = f1.form_paydate.value;\n";
921 setins("Ins1");
922 </script>
923 </body>
924 </html>