minor changes to prior commit
[openemr.git] / interface / reports / receipts_by_method_report.php
blob734116324919e99745e1bfbcc1ac1924c4b72ce7
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 * @package OpenEMR
13 * @link http://www.open-emr.org
14 * @author Rod Roark <rod@sunsetsystems.com>
15 * @author Brady Miller <brady.g.miller@gmail.com>
16 * @copyright Copyright (c) 2006-2016 Rod Roark <rod@sunsetsystems.com>
17 * @copyright Copyright (c) 2017-2018 Brady Miller <brady.g.miller@gmail.com>
18 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
22 require_once("../globals.php");
23 require_once("$srcdir/patient.inc");
24 require_once("$srcdir/acl.inc");
25 require_once "$srcdir/options.inc.php";
26 require_once("../../custom/code_types.inc.php");
28 use OpenEMR\Core\Header;
30 // This controls whether we show pt name, policy number and DOS.
31 $showing_ppd = true;
33 $insarray = array();
35 function bucks($amount)
37 if ($amount) {
38 return oeFormatMoney($amount);
42 function thisLineItem(
43 $patient_id,
44 $encounter_id,
45 $memo,
46 $transdate,
47 $rowmethod,
48 $rowpayamount,
49 $rowadjamount,
50 $payer_type = 0,
51 $irnumber = ''
52 ) {
54 global $form_report_by, $insarray, $grandpaytotal, $grandadjtotal;
56 if ($form_report_by != '1') { // reporting by method or check number
57 showLineItem(
58 $patient_id,
59 $encounter_id,
60 $memo,
61 $transdate,
62 $rowmethod,
63 $rowpayamount,
64 $rowadjamount,
65 $payer_type,
66 $irnumber
68 return;
71 // Reporting by payer.
73 if ($_POST['form_details']) { // details are wanted
74 // Save everything for later sorting.
75 $insarray[] = array($patient_id, $encounter_id, $memo, $transdate,
76 $rowmethod, $rowpayamount, $rowadjamount, $payer_type, $irnumber);
77 } else { // details not wanted
78 if (empty($insarray[$rowmethod])) {
79 $insarray[$rowmethod] = array(0, 0);
82 $insarray[$rowmethod][0] += $rowpayamount;
83 $insarray[$rowmethod][1] += $rowadjamount;
84 $grandpaytotal += $rowpayamount;
85 $grandadjtotal += $rowadjamount;
89 function showLineItem(
90 $patient_id,
91 $encounter_id,
92 $memo,
93 $transdate,
94 $rowmethod,
95 $rowpayamount,
96 $rowadjamount,
97 $payer_type = 0,
98 $irnumber = ''
99 ) {
101 global $paymethod, $paymethodleft, $methodpaytotal, $methodadjtotal,
102 $grandpaytotal, $grandadjtotal, $showing_ppd;
104 if (! $rowmethod) {
105 $rowmethod = 'Unknown';
108 $invnumber = $irnumber ? $irnumber : "$patient_id.$encounter_id";
110 if ($paymethod != $rowmethod) {
111 if ($paymethod) {
112 // Print method total.
115 <tr bgcolor="#ddddff">
116 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
117 <?php echo xlt('Total for ') . text($paymethod); ?>
118 </td>
119 <td align="right">
120 <?php echo text(bucks($methodadjtotal)); ?>
121 </td>
122 <td align="right">
123 <?php echo text(bucks($methodpaytotal)); ?>
124 </td>
125 </tr>
126 <?php
129 $methodpaytotal = 0;
130 $methodadjtotal = 0;
131 $paymethod = $rowmethod;
132 $paymethodleft = $paymethod;
135 if ($_POST['form_details']) {
138 <tr>
139 <td class="detail">
140 <?php echo text($paymethodleft); $paymethodleft = " " ?>
141 </td>
142 <td>
143 <?php echo text(oeFormatShortDate($transdate)); ?>
144 </td>
145 <td class="detail">
146 <?php echo text($invnumber); ?>
147 </td>
149 <?php
150 if ($showing_ppd) {
151 $pferow = sqlQuery("SELECT p.fname, p.mname, p.lname, fe.date " .
152 "FROM patient_data AS p, form_encounter AS fe WHERE " .
153 "p.pid = ? AND fe.pid = p.pid AND " .
154 "fe.encounter = ? LIMIT 1", array($patient_id, $encounter_id));
155 $dos = substr($pferow['date'], 0, 10);
157 echo " <td class='dehead'>\n";
158 echo " " . text($pferow['lname']) . ", " . text($pferow['fname']) . " " . text($pferow['mname']);
159 echo " </td>\n";
161 echo " <td class='dehead'>\n";
162 if ($payer_type) {
163 $ptarr = array(1 => 'primary', 2 => 'secondary', 3 => 'tertiary');
164 $insrow = getInsuranceDataByDate(
165 $patient_id,
166 $dos,
167 $ptarr[$payer_type],
168 "policy_number"
170 echo " " . text($insrow['policy_number']);
173 echo " </td>\n";
175 echo " <td class='dehead'>\n";
176 echo " " . text(oeFormatShortDate($dos)) . "\n";
177 echo " </td>\n";
181 <td>
182 <?php echo text($memo); ?>
183 </td>
184 <td align="right">
185 <?php echo text(bucks($rowadjamount)); ?>
186 </td>
187 <td align="right">
188 <?php echo text(bucks($rowpayamount)); ?>
189 </td>
190 </tr>
191 <?php
194 $methodpaytotal += $rowpayamount;
195 $grandpaytotal += $rowpayamount;
196 $methodadjtotal += $rowadjamount;
197 $grandadjtotal += $rowadjamount;
200 // This is called by usort() when reporting by payer with details.
201 // Sorts by payer/date/patient/encounter/memo.
202 function payerCmp($a, $b)
204 foreach (array(4,3,0,1,2,7) as $i) {
205 if ($a[$i] < $b[$i]) {
206 return -1;
209 if ($a[$i] > $b[$i]) {
210 return 1;
214 return 0;
217 if (! acl_check('acct', 'rep')) {
218 die(xlt("Unauthorized access."));
221 $form_from_date = (isset($_POST['form_from_date'])) ? DateToYYYYMMDD($_POST['form_from_date']) : date('Y-m-d');
222 $form_to_date = (isset($_POST['form_to_date'])) ? DateToYYYYMMDD($_POST['form_to_date']) : date('Y-m-d');
223 $form_use_edate = $_POST['form_use_edate'];
224 $form_facility = $_POST['form_facility'];
225 $form_report_by = $_POST['form_report_by'];
226 $form_proc_codefull = trim($_POST['form_proc_codefull']);
227 // Parse the code type and the code from <code_type>:<code>
228 $tmp_code_array = explode(':', $form_proc_codefull);
229 $form_proc_codetype = $tmp_code_array[0];
230 $form_proc_code = $tmp_code_array[1];
233 <html>
234 <head>
236 <title><?php echo xlt('Receipts Summary')?></title>
238 <?php Header::setupHeader(['datetime-picker', 'report-helper']); ?>
240 <style type="text/css">
241 /* specifically include & exclude from printing */
242 @media print {
243 #report_parameters {
244 visibility: hidden;
245 display: none;
247 #report_parameters_daterange {
248 visibility: visible;
249 display: inline;
251 #report_results {
252 margin-top: 30px;
256 /* specifically exclude some from the screen */
257 @media screen {
258 #report_parameters_daterange {
259 visibility: hidden;
260 display: none;
264 table.mymaintable, table.mymaintable td {
265 border: 1px solid #aaaaaa;
266 border-collapse: collapse;
268 table.mymaintable td {
269 padding: 1pt 4pt 1pt 4pt;
271 </style>
273 <script language="JavaScript">
274 $(document).ready(function() {
275 oeFixedHeaderSetup(document.getElementById('mymaintable'));
276 var win = top.printLogSetup ? top : opener.top;
277 win.printLogSetup(document.getElementById('printbutton'));
279 $('.datepicker').datetimepicker({
280 <?php $datetimepicker_timepicker = false; ?>
281 <?php $datetimepicker_showseconds = false; ?>
282 <?php $datetimepicker_formatInput = true; ?>
283 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
284 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
288 // This is for callback by the find-code popup.
289 // Erases the current entry
290 function set_related(codetype, code, selector, codedesc) {
291 var f = document.forms[0];
292 var s = f.form_proc_codefull.value;
293 if (code) {
294 s = codetype + ':' + code;
295 } else {
296 s = '';
298 f.form_proc_codefull.value = s;
301 // This invokes the find-code popup.
302 function sel_procedure() {
303 dlgopen('../patient_file/encounter/find_code_popup.php?codetype=<?php echo attr(collect_codetypes("procedure", "csv")) ?>', '_blank', 500, 400);
305 </script>
306 </head>
308 <body class="body_top">
310 <span class='title'><?php echo xlt('Report'); ?> - <?php echo xlt('Receipts Summary'); ?></span>
312 <form method='post' action='receipts_by_method_report.php' id='theform' onsubmit='return top.restoreSession()'>
314 <div id="report_parameters">
316 <input type='hidden' name='form_refresh' id='form_refresh' value=''/>
318 <table>
319 <tr>
320 <td width='630px'>
321 <div style='float:left'>
323 <table class='text'>
324 <tr>
325 <td class='control-label'>
326 <?php echo xlt('Report by'); ?>
327 </td>
328 <td>
329 <?php
330 echo " <select name='form_report_by' class='form-control'>\n";
331 foreach (array(1 => 'Payer', 2 => 'Payment Method', 3 => 'Check Number') as $key => $value) {
332 echo " <option value='" . attr($key) . "'";
333 if ($key == $form_report_by) {
334 echo ' selected';
337 echo ">" . xlt($value) . "</option>\n";
340 echo " </select>&nbsp;\n"; ?>
341 </td>
343 <td>
344 <?php dropdown_facility($form_facility, 'form_facility', false); ?>
345 </td>
347 <td class='control-label'>
348 <?php
349 if (!$GLOBALS['simplified_demographics']) {
350 echo '&nbsp;' . xlt('Procedure/Service') . ':';
351 } ?>
352 </td>
353 <td>
354 <input type='text' name='form_proc_codefull' class='form-control' size='12' value='<?php echo attr($form_proc_codefull); ?>' onclick='sel_procedure()'
355 title='<?php echo xla('Click to select optional procedure code'); ?>'
356 <?php
357 if ($GLOBALS['simplified_demographics']) {
358 echo "style='display:none'";
359 } ?> />
360 <br>
361 <div class="checkbox">
362 <label><input type='checkbox' name='form_details' value='1'<?php echo ($_POST['form_details']) ? " checked" : ""; ?> /><?php echo xlt('Details')?></label>
363 </div>
364 </td>
365 </tr>
366 <tr>
367 <td>&nbsp;</td>
368 <td>
369 <select name='form_use_edate' class='form-control'>
370 <option value='0'><?php echo xlt('Payment Date'); ?></option>
371 <option value='1'<?php echo ($form_use_edate) ? ' selected' : ''; ?>><?php echo xlt('Invoice Date'); ?></option>
372 </select>
373 </td>
374 <td>
375 <input type='text' class='datepicker form-control' name='form_from_date' id="form_from_date" size='10' value='<?php echo attr(oeFormatShortDate($form_from_date)); ?>'>
376 </td>
377 <td class='control-label'>
378 <?php xl('To', 'e'); ?>:
379 </td>
380 <td>
381 <input type='text' class='datepicker form-control' name='form_to_date' id="form_to_date" size='10' value='<?php echo attr(oeFormatShortDate($form_to_date)); ?>'>
382 </td>
383 </tr>
384 </table>
386 </div>
388 </td>
389 <td align='left' valign='middle' height="100%">
390 <table style='border-left:1px solid; width:100%; height:100%' >
391 <tr>
392 <td>
393 <div class="text-center">
394 <div class="btn-group" role="group">
395 <a href='#' class='btn btn-default btn-save' onclick='$("#form_refresh").attr("value","true"); $("#theform").submit();'>
396 <?php echo xlt('Submit'); ?>
397 </a>
398 <?php if ($_POST['form_refresh']) { ?>
399 <a href='#' class='btn btn-default btn-print' id='printbutton'>
400 <?php echo xlt('Print'); ?>
401 </a>
402 <?php } ?>
403 </div>
404 </div>
405 </td>
406 </tr>
407 </table>
408 </td>
409 </tr>
410 </table>
412 </div> <!-- end of parameters -->
414 <?php
415 if ($_POST['form_refresh']) {
417 <div id="report_results">
419 <table width='98%' id='mymaintable' class='mymaintable'>
421 <thead>
422 <tr bgcolor="#dddddd">
423 <th>
424 <?php echo xlt('Method') ?>
425 </th>
426 <th>
427 <?php echo xlt('Date') ?>
428 </th>
429 <th>
430 <?php echo xlt('Invoice') ?>
431 </th>
432 <?php if ($showing_ppd) { ?>
433 <th>
434 <?php echo xlt('Patient')?>
435 </th>
436 <th>
437 <?php echo xlt('Policy')?>
438 </th>
439 <th>
440 <?php echo xlt('DOS')?>
441 </th>
442 <?php } ?>
443 <th>
444 <?php echo xlt('Procedure')?>
445 </th>
446 <th align="right">
447 <?php echo xlt('Adjustments')?>
448 </th>
449 <th align="right">
450 <?php echo xlt('Payments')?>
451 </th>
452 </tr>
453 </thead>
454 <tbody>
455 <?php
457 if ($_POST['form_refresh']) {
458 $paymethod = "";
459 $paymethodleft = "";
460 $methodpaytotal = 0;
461 $grandpaytotal = 0;
462 $methodadjtotal = 0;
463 $grandadjtotal = 0;
466 // Get co-pays using the encounter date as the pay date. These will
467 // always be considered patient payments. Ignored if selecting by
468 // billing code.
470 if (!$form_proc_code || !$form_proc_codetype) {
471 $sqlBindArray = array();
472 $query = "SELECT b.fee, b.pid, b.encounter, b.code_type, " .
473 "fe.date, fe.facility_id, fe.invoice_refno " .
474 "FROM billing AS b " .
475 "JOIN form_encounter AS fe ON fe.pid = b.pid AND fe.encounter = b.encounter " .
476 "WHERE b.code_type = 'COPAY' AND b.activity = 1 AND b.fee != 0 AND " .
477 "fe.date >= ? AND fe.date <= ?";
478 array_push($sqlBindArray, $form_from_date.' 00:00:00', $form_to_date.' 23:59:59');
479 // If a facility was specified.
480 if ($form_facility) {
481 $query .= " AND fe.facility_id = ?";
482 array_push($sqlBindArray, $form_facility);
485 $query .= " ORDER BY fe.date, b.pid, b.encounter, fe.id";
487 $res = sqlStatement($query, $sqlBindArray);
488 while ($row = sqlFetchArray($res)) {
489 $rowmethod = $form_report_by == 1 ? 'Patient' : 'Co-Pay';
490 thisLineItem(
491 $row['pid'],
492 $row['encounter'],
493 $row['code_text'],
494 substr($row['date'], 0, 10),
495 $rowmethod,
496 0 - $row['fee'],
499 $row['invoice_refno']
502 } // end if not form_proc_code
504 // Get all other payments and adjustments and their dates, corresponding
505 // payers and check reference data, and the encounter dates separately.
507 $sqlBindArray = array();
508 $query = "SELECT a.pid, a.encounter, a.post_time, a.pay_amount, " .
509 "a.adj_amount, a.memo, a.session_id, a.code, a.payer_type, fe.id, fe.date, " .
510 "fe.invoice_refno, s.deposit_date, s.payer_id, s.reference, i.name " .
511 "FROM ar_activity AS a " .
512 "JOIN form_encounter AS fe ON fe.pid = a.pid AND fe.encounter = a.encounter " .
513 "JOIN forms AS f ON f.pid = a.pid AND f.encounter = a.encounter AND f.formdir = 'newpatient' " .
514 "LEFT JOIN ar_session AS s ON s.session_id = a.session_id " .
515 "LEFT JOIN insurance_companies AS i ON i.id = s.payer_id " .
516 "WHERE ( a.pay_amount != 0 OR a.adj_amount != 0 )";
518 if ($form_use_edate) {
519 $query .= " AND fe.date >= ? AND fe.date <= ?";
520 array_push($sqlBindArray, $form_from_date.' 00:00:00', $form_to_date.' 23:59:59');
521 } else {
522 $query .= " AND ( ( s.deposit_date IS NOT NULL AND " .
523 "s.deposit_date >= ? AND s.deposit_date <= ? ) OR " .
524 "( s.deposit_date IS NULL AND a.post_time >= ? AND " .
525 "a.post_time <= ? ) )";
526 array_push($sqlBindArray, $form_from_date, $form_to_date, $form_from_date.' 00:00:00', $form_to_date.' 23:59:59');
529 // If a procedure code was specified.
530 if ($form_proc_code && $form_proc_codetype) {
531 // 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.
532 $query .= " AND ( a.code_type = ? OR a.code_type = '' ) AND a.code LIKE ?";
533 array_push($sqlBindArray, $form_proc_codetype, $form_proc_code.'%');
536 // If a facility was specified.
537 if ($form_facility) {
538 $query .= " AND fe.facility_id = ?";
539 array_push($sqlBindArray, $form_facility);
543 if ($form_use_edate) {
544 $query .= " ORDER BY s.reference, fe.date, a.pid, a.encounter, fe.id";
545 } else {
546 $query .= " ORDER BY s.reference, s.deposit_date, a.post_time, a.pid, a.encounter, fe.id";
550 $res = sqlStatement($query, $sqlBindArray);
551 while ($row = sqlFetchArray($res)) {
552 if ($form_use_edate) {
553 $thedate = substr($row['date'], 0, 10);
554 } else if (!empty($row['deposit_date'])) {
555 $thedate = $row['deposit_date'];
556 } else {
557 $thedate = substr($row['post_time'], 0, 10);
560 // Compute reporting key: insurance company name or payment method.
561 if ($form_report_by == '1') {
562 if (empty($row['payer_id'])) {
563 $rowmethod = '';
564 } else {
565 if (empty($row['name'])) {
566 $rowmethod = xl('Unnamed insurance company');
567 } else {
568 $rowmethod = $row['name'];
571 } else {
572 if (empty($row['session_id'])) {
573 $rowmethod = trim($row['memo']);
574 } else {
575 $rowmethod = trim($row['reference']);
578 if ($form_report_by != '3') {
579 // Extract only the first word as the payment method because any
580 // following text will be some petty detail like a check number.
581 $rowmethod = substr($rowmethod, 0, strcspn($rowmethod, ' /'));
586 thisLineItem(
587 $row['pid'],
588 $row['encounter'],
589 $row['code'],
590 $thedate,
591 $rowmethod,
592 $row['pay_amount'],
593 $row['adj_amount'],
594 $row['payer_type'],
595 $row['invoice_refno']
599 // Not payer summary.
600 if ($form_report_by != '1' || $_POST['form_details']) {
601 if ($form_report_by == '1') { // by payer with details
602 // Sort and dump saved info, and consolidate items with all key
603 // fields being the same.
604 usort($insarray, 'payerCmp');
605 $b = array();
606 foreach ($insarray as $a) {
607 if (empty($a[4])) {
608 $a[4] = xl('Patient');
611 if (empty($b)) {
612 $b = $a;
613 } else {
614 $match = true;
615 foreach (array(4,3,0,1,2,7) as $i) {
616 if ($a[$i] != $b[$i]) {
617 $match = false;
621 if ($match) {
622 $b[5] += $a[5];
623 $b[6] += $a[6];
624 } else {
625 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);
626 $b = $a;
631 if (!empty($b)) {
632 showLineItem($b[0], $b[1], $b[2], $b[3], $b[4], $b[5], $b[6], $b[7], $b[8]);
634 } // end by payer with details
636 // Print last method total.
638 <tr bgcolor="#ddddff">
639 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
640 <?php echo xlt('Total for ') . text($paymethod); ?>
641 </td>
642 <td align="right">
643 <?php echo text(bucks($methodadjtotal)); ?>
644 </td>
645 <td align="right">
646 <?php echo text(bucks($methodpaytotal)); ?>
647 </td>
648 </tr>
649 <?php
650 } // Payer summary: need to sort and then print it all.
651 else {
652 ksort($insarray);
653 foreach ($insarray as $key => $value) {
654 if (empty($key)) {
655 $key = xl('Patient');
658 <tr bgcolor="#ddddff">
659 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
660 <?php echo text($key); ?>
661 </td>
662 <td align="right">
663 <?php echo text(bucks($value[1])); ?>
664 </td>
665 <td align="right">
666 <?php echo text(bucks($value[0])); ?>
667 </td>
668 </tr>
669 <?php
670 } // end foreach
671 } // end payer summary
673 <tr bgcolor="#ffdddd">
674 <td class="detail" colspan="<?php echo $showing_ppd ? 7 : 4; ?>">
675 <?php echo xlt('Grand Total') ?>
676 </td>
677 <td align="right">
678 <?php echo text(bucks($grandadjtotal)); ?>
679 </td>
680 <td align="right">
681 <?php echo text(bucks($grandpaytotal)); ?>
682 </td>
683 </tr>
685 <?php
686 } // end form refresh
689 </tbody>
690 </table>
691 </div>
692 <?php } else { ?>
693 <div class='text'>
694 <?php echo xlt('Please input search criteria above, and click Submit to view results.'); ?>
695 </div>
696 <?php } ?>
698 </form>
699 </body>
701 </html>