added gacl config files to upgrade instructions
[openemr.git] / interface / billing / sl_receipts_report.php
blob0e924b51cfaac82e46901b0ac0206b758de3dafd
1 <?php
2 // Copyright (C) 2006-2008 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 module was written for one of my clients to report on cash
10 // receipts by practitioner. It is not as complete as it should be
11 // but I wanted to make the code available to the project because
12 // many other practices have this same need. - rod@sunsetsystems.com
14 include_once("../globals.php");
15 include_once("../../library/patient.inc");
16 include_once("../../library/sql-ledger.inc");
17 include_once("../../library/acl.inc");
19 // This determines if a particular procedure code corresponds to receipts
20 // for the "Clinic" column as opposed to receipts for the practitioner. Each
21 // practice will have its own policies in this regard, so you'll probably
22 // have to customize this function. If you use the "fee sheet" encounter
23 // form then the code below may work for you.
25 include_once("../forms/fee_sheet/codes.php");
26 function is_clinic($code) {
27 global $bcodes;
28 $i = strpos($code, ':');
29 if ($i) $code = substr($code, 0, $i);
30 return ($bcodes['CPT4'][xl('Lab')][$code] ||
31 $bcodes['CPT4'][xl('Immunizations')][$code] ||
32 $bcodes['HCPCS'][xl('Therapeutic Injections')][$code]);
35 function bucks($amount) {
36 if ($amount)
37 printf("%.2f", $amount);
40 if (! acl_check('acct', 'rep')) die(xl("Unauthorized access."));
42 $INTEGRATED_AR = $GLOBALS['oer_config']['ws_accounting']['enabled'] === 2;
44 if (!$INTEGRATED_AR) {
45 SLConnect();
46 $chart_id_cash = SLQueryValue("select id from chart where accno = '$sl_cash_acc'");
47 if ($sl_err) die($sl_err);
50 $form_use_edate = $_POST['form_use_edate'];
51 $form_cptcode = trim($_POST['form_cptcode']);
52 $form_icdcode = trim($_POST['form_icdcode']);
53 $form_procedures = empty($_POST['form_procedures']) ? 0 : 1;
54 $form_from_date = fixDate($_POST['form_from_date'], date('Y-m-01'));
55 $form_to_date = fixDate($_POST['form_to_date'], date('Y-m-d'));
56 $form_facility = $_POST['form_facility'];
58 <html>
59 <head>
60 <?php if (function_exists('html_header_show')) html_header_show(); ?>
61 <title><?xl('Cash Receipts by Provider','e')?></title>
62 </head>
64 <body leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'>
65 <center>
67 <h2><?xl('Cash Receipts by Provider','e')?></h2>
69 <form method='post' action='sl_receipts_report.php'>
71 <table border='0' cellpadding='3'>
73 <tr>
74 <td>
75 <?php
76 // Build a drop-down list of facilities.
78 $query = "SELECT id, name FROM facility ORDER BY name";
79 $fres = sqlStatement($query);
80 echo " <select name='form_facility'>\n";
81 echo " <option value=''>-- All Facilities --\n";
82 while ($frow = sqlFetchArray($fres)) {
83 $facid = $frow['id'];
84 echo " <option value='$facid'";
85 if ($facid == $form_facility) echo " selected";
86 echo ">" . $frow['name'] . "\n";
88 echo " </select>\n";
90 <?php
91 if (acl_check('acct', 'rep_a')) {
92 // Build a drop-down list of providers.
94 $query = "select id, lname, fname from users where " .
95 "authorized = 1 order by lname, fname";
96 $res = sqlStatement($query);
97 echo " &nbsp;<select name='form_doctor'>\n";
98 echo " <option value=''>-- All Providers --\n";
99 while ($row = sqlFetchArray($res)) {
100 $provid = $row['id'];
101 echo " <option value='$provid'";
102 if ($provid == $_POST['form_doctor']) echo " selected";
103 echo ">" . $row['lname'] . ", " . $row['fname'] . "\n";
105 echo " </select>\n";
106 } else {
107 echo "<input type='hidden' name='form_doctor' value='" . $_SESSION['authUserID'] . "'>";
110 &nbsp;<select name='form_use_edate'>
111 <option value='0'><?php xl('Payment Date','e'); ?></option>
112 <option value='1'<?php if ($form_use_edate) echo ' selected' ?>><?php xl('Invoice Date','e'); ?></option>
113 </select>
114 &nbsp;<?xl('From:','e')?>
116 <input type='text' name='form_from_date' id="form_from_date" size='10' value='<?php echo $form_from_date ?>'
117 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='yyyy-mm-dd'>
118 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
119 id='img_from_date' border='0' alt='[?]' style='cursor:pointer'
120 title='<?php xl('Click here to choose a date','e'); ?>'>
121 &nbsp;To:
122 <input type='text' name='form_to_date' id="form_to_date" size='10' value='<?php echo $form_to_date ?>'
123 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='yyyy-mm-dd'>
124 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
125 id='img_to_date' border='0' alt='[?]' style='cursor:pointer'
126 title='<?php xl('Click here to choose a date','e'); ?>'>
127 <?php if (!$GLOBALS['simplified_demographics']) echo '&nbsp;' . xl('CPT') . ':'; ?>
128 <input type='text' name='form_cptcode' size='5' value='<? echo $form_cptcode; ?>'
129 title='<?php xl('Optional procedure code','e'); ?>'
130 <?php if ($GLOBALS['simplified_demographics']) echo "style='display:none'"; ?>>
131 <?php if (!$GLOBALS['simplified_demographics']) echo '&nbsp;' . xl('ICD') . ':'; ?>
132 <input type='text' name='form_icdcode' size='5' value='<? echo $form_icdcode; ?>'
133 title='<?php xl('Enter a diagnosis code to exclude all invoices not containing it','e'); ?>'
134 <?php if ($GLOBALS['simplified_demographics']) echo "style='display:none'"; ?>>
135 &nbsp;
136 <input type='checkbox' name='form_details' value='1'<? if ($_POST['form_details']) echo " checked"; ?>><?xl('Details','e')?>
137 &nbsp;
138 <input type='checkbox' name='form_procedures' value='1'<? if ($form_procedures) echo " checked"; ?>><?xl('Procedures','e')?>
139 &nbsp;
140 <input type='submit' name='form_refresh' value="<?xl('Refresh','e')?>">
141 &nbsp;
142 <input type='button' value='<?php xl('Print','e'); ?>' onclick='window.print()' />
143 </td>
144 </tr>
146 <tr>
147 <td height="1">
148 </td>
149 </tr>
151 </table>
153 <table border='0' cellpadding='1' cellspacing='2' width='98%'>
155 <tr bgcolor="#dddddd">
156 <td class="dehead">
157 <?php xl('Practitioner','e') ?>
158 </td>
159 <td class="dehead">
160 <?php xl('Date','e') ?>
161 </td>
162 <?php if ($form_procedures) { ?>
163 <td class="dehead">
164 <?php xl('Invoice','e') ?>
165 </td>
166 <?php } ?>
167 <?php if ($form_cptcode) { ?>
168 <td class="dehead" align='right'>
169 <?php xl('InvAmt','e') ?>
170 </td>
171 <?php } ?>
172 <?php if ($form_cptcode) { ?>
173 <td class="dehead">
174 <?php xl('Insurance','e') ?>
175 </td>
176 <?php } ?>
177 <?php if ($form_procedures) { ?>
178 <td class="dehead">
179 <?php xl('Procedure','e') ?>
180 </td>
181 <td class="dehead" align="right">
182 <?php xl('Prof.','e') ?>
183 </td>
184 <td class="dehead" align="right">
185 <?php xl('Clinic','e') ?>
186 </td>
187 <?php } else { ?>
188 <td class="dehead" align="right">
189 <?php xl('Received','e') ?>
190 </td>
191 <?php } ?>
192 </tr>
193 <?php
194 if ($_POST['form_refresh']) {
195 $form_doctor = $_POST['form_doctor'];
196 $arows = array();
198 if ($INTEGRATED_AR) {
199 $ids_to_skip = array();
200 $irow = 0;
202 // Get copays. These are ignored if a CPT code was specified.
204 if (!$form_cptcode) {
205 $query = "SELECT b.fee, b.pid, b.encounter, b.code_type, b.code, b.modifier, " .
206 "fe.date, fe.id AS trans_id, u.id AS docid " .
207 "FROM billing AS b " .
208 "JOIN form_encounter AS fe ON fe.pid = b.pid AND fe.encounter = b.encounter " .
209 "JOIN forms AS f ON f.pid = b.pid AND f.encounter = b.encounter AND f.formdir = 'newpatient' " .
210 "LEFT OUTER JOIN users AS u ON u.username = f.user " .
211 "WHERE b.code_type = 'COPAY' AND b.activity = 1 AND " .
212 "fe.date >= '$form_from_date 00:00:00' AND fe.date <= '$form_to_date 23:59:59'";
213 // If a facility was specified.
214 if ($form_facility) {
215 $query .= " AND fe.facility_id = '$form_facility'";
217 // If a doctor was specified.
218 if ($form_doctor) {
219 $query .= " AND u.id = '$form_doctor'";
222 $res = sqlStatement($query);
223 while ($row = sqlFetchArray($res)) {
224 $trans_id = $row['trans_id'];
225 $thedate = substr($row['date'], 0, 10);
226 $patient_id = $row['pid'];
227 $encounter_id = $row['encounter'];
229 if (!empty($ids_to_skip[$trans_id])) continue;
231 // If a diagnosis code was given then skip any invoices without
232 // that diagnosis.
233 if ($form_icdcode) {
234 $tmp = sqlQuery("SELECT count(*) AS count FROM billing WHERE " .
235 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
236 "code_type = 'ICD9' AND code LIKE '$form_icdcode' AND " .
237 "activity = 1");
238 if (empty($tmp['count'])) {
239 $ids_to_skip[$trans_id] = 1;
240 continue;
244 $key = sprintf("%08u%s%08u%08u%06u", $row['docid'], $thedate,
245 $patient_id, $encounter_id, ++$irow);
246 $arows[$key] = array();
247 $arows[$key]['transdate'] = $thedate;
248 $arows[$key]['amount'] = $row['fee'];
249 $arows[$key]['docid'] = $row['docid'];
250 $arows[$key]['project_id'] = 0;
251 $arows[$key]['memo'] = '';
252 $arows[$key]['invnumber'] = "$patient_id.$encounter_id";
253 } // end while
254 } // end copays (not $form_cptcode)
256 // Get ar_activity (having payments), form_encounter, forms, users, optional ar_session
257 $query = "SELECT a.pid, a.encounter, a.post_time, a.code, a.modifier, a.pay_amount, " .
258 "fe.date, fe.id AS trans_id, u.id AS docid, s.deposit_date, s.payer_id " .
259 "FROM ar_activity AS a " .
260 "JOIN form_encounter AS fe ON fe.pid = a.pid AND fe.encounter = a.encounter " .
261 "JOIN forms AS f ON f.pid = a.pid AND f.encounter = a.encounter AND f.formdir = 'newpatient' " .
262 "LEFT OUTER JOIN users AS u ON u.username = f.user " .
263 "LEFT OUTER JOIN ar_session AS s ON s.session_id = a.session_id " .
264 "WHERE a.pay_amount != 0 AND ( " .
265 "a.post_time >= '$form_from_date 00:00:00' AND a.post_time <= '$form_to_date 23:59:59' " .
266 "OR fe.date >= '$form_from_date 00:00:00' AND fe.date <= '$form_to_date 23:59:59' " .
267 "OR s.deposit_date >= '$form_from_date' AND s.deposit_date <= '$form_to_date' )";
268 // If a procedure code was specified.
269 if ($form_cptcode) $query .= " AND a.code = '$form_cptcode'";
270 // If a facility was specified.
271 if ($form_facility) $query .= " AND fe.facility_id = '$form_facility'";
272 // If a doctor was specified.
273 if ($form_doctor) $query .= " AND u.id = '$form_doctor'";
275 $res = sqlStatement($query);
276 while ($row = sqlFetchArray($res)) {
277 $trans_id = $row['trans_id'];
278 $patient_id = $row['pid'];
279 $encounter_id = $row['encounter'];
281 if (!empty($ids_to_skip[$trans_id])) continue;
283 if ($form_use_edate) {
284 $thedate = substr($row['date'], 0, 10);
285 } else {
286 if (!empty($row['deposit_date']))
287 $thedate = $row['deposit_date'];
288 else
289 $thedate = substr($row['post_time'], 0, 10);
291 if (strcmp($thedate, $form_from_date) < 0 || strcmp($thedate, $form_to_date) > 0) continue;
293 // If a diagnosis code was given then skip any invoices without
294 // that diagnosis.
295 if ($form_icdcode) {
296 $tmp = sqlQuery("SELECT count(*) AS count FROM billing WHERE " .
297 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
298 "code_type = 'ICD9' AND code LIKE '$form_icdcode' AND " .
299 "activity = 1");
300 if (empty($tmp['count'])) {
301 $ids_to_skip[$trans_id] = 1;
302 continue;
306 $key = sprintf("%08u%s%08u%08u%06u", $row['docid'], $thedate,
307 $patient_id, $encounter_id, ++$irow);
308 $arows[$key] = array();
309 $arows[$key]['transdate'] = $thedate;
310 $arows[$key]['amount'] = 0 - $row['pay_amount'];
311 $arows[$key]['docid'] = $row['docid'];
312 $arows[$key]['project_id'] = empty($row['payer_id']) ? 0 : $row['payer_id'];
313 $arows[$key]['memo'] = $row['code'];
314 $arows[$key]['invnumber'] = "$patient_id.$encounter_id";
315 } // end while
316 } // end $INTEGRATED_AR
318 else {
319 if ($form_cptcode) {
320 $query = "SELECT acc_trans.amount, acc_trans.transdate, " .
321 "acc_trans.memo, acc_trans.project_id, acc_trans.trans_id, " .
322 "ar.invnumber, ar.employee_id, invoice.sellprice, invoice.qty " .
323 "FROM acc_trans, ar, invoice WHERE " .
324 "acc_trans.chart_id = $chart_id_cash AND " .
325 "acc_trans.memo ILIKE '$form_cptcode' AND " .
326 "ar.id = acc_trans.trans_id AND " .
327 "invoice.trans_id = acc_trans.trans_id AND " .
328 "invoice.serialnumber ILIKE acc_trans.memo AND " .
329 "invoice.sellprice >= 0.00 AND " .
330 "( invoice.description ILIKE 'CPT%' OR invoice.description ILIKE 'Proc%' ) AND ";
332 else {
333 $query = "select acc_trans.amount, acc_trans.transdate, " .
334 "acc_trans.memo, acc_trans.trans_id, " .
335 "ar.invnumber, ar.employee_id from acc_trans, ar where " .
336 "acc_trans.chart_id = $chart_id_cash and " .
337 "ar.id = acc_trans.trans_id and ";
340 if ($form_use_edate) {
341 $query .= "ar.transdate >= '$form_from_date' and " .
342 "ar.transdate <= '$form_to_date'";
343 } else {
344 $query .= "acc_trans.transdate >= '$form_from_date' and " .
345 "acc_trans.transdate <= '$form_to_date'";
348 $query .= " order by ar.invnumber";
350 // echo "<!-- $query -->\n"; // debugging
352 $t_res = SLQuery($query);
353 if ($sl_err) die($sl_err);
355 $docname = "";
356 $docnameleft = "";
357 $docid = 0;
358 $doctotal1 = 0;
359 $grandtotal1 = 0;
360 $doctotal2 = 0;
361 $grandtotal2 = 0;
362 $last_trans_id = 0;
363 $skipping = false;
365 for ($irow = 0; $irow < SLRowCount($t_res); ++$irow) {
366 $row = SLGetRow($t_res, $irow);
368 list($patient_id, $encounter_id) = explode(".", $row['invnumber']);
370 // Under some conditions we may skip invoices that matched the SQL query.
372 if ($row['trans_id'] == $last_trans_id) {
373 if ($skipping) continue;
374 // same invoice and not skipping, do nothing.
375 } else { // new invoice
376 $skipping = false;
377 // If a diagnosis code was given then skip any invoices without
378 // that diagnosis.
379 if ($form_icdcode) {
380 if (!SLQueryValue("SELECT count(*) FROM invoice WHERE " .
381 "invoice.trans_id = '" . $row['trans_id'] . "' AND " .
382 "( invoice.description ILIKE 'ICD9:$form_icdcode %' OR " .
383 "invoice.serialnumber ILIKE 'ICD9:$form_icdcode' )"))
385 $skipping = true;
386 continue;
389 // If a facility was specified then skip invoices whose encounters
390 // do not indicate that facility.
391 if ($form_facility) {
392 $tmp = sqlQuery("SELECT count(*) AS count FROM form_encounter WHERE " .
393 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
394 "facility_id = '$form_facility'");
395 if (empty($tmp['count'])) {
396 $skipping = true;
397 continue;
400 // Find out who the practitioner is.
401 $tmp = sqlQuery("SELECT users.id, users.authorized FROM forms, users WHERE " .
402 "forms.pid = '$patient_id' AND forms.encounter = '$encounter_id' AND " .
403 "forms.formdir = 'newpatient' AND users.username = forms.user");
404 $docid = empty($tmp['id']) ? 0 : $tmp['id'];
405 if (empty($tmp['authorized'])) {
406 $tmp = sqlQuery("SELECT users.id FROM billing, users WHERE " .
407 "billing.pid = '$patient_id' AND billing.encounter = '$encounter_id' AND " .
408 "billing.activity = 1 AND billing.fee > 0 AND " .
409 "users.id = billing.provider_id AND users.authorized = 1 " .
410 "ORDER BY billing.fee DESC, billing.id ASC LIMIT 1");
411 if (!empty($tmp['id'])) $docid = $tmp['id'];
413 // If a practitioner was specified then skip other practitioners.
414 if ($form_doctor) {
415 if ($form_doctor != $docid) {
416 $skipping = true;
417 continue;
420 } // end new invoice
422 $row['docid'] = $docid;
423 $key = sprintf("%08u%s%08u%08u%06u", $docid, $row['transdate'],
424 $patient_id, $encounter_id, $irow);
425 $arows[$key] = $row;
428 } // end not $INTEGRATED_AR
430 ksort($arows);
431 $docid = 0;
433 foreach ($arows as $row) {
435 // Get insurance company name
436 $insconame = '';
437 if ($form_cptcode && $row['project_id']) {
438 $tmp = sqlQuery("SELECT name FROM insurance_companies WHERE " .
439 "id = '" . $row['project_id'] . "'");
440 $insconame = $tmp['name'];
443 $amount1 = 0;
444 $amount2 = 0;
445 if ($form_procedures && is_clinic($row['memo']))
446 $amount2 -= $row['amount'];
447 else
448 $amount1 -= $row['amount'];
450 // if ($docid != $row['employee_id']) {
451 if ($docid != $row['docid']) {
452 if ($docid) {
453 // Print doc totals.
456 <tr bgcolor="#ddddff">
457 <td class="detail" colspan="<?php echo ($form_cptcode ? 4 : 2) + ($form_procedures ? 2 : 0); ?>">
458 <? echo xl('Totals for ') . $docname ?>
459 </td>
460 <td class="dehead" align="right">
461 <?php bucks($doctotal1) ?>
462 </td>
463 <?php if ($form_procedures) { ?>
464 <td class="dehead" align="right">
465 <?php bucks($doctotal2) ?>
466 </td>
467 <?php } ?>
468 </tr>
471 $doctotal1 = 0;
472 $doctotal2 = 0;
474 $docid = $row['docid'];
475 $tmp = sqlQuery("SELECT lname, fname FROM users WHERE id = '$docid'");
476 $docname = empty($tmp) ? 'Unknown' : $tmp['fname'] . ' ' . $tmp['lname'];
478 $docnameleft = $docname;
481 if ($_POST['form_details']) {
484 <tr>
485 <td class="detail">
486 <?php echo $docnameleft; $docnameleft = "&nbsp;" ?>
487 </td>
488 <td class="detail">
489 <?php echo $row['transdate'] ?>
490 </td>
491 <?php if ($form_procedures) { ?>
492 <td class="detail">
493 <?php echo $row['invnumber'] ?>
494 </td>
495 <?php } ?>
496 <?php
497 if ($form_cptcode) {
498 echo " <td class='detail' align='right'>";
499 if ($INTEGRATED_AR) {
500 list($patient_id, $encounter_id) = explode(".", $row['invnumber']);
501 $tmp = sqlQuery("SELECT SUM(fee) AS sum FROM billing WHERE " .
502 "pid = '$patient_id' AND encounter = '$encounter_id' AND " .
503 "code = '$form_cptcode' AND activity = 1");
504 bucks($tmp['sum']);
506 else {
507 bucks($row['sellprice'] * $row['qty']);
509 echo " </td>\n";
512 <?php if ($form_cptcode) { ?>
513 <td class="detail">
514 <?php echo $insconame ?>
515 </td>
516 <?php } ?>
517 <?php if ($form_procedures) { ?>
518 <td class="detail">
519 <?php echo $row['memo'] ?>
520 </td>
521 <?php } ?>
522 <td class="detail" align="right">
523 <?php bucks($amount1) ?>
524 </td>
525 <?php if ($form_procedures) { ?>
526 <td class="detail" align="right">
527 <?php bucks($amount2) ?>
528 </td>
529 <?php } ?>
530 </tr>
532 } // end details
533 $doctotal1 += $amount1;
534 $doctotal2 += $amount2;
535 $grandtotal1 += $amount1;
536 $grandtotal2 += $amount2;
540 <tr bgcolor="#ddddff">
541 <td class="detail" colspan="<?php echo ($form_cptcode ? 4 : 2) + ($form_procedures ? 2 : 0); ?>">
542 <?echo xl('Totals for ') . $docname ?>
543 </td>
544 <td class="dehead" align="right">
545 <?php bucks($doctotal1) ?>
546 </td>
547 <?php if ($form_procedures) { ?>
548 <td class="dehead" align="right">
549 <?php bucks($doctotal2) ?>
550 </td>
551 <?php } ?>
552 </tr>
554 <tr bgcolor="#ffdddd">
555 <td class="detail" colspan="<?php echo ($form_cptcode ? 4 : 2) + ($form_procedures ? 2 : 0); ?>">
556 <?php xl('Grand Totals','e') ?>
557 </td>
558 <td class="dehead" align="right">
559 <?php bucks($grandtotal1) ?>
560 </td>
561 <?php if ($form_procedures) { ?>
562 <td class="dehead" align="right">
563 <?php bucks($grandtotal2) ?>
564 </td>
565 <?php } ?>
566 </tr>
570 if (!$INTEGRATED_AR) SLClose();
573 </table>
574 </form>
575 </center>
576 </body>
578 <!-- stuff for the popup calendar -->
579 <style type="text/css">@import url(../../library/dynarch_calendar.css);</style>
580 <script type="text/javascript" src="../../library/dynarch_calendar.js"></script>
581 <script type="text/javascript" src="../../library/dynarch_calendar_en.js"></script>
582 <script type="text/javascript" src="../../library/dynarch_calendar_setup.js"></script>
583 <script language="Javascript">
584 Calendar.setup({inputField:"form_from_date", ifFormat:"%Y-%m-%d", button:"img_from_date"});
585 Calendar.setup({inputField:"form_to_date", ifFormat:"%Y-%m-%d", button:"img_to_date"});
586 </script>
588 </html>