added plugin support
[openemr.git] / interface / reports / receipts_by_method_report.php
blobdcbc23e7f174bc19ea2eb1af9951c3e93507885e
1 <?php
2 // Copyright (C) 2006-2009 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 a report of receipts by payer or payment method.
11 // The payer option means an insurance company name or "Patient".
13 // The payment method option is most useful for sites using
14 // pos_checkout.php (e.g. weight loss clinics) because this plugs
15 // a payment method like Cash, Check, VISA, etc. into the "source"
16 // column of the SQL-Ledger acc_trans table or ar_session table.
18 require_once("../globals.php");
19 require_once("../../library/patient.inc");
20 require_once("../../library/sql-ledger.inc");
21 require_once("../../library/acl.inc");
23 // This controls whether we show pt name, policy number and DOS.
24 $showing_ppd = true;
26 $insarray = array();
28 function bucks($amount) {
29 if ($amount)
30 printf("%.2f", $amount);
33 function thisLineItem($patient_id, $encounter_id, $memo, $transdate,
34 $rowmethod, $rowpayamount, $rowadjamount, $payer_type=0)
36 global $form_report_by, $insarray, $grandpaytotal, $grandadjtotal;
38 if ($form_report_by != '1') { // reporting by method or check number
39 showLineItem($patient_id, $encounter_id, $memo, $transdate,
40 $rowmethod, $rowpayamount, $rowadjamount, $payer_type);
41 return;
44 // Reporting by payer.
46 if ($_POST['form_details']) { // details are wanted
47 // Save everything for later sorting.
48 $insarray[] = array($patient_id, $encounter_id, $memo, $transdate,
49 $rowmethod, $rowpayamount, $rowadjamount, $payer_type);
51 else { // details not wanted
52 if (empty($insarray[$rowmethod])) $insarray[$rowmethod] = array(0, 0);
53 $insarray[$rowmethod][0] += $rowpayamount;
54 $insarray[$rowmethod][1] += $rowadjamount;
55 $grandpaytotal += $rowpayamount;
56 $grandadjtotal += $rowadjamount;
60 function showLineItem($patient_id, $encounter_id, $memo, $transdate,
61 $rowmethod, $rowpayamount, $rowadjamount, $payer_type=0)
63 global $paymethod, $paymethodleft, $methodpaytotal, $methodadjtotal,
64 $grandpaytotal, $grandadjtotal, $showing_ppd;
66 if (! $rowmethod) $rowmethod = 'Unknown';
68 $invnumber = "$patient_id.$encounter_id";
70 if ($paymethod != $rowmethod) {
71 if ($paymethod) {
72 // Print method total.
75 <tr bgcolor="#ddddff">
76 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
77 <?php echo xl('Total for ') . $paymethod ?>
78 </td>
79 <td class="dehead" align="right">
80 <?php bucks($methodadjtotal) ?>
81 </td>
82 <td class="dehead" align="right">
83 <?php bucks($methodpaytotal) ?>
84 </td>
85 </tr>
86 <?php
88 $methodpaytotal = 0;
89 $methodadjtotal = 0;
90 $paymethod = $rowmethod;
91 $paymethodleft = $paymethod;
94 if ($_POST['form_details']) {
97 <tr>
98 <td class="detail">
99 <?php echo $paymethodleft; $paymethodleft = "&nbsp;" ?>
100 </td>
101 <td class="dehead">
102 <?php echo $transdate ?>
103 </td>
104 <td class="detail">
105 <?php echo $invnumber ?>
106 </td>
108 <?php
109 if ($showing_ppd) {
110 $pferow = sqlQuery("SELECT p.fname, p.mname, p.lname, fe.date " .
111 "FROM patient_data AS p, form_encounter AS fe WHERE " .
112 "p.pid = '$patient_id' AND fe.pid = p.pid AND " .
113 "fe.encounter = '$encounter_id' LIMIT 1");
114 $dos = substr($pferow['date'], 0, 10);
116 echo " <td class='dehead'>\n";
117 echo " " . $pferow['lname'] . ", " . $pferow['fname'] . " " . $pferow['mname'];
118 echo " </td>\n";
120 echo " <td class='dehead'>\n";
121 if ($payer_type) {
122 $ptarr = array(1 => 'primary', 2 => 'secondary', 3 => 'tertiary');
123 $insrow = getInsuranceDataByDate($patient_id, $dos,
124 $ptarr[$payer_type], "policy_number");
125 echo " " . $insrow['policy_number'];
127 echo " </td>\n";
129 echo " <td class='dehead'>\n";
130 echo " $dos\n";
131 echo " </td>\n";
135 <td class="dehead">
136 <?php echo $memo ?>
137 </td>
138 <td class="dehead" align="right">
139 <?php bucks($rowadjamount) ?>
140 </td>
141 <td class="dehead" align="right">
142 <?php bucks($rowpayamount) ?>
143 </td>
144 </tr>
145 <?php
147 $methodpaytotal += $rowpayamount;
148 $grandpaytotal += $rowpayamount;
149 $methodadjtotal += $rowadjamount;
150 $grandadjtotal += $rowadjamount;
153 // This is called by usort() when reporting by payer with details.
154 // Sorts by payer/date/patient/encounter/memo.
155 function payerCmp($a, $b) {
156 foreach (array(4,3,0,1,2,7) as $i) {
157 if ($a[$i] < $b[$i]) return -1;
158 if ($a[$i] > $b[$i]) return 1;
160 return 0;
163 if (! acl_check('acct', 'rep')) die(xl("Unauthorized access."));
165 $INTEGRATED_AR = $GLOBALS['oer_config']['ws_accounting']['enabled'] === 2;
167 if (!$INTEGRATED_AR) SLConnect();
169 $form_from_date = fixDate($_POST['form_from_date'], date('Y-m-d'));
170 $form_to_date = fixDate($_POST['form_to_date'] , date('Y-m-d'));
171 $form_use_edate = $_POST['form_use_edate'];
172 $form_facility = $_POST['form_facility'];
173 $form_report_by = $_POST['form_report_by'];
174 $form_cptcode = trim($_POST['form_cptcode']);
176 <html>
177 <head>
178 <?php if (function_exists('html_header_show')) html_header_show(); ?>
179 <title><?xl('Receipts Summary','e')?></title>
180 </head>
182 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
183 <center>
185 <h2><?php xl('Receipts Summary','e') ?></h2>
187 <form method='post' action='receipts_by_method_report.php'>
189 <table border='0' cellpadding='3'>
191 <tr>
192 <td>
193 <?php xl('Report by','e'); ?>
194 <?php
195 echo " <select name='form_report_by'>\n";
196 foreach (array(1 => 'Payer', 2 => 'Payment Method', 3 => 'Check Number') as $key => $value) {
197 echo " <option value='$key'";
198 if ($key == $form_report_by) echo ' selected';
199 echo ">" . xl($value) . "</option>\n";
201 echo " </select>&nbsp;\n";
203 // Build a drop-down list of facilities.
205 $query = "SELECT id, name FROM facility ORDER BY name";
206 $fres = sqlStatement($query);
207 echo " <select name='form_facility'>\n";
208 echo " <option value=''>-- " . xl('All Facilities') . " --\n";
209 while ($frow = sqlFetchArray($fres)) {
210 $facid = $frow['id'];
211 echo " <option value='$facid'";
212 if ($facid == $form_facility) echo " selected";
213 echo ">" . $frow['name'] . "\n";
215 echo " </select>\n";
217 <?php if (!$GLOBALS['simplified_demographics']) echo '&nbsp;' . xl('CPT') . ':'; ?>
218 <input type='text' name='form_cptcode' size='5' value='<?php echo $form_cptcode; ?>'
219 title='<?php xl('Optional procedure code','e'); ?>'
220 <?php if ($GLOBALS['simplified_demographics']) echo "style='display:none'"; ?> />
221 &nbsp;
222 <input type='checkbox' name='form_details' value='1'<?php if ($_POST['form_details']) echo " checked"; ?> /><?xl('Details','e')?>
223 </td>
224 </tr>
226 <tr>
227 <td>
228 <select name='form_use_edate'>
229 <option value='0'><?php xl('Payment Date','e'); ?></option>
230 <option value='1'<?php if ($form_use_edate) echo ' selected' ?>><?php xl('Invoice Date','e'); ?></option>
231 </select>
232 &nbsp;<?xl('From:','e')?>
233 <input type='text' name='form_from_date' id="form_from_date" size='10' value='<?php echo $form_from_date ?>'
234 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='yyyy-mm-dd'>
235 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
236 id='img_from_date' border='0' alt='[?]' style='cursor:pointer'
237 title='<?php xl('Click here to choose a date','e'); ?>'>
238 &nbsp;<?php xl('To:','e'); ?>
239 <input type='text' name='form_to_date' id="form_to_date" size='10' value='<?php echo $form_to_date ?>'
240 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='yyyy-mm-dd'>
241 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
242 id='img_to_date' border='0' alt='[?]' style='cursor:pointer'
243 title='<?php xl('Click here to choose a date','e'); ?>'>
244 &nbsp;
245 <input type='submit' name='form_refresh' value="<?xl('Refresh','e')?>">
246 &nbsp;
247 <input type='button' value='<?php xl('Print','e'); ?>' onclick='window.print()' />
248 </td>
249 </tr>
251 <tr>
252 <td height="1">
253 </td>
254 </tr>
256 </table>
258 <table border='0' cellpadding='1' cellspacing='2' width='98%'>
260 <tr bgcolor="#dddddd">
261 <td class="dehead">
262 <?xl('Method','e')?>
263 </td>
264 <td class="dehead">
265 <?xl('Date','e')?>
266 </td>
267 <td class="dehead">
268 <?xl('Invoice','e')?>
269 </td>
270 <?php if ($showing_ppd) { ?>
271 <td class="dehead">
272 <?xl('Patient','e')?>
273 </td>
274 <td class="dehead">
275 <?xl('Policy','e')?>
276 </td>
277 <td class="dehead">
278 <?xl('DOS','e')?>
279 </td>
280 <?php } ?>
281 <td class="dehead">
282 <?xl('Procedure','e')?>
283 </td>
284 <td class="dehead" align="right">
285 <?xl('Adjustments','e')?>
286 </td>
287 <td class="dehead" align="right">
288 <?xl('Payments','e')?>
289 </td>
290 </tr>
291 <?php
293 if (!$INTEGRATED_AR) {
294 $chart_id_cash = SLQueryValue("select id from chart where accno = '$sl_cash_acc'");
295 if ($sl_err) die($sl_err);
296 $chart_id_income = SLQueryValue("select id from chart where accno = '$sl_income_acc'");
297 if ($sl_err) die($sl_err);
300 if ($_POST['form_refresh']) {
301 $from_date = $form_from_date;
302 $to_date = $form_to_date;
304 $paymethod = "";
305 $paymethodleft = "";
306 $methodpaytotal = 0;
307 $grandpaytotal = 0;
308 $methodadjtotal = 0;
309 $grandadjtotal = 0;
311 if ($INTEGRATED_AR) {
313 // Get co-pays using the encounter date as the pay date. These will
314 // always be considered patient payments. Ignored if selecting by
315 // billing code.
317 if (!$form_cptcode) {
318 $query = "SELECT b.fee, b.pid, b.encounter, b.code_type, " .
319 "fe.date, fe.facility_id " .
320 "FROM billing AS b " .
321 "JOIN form_encounter AS fe ON fe.pid = b.pid AND fe.encounter = b.encounter " .
322 "WHERE b.code_type = 'COPAY' AND b.activity = 1 AND b.fee != 0 AND " .
323 "fe.date >= '$from_date 00:00:00' AND fe.date <= '$to_date 23:59:59'";
324 // If a facility was specified.
325 if ($form_facility) $query .= " AND fe.facility_id = '$form_facility'";
326 $query .= " ORDER BY fe.date, b.pid, b.encounter, fe.id";
328 $res = sqlStatement($query);
329 while ($row = sqlFetchArray($res)) {
330 $rowmethod = $form_report_by == 1 ? 'Patient' : 'Co-Pay';
331 thisLineItem($row['pid'], $row['encounter'], $row['code_text'],
332 substr($row['date'], 0, 10), $rowmethod, 0 - $row['fee'], 0);
334 } // end if not form_cptcode
336 // Get all other payments and adjustments and their dates, corresponding
337 // payers and check reference data, and the encounter dates separately.
339 $query = "SELECT a.pid, a.encounter, a.post_time, a.pay_amount, " .
340 "a.adj_amount, a.memo, a.session_id, a.code, a.payer_type, fe.id, fe.date, " .
341 "s.deposit_date, s.payer_id, s.reference, i.name " .
342 "FROM ar_activity AS a " .
343 "JOIN form_encounter AS fe ON fe.pid = a.pid AND fe.encounter = a.encounter " .
344 "JOIN forms AS f ON f.pid = a.pid AND f.encounter = a.encounter AND f.formdir = 'newpatient' " .
345 "LEFT JOIN ar_session AS s ON s.session_id = a.session_id " .
346 "LEFT JOIN insurance_companies AS i ON i.id = s.payer_id " .
347 "WHERE ( a.pay_amount != 0 OR a.adj_amount != 0 )";
349 if ($form_use_edate) {
350 $query .= " AND fe.date >= '$from_date 00:00:00' AND fe.date <= '$to_date 23:59:59'";
351 } else {
352 $query .= " AND ( ( s.deposit_date IS NOT NULL AND " .
353 "s.deposit_date >= '$from_date' AND s.deposit_date <= '$to_date' ) OR " .
354 "( s.deposit_date IS NULL AND a.post_time >= '$from_date 00:00:00' AND " .
355 "a.post_time <= '$to_date 23:59:59' ) )";
357 // If a procedure code was specified.
358 if ($form_cptcode) $query .= " AND a.code LIKE '$form_cptcode%'";
359 // If a facility was specified.
360 if ($form_facility) $query .= " AND fe.facility_id = '$form_facility'";
362 if ($form_use_edate) {
363 $query .= " ORDER BY s.reference, fe.date, a.pid, a.encounter, fe.id";
364 } else {
365 $query .= " ORDER BY s.reference, s.deposit_date, a.post_time, a.pid, a.encounter, fe.id";
368 $res = sqlStatement($query);
369 while ($row = sqlFetchArray($res)) {
370 if ($form_use_edate) {
371 $thedate = substr($row['date'], 0, 10);
372 } else if (!empty($row['deposit_date'])) {
373 $thedate = $row['deposit_date'];
374 } else {
375 $thedate = substr($row['post_time'], 0, 10);
377 // Compute reporting key: insurance company name or payment method.
378 if ($form_report_by == '1') {
379 if (empty($row['payer_id'])) {
380 $rowmethod = '';
381 } else {
382 if (empty($row['name'])) $rowmethod = xl('Unnamed insurance company');
383 else $rowmethod = $row['name'];
386 else {
387 if (empty($row['session_id'])) {
388 $rowmethod = trim($row['memo']);
389 } else {
390 $rowmethod = trim($row['reference']);
392 if ($form_report_by != '3') {
393 // Extract only the first word as the payment method because any
394 // following text will be some petty detail like a check number.
395 $rowmethod = substr($rowmethod, 0, strcspn($rowmethod, ' /'));
399 thisLineItem($row['pid'], $row['encounter'], $row['code'], $thedate,
400 $rowmethod, $row['pay_amount'], $row['adj_amount'], $row['payer_type']);
402 } // end $INTEGRATED_AR
403 else {
404 $query = "SELECT acc_trans.amount, acc_trans.transdate, acc_trans.memo, " .
405 "replace(acc_trans.source, 'InvAdj ', '') AS source, " .
406 "acc_trans.chart_id, ar.invnumber, ar.employee_id, ar.notes " .
407 "FROM acc_trans, ar WHERE " .
408 "( acc_trans.chart_id = $chart_id_cash OR " .
409 "( acc_trans.chart_id = $chart_id_income AND " .
410 "acc_trans.source LIKE 'InvAdj %' ) ) AND " .
411 "ar.id = acc_trans.trans_id AND ";
412 if ($form_cptcode) {
413 $query .= "acc_trans.memo ILIKE '$form_cptcode%' AND ";
415 if ($form_use_edate) {
416 $query .= "ar.transdate >= '$from_date' AND " .
417 "ar.transdate <= '$to_date'";
418 } else {
419 $query .= "acc_trans.transdate >= '$from_date' AND " .
420 "acc_trans.transdate <= '$to_date'";
422 $query .= " ORDER BY source, acc_trans.transdate, ar.invnumber, acc_trans.memo";
424 // echo "<!-- $query -->\n";
426 $t_res = SLQuery($query);
427 if ($sl_err) die($sl_err);
429 for ($irow = 0; $irow < SLRowCount($t_res); ++$irow) {
430 $row = SLGetRow($t_res, $irow);
431 list($patient_id, $encounter_id) = explode(".", $row['invnumber']);
433 // If a facility was specified then skip invoices whose encounters
434 // do not indicate that facility.
435 if ($form_facility) {
436 $tmp = sqlQuery("SELECT count(*) AS count FROM form_encounter WHERE " .
437 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
438 "facility_id = '$form_facility'");
439 if (empty($tmp['count'])) continue;
442 $rowpayamount = 0 - $row['amount'];
443 $rowadjamount = 0;
444 if ($row['chart_id'] == $chart_id_income) {
445 $rowadjamount = $rowpayamount;
446 $rowpayamount = 0;
449 // Compute reporting key: insurance company name or payment method.
450 $payer_type = 0; // will be 0=pt, 1=ins1, 2=ins2 or 3=ins3
451 if ($form_report_by == '1') {
452 $rowmethod = '';
453 $rowsrc = strtolower($row['source']);
454 $insgot = strtolower($row['notes']);
455 foreach (array('ins1', 'ins2', 'ins3') as $value) {
456 if (strpos($rowsrc, $value) !== false) {
457 $i = strpos($insgot, $value);
458 if ($i !== false) {
459 $j = strpos($insgot, "\n", $i);
460 if (!$j) $j = strlen($insgot);
461 $payer_type = 0 + substr($value, 3);
462 $rowmethod = trim(substr($row['notes'], $i + 5, $j - $i - 5));
463 break;
466 } // end foreach
467 } // end reporting by payer
468 else {
469 $rowmethod = trim($row['source']);
470 if ($form_report_by != '3') {
471 // Extract only the first word as the payment method because any
472 // following text will be some petty detail like a check number.
473 $rowmethod = substr($rowmethod, 0, strcspn($rowmethod, ' /'));
475 } // end reporting by method
477 thisLineItem($patient_id, $encounter_id, $row['memo'], $row['transdate'],
478 $rowmethod, $rowpayamount, $rowadjamount, $payer_type);
479 } // end for
480 } // end not $INTEGRATED_AR
482 // Not payer summary.
483 if ($form_report_by != '1' || $_POST['form_details']) {
485 if ($form_report_by == '1') { // by payer with details
486 // Sort and dump saved info, and consolidate items with all key
487 // fields being the same.
488 usort($insarray, 'payerCmp');
489 $b = array();
490 foreach ($insarray as $a) {
491 if (empty($a[4])) $a[4] = xl('Patient');
492 if (empty($b)) {
493 $b = $a;
495 else {
496 $match = true;
497 foreach (array(4,3,0,1,2,7) as $i) if ($a[$i] != $b[$i]) $match = false;
498 if ($match) {
499 $b[5] += $a[5];
500 $b[6] += $a[6];
501 } else {
502 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7]);
503 $b = $a;
507 if (!empty($b)) {
508 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7]);
510 } // end by payer with details
512 // Print last method total.
514 <tr bgcolor="#ddddff">
515 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
516 <?echo xl('Total for ') . $paymethod ?>
517 </td>
518 <td class="dehead" align="right">
519 <?php bucks($methodadjtotal) ?>
520 </td>
521 <td class="dehead" align="right">
522 <?php bucks($methodpaytotal) ?>
523 </td>
524 </tr>
525 <?php
528 // Payer summary: need to sort and then print it all.
529 else {
530 ksort($insarray);
531 foreach ($insarray as $key => $value) {
532 if (empty($key)) $key = xl('Patient');
534 <tr bgcolor="#ddddff">
535 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
536 <?php echo $key; ?>
537 </td>
538 <td class="dehead" align="right">
539 <?php bucks($value[1]); ?>
540 </td>
541 <td class="dehead" align="right">
542 <?php bucks($value[0]); ?>
543 </td>
544 </tr>
545 <?php
546 } // end foreach
547 } // end payer summary
549 <tr bgcolor="#ffdddd">
550 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
551 <?php xl('Grand Total','e') ?>
552 </td>
553 <td class="dehead" align="right">
554 <?php bucks($grandadjtotal) ?>
555 </td>
556 <td class="dehead" align="right">
557 <?php bucks($grandpaytotal) ?>
558 </td>
559 </tr>
561 <?php
562 } // end form refresh
563 if (!$INTEGRATED_AR) SLClose();
566 </table>
567 </form>
568 </center>
569 </body>
571 <!-- stuff for the popup calendar -->
572 <style type="text/css">@import url(../../library/dynarch_calendar.css);</style>
573 <script type="text/javascript" src="../../library/dynarch_calendar.js"></script>
574 <script type="text/javascript" src="../../library/dynarch_calendar_en.js"></script>
575 <script type="text/javascript" src="../../library/dynarch_calendar_setup.js"></script>
576 <script language="Javascript">
577 Calendar.setup({inputField:"form_from_date", ifFormat:"%Y-%m-%d", button:"img_from_date"});
578 Calendar.setup({inputField:"form_to_date", ifFormat:"%Y-%m-%d", button:"img_to_date"});
579 </script>
581 </html>