added untimely filing as an adjustment reason
[openemr.git] / interface / patient_file / front_payment.php
blob50251cdadfd2d9306eaa8cc8570ac1a4da87dde9
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");
16 <html>
17 <head>
18 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
19 <?php
21 // Format dollars for display.
23 function bucks($amount) {
24 if ($amount) {
25 $amount = sprintf("%.2f", $amount);
26 if ($amount != 0.00) return $amount;
28 return '';
31 // Get the co-pay amount that is effective on the given date.
32 // Or if no insurance on that date, return -1.
34 function getCopay($patient_id, $encdate) {
35 $tmp = sqlQuery("SELECT provider, copay FROM insurance_data " .
36 "WHERE pid = '$patient_id' AND type = 'primary' " .
37 "AND date <= '$encdate' ORDER BY date DESC LIMIT 1");
38 if ($tmp['provider']) return sprintf('%01.2f', 0 + $tmp['copay']);
39 return -1;
42 // Display a row of data for an encounter.
44 function echoLine($iname, $date, $charges, $ptpaid, $inspaid, $duept) {
45 $balance = bucks($charges - $ptpaid - $inspaid);
46 $getfrompt = ($duept > 0) ? $duept : 0;
47 echo " <tr>\n";
48 echo " <td class='detail'>$date</td>\n";
49 echo " <td class='detail' align='right'>" . bucks($charges) . "</td>\n";
50 echo " <td class='detail' align='right'>" . bucks($ptpaid) . "</td>\n";
51 echo " <td class='detail' align='right'>" . bucks($inspaid) . "</td>\n";
52 echo " <td class='detail' align='right'>$balance</td>\n";
53 echo " <td class='detail' align='right'>" . bucks($duept) . "</td>\n";
54 echo " <td class='detail' align='right'><input type='text' name='$iname' " .
55 "size='6' value='" . bucks($getfrompt) . "' onchange='calctotal()' " .
56 "onkeyup='calctotal()' /></td>\n";
57 echo " </tr>\n";
60 // Post a payment to the payments table.
62 function frontPayment($patient_id, $encounter, $method, $source, $amount1, $amount2) {
63 global $timestamp;
64 $payid = sqlInsert("INSERT INTO payments ( " .
65 "pid, encounter, dtime, user, method, source, amount1, amount2 " .
66 ") VALUES ( " .
67 "'$patient_id', " .
68 "'$encounter', " .
69 "'$timestamp', " .
70 "'" . $_SESSION['authUser'] . "', " .
71 "'$method', " .
72 "'$source', " .
73 "'$amount1', " .
74 "'$amount2' " .
75 ")");
76 return $payid;
79 // Get the patient's encounter ID for today, creating it if there is none.
81 function todaysEncounter($patient_id) {
82 global $today;
84 $tmprow = sqlQuery("SELECT encounter FROM form_encounter WHERE " .
85 "pid = '$patient_id' AND date = '$today 00:00:00'");
87 if (!empty($tmprow['encounter'])) return $tmprow['encounter'];
89 $tmprow = sqlQuery("SELECT username, facility, facility_id FROM users " .
90 "WHERE id = '" . $_SESSION["authUserID"] . "'");
91 $username = $tmprow['username'];
92 $facility = $tmprow['facility'];
93 $facility_id = $tmprow['facility_id'];
94 $conn = $GLOBALS['adodb']['db'];
95 $encounter = $conn->GenID("sequences");
96 addForm($encounter, "New Patient Encounter",
97 sqlInsert("INSERT INTO form_encounter SET " .
98 "date = '$today', " .
99 "onset_date = '$today', " .
100 "reason = 'Please indicate visit reason', " .
101 "facility = '$facility', " .
102 "facility_id = '$facility_id', " .
103 "pid = '$patient_id', " .
104 "encounter = '$encounter'"
106 "newpatient", $patient_id, "1", "NOW()", $username
108 return $encounter;
111 // We use this to put dashes, colons, etc. back into a timestamp.
113 function decorateString($fmt, $str) {
114 $res = '';
115 while ($fmt) {
116 $fc = substr($fmt, 0, 1);
117 $fmt = substr($fmt, 1);
118 if ($fc == '.') {
119 $res .= substr($str, 0, 1);
120 $str = substr($str, 1);
121 } else {
122 $res .= $fc;
125 return $res;
128 $payment_methods = array(
129 xl('Cash'),
130 xl('Check'),
131 xl('MC'),
132 xl('VISA'),
133 xl('AMEX'),
134 xl('DISC'),
135 xl('Other'));
137 $now = time();
138 $today = date('Y-m-d', $now);
139 $timestamp = date('Y-m-d H:i:s', $now);
141 slInitialize();
143 // $patdata = getPatientData($pid, 'fname,lname,pubpid');
145 $patdata = sqlQuery("SELECT " .
146 "p.fname, p.mname, p.lname, p.pubpid, i.copay " .
147 "FROM patient_data AS p " .
148 "LEFT OUTER JOIN insurance_data AS i ON " .
149 "i.pid = p.pid AND i.type = 'primary' " .
150 "WHERE p.pid = '$pid' ORDER BY i.date DESC LIMIT 1");
152 $alertmsg = ''; // anything here pops up in an alert box
154 // If the Save button was clicked...
155 if ($_POST['form_save']) {
156 $form_pid = $_POST['form_pid'];
157 $form_method = trim($_POST['form_method']);
158 $form_source = trim($_POST['form_source']);
160 foreach ($_POST['form_upay'] as $encounter => $payment) {
161 if ($amount = 0 + $payment) {
162 if (!$encounter) $encounter = todaysEncounter($form_pid);
163 addBilling($encounter, 'COPAY', sprintf('%.2f', $amount),
164 $form_method, $form_pid, 1, $_SESSION["authUserID"],
165 '', 1, 0 - $amount, '', '');
166 frontPayment($form_pid, $encounter, $form_method, $form_source, $amount, 0);
170 foreach ($_POST['form_bpay'] as $encounter => $payment) {
171 if ($amount = 0 + $payment) {
172 $thissrc = 'Pt/';
173 if ($form_method) {
174 $thissrc .= $form_method;
175 if ($form_source) $thissrc .= " $form_source";
177 $trans_id = SLQueryValue("SELECT id FROM ar WHERE " .
178 "ar.invnumber = '$form_pid.$encounter' LIMIT 1");
179 if (! $trans_id) die("Cannot find invoice '$form_pid.$encounter'!");
180 slPostPayment($trans_id, $amount, date('Y-m-d'), $thissrc,
181 '', 0, 0);
182 frontPayment($form_pid, $encounter, $form_method, $form_source, 0, $amount);
188 <?php
189 if ($_POST['form_save'] || $_REQUEST['receipt']) {
191 if ($_REQUEST['receipt']) {
192 $form_pid = $_GET['patient'];
193 $timestamp = decorateString('....-..-.. ..:..:..', $_GET['time']);
196 // Get details for what we guess is the primary facility.
197 $frow = sqlQuery("SELECT * FROM facility " .
198 "ORDER BY billing_location DESC, accepts_assignment DESC, id LIMIT 1");
200 // Get the patient's name and chart number.
201 $patdata = getPatientData($form_pid, 'fname,mname,lname,pubpid');
203 // Re-fetch payment info.
204 $payrow = sqlQuery("SELECT " .
205 "SUM(amount1) AS amount1, " .
206 "SUM(amount2) AS amount2, " .
207 "MAX(method) AS method, " .
208 "MAX(source) AS source, " .
209 "MAX(dtime) AS dtime, " .
210 "MAX(user) AS user " .
211 "FROM payments WHERE " .
212 "pid = '$form_pid' AND dtime = '$timestamp'");
214 // Create key for deleting, just in case.
215 $payment_key = $form_pid . '.' . preg_replace('/[^0-9]/', '', $timestamp);
217 // Now proceed with printing the receipt.
220 <title><? xl('Receipt for Payment','e'); ?></title>
221 <script type="text/javascript" src="../../library/dialog.js"></script>
222 <script language="JavaScript">
224 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
226 // Process click on Print button.
227 function printme() {
228 var divstyle = document.getElementById('hideonprint').style;
229 divstyle.display = 'none';
230 window.print();
231 // divstyle.display = 'block';
233 // Process click on Delete button.
234 function deleteme() {
235 dlgopen('deleter.php?payment=<?php echo $payment_key ?>', '_blank', 500, 450);
236 return false;
238 // Called by the deleteme.php window on a successful delete.
239 function imdeleted() {
240 window.close();
243 </script>
244 </head>
245 <body bgcolor='#ffffff'>
246 <center>
248 <p><h2><? xl('Receipt for Payment','e'); ?></h2>
250 <p><?php echo htmlentities($frow['name']) ?>
251 <br><?php echo htmlentities($frow['street']) ?>
252 <br><?php echo htmlentities($frow['city'] . ', ' . $frow['state']) . ' ' .
253 $frow['postal_code'] ?>
254 <br><?php echo htmlentities($frow['phone']) ?>
257 <table border='0' cellspacing='8'>
258 <tr>
259 <td><? xl('Date','e'); ?>:</td>
260 <td><?php echo date('Y-m-d', strtotime($payrow['dtime'])) ?></td>
261 </tr>
262 <tr>
263 <td><? xl('Patient','e'); ?>:</td>
264 <td><?php echo $patdata['fname'] . " " . $patdata['mname'] . " " .
265 $patdata['lname'] . " (" . $patdata['pubpid'] . ")" ?></td>
266 </tr>
267 <tr>
268 <td><? xl('Paid Via','e'); ?>:</td>
269 <td><?php echo $payrow['method'] ?></td>
270 </tr>
271 <tr>
272 <td><? xl('Check/Ref Number','e'); ?>:</td>
273 <td><?php echo $payrow['source'] ?></td>
274 </tr>
275 <tr>
276 <td><? xl('Amount for This Visit','e'); ?>:</td>
277 <td><?php echo $payrow['amount1'] ?></td>
278 </tr>
279 <tr>
280 <td><? xl('Amount for Past Balance','e'); ?>:</td>
281 <td><?php echo $payrow['amount2'] ?></td>
282 </tr>
283 <tr>
284 <td><? xl('Received By','e'); ?>:</td>
285 <td><?php echo $payrow['user'] ?></td>
286 </tr>
287 </table>
289 <div id='hideonprint'>
291 <input type='button' value='<?php xl('Print','e'); ?>' onclick='printme()' />
293 <?php if (acl_check('admin', 'super')) { ?>
294 &nbsp;
295 <input type='button' value='<?php xl('Delete','e'); ?>' style='color:red' onclick='deleteme()' />
296 <?php } ?>
298 </div>
299 </center>
300 </body>
302 <?php
304 // End of receipt printing logic.
306 } else {
308 // Here we display the form for data entry.
311 <title><? xl('Record Payment','e'); ?></title>
313 <style type="text/css">
314 body { font-family:sans-serif; font-size:10pt; font-weight:normal }
315 .dehead { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:bold }
316 .detail { color:#000000; font-family:sans-serif; font-size:10pt; font-weight:normal }
317 </style>
319 <script type="text/javascript" src="../../library/topdialog.js"></script>
320 <script type="text/javascript" src="../../library/dialog.js"></script>
322 <script language="JavaScript">
323 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
325 function calctotal() {
326 var f = document.forms[0];
327 var total = 0;
328 for (var i = 0; i < f.elements.length; ++i) {
329 var elem = f.elements[i];
330 var ename = elem.name;
331 if (ename.indexOf('form_upay[') == 0 || ename.indexOf('form_bpay[') == 0) {
332 if (elem.value.length > 0) total += Number(elem.value);
335 f.form_paytotal.value = Number(total).toFixed(2);
336 return true;
339 </script>
341 </head>
343 <body <?echo $top_bg_line;?> leftmargin='0' topmargin='0' marginwidth='0'
344 marginheight='0' onunload='imclosing()'>
346 <form method='post' action='front_payment.php<?php if ($payid) echo "?payid=$payid"; ?>'
347 onsubmit='return top.restoreSession()'>
348 <input type='hidden' name='form_pid' value='<?php echo $pid ?>' />
350 <center>
352 <table border='0' cellspacing='8'>
354 <tr>
355 <td colspan='2' align='center'>
356 &nbsp;<br>
357 <b><? xl('Accept Payment for ','e'); ?><?php echo $patdata['fname'] . " " .
358 $patdata['lname'] . " (" . $patdata['pubpid'] . ")" ?></b>
359 <br>&nbsp;
360 </td>
361 </tr>
363 <tr>
364 <td>
365 <? xl('Payment Method','e'); ?>:
366 </td>
367 <td>
368 <select name='form_method'>
369 <?php
370 foreach ($payment_methods as $value) {
371 echo " <option value='$value'";
372 if ($value == $payrow['method']) echo " selected";
373 echo ">$value</option>\n";
376 </select>
377 </td>
378 </tr>
380 <tr>
381 <td>
382 <? xl('Check/Reference Number','e'); ?>:
383 </td>
384 <td>
385 <input type='text' name='form_source' size='10' value='<?php echo $payrow['source'] ?>'>
386 </td>
387 </tr>
389 </table>
391 <table border='0' cellpadding='2' cellspacing='0' width='98%'>
392 <tr bgcolor="#cccccc">
393 <td class="dehead">
394 <?php xl('DOS','e')?>
395 </td>
396 <td class="dehead" align="right">
397 <?php xl('Charges','e')?>
398 </td>
399 <td class="dehead" align="right">
400 <?php xl('Pt Paid','e')?>&nbsp;
401 </td>
402 <td class="dehead" align="right">
403 <?php xl('Insurance','e')?>
404 </td>
405 <td class="dehead" align="right">
406 <?php xl('Balance','e')?>
407 </td>
408 <td class="dehead" align="right">
409 <?php xl('Due Pt','e')?>
410 </td>
411 <td class="dehead" align="right">
412 <?php xl('Paying','e')?>
413 </td>
414 </tr>
416 <?php
417 $gottoday = false;
419 // Show the unbilled charges and payments by encounter for this patient.
421 $query = "SELECT b.encounter, " .
422 "SUM(IF(b.code_type = 'COPAY', 0, b.fee)) AS charges, " .
423 "SUM(IF(b.code_type = 'COPAY', 0 - b.fee, 0)) AS payments, " .
424 "LEFT(fe.date, 10) AS encdate " .
425 "FROM billing AS b, form_encounter AS fe " .
426 "WHERE b.pid = '$pid' AND b.activity = 1 AND b.billed = 0 " .
427 "AND fe.pid = b.pid AND fe.encounter = b.encounter " .
428 "GROUP BY b.encounter ORDER BY b.encounter";
429 $bres = sqlStatement($query);
431 while ($brow = sqlFetchArray($bres)) {
432 $dispdate = $brow['encdate'];
433 if (strcmp($dispdate, $today) == 0) {
434 $dispdate = 'Today';
435 $gottoday = true;
437 $inscopay = getCopay($pid, $brow['encdate']);
438 $encounter = $brow['encounter'];
439 $balance = bucks($brow['charges'] - $brow['payments']);
440 $duept = (($inscopay >= 0) ? $inscopay : $brow['charges']) - $brow['payments'];
441 echoLine("form_upay[$encounter]", $dispdate, $brow['charges'],
442 $brow['payments'], 0, $duept);
445 // If no billing was entered yet for today, then generate a line for
446 // entering today's co-pay.
448 if (! $gottoday) {
449 $inscopay = getCopay($pid, $today);
450 $duept = ($inscopay >= 0) ? $inscopay : 0;
451 echoLine("form_upay[0]", "Today", 0, 0, 0, $duept);
454 // Query for all open invoices.
455 $query = "SELECT ar.id, ar.invnumber, ar.amount, ar.paid, " .
456 "ar.intnotes, ar.notes, ar.shipvia, " .
457 "(SELECT SUM(invoice.fxsellprice) FROM invoice WHERE " .
458 "invoice.trans_id = ar.id AND invoice.fxsellprice > 0) AS charges, " .
459 "(SELECT SUM(invoice.fxsellprice) FROM invoice WHERE " .
460 "invoice.trans_id = ar.id AND invoice.fxsellprice < 0) AS adjustments, " .
461 "(SELECT SUM(acc_trans.amount) FROM acc_trans WHERE " .
462 "acc_trans.trans_id = ar.id AND acc_trans.chart_id = $chart_id_cash " .
463 "AND acc_trans.source NOT LIKE 'Ins%') AS ptpayments " .
464 "FROM ar WHERE ar.invnumber LIKE '$pid.%' AND " .
465 "ar.amount != ar.paid " .
466 "ORDER BY ar.invnumber";
467 $ires = SLQuery($query);
468 if ($sl_err) die($sl_err);
469 $num_invoices = SLRowCount($ires);
471 for ($ix = 0; $ix < $num_invoices; ++$ix) {
472 $irow = SLGetRow($ires, $ix);
474 // Get encounter ID and date of service.
475 list($patient_id, $encounter) = explode(".", $irow['invnumber']);
476 $tmp = sqlQuery("SELECT LEFT(date, 10) AS encdate FROM form_encounter " .
477 "WHERE encounter = '$encounter'");
478 $svcdate = $tmp['encdate'];
480 // Compute $duncount as in sl_eob_search.php to determine if
481 // this invoice is at patient responsibility.
482 $duncount = substr_count(strtolower($irow['intnotes']), "statement sent");
483 if (! $duncount) {
484 $insgot = strtolower($irow['notes']);
485 $inseobs = strtolower($irow['shipvia']);
486 foreach (array('ins1', 'ins2', 'ins3') as $value) {
487 if (strpos($insgot, $value) !== false &&
488 strpos($inseobs, $value) === false)
489 --$duncount;
493 $inspaid = $irow['paid'] + $irow['ptpayments'] - $irow['adjustments'];
494 $balance = $irow['amount'] - $irow['paid'];
495 $duept = ($duncount < 0) ? 0 : $balance;
497 echoLine("form_bpay[$encounter]", $svcdate, $irow['charges'],
498 0 - $irow['ptpayments'], $inspaid, $duept);
501 // Continue with display of the data entry form.
504 <tr bgcolor="#cccccc">
505 <td class="dehead" colspan="6">
506 <?php xl('Total Amount Paid','e')?>
507 </td>
508 <td class="dehead" align="right">
509 <input type='text' name='form_paytotal' size='6' value=''
510 style='color:#00aa00' readonly />
511 </td>
512 </tr>
514 </table>
517 <input type='submit' name='form_save' value='<?php xl('Save','e'); ?>' /> &nbsp;
518 <input type='button' value='<?php xl('Cancel','e'); ?>' onclick='window.close()' />
520 </center>
521 </form>
522 <script language="JavaScript">
523 calctotal();
524 </script>
525 </body>
527 <?php
529 SLClose();
531 </html>