Added a link to new prescription generator.
[openemr.git] / interface / patient_file / front_payment.php
blob49913bd5c062bb5bec8ab968a26b61cef3de85c1
1 <?php
2 // Copyright (C) 2006-2007 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 require_once("../globals.php");
10 require_once("$srcdir/acl.inc");
11 require_once("$srcdir/patient.inc");
12 require_once("$srcdir/forms.inc");
13 require_once("$srcdir/sl_eob.inc.php");
14 require_once("$srcdir/invoice_summary.inc.php");
15 require_once("../../custom/code_types.inc.php");
17 <html>
18 <head>
19 <?php html_header_show();?>
20 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
21 <?php
23 // Format dollars for display.
25 function bucks($amount) {
26 if ($amount) {
27 $amount = sprintf("%.2f", $amount);
28 if ($amount != 0.00) return $amount;
30 return '';
33 // Get the co-pay amount that is effective on the given date.
34 // Or if no insurance on that date, return -1.
36 function getCopay($patient_id, $encdate) {
37 $tmp = sqlQuery("SELECT provider, copay FROM insurance_data " .
38 "WHERE pid = '$patient_id' AND type = 'primary' " .
39 "AND date <= '$encdate' ORDER BY date DESC LIMIT 1");
40 if ($tmp['provider']) return sprintf('%01.2f', 0 + $tmp['copay']);
41 return -1;
44 // Display a row of data for an encounter.
46 function echoLine($iname, $date, $charges, $ptpaid, $inspaid, $duept) {
47 $balance = bucks($charges - $ptpaid - $inspaid);
48 $getfrompt = ($duept > 0) ? $duept : 0;
49 echo " <tr>\n";
50 echo " <td class='detail'>$date</td>\n";
51 echo " <td class='detail' align='right'>" . bucks($charges) . "</td>\n";
52 echo " <td class='detail' align='right'>" . bucks($ptpaid) . "</td>\n";
53 echo " <td class='detail' align='right'>" . bucks($inspaid) . "</td>\n";
54 echo " <td class='detail' align='right'>$balance</td>\n";
55 echo " <td class='detail' align='right'>" . bucks($duept) . "</td>\n";
56 echo " <td class='detail' align='right'><input type='text' name='$iname' " .
57 "size='6' value='" . bucks($getfrompt) . "' onchange='calctotal()' " .
58 "onkeyup='calctotal()' /></td>\n";
59 echo " </tr>\n";
62 // Post a payment to the payments table.
64 function frontPayment($patient_id, $encounter, $method, $source, $amount1, $amount2) {
65 global $timestamp;
66 $payid = sqlInsert("INSERT INTO payments ( " .
67 "pid, encounter, dtime, user, method, source, amount1, amount2 " .
68 ") VALUES ( " .
69 "'$patient_id', " .
70 "'$encounter', " .
71 "'$timestamp', " .
72 "'" . $_SESSION['authUser'] . "', " .
73 "'$method', " .
74 "'$source', " .
75 "'$amount1', " .
76 "'$amount2' " .
77 ")");
78 return $payid;
81 // Get the patient's encounter ID for today, creating it if there is none.
82 // In the case of more than one encounter today, pick the last one.
84 function todaysEncounter($patient_id) {
85 global $today;
87 $tmprow = sqlQuery("SELECT encounter FROM form_encounter WHERE " .
88 "pid = '$patient_id' AND date = '$today 00:00:00' " .
89 "ORDER BY encounter DESC LIMIT 1");
91 if (!empty($tmprow['encounter'])) return $tmprow['encounter'];
93 $tmprow = sqlQuery("SELECT username, facility, facility_id FROM users " .
94 "WHERE id = '" . $_SESSION["authUserID"] . "'");
95 $username = $tmprow['username'];
96 $facility = $tmprow['facility'];
97 $facility_id = $tmprow['facility_id'];
98 $conn = $GLOBALS['adodb']['db'];
99 $encounter = $conn->GenID("sequences");
100 addForm($encounter, "New Patient Encounter",
101 sqlInsert("INSERT INTO form_encounter SET " .
102 "date = '$today', " .
103 "onset_date = '$today', " .
104 "reason = 'Please indicate visit reason', " .
105 "facility = '$facility', " .
106 "facility_id = '$facility_id', " .
107 "pid = '$patient_id', " .
108 "encounter = '$encounter'"
110 "newpatient", $patient_id, "1", "NOW()", $username
112 return $encounter;
115 // We use this to put dashes, colons, etc. back into a timestamp.
117 function decorateString($fmt, $str) {
118 $res = '';
119 while ($fmt) {
120 $fc = substr($fmt, 0, 1);
121 $fmt = substr($fmt, 1);
122 if ($fc == '.') {
123 $res .= substr($str, 0, 1);
124 $str = substr($str, 1);
125 } else {
126 $res .= $fc;
129 return $res;
132 // Compute taxes from a tax rate string and a possibly taxable amount.
134 function calcTaxes($row, $amount) {
135 $total = 0;
136 if (empty($row['taxrates'])) return $total;
137 $arates = explode(':', $row['taxrates']);
138 if (empty($arates)) return $total;
139 foreach ($arates as $value) {
140 if (empty($value)) continue;
141 $trow = sqlQuery("SELECT option_value FROM list_options WHERE " .
142 "list_id = 'taxrate' AND option_id = '$value' LIMIT 1");
143 if (empty($trow['option_value'])) {
144 echo "<!-- Missing tax rate '$value'! -->\n";
145 continue;
147 $tax = sprintf("%01.2f", $amount * $trow['option_value']);
148 echo "<!-- Rate = '$value', amount = '$amount', tax = '$tax' -->\n";
149 $total += $tax;
151 return $total;
154 $payment_methods = array(
155 xl('Cash'),
156 xl('Check'),
157 xl('MC'),
158 xl('VISA'),
159 xl('AMEX'),
160 xl('DISC'),
161 xl('Other'));
163 $now = time();
164 $today = date('Y-m-d', $now);
165 $timestamp = date('Y-m-d H:i:s', $now);
167 slInitialize();
169 // $patdata = getPatientData($pid, 'fname,lname,pubpid');
171 $patdata = sqlQuery("SELECT " .
172 "p.fname, p.mname, p.lname, p.pubpid, i.copay " .
173 "FROM patient_data AS p " .
174 "LEFT OUTER JOIN insurance_data AS i ON " .
175 "i.pid = p.pid AND i.type = 'primary' " .
176 "WHERE p.pid = '$pid' ORDER BY i.date DESC LIMIT 1");
178 $alertmsg = ''; // anything here pops up in an alert box
180 // If the Save button was clicked...
181 if ($_POST['form_save']) {
182 $form_pid = $_POST['form_pid'];
183 $form_method = trim($_POST['form_method']);
184 $form_source = trim($_POST['form_source']);
186 // Post payments for unbilled encounters. These go into the billing table.
187 if ($_POST['form_upay']) {
188 foreach ($_POST['form_upay'] as $enc => $payment) {
189 if ($amount = 0 + $payment) {
190 if (!$enc) $enc = todaysEncounter($form_pid);
191 addBilling($enc, 'COPAY', sprintf('%.2f', $amount),
192 $form_method, $form_pid, 1, $_SESSION["authUserID"],
193 '', 1, 0 - $amount, '', '');
194 frontPayment($form_pid, $enc, $form_method, $form_source, $amount, 0);
199 // Post payments for previously billed encounters. These go to SQL-Ledger.
200 if ($_POST['form_bpay']) {
201 foreach ($_POST['form_bpay'] as $enc => $payment) {
202 if ($amount = 0 + $payment) {
203 $thissrc = 'Pt/';
204 if ($form_method) {
205 $thissrc .= $form_method;
206 if ($form_source) $thissrc .= " $form_source";
208 $trans_id = SLQueryValue("SELECT id FROM ar WHERE " .
209 "ar.invnumber = '$form_pid.$enc' LIMIT 1");
210 if (! $trans_id) die("Cannot find invoice '$form_pid.$enc'!");
211 slPostPayment($trans_id, $amount, date('Y-m-d'), $thissrc,
212 '', 0, 0);
213 frontPayment($form_pid, $enc, $form_method, $form_source, 0, $amount);
220 <?php
221 if ($_POST['form_save'] || $_REQUEST['receipt']) {
223 if ($_REQUEST['receipt']) {
224 $form_pid = $_GET['patient'];
225 $timestamp = decorateString('....-..-.. ..:..:..', $_GET['time']);
228 // Get details for what we guess is the primary facility.
229 $frow = sqlQuery("SELECT * FROM facility " .
230 "ORDER BY billing_location DESC, accepts_assignment DESC, id LIMIT 1");
232 // Get the patient's name and chart number.
233 $patdata = getPatientData($form_pid, 'fname,mname,lname,pubpid');
235 // Re-fetch payment info.
236 $payrow = sqlQuery("SELECT " .
237 "SUM(amount1) AS amount1, " .
238 "SUM(amount2) AS amount2, " .
239 "MAX(method) AS method, " .
240 "MAX(source) AS source, " .
241 "MAX(dtime) AS dtime, " .
242 "MAX(user) AS user " .
243 "FROM payments WHERE " .
244 "pid = '$form_pid' AND dtime = '$timestamp'");
246 // Create key for deleting, just in case.
247 $payment_key = $form_pid . '.' . preg_replace('/[^0-9]/', '', $timestamp);
249 // Now proceed with printing the receipt.
252 <title><?php xl('Receipt for Payment','e'); ?></title>
253 <script type="text/javascript" src="../../library/dialog.js"></script>
254 <script language="JavaScript">
256 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
258 // Process click on Print button.
259 function printme() {
260 var divstyle = document.getElementById('hideonprint').style;
261 divstyle.display = 'none';
262 window.print();
263 // divstyle.display = 'block';
265 // Process click on Delete button.
266 function deleteme() {
267 dlgopen('deleter.php?payment=<?php echo $payment_key ?>', '_blank', 500, 450);
268 return false;
270 // Called by the deleteme.php window on a successful delete.
271 function imdeleted() {
272 window.close();
275 </script>
276 </head>
277 <body bgcolor='#ffffff'>
278 <center>
280 <p><h2><?php xl('Receipt for Payment','e'); ?></h2>
282 <p><?php echo htmlentities($frow['name']) ?>
283 <br><?php echo htmlentities($frow['street']) ?>
284 <br><?php echo htmlentities($frow['city'] . ', ' . $frow['state']) . ' ' .
285 $frow['postal_code'] ?>
286 <br><?php echo htmlentities($frow['phone']) ?>
289 <table border='0' cellspacing='8'>
290 <tr>
291 <td><?php xl('Date','e'); ?>:</td>
292 <td><?php echo date('Y-m-d', strtotime($payrow['dtime'])) ?></td>
293 </tr>
294 <tr>
295 <td><?php xl('Patient','e'); ?>:</td>
296 <td><?php echo $patdata['fname'] . " " . $patdata['mname'] . " " .
297 $patdata['lname'] . " (" . $patdata['pubpid'] . ")" ?></td>
298 </tr>
299 <tr>
300 <td><?php xl('Paid Via','e'); ?>:</td>
301 <td><?php echo $payrow['method'] ?></td>
302 </tr>
303 <tr>
304 <td><?php xl('Check/Ref Number','e'); ?>:</td>
305 <td><?php echo $payrow['source'] ?></td>
306 </tr>
307 <tr>
308 <td><?php xl('Amount for This Visit','e'); ?>:</td>
309 <td><?php echo $payrow['amount1'] ?></td>
310 </tr>
311 <tr>
312 <td><?php xl('Amount for Past Balance','e'); ?>:</td>
313 <td><?php echo $payrow['amount2'] ?></td>
314 </tr>
315 <tr>
316 <td><?php xl('Received By','e'); ?>:</td>
317 <td><?php echo $payrow['user'] ?></td>
318 </tr>
319 </table>
321 <div id='hideonprint'>
323 <input type='button' value='<?php xl('Print','e'); ?>' onclick='printme()' />
325 <?php if (acl_check('admin', 'super')) { ?>
326 &nbsp;
327 <input type='button' value='<?php xl('Delete','e'); ?>' style='color:red' onclick='deleteme()' />
328 <?php } ?>
330 </div>
331 </center>
332 </body>
334 <?php
336 // End of receipt printing logic.
338 } else {
340 // Here we display the form for data entry.
343 <title><?php xl('Record Payment','e'); ?></title>
345 <style type="text/css">
346 body { font-family:sans-serif; font-size:10pt; font-weight:normal }
347 .dehead { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:bold }
348 .detail { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:normal }
349 </style>
351 <script type="text/javascript" src="../../library/topdialog.js"></script>
352 <script type="text/javascript" src="../../library/dialog.js"></script>
354 <script language="JavaScript">
355 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
357 function calctotal() {
358 var f = document.forms[0];
359 var total = 0;
360 for (var i = 0; i < f.elements.length; ++i) {
361 var elem = f.elements[i];
362 var ename = elem.name;
363 if (ename.indexOf('form_upay[') == 0 || ename.indexOf('form_bpay[') == 0) {
364 if (elem.value.length > 0) total += Number(elem.value);
367 f.form_paytotal.value = Number(total).toFixed(2);
368 return true;
371 </script>
373 </head>
375 <body class="body_top" onunload='imclosing()'>
377 <form method='post' action='front_payment.php<?php if ($payid) echo "?payid=$payid"; ?>'
378 onsubmit='return top.restoreSession()'>
379 <input type='hidden' name='form_pid' value='<?php echo $pid ?>' />
381 <center>
383 <table border='0' cellspacing='8'>
385 <tr>
386 <td colspan='2' align='center'>
387 &nbsp;<br>
388 <b><?php xl('Accept Payment for ','e'); ?><?php echo $patdata['fname'] . " " .
389 $patdata['lname'] . " (" . $patdata['pubpid'] . ")" ?></b>
390 <br>&nbsp;
391 </td>
392 </tr>
394 <tr>
395 <td>
396 <?php xl('Payment Method','e'); ?>:
397 </td>
398 <td>
399 <select name='form_method'>
400 <?php
401 foreach ($payment_methods as $value) {
402 echo " <option value='$value'";
403 if ($value == $payrow['method']) echo " selected";
404 echo ">$value</option>\n";
407 </select>
408 </td>
409 </tr>
411 <tr>
412 <td>
413 <?php xl('Check/Reference Number','e'); ?>:
414 </td>
415 <td>
416 <input type='text' name='form_source' size='10' value='<?php echo $payrow['source'] ?>'>
417 </td>
418 </tr>
420 </table>
422 <table border='0' cellpadding='2' cellspacing='0' width='98%'>
423 <tr bgcolor="#cccccc">
424 <td class="dehead">
425 <?php xl('DOS','e')?>
426 </td>
427 <td class="dehead" align="right">
428 <?php xl('Charges','e')?>
429 </td>
430 <td class="dehead" align="right">
431 <?php xl('Pt Paid','e')?>&nbsp;
432 </td>
433 <td class="dehead" align="right">
434 <?php xl('Insurance','e')?>
435 </td>
436 <td class="dehead" align="right">
437 <?php xl('Balance','e')?>
438 </td>
439 <td class="dehead" align="right">
440 <?php xl('Due Pt','e')?>
441 </td>
442 <td class="dehead" align="right">
443 <?php xl('Paying','e')?>
444 </td>
445 </tr>
447 <?php
448 $encs = array();
450 // Get the unbilled service charges and payments by encounter for this patient.
452 $query = "SELECT b.encounter, b.code_type, b.code, b.modifier, b.fee, " .
453 "LEFT(fe.date, 10) AS encdate " .
454 "FROM billing AS b, form_encounter AS fe " .
455 "WHERE b.pid = '$pid' AND b.activity = 1 AND b.billed = 0 " .
456 "AND fe.pid = b.pid AND fe.encounter = b.encounter " .
457 "ORDER BY b.encounter";
458 $bres = sqlStatement($query);
460 while ($brow = sqlFetchArray($bres)) {
461 $key = 0 - $brow['encounter'];
462 if (empty($encs[$key])) {
463 $encs[$key] = array(
464 'encounter' => $brow['encounter'],
465 'date' => $brow['encdate'],
466 'charges' => 0,
467 'payments' => 0);
469 if ($brow['code_type'] === 'COPAY') {
470 $encs[$key]['payments'] -= $brow['fee'];
471 } else {
472 $encs[$key]['charges'] += $brow['fee'];
473 // Add taxes.
474 $query = "SELECT taxrates FROM codes WHERE " .
475 "code_type = '" . $code_types[$brow['code_type']]['id'] . "' AND " .
476 "code = '" . $brow['code'] . "' AND ";
477 if ($brow['modifier']) {
478 $query .= "modifier = '" . $brow['modifier'] . "'";
479 } else {
480 $query .= "(modifier IS NULL OR modifier = '')";
482 $query .= " LIMIT 1";
483 $trow = sqlQuery($query);
484 $encs[$key]['charges'] += calcTaxes($trow, $brow['fee']);
488 // Do the same for unbilled product sales.
490 $query = "SELECT s.encounter, s.drug_id, s.fee, " .
491 "LEFT(fe.date, 10) AS encdate " .
492 "FROM drug_sales AS s, form_encounter AS fe " .
493 "WHERE s.pid = '$pid' AND s.billed = 0 " .
494 "AND fe.pid = s.pid AND fe.encounter = s.encounter " .
495 "ORDER BY s.encounter";
496 $dres = sqlStatement($query);
498 while ($drow = sqlFetchArray($dres)) {
499 $key = 0 - $drow['encounter'];
500 if (empty($encs[$key])) {
501 $encs[$key] = array(
502 'encounter' => $drow['encounter'],
503 'date' => $drow['encdate'],
504 'charges' => 0,
505 'payments' => 0);
507 $encs[$key]['charges'] += $drow['fee'];
508 // Add taxes.
509 $trow = sqlQuery("SELECT taxrates FROM drug_templates WHERE drug_id = '" .
510 $drow['drug_id'] . "' ORDER BY selector LIMIT 1");
511 $encs[$key]['charges'] += calcTaxes($trow, $drow['fee']);
514 ksort($encs, SORT_NUMERIC);
515 $gottoday = false;
516 foreach ($encs as $key => $value) {
517 $enc = $value['encounter'];
518 $dispdate = $value['date'];
519 if (strcmp($dispdate, $today) == 0 && !$gottoday) {
520 $dispdate = 'Today';
521 $gottoday = true;
523 $inscopay = getCopay($pid, $value['date']);
524 $balance = bucks($value['charges'] - $value['payments']);
525 $duept = (($inscopay >= 0) ? $inscopay : $value['charges']) - $value['payments'];
526 echoLine("form_upay[$enc]", $dispdate, $value['charges'],
527 $value['payments'], 0, $duept);
530 // If no billing was entered yet for today, then generate a line for
531 // entering today's co-pay.
533 if (! $gottoday) {
534 $inscopay = getCopay($pid, $today);
535 $duept = ($inscopay >= 0) ? $inscopay : 0;
536 echoLine("form_upay[0]", "Today", 0, 0, 0, $duept);
539 // Query for all open invoices.
540 $query = "SELECT ar.id, ar.invnumber, ar.amount, ar.paid, " .
541 "ar.intnotes, ar.notes, ar.shipvia, " .
542 "(SELECT SUM(invoice.sellprice * invoice.qty) FROM invoice WHERE " .
543 "invoice.trans_id = ar.id AND invoice.sellprice > 0) AS charges, " .
544 "(SELECT SUM(invoice.sellprice * invoice.qty) FROM invoice WHERE " .
545 "invoice.trans_id = ar.id AND invoice.sellprice < 0) AS adjustments, " .
546 "(SELECT SUM(acc_trans.amount) FROM acc_trans WHERE " .
547 "acc_trans.trans_id = ar.id AND acc_trans.chart_id = $chart_id_cash " .
548 "AND acc_trans.source NOT LIKE 'Ins%') AS ptpayments " .
549 "FROM ar WHERE ar.invnumber LIKE '$pid.%' AND " .
550 "ar.amount != ar.paid " .
551 "ORDER BY ar.invnumber";
552 $ires = SLQuery($query);
553 if ($sl_err) die($sl_err);
554 $num_invoices = SLRowCount($ires);
556 for ($ix = 0; $ix < $num_invoices; ++$ix) {
557 $irow = SLGetRow($ires, $ix);
559 // Get encounter ID and date of service.
560 list($patient_id, $enc) = explode(".", $irow['invnumber']);
561 $tmp = sqlQuery("SELECT LEFT(date, 10) AS encdate FROM form_encounter " .
562 "WHERE encounter = '$enc'");
563 $svcdate = $tmp['encdate'];
565 // Compute $duncount as in sl_eob_search.php to determine if
566 // this invoice is at patient responsibility.
567 $duncount = substr_count(strtolower($irow['intnotes']), "statement sent");
568 if (! $duncount) {
569 $insgot = strtolower($irow['notes']);
570 $inseobs = strtolower($irow['shipvia']);
571 foreach (array('ins1', 'ins2', 'ins3') as $value) {
572 if (strpos($insgot, $value) !== false &&
573 strpos($inseobs, $value) === false)
574 --$duncount;
578 $inspaid = $irow['paid'] + $irow['ptpayments'] - $irow['adjustments'];
579 $balance = $irow['amount'] - $irow['paid'];
580 $duept = ($duncount < 0) ? 0 : $balance;
582 echoLine("form_bpay[$enc]", $svcdate, $irow['charges'],
583 0 - $irow['ptpayments'], $inspaid, $duept);
586 // Continue with display of the data entry form.
589 <tr bgcolor="#cccccc">
590 <td class="dehead" colspan="6">
591 <?php xl('Total Amount Paid','e')?>
592 </td>
593 <td class="dehead" align="right">
594 <input type='text' name='form_paytotal' size='6' value=''
595 style='color:#00aa00' readonly />
596 </td>
597 </tr>
599 </table>
602 <input type='submit' name='form_save' value='<?php xl('Save','e'); ?>' /> &nbsp;
603 <input type='button' value='<?php xl('Cancel','e'); ?>' onclick='window.close()' />
605 </center>
606 </form>
607 <script language="JavaScript">
608 calctotal();
609 </script>
610 </body>
612 <?php
614 SLClose();
616 </html>