2 // Copyright (C) 2006 Rod Roark <rod@sunsetsystems.com>
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 include_once("../globals.php");
10 include_once("../../library/patient.inc");
11 include_once("../../library/sql-ledger.inc");
12 include_once("../../library/invoice_summary.inc.php");
13 include_once("../../custom/statement.inc.php");
14 include_once("../../library/sl_eob.inc.php");
18 $export_patient_count = 0;
21 function bucks($amount) {
23 printf("%.2f", $amount);
26 $today = date("Y-m-d");
28 $form_date = fixDate($_POST['form_date'], "");
29 $form_to_date = fixDate($_POST['form_to_date'], "");
30 $is_due_ins = $_POST['form_category'] == xl('Due Ins');
31 $is_due_pt = $_POST['form_category'] == xl('Due Pt');
34 $grand_total_charges = 0;
35 $grand_total_adjustments = 0;
36 $grand_total_paid = 0;
40 function endPatient($ptrow) {
41 global $export_patient_count, $export_dollars, $bgcolor;
42 global $grand_total_charges, $grand_total_adjustments, $grand_total_paid;
45 if (!$ptrow['pid']) return;
47 $pt_balance = $ptrow['amount'] - $ptrow['paid'];
49 if ($_POST['form_export']) {
50 // This is a fixed-length format used by Transworld Systems. Your
51 // needs will surely be different, so consider this just an example.
53 echo "1896H"; // client number goes here
55 echo sprintf("%-30s", substr($ptrow['ptname'], 0, 30));
56 echo sprintf("%-30s", " ");
57 echo sprintf("%-30s", substr($ptrow['address1'], 0, 30));
58 echo sprintf("%-15s", substr($ptrow['city'], 0, 15));
59 echo sprintf("%-2s", substr($ptrow['state'], 0, 2));
60 echo sprintf("%-5s", $ptrow['zipcode'] ?
substr($ptrow['zipcode'], 0, 5) : '00000');
61 echo "1"; // service code
62 echo sprintf("%010.0f", $ptrow['pid']); // transmittal number = patient id
64 echo sprintf("%-15s", substr($ptrow['ss'], 0, 15));
65 echo substr($ptrow['dos'], 5, 2) . substr($ptrow['dos'], 8, 2) . substr($ptrow['dos'], 2, 2);
66 echo sprintf("%08.0f", $pt_balance * 100);
67 echo sprintf("%-9s\n", " ");
69 if (!$_POST['form_without']) {
70 sqlStatement("UPDATE patient_data SET " .
71 "genericname2 = 'Billing', " .
72 "genericval2 = 'IN COLLECTIONS " . date("Y-m-d") . "' " .
73 "WHERE pid = '" . $ptrow['pid'] . "'");
75 $export_patient_count +
= 1;
76 $export_dollars +
= $pt_balance;
79 if ($ptrow['count'] > 1) {
80 echo " <tr bgcolor='$bgcolor'>\n";
81 echo " <td class='detail' colspan='" . ($is_due_ins ?
'5' : '4') . "'>\n";
84 echo " <td class='detotal' colspan='5'>\n";
85 echo " Total Patient Balance:\n";
87 echo " <td class='detotal' align='right'>\n";
88 echo " " . sprintf("%.2f", $pt_balance) . " \n";
90 echo " <td class='detail' colspan='2'>\n";
96 $grand_total_charges +
= $ptrow['charges'];
97 $grand_total_adjustments +
= $ptrow['adjustments'];
98 $grand_total_paid +
= $ptrow['paid'];
103 <link rel
=stylesheet href
="<?echo $css_header;?>" type
="text/css">
104 <title
><?
xl('Collections Report','e')?
></title
>
105 <style type
="text/css">
106 body
{ font
-family
:sans
-serif
; font
-size
:10pt
; font
-weight
:normal
}
107 .dehead
{ color
:#000000; font-family:sans-serif; font-size:10pt; font-weight:bold }
108 .detail
{ color
:#000000; font-family:sans-serif; font-size:10pt; font-weight:normal }
109 .detotal
{ color
:#996600; font-family:sans-serif; font-size:10pt; font-weight:normal }
112 <script language
="JavaScript">
114 function checkAll(checked
) {
115 var f
= document
.forms
[0];
116 for (var i
= 0; i
< f
.elements
.length
; ++i
) {
117 var ename
= f
.elements
[i
].name
;
118 if (ename
.indexOf('form_cb[') == 0)
119 f
.elements
[i
].checked
= checked
;
127 <body leftmargin
='0' topmargin
='0' marginwidth
='0' marginheight
='0'>
130 <form method
='post' action
='collections_report.php' enctype
='multipart/form-data'>
132 <table border
='0' cellpadding
='5' cellspacing
='0'>
135 <td height
="1" colspan
="4">
139 <tr bgcolor
='#ddddff'>
141 <?
xl('Svc Date:','e')?
>
142 <input type
='text' name
='form_date' size
='10' value
='<?php echo $_POST['form_date
']; ?>'
143 title
='<?xl("Date of service mm/dd/yyyy","e")?>'>
147 <input type
='text' name
='form_to_date' size
='10' value
='<?php echo $_POST['form_to_date
']; ?>'
148 title
='<?xl("Ending DOS mm/dd/yyyy if you wish to enter a range","e")?>'>
151 <select name
='form_category'>
153 foreach (array(xl('Open'), xl('Due Pt'), xl('Due Ins'), xl('Credits')) as $value) {
154 echo " <option value='$value'";
155 if ($_POST['form_category'] == $value) echo " selected";
156 echo ">$value</option>\n";
162 <input type
='submit' name
='form_search' value
='<?xl("Search","e")?>'>
167 <td height
="1" colspan
="4">
174 if ($_POST['form_search'] ||
$_POST['form_export']) {
177 if ($_POST['form_export']) {
179 foreach ($_POST['form_cb'] as $key => $value) $where .= " OR ar.customer_id = $key";
184 if ($where) $where .= " AND ";
185 $date1 = substr($form_date, 0, 4) . substr($form_date, 5, 2) .
186 substr($form_date, 8, 2);
188 $date2 = substr($form_to_date, 0, 4) . substr($form_to_date, 5, 2) .
189 substr($form_to_date, 8, 2);
190 $where .= "((CAST (substring(ar.invnumber from position('.' in ar.invnumber) + 1 for 8) AS integer) " .
191 "BETWEEN '$date1' AND '$date2')";
192 $tmp = "date >= '$form_date' AND date <= '$form_to_date'";
195 // This catches old converted invoices where we have no encounters:
196 $where .= "(ar.invnumber LIKE '%.$date1'";
197 $tmp = "date = '$form_date'";
199 // Pick out the encounters from MySQL with the desired DOS:
200 $rez = sqlStatement("SELECT pid, encounter FROM form_encounter WHERE $tmp");
201 while ($row = sqlFetchArray($rez)) {
202 $where .= " OR ar.invnumber = '" . $row['pid'] . "." . $row['encounter'] . "'";
211 $query = "SELECT ar.id, ar.invnumber, ar.duedate, ar.amount, ar.paid, " .
212 "ar.intnotes, ar.notes, ar.shipvia, " .
213 "customer.id AS custid, customer.name, customer.address1, " .
214 "customer.city, customer.state, customer.zipcode, customer.phone, " .
215 "(SELECT SUM(invoice.fxsellprice) FROM invoice WHERE " .
216 "invoice.trans_id = ar.id AND invoice.fxsellprice > 0) AS charges, " .
217 "(SELECT SUM(invoice.fxsellprice) FROM invoice WHERE " .
218 "invoice.trans_id = ar.id AND invoice.fxsellprice < 0) AS adjustments " .
219 "FROM ar JOIN customer ON customer.id = ar.customer_id " .
221 if ($_POST['form_search']) {
222 $query .= "AND ar.amount != ar.paid ";
224 $query .= "ORDER BY ar.invnumber";
226 // echo "<!-- $query -->\n"; // debugging
228 $t_res = SLQuery($query);
229 if ($sl_err) die($sl_err);
230 $num_invoices = SLRowCount($t_res);
232 //////////////////////////////////////////////////////////////////
235 for ($irow = 0; $irow < $num_invoices; ++
$irow) {
236 $row = SLGetRow($t_res, $irow);
237 $pt_balance = sprintf("%.2f",$row['amount']) - sprintf("%.2f",$row['paid']);
239 if ($_POST['form_category'] == 'Credits') {
240 if ($pt_balance > 0) continue;
243 // if ($pt_balance < 0) continue;
246 // $duncount was originally supposed to be the number of times that
247 // the patient was sent a statement for this invoice.
249 $duncount = substr_count(strtolower($row['intnotes']), "statement sent");
251 // But if we have not yet billed the patient, then compute $duncount as a
252 // negative count of the number of insurance plans for which we have not
253 // yet closed out insurance. Here we also compute $insname as the name of
254 // the insurance plan from which we are awaiting payment.
258 $insgot = strtolower($row['notes']);
259 $inseobs = strtolower($row['shipvia']);
260 foreach (array('ins1', 'ins2', 'ins3') as $value) {
261 $i = strpos($insgot, $value);
262 if ($i !== false && strpos($inseobs, $value) === false) {
264 if (!$insname && $is_due_ins) {
265 $j = strpos($insgot, "\n", $i);
266 if (!$j) $j = strlen($insgot);
267 $insname = trim(substr($row['notes'], $i +
5, $j - $i - 5));
273 // An invoice is now due from the patient if money is owed and we are
274 // not waiting for insurance to pay. We no longer look at the due date
277 $isduept = ($duncount >= 0) ?
" checked" : "";
279 // Skip invoices not in the desired "Due..." category.
281 if ($is_due_ins && $duncount >= 0) continue;
282 if ($is_due_pt && $duncount < 0) continue;
284 $row['duncount'] = $duncount;
286 // Determine the date of service. An 8-digit encounter number is
287 // presumed to be a date of service imported during conversion.
288 // Otherwise look it up in the form_encounter table.
291 list($pid, $encounter) = explode(".", $row['invnumber']);
292 if (strlen($encounter) == 8) {
293 $svcdate = substr($encounter, 0, 4) . "-" . substr($encounter, 4, 2) .
294 "-" . substr($encounter, 6, 2);
296 else if ($encounter) {
297 $tmp = sqlQuery("SELECT date FROM form_encounter WHERE " .
298 "encounter = $encounter");
299 $svcdate = substr($tmp['date'], 0, 10);
302 $row['dos'] = $svcdate;
304 $pdrow = sqlQuery("SELECT pd.fname, pd.lname, pd.mname, pd.ss, " .
305 "pd.genericname2, pd.genericval2 FROM " .
306 "integration_mapping AS im, patient_data AS pd WHERE " .
307 "im.foreign_id = " . $row['custid'] . " AND " .
308 "im.foreign_table = 'customer' AND " .
309 "pd.id = im.local_id");
311 $row['ss'] = $pdrow['ss'];
312 $row['billnote'] = ($pdrow['genericname2'] == 'Billing') ?
$pdrow['genericval2'] : '';
314 $ptname = $pdrow['lname'] . ", " . $pdrow['fname'];
315 if ($pdrow['mname']) $ptname .= " " . substr($pdrow['mname'], 0, 1);
317 // $rows[$ptname] = $row;
318 $rows[$insname . '|' . $ptname . '|' . $encounter] = $row; // new
323 if ($_POST['form_export']) {
324 echo "<textarea rows='35' cols='100' readonly>";
329 <table border
='0' cellpadding
='1' cellspacing
='2' width
='98%'>
331 <tr bgcolor
="#dddddd">
332 <?php
if ($is_due_ins) { ?
>
334  
;<?
xl('Insurance','e')?
>
338  
;<?
xl('Name','e')?
>
341  
;<?
xl('SSN','e')?
>
344  
;<?
xl('Phone','e')?
>
347  
;<?
xl('City','e')?
>
350  
;<?php
xl('Invoice','e') ?
>
353  
;<?php
xl('Svc Date','e') ?
>
355 <td
class="dehead" align
="right">
356 <?php
xl('Charge','e') ?
> 
;
358 <td
class="dehead" align
="right">
359 <?php
xl('Adjust','e') ?
> 
;
361 <td
class="dehead" align
="right">
362 <?php
xl('Paid','e') ?
> 
;
364 <td
class="dehead" align
="right">
365 <?php
xl('Balance','e') ?
> 
;
367 <td
class="dehead" align
="center">
368 <?php
xl('Prv','e') ?
>
370 <td
class="dehead" align
="center">
371 <?php
xl('Sel','e') ?
>
378 $ptrow = array('insname' => '', 'pid' => 0);
381 foreach ($rows as $key => $row) {
382 list($insname, $ptname, $trash) = explode('|', $key);
383 list($pid, $encounter) = explode(".", $row['invnumber']);
385 if ($insname != $ptrow['insname'] ||
$pid != $ptrow['pid']) {
386 // For the report, this will write the patient totals. For the
387 // export this writes everything for the patient:
389 $bgcolor = ((++
$orow & 1) ?
"#ffdddd" : "#ddddff");
390 $ptrow = array('insname' => $insname, 'ptname' => $ptname, 'pid' => $pid, 'count' => 1);
391 foreach ($row as $key => $value) $ptrow[$key] = $value;
393 $ptrow['amount'] +
= $row['amount'];
394 $ptrow['paid'] +
= $row['paid'];
395 $ptrow['charges'] +
= $row['charges'];
396 $ptrow['adjustments'] +
= $row['adjustments'];
400 if (!$_POST['form_export']) {
402 $in_collections = stristr($row['billnote'], 'IN COLLECTIONS') !== false;
405 <tr bgcolor
='<?php echo $bgcolor ?>'>
407 if ($ptrow['count'] == 1) {
409 echo " <td class='detail'>\n";
410 echo " $insname\n";
413 echo " <td class='detail'>\n";
414 echo " $ptname\n";
416 echo " <td class='detail'>\n";
417 echo " " . $row['ss'] . "\n";
419 echo " <td class='detail'>\n";
420 echo " " . $row['phone'] . "\n";
422 echo " <td class='detail'>\n";
423 echo " " . $row['city'] . "\n";
426 echo " <td class='detail' colspan='" . ($is_due_ins ?
'5' : '4') . "'>\n";
432  
;<a href
="../billing/sl_eob_invoice.php?id=<?php echo $row['id'] ?>"
433 target
="_blank"><?php
echo $row['invnumber'] ?
></a
>
436  
;<?php
echo $row['dos']; ?
>
438 <td
class="detail" align
="right">
439 <?php
bucks($row['charges']) ?
> 
;
441 <td
class="detail" align
="right">
442 <?php
bucks($row['adjustments']) ?
> 
;
444 <td
class="detail" align
="right">
445 <?php
bucks($row['paid']) ?
> 
;
447 <td
class="detail" align
="right">
448 <?php
bucks($row['charges'] +
$row['adjustments'] - $row['paid']) ?
> 
;
450 <td
class="detail" align
="center">
451 <?php
echo $row['duncount'] ?
$row['duncount'] : " " ?
>
453 <td
class="detail" align
="center">
455 if ($ptrow['count'] == 1) {
456 if ($in_collections) {
457 echo " <b><font color='red'>IC</font></b>\n";
459 echo " <input type='checkbox' name='form_cb[" . $row['custid'] . "]' />\n";
468 } // end not $form_export
473 if ($_POST['form_export']) {
474 echo "</textarea>\n";
475 $alertmsg .= "$export_patient_count patients representing $" .
476 sprintf("%.2f", $export_dollars) . " have been exported ";
477 if ($_POST['form_without']) {
478 $alertmsg .= "but NOT flagged as in collections.";
480 $alertmsg .= "AND flagged as in collections.";
484 echo " <tr bgcolor='#ffffff'>\n";
485 echo " <td class='detail' colspan='" . ($is_due_ins ?
'5' : '4') . "'>\n";
488 echo " <td class='dehead' colspan='2'>\n";
489 echo " Report Totals:\n";
491 echo " <td class='dehead' align='right'>\n";
492 echo " " . sprintf("%.2f", $grand_total_charges) . " \n";
494 echo " <td class='dehead' align='right'>\n";
495 echo " " . sprintf("%.2f", $grand_total_adjustments) . " \n";
497 echo " <td class='dehead' align='right'>\n";
498 echo " " . sprintf("%.2f", $grand_total_paid) . " \n";
500 echo " <td class='dehead' align='right'>\n";
501 echo " " . sprintf("%.2f", $grand_total_charges +
502 $grand_total_adjustments - $grand_total_paid) . " \n";
504 echo " <td class='detail' colspan='2'>\n";
510 } // end if form_search
515 <?php
if (!$_POST['form_export']) { ?
>
516 <input type
='button' value
='Select All' onclick
='checkAll(true)' />  
;
517 <input type
='button' value
='Clear All' onclick
='checkAll(false)' />  
;
518 <input type
='submit' name
='form_export' value
='Export Selected to Collections' />  
;
519 <input type
='checkbox' name
='form_without' value
='1' /> <?php
xl('Without Update','e') ?
>
525 <script language
="JavaScript">
528 echo "alert('" . htmlentities($alertmsg) . "');\n";