Merge branch 'master' of git://github.com/openemr/openemr
[openemr.git] / interface / reports / receipts_by_method_report.php
blob90c5f4225bb330707e01ae586db29bcfb9f563f9
1 <?php
2 // Copyright (C) 2006-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 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("$srcdir/patient.inc");
20 require_once("$srcdir/sql-ledger.inc");
21 require_once("$srcdir/acl.inc");
22 require_once("$srcdir/formatting.inc.php");
23 require_once "$srcdir/options.inc.php";
24 require_once "$srcdir/formdata.inc.php";
26 // This controls whether we show pt name, policy number and DOS.
27 $showing_ppd = true;
29 $insarray = array();
31 function bucks($amount) {
32 if ($amount) echo oeFormatMoney($amount);
35 function thisLineItem($patient_id, $encounter_id, $memo, $transdate,
36 $rowmethod, $rowpayamount, $rowadjamount, $payer_type=0, $irnumber='')
38 global $form_report_by, $insarray, $grandpaytotal, $grandadjtotal;
40 if ($form_report_by != '1') { // reporting by method or check number
41 showLineItem($patient_id, $encounter_id, $memo, $transdate,
42 $rowmethod, $rowpayamount, $rowadjamount, $payer_type, $irnumber);
43 return;
46 // Reporting by payer.
48 if ($_POST['form_details']) { // details are wanted
49 // Save everything for later sorting.
50 $insarray[] = array($patient_id, $encounter_id, $memo, $transdate,
51 $rowmethod, $rowpayamount, $rowadjamount, $payer_type, $irnumber);
53 else { // details not wanted
54 if (empty($insarray[$rowmethod])) $insarray[$rowmethod] = array(0, 0);
55 $insarray[$rowmethod][0] += $rowpayamount;
56 $insarray[$rowmethod][1] += $rowadjamount;
57 $grandpaytotal += $rowpayamount;
58 $grandadjtotal += $rowadjamount;
62 function showLineItem($patient_id, $encounter_id, $memo, $transdate,
63 $rowmethod, $rowpayamount, $rowadjamount, $payer_type=0, $irnumber='')
65 global $paymethod, $paymethodleft, $methodpaytotal, $methodadjtotal,
66 $grandpaytotal, $grandadjtotal, $showing_ppd;
68 if (! $rowmethod) $rowmethod = 'Unknown';
70 $invnumber = $irnumber ? $irnumber : "$patient_id.$encounter_id";
72 if ($paymethod != $rowmethod) {
73 if ($paymethod) {
74 // Print method total.
77 <tr bgcolor="#ddddff">
78 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
79 <?php echo xl('Total for ') . $paymethod ?>
80 </td>
81 <td align="right">
82 <?php bucks($methodadjtotal) ?>
83 </td>
84 <td align="right">
85 <?php bucks($methodpaytotal) ?>
86 </td>
87 </tr>
88 <?php
90 $methodpaytotal = 0;
91 $methodadjtotal = 0;
92 $paymethod = $rowmethod;
93 $paymethodleft = $paymethod;
96 if ($_POST['form_details']) {
99 <tr>
100 <td class="detail">
101 <?php echo $paymethodleft; $paymethodleft = "&nbsp;" ?>
102 </td>
103 <td>
104 <?php echo oeFormatShortDate($transdate) ?>
105 </td>
106 <td class="detail">
107 <?php echo $invnumber ?>
108 </td>
110 <?php
111 if ($showing_ppd) {
112 $pferow = sqlQuery("SELECT p.fname, p.mname, p.lname, fe.date " .
113 "FROM patient_data AS p, form_encounter AS fe WHERE " .
114 "p.pid = '$patient_id' AND fe.pid = p.pid AND " .
115 "fe.encounter = '$encounter_id' LIMIT 1");
116 $dos = substr($pferow['date'], 0, 10);
118 echo " <td class='dehead'>\n";
119 echo " " . $pferow['lname'] . ", " . $pferow['fname'] . " " . $pferow['mname'];
120 echo " </td>\n";
122 echo " <td class='dehead'>\n";
123 if ($payer_type) {
124 $ptarr = array(1 => 'primary', 2 => 'secondary', 3 => 'tertiary');
125 $insrow = getInsuranceDataByDate($patient_id, $dos,
126 $ptarr[$payer_type], "policy_number");
127 echo " " . $insrow['policy_number'];
129 echo " </td>\n";
131 echo " <td class='dehead'>\n";
132 echo " " . oeFormatShortDate($dos) . "\n";
133 echo " </td>\n";
137 <td>
138 <?php echo $memo ?>
139 </td>
140 <td align="right">
141 <?php bucks($rowadjamount) ?>
142 </td>
143 <td align="right">
144 <?php bucks($rowpayamount) ?>
145 </td>
146 </tr>
147 <?php
149 $methodpaytotal += $rowpayamount;
150 $grandpaytotal += $rowpayamount;
151 $methodadjtotal += $rowadjamount;
152 $grandadjtotal += $rowadjamount;
155 // This is called by usort() when reporting by payer with details.
156 // Sorts by payer/date/patient/encounter/memo.
157 function payerCmp($a, $b) {
158 foreach (array(4,3,0,1,2,7) as $i) {
159 if ($a[$i] < $b[$i]) return -1;
160 if ($a[$i] > $b[$i]) return 1;
162 return 0;
165 if (! acl_check('acct', 'rep')) die(xl("Unauthorized access."));
167 $INTEGRATED_AR = $GLOBALS['oer_config']['ws_accounting']['enabled'] === 2;
169 if (!$INTEGRATED_AR) SLConnect();
171 $form_from_date = fixDate($_POST['form_from_date'], date('Y-m-d'));
172 $form_to_date = fixDate($_POST['form_to_date'] , date('Y-m-d'));
173 $form_use_edate = $_POST['form_use_edate'];
174 $form_facility = $_POST['form_facility'];
175 $form_report_by = $_POST['form_report_by'];
176 $form_cptcode = trim($_POST['form_cptcode']);
178 <html>
179 <head>
180 <?php if (function_exists('html_header_show')) html_header_show(); ?>
181 <style type="text/css">
182 /* specifically include & exclude from printing */
183 @media print {
184 #report_parameters {
185 visibility: hidden;
186 display: none;
188 #report_parameters_daterange {
189 visibility: visible;
190 display: inline;
192 #report_results {
193 margin-top: 30px;
197 /* specifically exclude some from the screen */
198 @media screen {
199 #report_parameters_daterange {
200 visibility: hidden;
201 display: none;
204 </style>
205 <title><?xl('Receipts Summary','e')?></title>
206 </head>
208 <body class="body_top">
210 <span class='title'><?php xl('Report','e'); ?> - <?php xl('Receipts Summary','e'); ?></span>
212 <form method='post' action='receipts_by_method_report.php' id='theform'>
214 <div id="report_parameters">
216 <input type='hidden' name='form_refresh' id='form_refresh' value=''/>
218 <table>
219 <tr>
220 <td width='630px'>
221 <div style='float:left'>
223 <table class='text'>
224 <tr>
225 <td class='label'>
226 <?php xl('Report by','e'); ?>
227 </td>
228 <td>
229 <?php
230 echo " <select name='form_report_by'>\n";
231 foreach (array(1 => 'Payer', 2 => 'Payment Method', 3 => 'Check Number') as $key => $value) {
232 echo " <option value='$key'";
233 if ($key == $form_report_by) echo ' selected';
234 echo ">" . xl($value) . "</option>\n";
236 echo " </select>&nbsp;\n"; ?>
237 </td>
239 <td>
240 <?php dropdown_facility(strip_escape_custom($form_facility), 'form_facility', false); ?>
241 </td>
243 <td>
244 <?php if (!$GLOBALS['simplified_demographics']) echo '&nbsp;' . xl('CPT') . ':'; ?>
245 </td>
246 <td>
247 <input type='text' name='form_cptcode' size='5' value='<?php echo $form_cptcode; ?>'
248 title='<?php xl('Optional procedure code','e'); ?>'
249 <?php if ($GLOBALS['simplified_demographics']) echo "style='display:none'"; ?> />
250 &nbsp;<input type='checkbox' name='form_details' value='1'<?php if ($_POST['form_details']) echo " checked"; ?> /><?xl('Details','e')?>
251 </td>
252 </tr>
253 <tr>
254 <td>&nbsp;</td>
255 <td>
256 <select name='form_use_edate'>
257 <option value='0'><?php xl('Payment Date','e'); ?></option>
258 <option value='1'<?php if ($form_use_edate) echo ' selected' ?>><?php xl('Invoice Date','e'); ?></option>
259 </select>
260 </td>
261 <td>
262 <input type='text' name='form_from_date' id="form_from_date" size='10' value='<?php echo $form_from_date ?>'
263 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='yyyy-mm-dd'>
264 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
265 id='img_from_date' border='0' alt='[?]' style='cursor:pointer'
266 title='<?php xl('Click here to choose a date','e'); ?>'>
267 </td>
268 <td class='label'>
269 <?php xl('To','e'); ?>:
270 </td>
271 <td>
272 <input type='text' name='form_to_date' id="form_to_date" size='10' value='<?php echo $form_to_date ?>'
273 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='yyyy-mm-dd'>
274 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
275 id='img_to_date' border='0' alt='[?]' style='cursor:pointer'
276 title='<?php xl('Click here to choose a date','e'); ?>'>
277 </td>
278 </tr>
279 </table>
281 </div>
283 </td>
284 <td align='left' valign='middle' height="100%">
285 <table style='border-left:1px solid; width:100%; height:100%' >
286 <tr>
287 <td>
288 <div style='margin-left:15px'>
289 <a href='#' class='css_button' onclick='$("#form_refresh").attr("value","true"); $("#theform").submit();'>
290 <span>
291 <?php xl('Submit','e'); ?>
292 </span>
293 </a>
295 <?php if ($_POST['form_refresh']) { ?>
296 <a href='#' class='css_button' onclick='window.print()'>
297 <span>
298 <?php xl('Print','e'); ?>
299 </span>
300 </a>
301 <?php } ?>
302 </div>
303 </td>
304 </tr>
305 </table>
306 </td>
307 </tr>
308 </table>
310 </div> <!-- end of parameters -->
312 <?php
313 if ($_POST['form_refresh']) {
315 <div id="report_results">
317 <table>
319 <thead>
320 <th>
321 <?xl('Method','e')?>
322 </th>
323 <th>
324 <?xl('Date','e')?>
325 </th>
326 <th>
327 <?xl('Invoice','e')?>
328 </th>
329 <?php if ($showing_ppd) { ?>
330 <th>
331 <?xl('Patient','e')?>
332 </th>
333 <th>
334 <?xl('Policy','e')?>
335 </th>
336 <th>
337 <?xl('DOS','e')?>
338 </th>
339 <?php } ?>
340 <th>
341 <?xl('Procedure','e')?>
342 </th>
343 <th align="right">
344 <?xl('Adjustments','e')?>
345 </th>
346 <th align="right">
347 <?xl('Payments','e')?>
348 </th>
349 </thead>
350 <?php
352 if (!$INTEGRATED_AR) {
353 $chart_id_cash = SLQueryValue("select id from chart where accno = '$sl_cash_acc'");
354 if ($sl_err) die($sl_err);
355 $chart_id_income = SLQueryValue("select id from chart where accno = '$sl_income_acc'");
356 if ($sl_err) die($sl_err);
359 if ($_POST['form_refresh']) {
360 $from_date = $form_from_date;
361 $to_date = $form_to_date;
363 $paymethod = "";
364 $paymethodleft = "";
365 $methodpaytotal = 0;
366 $grandpaytotal = 0;
367 $methodadjtotal = 0;
368 $grandadjtotal = 0;
370 if ($INTEGRATED_AR) {
372 // Get co-pays using the encounter date as the pay date. These will
373 // always be considered patient payments. Ignored if selecting by
374 // billing code.
376 if (!$form_cptcode) {
377 $query = "SELECT b.fee, b.pid, b.encounter, b.code_type, " .
378 "fe.date, fe.facility_id, fe.invoice_refno " .
379 "FROM billing AS b " .
380 "JOIN form_encounter AS fe ON fe.pid = b.pid AND fe.encounter = b.encounter " .
381 "WHERE b.code_type = 'COPAY' AND b.activity = 1 AND b.fee != 0 AND " .
382 "fe.date >= '$from_date 00:00:00' AND fe.date <= '$to_date 23:59:59'";
383 // If a facility was specified.
384 if ($form_facility) $query .= " AND fe.facility_id = '$form_facility'";
385 $query .= " ORDER BY fe.date, b.pid, b.encounter, fe.id";
387 $res = sqlStatement($query);
388 while ($row = sqlFetchArray($res)) {
389 $rowmethod = $form_report_by == 1 ? 'Patient' : 'Co-Pay';
390 thisLineItem($row['pid'], $row['encounter'], $row['code_text'],
391 substr($row['date'], 0, 10), $rowmethod, 0 - $row['fee'], 0, 0, $row['invoice_refno']);
393 } // end if not form_cptcode
395 // Get all other payments and adjustments and their dates, corresponding
396 // payers and check reference data, and the encounter dates separately.
398 $query = "SELECT a.pid, a.encounter, a.post_time, a.pay_amount, " .
399 "a.adj_amount, a.memo, a.session_id, a.code, a.payer_type, fe.id, fe.date, " .
400 "fe.invoice_refno, s.deposit_date, s.payer_id, s.reference, i.name " .
401 "FROM ar_activity AS a " .
402 "JOIN form_encounter AS fe ON fe.pid = a.pid AND fe.encounter = a.encounter " .
403 "JOIN forms AS f ON f.pid = a.pid AND f.encounter = a.encounter AND f.formdir = 'newpatient' " .
404 "LEFT JOIN ar_session AS s ON s.session_id = a.session_id " .
405 "LEFT JOIN insurance_companies AS i ON i.id = s.payer_id " .
406 "WHERE ( a.pay_amount != 0 OR a.adj_amount != 0 )";
408 if ($form_use_edate) {
409 $query .= " AND fe.date >= '$from_date 00:00:00' AND fe.date <= '$to_date 23:59:59'";
410 } else {
411 $query .= " AND ( ( s.deposit_date IS NOT NULL AND " .
412 "s.deposit_date >= '$from_date' AND s.deposit_date <= '$to_date' ) OR " .
413 "( s.deposit_date IS NULL AND a.post_time >= '$from_date 00:00:00' AND " .
414 "a.post_time <= '$to_date 23:59:59' ) )";
416 // If a procedure code was specified.
417 if ($form_cptcode) $query .= " AND a.code LIKE '$form_cptcode%'";
418 // If a facility was specified.
419 if ($form_facility) $query .= " AND fe.facility_id = '$form_facility'";
421 if ($form_use_edate) {
422 $query .= " ORDER BY s.reference, fe.date, a.pid, a.encounter, fe.id";
423 } else {
424 $query .= " ORDER BY s.reference, s.deposit_date, a.post_time, a.pid, a.encounter, fe.id";
427 $res = sqlStatement($query);
428 while ($row = sqlFetchArray($res)) {
429 if ($form_use_edate) {
430 $thedate = substr($row['date'], 0, 10);
431 } else if (!empty($row['deposit_date'])) {
432 $thedate = $row['deposit_date'];
433 } else {
434 $thedate = substr($row['post_time'], 0, 10);
436 // Compute reporting key: insurance company name or payment method.
437 if ($form_report_by == '1') {
438 if (empty($row['payer_id'])) {
439 $rowmethod = '';
440 } else {
441 if (empty($row['name'])) $rowmethod = xl('Unnamed insurance company');
442 else $rowmethod = $row['name'];
445 else {
446 if (empty($row['session_id'])) {
447 $rowmethod = trim($row['memo']);
448 } else {
449 $rowmethod = trim($row['reference']);
451 if ($form_report_by != '3') {
452 // Extract only the first word as the payment method because any
453 // following text will be some petty detail like a check number.
454 $rowmethod = substr($rowmethod, 0, strcspn($rowmethod, ' /'));
458 thisLineItem($row['pid'], $row['encounter'], $row['code'], $thedate,
459 $rowmethod, $row['pay_amount'], $row['adj_amount'], $row['payer_type'],
460 $row['invoice_refno']);
462 } // end $INTEGRATED_AR
463 else {
464 $query = "SELECT acc_trans.amount, acc_trans.transdate, acc_trans.memo, " .
465 "replace(acc_trans.source, 'InvAdj ', '') AS source, " .
466 "acc_trans.chart_id, ar.invnumber, ar.employee_id, ar.notes " .
467 "FROM acc_trans, ar WHERE " .
468 "( acc_trans.chart_id = $chart_id_cash OR " .
469 "( acc_trans.chart_id = $chart_id_income AND " .
470 "acc_trans.source LIKE 'InvAdj %' ) ) AND " .
471 "ar.id = acc_trans.trans_id AND ";
472 if ($form_cptcode) {
473 $query .= "acc_trans.memo ILIKE '$form_cptcode%' AND ";
475 if ($form_use_edate) {
476 $query .= "ar.transdate >= '$from_date' AND " .
477 "ar.transdate <= '$to_date'";
478 } else {
479 $query .= "acc_trans.transdate >= '$from_date' AND " .
480 "acc_trans.transdate <= '$to_date'";
482 $query .= " ORDER BY source, acc_trans.transdate, ar.invnumber, acc_trans.memo";
484 // echo "<!-- $query -->\n";
486 $t_res = SLQuery($query);
487 if ($sl_err) die($sl_err);
489 for ($irow = 0; $irow < SLRowCount($t_res); ++$irow) {
490 $row = SLGetRow($t_res, $irow);
491 list($patient_id, $encounter_id) = explode(".", $row['invnumber']);
493 // If a facility was specified then skip invoices whose encounters
494 // do not indicate that facility.
495 if ($form_facility) {
496 $tmp = sqlQuery("SELECT count(*) AS count FROM form_encounter WHERE " .
497 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
498 "facility_id = '$form_facility'");
499 if (empty($tmp['count'])) continue;
502 $rowpayamount = 0 - $row['amount'];
503 $rowadjamount = 0;
504 if ($row['chart_id'] == $chart_id_income) {
505 $rowadjamount = $rowpayamount;
506 $rowpayamount = 0;
509 // Compute reporting key: insurance company name or payment method.
510 $payer_type = 0; // will be 0=pt, 1=ins1, 2=ins2 or 3=ins3
511 if ($form_report_by == '1') {
512 $rowmethod = '';
513 $rowsrc = strtolower($row['source']);
514 $insgot = strtolower($row['notes']);
515 foreach (array('ins1', 'ins2', 'ins3') as $value) {
516 if (strpos($rowsrc, $value) !== false) {
517 $i = strpos($insgot, $value);
518 if ($i !== false) {
519 $j = strpos($insgot, "\n", $i);
520 if (!$j) $j = strlen($insgot);
521 $payer_type = 0 + substr($value, 3);
522 $rowmethod = trim(substr($row['notes'], $i + 5, $j - $i - 5));
523 break;
526 } // end foreach
527 } // end reporting by payer
528 else {
529 $rowmethod = trim($row['source']);
530 if ($form_report_by != '3') {
531 // Extract only the first word as the payment method because any
532 // following text will be some petty detail like a check number.
533 $rowmethod = substr($rowmethod, 0, strcspn($rowmethod, ' /'));
535 } // end reporting by method
537 thisLineItem($patient_id, $encounter_id, $row['memo'], $row['transdate'],
538 $rowmethod, $rowpayamount, $rowadjamount, $payer_type);
539 } // end for
540 } // end not $INTEGRATED_AR
542 // Not payer summary.
543 if ($form_report_by != '1' || $_POST['form_details']) {
545 if ($form_report_by == '1') { // by payer with details
546 // Sort and dump saved info, and consolidate items with all key
547 // fields being the same.
548 usort($insarray, 'payerCmp');
549 $b = array();
550 foreach ($insarray as $a) {
551 if (empty($a[4])) $a[4] = xl('Patient');
552 if (empty($b)) {
553 $b = $a;
555 else {
556 $match = true;
557 foreach (array(4,3,0,1,2,7) as $i) if ($a[$i] != $b[$i]) $match = false;
558 if ($match) {
559 $b[5] += $a[5];
560 $b[6] += $a[6];
561 } else {
562 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);
563 $b = $a;
567 if (!empty($b)) {
568 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);
570 } // end by payer with details
572 // Print last method total.
574 <tr bgcolor="#ddddff">
575 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
576 <?echo xl('Total for ') . $paymethod ?>
577 </td>
578 <td align="right">
579 <?php bucks($methodadjtotal) ?>
580 </td>
581 <td align="right">
582 <?php bucks($methodpaytotal) ?>
583 </td>
584 </tr>
585 <?php
588 // Payer summary: need to sort and then print it all.
589 else {
590 ksort($insarray);
591 foreach ($insarray as $key => $value) {
592 if (empty($key)) $key = xl('Patient');
594 <tr bgcolor="#ddddff">
595 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
596 <?php echo $key; ?>
597 </td>
598 <td align="right">
599 <?php bucks($value[1]); ?>
600 </td>
601 <td align="right">
602 <?php bucks($value[0]); ?>
603 </td>
604 </tr>
605 <?php
606 } // end foreach
607 } // end payer summary
609 <tr bgcolor="#ffdddd">
610 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
611 <?php xl('Grand Total','e') ?>
612 </td>
613 <td align="right">
614 <?php bucks($grandadjtotal) ?>
615 </td>
616 <td align="right">
617 <?php bucks($grandpaytotal) ?>
618 </td>
619 </tr>
621 <?php
622 } // end form refresh
623 if (!$INTEGRATED_AR) SLClose();
626 </table>
627 </div>
628 <?php } else { ?>
629 <div class='text'>
630 <?php echo xl('Please input search criteria above, and click Submit to view results.', 'e' ); ?>
631 </div>
632 <?php } ?>
634 </form>
635 </body>
637 <!-- stuff for the popup calendar -->
638 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
639 <style type="text/css">@import url(../../library/dynarch_calendar.css);</style>
640 <script type="text/javascript" src="../../library/dynarch_calendar.js"></script>
641 <?php include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?>
642 <script type="text/javascript" src="../../library/dynarch_calendar_setup.js"></script>
643 <script type="text/javascript" src="../../library/js/jquery.1.3.2.js"></script>
644 <script language="Javascript">
645 Calendar.setup({inputField:"form_from_date", ifFormat:"%Y-%m-%d", button:"img_from_date"});
646 Calendar.setup({inputField:"form_to_date", ifFormat:"%Y-%m-%d", button:"img_to_date"});
647 </script>
649 </html>