a new and improved date widget
[openemr.git] / interface / billing / sl_eob_invoice.php
blobb29a1b9aac7978a887ddb3a42e78a517fc9d4926
1 <?
2 // Copyright (C) 2005 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 is the second of two pages to support posting of EOBs.
10 // The first is sl_eob_search.php.
12 include_once("../globals.php");
13 include_once("../../library/patient.inc");
14 include_once("../../library/forms.inc");
15 include_once("../../library/sql-ledger.inc");
16 include_once("../../library/invoice_summary.inc.php");
17 include_once("../../custom/code_types.inc.php");
19 $debug = 0; // set to 1 for debugging mode
21 $reasons = array(
22 "", // not choosing this allows a reason with no adjustment amount
23 xl("Ins adjust"),
24 xl("Coll w/o"),
25 xl("Pt released"),
26 xl("Sm debt w/o"),
27 xl("To ded'ble"),
28 xl("To copay"),
29 xl("Bad check"),
30 xl("Bad debt"),
31 xl("Discount"),
32 xl("Hardship w/o"),
33 xl("Ins refund"),
34 xl("Pt refund"),
35 xl("Ins overpaid"),
36 xl("Pt overpaid")
39 $info_msg = "";
41 // Format money for display.
43 function bucks($amount) {
44 if ($amount)
45 printf("%.2f", $amount);
48 // Insert a row into the acc_trans table.
50 function addTransaction($invid, $chartid, $amount, $date, $source, $memo, $insplan) {
51 global $sl_err, $debug;
52 $date = fixDate($date);
53 $query = "INSERT INTO acc_trans ( " .
54 "trans_id, " .
55 "chart_id, " .
56 "amount, " .
57 "transdate, " .
58 "source, " .
59 "project_id, " .
60 "memo " .
61 ") VALUES ( " .
62 "$invid, " . // trans_id
63 "$chartid, " . // chart_id
64 "$amount, " . // amount
65 "'$date', " . // transdate
66 "'$source', " . // source
67 "$insplan, " . // project_id
68 "'$memo' " . // memo
69 ")";
70 if ($debug) {
71 echo $query . "<br>\n";
72 } else {
73 SLQuery($query);
74 if ($sl_err) die($sl_err);
78 // Insert a row into the invoice table.
80 function addLineItem($invid, $serialnumber, $amount, $adjdate, $insplan, $reason) {
81 global $sl_err, $services_id, $debug;
82 $adjdate = fixDate($adjdate);
83 $description = "Adjustment $adjdate $reason";
84 $query = "INSERT INTO invoice ( " .
85 "trans_id, " .
86 "parts_id, " .
87 "description, " .
88 "qty, " .
89 "allocated, " .
90 "sellprice, " .
91 "fxsellprice, " .
92 "discount, " .
93 "unit, " .
94 "project_id, " .
95 "serialnumber " .
96 ") VALUES ( " .
97 "$invid, " . // trans_id
98 "$services_id, " . // parts_id
99 "'$description', " . // description
100 "1, " . // qty
101 "0, " . // allocated
102 "$amount, " . // sellprice
103 "$amount, " . // fxsellprice
104 "0, " . // discount
105 "'', " . // unit
106 "$insplan, " . // project_id
107 "'$serialnumber'" . // serialnumber
108 ")";
109 if ($debug) {
110 echo $query . "<br>\n";
111 } else {
112 SLQuery($query);
113 if ($sl_err) die($sl_err);
117 // Update totals and payment date in the invoice header. Dollar amounts are
118 // stored as double precision floats so we have to be careful about rounding.
120 function updateAR($invid, $amount, $paid = 0, $paydate = "") {
121 global $sl_err, $debug;
122 $paydate = fixDate($paydate);
123 $query = "UPDATE ar SET amount = round(CAST (amount AS numeric) + $amount, 2), " .
124 "netamount = round(CAST (netamount AS numeric) + $amount, 2)";
125 if ($paid) $query .= ", paid = round(CAST (paid AS numeric) + $paid, 2), datepaid = '$paydate'";
126 $query .= " WHERE id = $invid";
127 if ($debug) {
128 echo $query . "<br>\n";
129 } else {
130 SLQuery($query);
131 if ($sl_err) die($sl_err);
135 // Do whatever is necessary to make this invoice re-billable.
137 function setupSecondary($invid) {
138 global $sl_err, $debug, $info_msg, $GLOBALS;
140 // Get some needed items from the SQL-Ledger invoice.
141 $arres = SLQuery("select invnumber, transdate, customer_id, employee_id " .
142 "from ar where ar.id = $invid");
143 if ($sl_err) die($sl_err);
144 $arrow = SLGetRow($arres, 0);
145 if (! $arrow) die(xl('There is no match for invoice id') . ' = ' . "$trans_id.");
146 $customer_id = $arrow['customer_id'];
147 list($trash, $encounter) = explode(".", $arrow['invnumber']);
149 // Get the OpenEMR PID corresponding to the customer.
150 $pdrow = sqlQuery("SELECT patient_data.pid " .
151 "FROM integration_mapping, patient_data WHERE " .
152 "integration_mapping.foreign_id = $customer_id AND " .
153 "integration_mapping.foreign_table = 'customer' AND " .
154 "patient_data.id = integration_mapping.local_id");
155 $pid = $pdrow['pid'];
156 if (! $pid) die(xl("Cannot find patient from SQL-Ledger customer id") . " = $customer_id.");
158 // Find out if the encounter exists.
159 $ferow = sqlQuery("SELECT pid FROM form_encounter WHERE " .
160 "encounter = $encounter");
161 $encounter_pid = $ferow['pid'];
163 // If it exists, just update the billing items.
164 if ($encounter_pid) {
165 if ($encounter_pid != $pid)
166 die(xl("Expected form_encounter.pid to be ") . $pid . ', ' . xl(' but was ') . $encounter_pid);
167 $query = "UPDATE billing SET billed = 0, bill_process = 0, payer_id = -1, " .
168 "bill_date = NULL, process_date = NULL, process_file = NULL " .
169 "WHERE encounter = $encounter AND pid = $pid AND activity = 1";
170 if ($debug) {
171 echo $query . "<br>\n";
172 } else {
173 sqlQuery($query);
175 $info_msg = xl("Encounter ") . $encounter . xl(" is ready for re-billing.");
176 return;
179 // It does not exist then it better be a date.
180 if (! preg_match("/^20\d\d\d\d\d\d$/", $encounter))
181 die(xl("Internal error: encounter '") . $encounter . xl("' should exist but does not."));
183 $employee_id = $arrow['employee_id'];
185 // Get the OpenEMR provider info corresponding to the SQL-Ledger salesman.
186 $drrow = sqlQuery("SELECT users.id, users.username, users.facility " .
187 "FROM integration_mapping, users WHERE " .
188 "integration_mapping.foreign_id = $employee_id AND " .
189 "integration_mapping.foreign_table = 'salesman' AND " .
190 "users.id = integration_mapping.local_id");
191 $provider_id = $drrow['id'];
192 if (! $provider_id) die(xl("Cannot find provider from SQL-Ledger employee = ") . $employee_id );
194 $date_of_service = $arrow['transdate'];
195 if (! $date_of_service) die(xl("Invoice has no date!"));
197 // Generate a new encounter number.
198 $conn = $GLOBALS['adodb']['db'];
199 $new_encounter = $conn->GenID("sequences");
201 // Create the "new encounter".
202 $encounter_id = 0;
203 $query = "INSERT INTO form_encounter ( " .
204 "date, reason, facility, pid, encounter, onset_date " .
205 ") VALUES ( " .
206 "'$date_of_service', " .
207 "'" . xl('Imported from Accounting') . "', " .
208 "'" . addslashes($drrow['facility']) . "', " .
209 "$pid, " .
210 "$new_encounter, " .
211 "'$date_of_service' " .
212 ")";
213 if ($debug) {
214 echo $query . "<br>\n";
215 echo xl("Call to addForm() goes here.<br>") . "\n";
216 } else {
217 $encounter_id = idSqlStatement($query);
218 if (! $encounter_id) die(xl("Insert failed: ") . $query);
219 addForm($new_encounter, xl("New Patient Encounter"), $encounter_id,
220 "newpatient", $pid, 1, $date_of_service);
221 $info_msg = xl("Encounter ") . $new_encounter . xl(" has been created. ");
224 // For each invoice line item with a billing code we will insert
225 // a billing row with payer_id set to -1. Order the line items
226 // chronologically so that each procedure code will be followed by
227 // its associated icd9 code.
229 $inres = SLQuery("SELECT * FROM invoice WHERE trans_id = $invid " .
230 "ORDER BY id");
231 if ($sl_err) die($sl_err);
233 // When nonzero, this will be the ID of a billing row that needs to
234 // have its justify field set.
235 $proc_ins_id = 0;
237 for ($irow = 0; $irow < SLRowCount($inres); ++$irow) {
238 $row = SLGetRow($inres, $irow);
239 $amount = $row['sellprice'];
241 // Extract the billing code.
242 $code = xl("Unknown");
243 if (preg_match("/([A-Za-z0-9]\d\d\S*)/", $row['serialnumber'], $matches)) {
244 $code = strtoupper($matches[1]);
246 else if (preg_match("/([A-Za-z0-9]\d\d\S*)/", $row['description'], $matches)) {
247 $code = strtoupper($matches[1]);
250 list($code, $modifier) = explode("-", $code);
252 // Set the billing code type and description.
253 $code_type = "";
254 $code_text = "";
256 /****
257 if (preg_match("/CPT/", $row['serialnumber'])) {
258 $code_type = "CPT4";
259 $code_text = "Procedure $code";
261 else if (preg_match("/HCPCS/", $row['serialnumber'])) {
262 $code_type = "HCPCS";
263 $code_text = "Procedure $code";
265 else if (preg_match("/ICD/", $row['serialnumber'])) {
266 $code_type = "ICD9";
267 $code_text = "Diagnosis $code";
268 if ($proc_ins_id) {
269 $query = "UPDATE billing SET justify = '$code' WHERE id = $proc_ins_id";
270 if ($debug) {
271 echo $query . "<br>\n";
272 } else {
273 sqlQuery($query);
275 $proc_ins_id = 0;
278 ****/
280 foreach ($code_types as $key => $value) {
281 if (preg_match("/$key/", $row['serialnumber'])) {
282 $code_type = $key;
283 if ($value['fee']) {
284 $code_text = xl("Procedure") . " $code";
285 } else {
286 $code_text = xl("Diagnosis") . " $code";
287 if ($proc_ins_id) {
288 $query = "UPDATE billing SET justify = '$code' WHERE id = $proc_ins_id";
289 if ($debug) {
290 echo $query . "<br>\n";
291 } else {
292 sqlQuery($query);
294 $proc_ins_id = 0;
297 break;
301 // Skip adjustments.
302 if (! $code_type) continue;
304 // Insert the billing item. If this for a procedure code then save
305 // the row ID so that we can update the "justify" field with the ICD9
306 // code, which should come next in the loop.
308 $query = "INSERT INTO billing ( " .
309 "date, code_type, code, pid, provider_id, user, groupname, authorized, " .
310 "encounter, code_text, activity, payer_id, billed, bill_process, " .
311 "modifier, units, fee, justify " .
312 ") VALUES ( " .
313 "NOW(), " .
314 "'$code_type', " .
315 "'$code', " .
316 "$pid, " .
317 "$provider_id, " .
318 "'" . $_SESSION['authId'] . "', " .
319 "'" . $_SESSION['authProvider'] . "', " .
320 "1, " .
321 "$new_encounter, " .
322 "'$code_text', " .
323 "1, " .
324 "-1, " .
325 "0, " .
326 "0, " .
327 "'$modifier', " .
328 "0, " .
329 "$amount, " .
330 "'' " .
331 ")";
332 if ($debug) {
333 echo $query . "<br>\n";
334 } else {
335 $proc_ins_id = idSqlStatement($query);
336 if ($code_type != "CPT4" && $code_type != "HCPCS")
337 $proc_ins_id = 0;
341 // Finally, change this invoice number to contain the new encounter number.
343 $new_invnumber = "$pid.$new_encounter";
344 $query = "UPDATE ar SET invnumber = '$new_invnumber' WHERE id = $invid";
345 if ($debug) {
346 echo $query . "<br>\n";
347 } else {
348 SLQuery($query);
349 if ($sl_err) die($sl_err);
350 $info_msg .= xl("This invoice number has been changed to ") . $new_invnumber;
354 <html>
355 <head>
356 <link rel=stylesheet href="<?echo $css_header;?>" type="text/css">
357 <title><?xl('EOB Posting - Invoice','e')?></title>
358 <script language="JavaScript">
360 // An insurance radio button is selected.
361 function setins(istr) {
362 var f = document.forms[0];
363 for (var i = 0; i < f.elements.length; ++i) {
364 var ename = f.elements[i].name;
365 if (ename.indexOf('[src]') < 0) continue;
366 var evalue = f.elements[i].value;
367 var tmp = evalue.substring(0, 4).toLowerCase();
368 if (tmp >= 'ins1' && tmp <= 'ins3')
369 evalue = evalue.substring(4);
370 else if (evalue.substring(0, 2).toLowerCase() == 'pt')
371 evalue = evalue.substring(2);
372 while (evalue.substring(0, 1) == '/')
373 evalue = evalue.substring(1);
374 f.elements[i].value = istr + '/' + evalue;
376 return true;
379 // Compute an adjustment that writes off the balance:
380 function writeoff(code) {
381 var f = document.forms[0];
382 var tmp =
383 f['form_line[' + code + '][bal]'].value -
384 f['form_line[' + code + '][pay]'].value;
385 f['form_line[' + code + '][adj]'].value = Number(tmp).toFixed(2);
386 return false;
389 // Onsubmit handler. A good excuse to write some JavaScript.
390 function validate(f) {
391 for (var i = 0; i < f.elements.length; ++i) {
392 var ename = f.elements[i].name;
393 var pfxlen = ename.indexOf('[pay]');
394 if (pfxlen < 0) continue;
395 var pfx = ename.substring(0, pfxlen);
396 var code = pfx.substring(pfx.indexOf('[')+1, pfxlen-1);
397 if (f[pfx+'[pay]'].value || f[pfx+'[adj]'].value) {
398 var srcobj = f[pfx+'[src]'];
399 while (srcobj.value.length) {
400 var tmp = srcobj.value.substring(srcobj.value.length - 1);
401 if (tmp > ' ' && tmp != '/') break;
402 srcobj.value = srcobj.value.substring(0, srcobj.value.length - 1);
404 var svalue = srcobj.value;
405 if (! svalue) {
406 alert('<? xl('Source is missing for code ','e') ?>' + code);
407 return false;
408 } else {
409 var tmp = svalue.substring(0, 4).toLowerCase();
410 if (tmp >= 'ins1' && tmp <= 'ins3') {
411 svalue = svalue.substring(4);
412 } else if (svalue.substring(0, 2).toLowerCase() == 'pt') {
413 svalue = svalue.substring(2);
414 } else {
415 alert('<?xl('Invalid or missing payer in source for code ','e')?>' + code);
416 return false;
418 if (svalue) {
419 if (svalue.substring(0, 1) != '/') {
420 alert('<?xl('Missing slash after payer in source for code ','e')?>' + code);
421 return false;
423 if (false) { // Please keep this, Oakland Clinic wants it. -- Rod
424 tmp = svalue.substring(1, 3).toLowerCase();
425 if (tmp != 'nm' && tmp != 'ci' && tmp != 'cp' && tmp != 'ne' &&
426 tmp != 'it' && tmp != 'pf' && tmp != 'pp' && tmp != 'ok')
428 alert('<? xl('Invalid source designation "','e') ?>' + tmp + '<? xl('" for code ','e') ?>' + code);
429 return false;
431 } // End of OC code
434 if (! f[pfx+'[date]'].value) {
435 alert('<?xl('Date is missing for code ','e')?>' + code);
436 return false;
439 if (f[pfx+'[pay]'].value && isNaN(parseFloat(f[pfx+'[pay]'].value))) {
440 alert('<? xl('Payment value for code ','e') ?>' + code + '<? xl(' is not a number','e') ?>');
441 return false;
443 if (f[pfx+'[adj]'].value && isNaN(parseFloat(f[pfx+'[adj]'].value))) {
444 alert('<? xl('Adjustment value for code ','e') ?>' + code + '<? xl(' is not a number','e') ?>');
445 return false;
447 if (f[pfx+'[adj]'].value && ! f[pfx+'[reason]'].value) {
448 alert('<? xl('Please select an adjustment reason for code ','e') ?>' + code);
449 return false;
451 // TBD: validate the date format
453 return true;
456 </script>
457 </head>
458 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
460 $trans_id = $_GET['id'];
461 if (! $trans_id) die(xl("You cannot access this page directly."));
463 SLConnect();
465 $chart_id_cash = SLQueryValue("select id from chart where accno = '$sl_cash_acc'");
466 if ($sl_err) die($sl_err);
467 if (! $chart_id_cash) die(xl("There is no COA entry for cash account ") . "'$sl_cash_acc'");
469 $chart_id_ar = SLQueryValue("select id from chart where accno = '$sl_ar_acc'");
470 if ($sl_err) die($sl_err);
471 if (! $chart_id_ar) die(xl("There is no COA entry for AR account ") . "'$sl_ar_acc'");
473 $chart_id_income = SLQueryValue("select id from chart where accno = '$sl_income_acc'");
474 if ($sl_err) die($sl_err);
475 if (! $chart_id_income) die(xl("There is no COA entry for income account ") . "'$sl_income_acc'");
477 $services_id = SLQueryValue("select id from parts where partnumber = '$sl_services_id'");
478 if ($sl_err) die($sl_err);
479 if (! $services_id) die(xl("There is no parts entry for services ID ") . "'$sl_services_id'");
481 if ($_POST['form_save'] || $_POST['form_cancel']) {
482 if ($_POST['form_save']) {
483 if ($debug) {
484 echo xl("This module is in test mode. The database will not be changed.",'','<p><b>',"</b><p>\n");
486 $paytotal = 0;
487 foreach ($_POST['form_line'] as $code => $cdata) {
488 $thissrc = trim($cdata['src']);
489 $thisdate = trim($cdata['date']);
490 $thispay = trim($cdata['pay']);
491 $thisadj = trim($cdata['adj']);
492 $thisins = trim($cdata['ins']);
493 $reason = trim($cdata['reason']);
494 if (strpos(strtolower($reason), 'ins') !== false)
495 $reason .= ' ' . $_POST['form_insurance'];
496 if (! $thisins) $thisins = 0;
497 if ($thispay) {
498 // Post a payment: add to ar, subtract from cash.
499 addTransaction($trans_id, $chart_id_ar, $thispay, $thisdate, $thissrc, $code, $thisins);
500 addTransaction($trans_id, $chart_id_cash, 0 - $thispay, $thisdate, $thissrc, $code, $thisins);
501 updateAR($trans_id, 0, $thispay, $thisdate);
502 $paytotal += $thispay;
505 // if ($thisadj) {
506 // // Post an adjustment: add negative invoice item, add to ar, subtract from income
507 // addLineItem($trans_id, $code, 0 - $thisadj, $thisdate, $thisins, $reason);
508 // addTransaction($trans_id, $chart_id_ar, $thisadj, $thisdate, "InvAdj $thissrc", $code, $thisins);
509 // addTransaction($trans_id, $chart_id_income, 0 - $thisadj, $thisdate, "InvAdj $thissrc", $code, $thisins);
510 // updateAR($trans_id, 0 - $thisadj);
511 // }
513 // Be sure to record adjustment reasons even for zero adjustments.
514 if ($thisadj || $reason) {
515 // Post an adjustment: add negative invoice item, add to ar, subtract from income
516 addLineItem($trans_id, $code, 0 - $thisadj, $thisdate, $thisins, $reason);
517 if ($thisadj) {
518 addTransaction($trans_id, $chart_id_ar, $thisadj, $thisdate, "InvAdj $thissrc", $code, $thisins);
519 addTransaction($trans_id, $chart_id_income, 0 - $thisadj, $thisdate, "InvAdj $thissrc", $code, $thisins);
520 updateAR($trans_id, 0 - $thisadj);
525 $form_duedate = fixDate($_POST['form_duedate']);
526 $form_notes = trim($_POST['form_notes']);
528 // Maintain the list of insurances that we mark as finished.
529 // We use the "Ship Via" field of the invoice to hold these.
531 $form_eobs = "";
532 foreach (array('Ins1', 'Ins2', 'Ins3') as $value) {
533 if ($_POST["form_done_$value"]) {
534 if ($form_eobs) $form_eobs .= ","; else $form_eobs = "Done: ";
535 $form_eobs .= $value;
539 $query = "UPDATE ar SET duedate = '$form_duedate', notes = '$form_notes', " .
540 "shipvia = '$form_eobs' WHERE id = $trans_id";
542 if ($debug) {
543 echo $query . "<br>\n";
544 } else {
545 SLQuery($query);
546 if ($sl_err) die($sl_err);
548 if ($_POST['form_secondary']) {
549 setupSecondary($trans_id);
551 echo "<script language='JavaScript'>\n";
552 echo " var tmp = opener.document.forms[0].form_amount.value - $paytotal;\n";
553 echo " opener.document.forms[0].form_amount.value = Number(tmp).toFixed(2);\n";
554 } else {
555 echo "<script language='JavaScript'>\n";
557 if ($info_msg) echo " alert('$info_msg');\n";
558 if (! $debug) echo " window.close();\n";
559 echo "</script></body></html>\n";
560 SLClose();
561 exit();
564 // Get invoice data into $arrow.
565 $arres = SLQuery("select ar.*, customer.name, employee.name as doctor " .
566 "from ar, customer, employee where ar.id = $trans_id and " .
567 "customer.id = ar.customer_id and employee.id = ar.employee_id");
568 if ($sl_err) die($sl_err);
569 $arrow = SLGetRow($arres, 0);
570 if (! $arrow) die(xl("There is no match for invoice id = ") . $trans_id);
572 // Determine the date of service. An 8-digit encounter number is
573 // presumed to be a date of service imported during conversion.
574 // Otherwise look it up in the form_encounter table.
576 $svcdate = "";
577 list($trash, $encounter) = explode(".", $arrow['invnumber']);
578 if (strlen($encounter) == 8) {
579 $svcdate = substr($encounter, 0, 4) . "-" . substr($encounter, 4, 2) .
580 "-" . substr($encounter, 6, 2);
582 else if ($encounter) {
583 $tmp = sqlQuery("SELECT date FROM form_encounter WHERE " .
584 "encounter = $encounter");
585 $svcdate = substr($tmp['date'], 0, 10);
588 // Get invoice charge details.
589 $codes = get_invoice_summary($trans_id, true);
591 <center>
593 <form method='post' action='sl_eob_invoice.php?id=<? echo $trans_id ?>'
594 onsubmit='return validate(this)'>
596 <table border='0' cellpadding='3'>
597 <tr>
598 <td>
599 <?xl('Patient:','e')?>
600 </td>
601 <td>
602 <?echo $arrow['name'] ?>
603 </td>
604 <td colspan="2" rowspan="3">
605 <textarea name="form_notes" cols="50" style="height:100%"><?echo $arrow['notes'] ?></textarea>
606 </td>
607 </tr>
608 <tr>
609 <td>
610 <?xl('Provider:','e')?>
611 </td>
612 <td>
613 <?echo $arrow['doctor'] ?>
614 </td>
615 </tr>
616 <tr>
617 <td>
618 <?xl('Invoice:','e')?>
619 </td>
620 <td>
621 <?echo $arrow['invnumber'] ?>
622 </td>
623 </tr>
625 <tr>
626 <td>
627 <?xl('Svc Date:','e')?>
628 </td>
629 <td>
630 <?echo $svcdate ?>
631 </td>
632 <td colspan="2">
633 <!-- <?echo $arrow['shipvia'] ?> -->
634 <?xl('Done with:','e','',"&nbsp")?>;
636 // Write a checkbox for each insurance. It is to be checked when
637 // we no longer expect any payments from that company for the claim.
638 // The information is stored in the 'shipvia' field of the invoice.
640 $insgot = strtolower($arrow['notes']);
641 $insdone = strtolower($arrow['shipvia']);
642 foreach (array('Ins1', 'Ins2', 'Ins3') as $value) {
643 $lcvalue = strtolower($value);
644 $checked = (strpos($insdone, $lcvalue) === false) ? "" : " checked";
645 if (strpos($insgot, $lcvalue) !== false) {
646 echo " <input type='checkbox' name='form_done_$value' value='1'$checked />$value&nbsp;\n";
650 </td>
651 </tr>
653 <tr>
654 <td>
655 <?php xl('Bill Date:','e') ?>
656 </td>
657 <td>
658 <?echo $arrow['transdate'] ?>
659 </td>
660 <td colspan="2">
661 <?xl('Now posting for:','e','',"&nbsp")?>;
662 <input type='radio' name='form_insurance' value='Ins1' onclick='setins("Ins1")' checked /><?xl('Ins1','e')?>&nbsp;
663 <input type='radio' name='form_insurance' value='Ins2' onclick='setins("Ins2")' /><?xl('Ins2','e')?>&nbsp;
664 <input type='radio' name='form_insurance' value='Ins3' onclick='setins("Ins3")' /><?xl('Ins3','e')?>&nbsp;
665 <input type='radio' name='form_insurance' value='Pt' onclick='setins("Pt")' /><?xl('Patient','e')?>
666 <input type='hidden' name='form_eobs' value='<?echo addslashes($arrow['shipvia']) ?>' />
667 </td>
668 </tr>
669 <tr>
670 <td>
671 <?xl('Due Date:','e')?>
672 </td>
673 <td>
674 <input type='text' name='form_duedate' size='10' value='<?echo $arrow['duedate'] ?>'
675 title='<?xl('Due date mm/dd/yyyy or yyyy-mm-dd','e')?>'>
676 </td>
677 <td colspan="2">
678 <input type="checkbox" name="form_secondary" value="1"> <?xl('Needs secondary billing','e')?>
679 &nbsp;&nbsp;
680 <input type='submit' name='form_save' value='<?xl('Save','e')?>'>
681 &nbsp;
682 <input type='button' value='<?xl('Cancel','e')?>' onclick='window.close()'>
683 </td>
684 </tr>
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 <?xl('Code','e')?>
696 </td>
697 <td class="dehead" align="right">
698 <?xl('Charge','e')?>
699 </td>
700 <td class="dehead" align="right">
701 <?xl('Balance','e')?>&nbsp;
702 </td>
703 <td class="dehead">
704 <?xl('Source','e')?>
705 </td>
706 <td class="dehead">
707 <?xl('Date','e')?>
708 </td>
709 <td class="dehead">
710 <?xl('Pay','e')?>
711 </td>
712 <td class="dehead">
713 <?xl('Adjust','e')?>
714 </td>
715 <td class="dehead">
716 <?xl('Reason','e')?>
717 </td>
718 </tr>
720 $encount = 0;
721 foreach ($codes as $code => $cdata) {
722 ++$encount;
723 $bgcolor = "#" . (($encount & 1) ? "ddddff" : "ffdddd");
724 $dispcode = $code;
725 // this sorts the details more or less chronologically:
726 ksort($cdata['dtl']);
727 foreach ($cdata['dtl'] as $dkey => $ddata) {
728 $ddate = substr($dkey, 0, 10);
729 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
730 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
732 $tmpchg = "";
733 $tmpadj = "";
734 if ($ddata['chg'] > 0)
735 $tmpchg = $ddata['chg'];
736 else if ($ddata['chg'] < 0)
737 $tmpadj = 0 - $ddata['chg'];
739 <tr bgcolor='<? echo $bgcolor ?>'>
740 <td class="detail">
741 <? echo $dispcode; $dispcode = "" ?>
742 </td>
743 <td class="detail" align="right">
744 <? bucks($tmpchg) ?>
745 </td>
746 <td class="detail" align="right">
747 &nbsp;
748 </td>
749 <td class="detail">
750 <? echo $ddata['src'] ?>
751 </td>
752 <td class="detail">
753 <? echo $ddate ?>
754 </td>
755 <td class="detail">
756 <? bucks($ddata['pmt']) ?>
757 </td>
758 <td class="detail">
759 <? bucks($tmpadj) ?>
760 </td>
761 <td class="detail">
762 <? echo $ddata['rsn'] ?>
763 </td>
764 </tr>
766 } // end of prior detail line
768 <tr bgcolor='<? echo $bgcolor ?>'>
769 <td class="detail">
770 <? echo $dispcode; $dispcode = "" ?>
771 </td>
772 <td class="detail" align="right">
773 &nbsp;
774 </td>
775 <td class="detail" align="right">
776 <input type="hidden" name="form_line[<? echo $code ?>][bal]" value="<? bucks($cdata['bal']) ?>">
777 <input type="hidden" name="form_line[<? echo $code ?>][ins]" value="<? echo $cdata['ins'] ?>">
778 <? printf("%.2f", $cdata['bal']) ?>&nbsp;
779 </td>
780 <td class="detail">
781 <input type="text" name="form_line[<? echo $code ?>][src]" size="10"
782 style="background-color:<? echo $bgcolor ?>"
783 <?php if (false) { ?>
784 title="NM=notmet, CI=coins, CP=copay, NE=notelig, IT=insterm, PF=ptfull, PP=ptpart"
785 <?php } ?>
787 </td>
788 <td class="detail">
789 <input type="text" name="form_line[<? echo $code ?>][date]" size="10" style="background-color:<? echo $bgcolor ?>" />
790 </td>
791 <td class="detail">
792 <input type="text" name="form_line[<? echo $code ?>][pay]" size="10" style="background-color:<? echo $bgcolor ?>" />
793 </td>
794 <td class="detail">
795 <input type="text" name="form_line[<? echo $code ?>][adj]" size="10" style="background-color:<? echo $bgcolor ?>" />
796 &nbsp; <a href="" onclick="return writeoff('<? echo $code ?>')">W</a>
797 </td>
798 <td class="detail">
799 <select name="form_line[<? echo $code ?>][reason]" style="background-color:<? echo $bgcolor ?>">
801 foreach ($reasons as $value) {
802 echo " <option value=\"$value\">$value</option>\n";
805 </select>
806 </td>
807 </tr>
809 } // end of code
810 SLClose();
813 </table>
814 </form>
815 </center>
816 <script language="JavaScript">
817 var f1 = opener.document.forms[0];
818 var f2 = document.forms[0];
820 foreach ($codes as $code => $cdata) {
821 echo " f2['form_line[$code][src]'].value = f1.form_source.value;\n";
822 echo " f2['form_line[$code][date]'].value = f1.form_paydate.value;\n";
825 setins("Ins1");
826 </script>
827 </body>
828 </html>