Highway to PSR2
[openemr.git] / interface / reports / receipts_by_method_report.php
blob63c9e00542a87f79d94f0326cf1d7f2242a1ede1
1 <?php
2 /**
3 * This is a report of receipts by payer or payment method.
5 * The payer option means an insurance company name or "Patient".
7 * The payment method option is most useful for sites using
8 * pos_checkout.php (e.g. weight loss clinics) because this plugs
9 * a payment method like Cash, Check, VISA, etc. into the "source"
10 * column of the SQL-Ledger acc_trans table or ar_session table.
12 * Copyright (C) 2006-2016 Rod Roark <rod@sunsetsystems.com>
13 * Copyright (C) 2017 Brady Miller <brady.g.miller@gmail.com>
15 * LICENSE: This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
26 * @package OpenEMR
27 * @author Rod Roark <rod@sunsetsystems.com>
28 * @author Brady Miller <brady.g.miller@gmail.com>
29 * @link http://www.open-emr.org
32 use OpenEMR\Core\Header;
34 require_once("../globals.php");
35 require_once("$srcdir/patient.inc");
36 require_once("$srcdir/acl.inc");
37 require_once "$srcdir/options.inc.php";
38 require_once("../../custom/code_types.inc.php");
40 // This controls whether we show pt name, policy number and DOS.
41 $showing_ppd = true;
43 $insarray = array();
45 function bucks($amount)
47 if ($amount) {
48 echo oeFormatMoney($amount);
52 function thisLineItem(
53 $patient_id,
54 $encounter_id,
55 $memo,
56 $transdate,
57 $rowmethod,
58 $rowpayamount,
59 $rowadjamount,
60 $payer_type = 0,
61 $irnumber = ''
62 ) {
64 global $form_report_by, $insarray, $grandpaytotal, $grandadjtotal;
66 if ($form_report_by != '1') { // reporting by method or check number
67 showLineItem(
68 $patient_id,
69 $encounter_id,
70 $memo,
71 $transdate,
72 $rowmethod,
73 $rowpayamount,
74 $rowadjamount,
75 $payer_type,
76 $irnumber
78 return;
81 // Reporting by payer.
83 if ($_POST['form_details']) { // details are wanted
84 // Save everything for later sorting.
85 $insarray[] = array($patient_id, $encounter_id, $memo, $transdate,
86 $rowmethod, $rowpayamount, $rowadjamount, $payer_type, $irnumber);
87 } else { // details not wanted
88 if (empty($insarray[$rowmethod])) {
89 $insarray[$rowmethod] = array(0, 0);
92 $insarray[$rowmethod][0] += $rowpayamount;
93 $insarray[$rowmethod][1] += $rowadjamount;
94 $grandpaytotal += $rowpayamount;
95 $grandadjtotal += $rowadjamount;
99 function showLineItem(
100 $patient_id,
101 $encounter_id,
102 $memo,
103 $transdate,
104 $rowmethod,
105 $rowpayamount,
106 $rowadjamount,
107 $payer_type = 0,
108 $irnumber = ''
111 global $paymethod, $paymethodleft, $methodpaytotal, $methodadjtotal,
112 $grandpaytotal, $grandadjtotal, $showing_ppd;
114 if (! $rowmethod) {
115 $rowmethod = 'Unknown';
118 $invnumber = $irnumber ? $irnumber : "$patient_id.$encounter_id";
120 if ($paymethod != $rowmethod) {
121 if ($paymethod) {
122 // Print method total.
125 <tr bgcolor="#ddddff">
126 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
127 <?php echo xl('Total for ') . $paymethod ?>
128 </td>
129 <td align="right">
130 <?php bucks($methodadjtotal) ?>
131 </td>
132 <td align="right">
133 <?php bucks($methodpaytotal) ?>
134 </td>
135 </tr>
136 <?php
139 $methodpaytotal = 0;
140 $methodadjtotal = 0;
141 $paymethod = $rowmethod;
142 $paymethodleft = $paymethod;
145 if ($_POST['form_details']) {
148 <tr>
149 <td class="detail">
150 <?php echo $paymethodleft; $paymethodleft = "&nbsp;" ?>
151 </td>
152 <td>
153 <?php echo oeFormatShortDate($transdate) ?>
154 </td>
155 <td class="detail">
156 <?php echo $invnumber ?>
157 </td>
159 <?php
160 if ($showing_ppd) {
161 $pferow = sqlQuery("SELECT p.fname, p.mname, p.lname, fe.date " .
162 "FROM patient_data AS p, form_encounter AS fe WHERE " .
163 "p.pid = '$patient_id' AND fe.pid = p.pid AND " .
164 "fe.encounter = '$encounter_id' LIMIT 1");
165 $dos = substr($pferow['date'], 0, 10);
167 echo " <td class='dehead'>\n";
168 echo " " . $pferow['lname'] . ", " . $pferow['fname'] . " " . $pferow['mname'];
169 echo " </td>\n";
171 echo " <td class='dehead'>\n";
172 if ($payer_type) {
173 $ptarr = array(1 => 'primary', 2 => 'secondary', 3 => 'tertiary');
174 $insrow = getInsuranceDataByDate(
175 $patient_id,
176 $dos,
177 $ptarr[$payer_type],
178 "policy_number"
180 echo " " . $insrow['policy_number'];
183 echo " </td>\n";
185 echo " <td class='dehead'>\n";
186 echo " " . oeFormatShortDate($dos) . "\n";
187 echo " </td>\n";
191 <td>
192 <?php echo $memo ?>
193 </td>
194 <td align="right">
195 <?php bucks($rowadjamount) ?>
196 </td>
197 <td align="right">
198 <?php bucks($rowpayamount) ?>
199 </td>
200 </tr>
201 <?php
204 $methodpaytotal += $rowpayamount;
205 $grandpaytotal += $rowpayamount;
206 $methodadjtotal += $rowadjamount;
207 $grandadjtotal += $rowadjamount;
210 // This is called by usort() when reporting by payer with details.
211 // Sorts by payer/date/patient/encounter/memo.
212 function payerCmp($a, $b)
214 foreach (array(4,3,0,1,2,7) as $i) {
215 if ($a[$i] < $b[$i]) {
216 return -1;
219 if ($a[$i] > $b[$i]) {
220 return 1;
224 return 0;
227 if (! acl_check('acct', 'rep')) {
228 die(xl("Unauthorized access."));
232 $form_from_date = fixDate($_POST['form_from_date'], date('Y-m-d'));
233 $form_to_date = fixDate($_POST['form_to_date'], date('Y-m-d'));
234 $form_use_edate = $_POST['form_use_edate'];
235 $form_facility = $_POST['form_facility'];
236 $form_report_by = $_POST['form_report_by'];
237 $form_proc_codefull = trim($_POST['form_proc_codefull']);
238 // Parse the code type and the code from <code_type>:<code>
239 $tmp_code_array = explode(':', $form_proc_codefull);
240 $form_proc_codetype = $tmp_code_array[0];
241 $form_proc_code = $tmp_code_array[1];
244 <html>
245 <head>
247 <?php Header::setupHeader(['datetime-picker', 'report-helper']); ?>
249 <style type="text/css">
250 /* specifically include & exclude from printing */
251 @media print {
252 #report_parameters {
253 visibility: hidden;
254 display: none;
256 #report_parameters_daterange {
257 visibility: visible;
258 display: inline;
260 #report_results {
261 margin-top: 30px;
265 /* specifically exclude some from the screen */
266 @media screen {
267 #report_parameters_daterange {
268 visibility: hidden;
269 display: none;
273 table.mymaintable, table.mymaintable td {
274 border: 1px solid #aaaaaa;
275 border-collapse: collapse;
277 table.mymaintable td {
278 padding: 1pt 4pt 1pt 4pt;
280 </style>
282 <script language="JavaScript">
284 $(document).ready(function() {
285 oeFixedHeaderSetup(document.getElementById('mymaintable'));
286 var win = top.printLogSetup ? top : opener.top;
287 win.printLogSetup(document.getElementById('printbutton'));
289 $('.datepicker').datetimepicker({
290 <?php $datetimepicker_timepicker = false; ?>
291 <?php $datetimepicker_showseconds = false; ?>
292 <?php $datetimepicker_formatInput = false; ?>
293 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
294 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
298 // This is for callback by the find-code popup.
299 // Erases the current entry
300 function set_related(codetype, code, selector, codedesc) {
301 var f = document.forms[0];
302 var s = f.form_proc_codefull.value;
303 if (code) {
304 s = codetype + ':' + code;
305 } else {
306 s = '';
308 f.form_proc_codefull.value = s;
311 // This invokes the find-code popup.
312 function sel_procedure() {
313 dlgopen('../patient_file/encounter/find_code_popup.php?codetype=<?php echo attr(collect_codetypes("procedure", "csv")) ?>', '_blank', 500, 400);
316 </script>
318 <title><?xl('Receipts Summary','e')?></title>
319 </head>
321 <body class="body_top">
323 <span class='title'><?php xl('Report', 'e'); ?> - <?php xl('Receipts Summary', 'e'); ?></span>
325 <form method='post' action='receipts_by_method_report.php' id='theform'>
327 <div id="report_parameters">
329 <input type='hidden' name='form_refresh' id='form_refresh' value=''/>
331 <table>
332 <tr>
333 <td width='630px'>
334 <div style='float:left'>
336 <table class='text'>
337 <tr>
338 <td class='control-label'>
339 <?php xl('Report by', 'e'); ?>
340 </td>
341 <td>
342 <?php
343 echo " <select name='form_report_by' class='form-control'>\n";
344 foreach (array(1 => 'Payer', 2 => 'Payment Method', 3 => 'Check Number') as $key => $value) {
345 echo " <option value='$key'";
346 if ($key == $form_report_by) {
347 echo ' selected';
350 echo ">" . xl($value) . "</option>\n";
353 echo " </select>&nbsp;\n"; ?>
354 </td>
356 <td>
357 <?php dropdown_facility(strip_escape_custom($form_facility), 'form_facility', false); ?>
358 </td>
360 <td class='control-label'>
361 <?php if (!$GLOBALS['simplified_demographics']) {
362 echo '&nbsp;' . xl('Procedure/Service') . ':';
363 } ?>
364 </td>
365 <td>
366 <input type='text' name='form_proc_codefull' class='form-control' size='12' value='<?php echo $form_proc_codefull; ?>' onclick='sel_procedure()'
367 title='<?php xl('Click to select optional procedure code', 'e'); ?>'
368 <?php if ($GLOBALS['simplified_demographics']) {
369 echo "style='display:none'";
370 } ?> />
371 <br>
372 <div class="checkbox">
373 <label><input type='checkbox' name='form_details' value='1'<?php if ($_POST['form_details']) {
374 echo " checked";
375 } ?> /><?php echo xl('Details')?></label>
376 </div>
377 </td>
378 </tr>
379 <tr>
380 <td>&nbsp;</td>
381 <td>
382 <select name='form_use_edate' class='form-control'>
383 <option value='0'><?php xl('Payment Date', 'e'); ?></option>
384 <option value='1'<?php if ($form_use_edate) {
385 echo ' selected';
386 } ?>><?php xl('Invoice Date', 'e'); ?></option>
387 </select>
388 </td>
389 <td>
390 <input type='text' class='datepicker form-control' name='form_from_date' id="form_from_date" size='10' value='<?php echo $form_from_date ?>'
391 title='yyyy-mm-dd'>
392 </td>
393 <td class='control-label'>
394 <?php xl('To', 'e'); ?>:
395 </td>
396 <td>
397 <input type='text' class='datepicker form-control' name='form_to_date' id="form_to_date" size='10' value='<?php echo $form_to_date ?>'
398 title='yyyy-mm-dd'>
399 </td>
400 </tr>
401 </table>
403 </div>
405 </td>
406 <td align='left' valign='middle' height="100%">
407 <table style='border-left:1px solid; width:100%; height:100%' >
408 <tr>
409 <td>
410 <div class="text-center">
411 <div class="btn-group" role="group">
412 <a href='#' class='btn btn-default btn-save' onclick='$("#form_refresh").attr("value","true"); $("#theform").submit();'>
413 <?php echo xlt('Submit'); ?>
414 </a>
415 <?php if ($_POST['form_refresh']) { ?>
416 <a href='#' class='btn btn-default btn-print' id='printbutton'>
417 <?php echo xlt('Print'); ?>
418 </a>
419 <?php } ?>
420 </div>
421 </div>
422 </td>
423 </tr>
424 </table>
425 </td>
426 </tr>
427 </table>
429 </div> <!-- end of parameters -->
431 <?php
432 if ($_POST['form_refresh']) {
434 <div id="report_results">
436 <table width='98%' id='mymaintable' class='mymaintable'>
438 <thead>
439 <tr bgcolor="#dddddd">
440 <th>
441 <?php xl('Method', 'e') ?>
442 </th>
443 <th>
444 <?php xl('Date', 'e') ?>
445 </th>
446 <th>
447 <?php xl('Invoice', 'e') ?>
448 </th>
449 <?php if ($showing_ppd) { ?>
450 <th>
451 <?xl('Patient','e')?>
452 </th>
453 <th>
454 <?xl('Policy','e')?>
455 </th>
456 <th>
457 <?xl('DOS','e')?>
458 </th>
459 <?php } ?>
460 <th>
461 <?xl('Procedure','e')?>
462 </th>
463 <th align="right">
464 <?xl('Adjustments','e')?>
465 </th>
466 <th align="right">
467 <?xl('Payments','e')?>
468 </th>
469 </tr>
470 </thead>
471 <tbody>
472 <?php
474 if ($_POST['form_refresh']) {
475 $from_date = $form_from_date;
476 $to_date = $form_to_date;
478 $paymethod = "";
479 $paymethodleft = "";
480 $methodpaytotal = 0;
481 $grandpaytotal = 0;
482 $methodadjtotal = 0;
483 $grandadjtotal = 0;
486 // Get co-pays using the encounter date as the pay date. These will
487 // always be considered patient payments. Ignored if selecting by
488 // billing code.
490 if (!$form_proc_code || !$form_proc_codetype) {
491 $query = "SELECT b.fee, b.pid, b.encounter, b.code_type, " .
492 "fe.date, fe.facility_id, fe.invoice_refno " .
493 "FROM billing AS b " .
494 "JOIN form_encounter AS fe ON fe.pid = b.pid AND fe.encounter = b.encounter " .
495 "WHERE b.code_type = 'COPAY' AND b.activity = 1 AND b.fee != 0 AND " .
496 "fe.date >= '$from_date 00:00:00' AND fe.date <= '$to_date 23:59:59'";
497 // If a facility was specified.
498 if ($form_facility) {
499 $query .= " AND fe.facility_id = '$form_facility'";
502 $query .= " ORDER BY fe.date, b.pid, b.encounter, fe.id";
504 $res = sqlStatement($query);
505 while ($row = sqlFetchArray($res)) {
506 $rowmethod = $form_report_by == 1 ? 'Patient' : 'Co-Pay';
507 thisLineItem(
508 $row['pid'],
509 $row['encounter'],
510 $row['code_text'],
511 substr($row['date'], 0, 10),
512 $rowmethod,
513 0 - $row['fee'],
516 $row['invoice_refno']
519 } // end if not form_proc_code
521 // Get all other payments and adjustments and their dates, corresponding
522 // payers and check reference data, and the encounter dates separately.
524 $query = "SELECT a.pid, a.encounter, a.post_time, a.pay_amount, " .
525 "a.adj_amount, a.memo, a.session_id, a.code, a.payer_type, fe.id, fe.date, " .
526 "fe.invoice_refno, s.deposit_date, s.payer_id, s.reference, i.name " .
527 "FROM ar_activity AS a " .
528 "JOIN form_encounter AS fe ON fe.pid = a.pid AND fe.encounter = a.encounter " .
529 "JOIN forms AS f ON f.pid = a.pid AND f.encounter = a.encounter AND f.formdir = 'newpatient' " .
530 "LEFT JOIN ar_session AS s ON s.session_id = a.session_id " .
531 "LEFT JOIN insurance_companies AS i ON i.id = s.payer_id " .
532 "WHERE ( a.pay_amount != 0 OR a.adj_amount != 0 )";
534 if ($form_use_edate) {
535 $query .= " AND fe.date >= '$from_date 00:00:00' AND fe.date <= '$to_date 23:59:59'";
536 } else {
537 $query .= " AND ( ( s.deposit_date IS NOT NULL AND " .
538 "s.deposit_date >= '$from_date' AND s.deposit_date <= '$to_date' ) OR " .
539 "( s.deposit_date IS NULL AND a.post_time >= '$from_date 00:00:00' AND " .
540 "a.post_time <= '$to_date 23:59:59' ) )";
543 // If a procedure code was specified.
544 if ($form_proc_code && $form_proc_codetype) {
545 // if a code_type is entered into the ar_activity table, then use it. If it is not entered in, then do not use it.
546 $query .= " AND ( a.code_type = '$form_proc_codetype' OR a.code_type = '' ) AND a.code LIKE '$form_proc_code%'";
549 // If a facility was specified.
550 if ($form_facility) {
551 $query .= " AND fe.facility_id = '$form_facility'";
555 if ($form_use_edate) {
556 $query .= " ORDER BY s.reference, fe.date, a.pid, a.encounter, fe.id";
557 } else {
558 $query .= " ORDER BY s.reference, s.deposit_date, a.post_time, a.pid, a.encounter, fe.id";
562 $res = sqlStatement($query);
563 while ($row = sqlFetchArray($res)) {
564 if ($form_use_edate) {
565 $thedate = substr($row['date'], 0, 10);
566 } else if (!empty($row['deposit_date'])) {
567 $thedate = $row['deposit_date'];
568 } else {
569 $thedate = substr($row['post_time'], 0, 10);
572 // Compute reporting key: insurance company name or payment method.
573 if ($form_report_by == '1') {
574 if (empty($row['payer_id'])) {
575 $rowmethod = '';
576 } else {
577 if (empty($row['name'])) {
578 $rowmethod = xl('Unnamed insurance company');
579 } else {
580 $rowmethod = $row['name'];
583 } else {
584 if (empty($row['session_id'])) {
585 $rowmethod = trim($row['memo']);
586 } else {
587 $rowmethod = trim($row['reference']);
590 if ($form_report_by != '3') {
591 // Extract only the first word as the payment method because any
592 // following text will be some petty detail like a check number.
593 $rowmethod = substr($rowmethod, 0, strcspn($rowmethod, ' /'));
598 thisLineItem(
599 $row['pid'],
600 $row['encounter'],
601 $row['code'],
602 $thedate,
603 $rowmethod,
604 $row['pay_amount'],
605 $row['adj_amount'],
606 $row['payer_type'],
607 $row['invoice_refno']
611 // Not payer summary.
612 if ($form_report_by != '1' || $_POST['form_details']) {
613 if ($form_report_by == '1') { // by payer with details
614 // Sort and dump saved info, and consolidate items with all key
615 // fields being the same.
616 usort($insarray, 'payerCmp');
617 $b = array();
618 foreach ($insarray as $a) {
619 if (empty($a[4])) {
620 $a[4] = xl('Patient');
623 if (empty($b)) {
624 $b = $a;
625 } else {
626 $match = true;
627 foreach (array(4,3,0,1,2,7) as $i) {
628 if ($a[$i] != $b[$i]) {
629 $match = false;
633 if ($match) {
634 $b[5] += $a[5];
635 $b[6] += $a[6];
636 } else {
637 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);
638 $b = $a;
643 if (!empty($b)) {
644 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);
646 } // end by payer with details
648 // Print last method total.
650 <tr bgcolor="#ddddff">
651 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
652 <?php echo xl('Total for ') . $paymethod ?>
653 </td>
654 <td align="right">
655 <?php bucks($methodadjtotal) ?>
656 </td>
657 <td align="right">
658 <?php bucks($methodpaytotal) ?>
659 </td>
660 </tr>
661 <?php
662 } // Payer summary: need to sort and then print it all.
663 else {
664 ksort($insarray);
665 foreach ($insarray as $key => $value) {
666 if (empty($key)) {
667 $key = xl('Patient');
670 <tr bgcolor="#ddddff">
671 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
672 <?php echo $key; ?>
673 </td>
674 <td align="right">
675 <?php bucks($value[1]); ?>
676 </td>
677 <td align="right">
678 <?php bucks($value[0]); ?>
679 </td>
680 </tr>
681 <?php
682 } // end foreach
683 } // end payer summary
685 <tr bgcolor="#ffdddd">
686 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
687 <?php xl('Grand Total', 'e') ?>
688 </td>
689 <td align="right">
690 <?php bucks($grandadjtotal) ?>
691 </td>
692 <td align="right">
693 <?php bucks($grandpaytotal) ?>
694 </td>
695 </tr>
697 <?php
698 } // end form refresh
701 </tbody>
702 </table>
703 </div>
704 <?php } else { ?>
705 <div class='text'>
706 <?php echo xl('Please input search criteria above, and click Submit to view results.', 'e'); ?>
707 </div>
708 <?php } ?>
710 </form>
711 </body>
713 </html>