Feat openemr fix 7480 7494 email prescription (#7495)
[openemr.git] / portal / portal_payment.php
blobaf9be0a6b6f6106dcfc825e2925ebc3c911220b6
1 <?php
3 /**
5 * namespace OnsitePortal
7 * @package OpenEMR
8 * @link http://www.open-emr.org
9 * @author Rod Roark <rod@sunsetsystems.com>
10 * @author Jerry Padgett <sjpadgett@gmail.com>
11 * @author Brady Miller <brady.g.miller@gmail.com>
12 * @copyright Copyright (c) 2006-2020 Rod Roark <rod@sunsetsystems.com>
13 * @copyright Copyright (c) 2016-2019 Jerry Padgett <sjpadgett@gmail.com>
14 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
15 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
18 // Will start the (patient) portal OpenEMR session/cookie.
19 require_once(__DIR__ . "/../src/Common/Session/SessionUtil.php");
20 OpenEMR\Common\Session\SessionUtil::portalSessionStart();
22 $isPortal = false;
23 if (isset($_SESSION['pid']) && isset($_SESSION['patient_portal_onsite_two'])) {
24 $pid = $_SESSION['pid'];
25 $ignoreAuth_onsite_portal = true;
26 $isPortal = true;
27 require_once(__DIR__ . "/../interface/globals.php");
28 } else {
29 OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy();
30 $ignoreAuth = false;
31 require_once(__DIR__ . "/../interface/globals.php");
32 if (!isset($_SESSION['authUserID'])) {
33 $landingpage = "index.php";
34 header('Location: ' . $landingpage);
35 exit();
39 require_once(__DIR__ . "/lib/appsql.class.php");
40 require_once("$srcdir/patient.inc.php");
41 require_once("$srcdir/payment.inc.php");
42 require_once("$srcdir/forms.inc.php");
43 require_once("../custom/code_types.inc.php");
44 require_once("$srcdir/options.inc.php");
45 require_once("$srcdir/encounter_events.inc.php");
47 use OpenEMR\Billing\BillingUtilities;
48 use OpenEMR\Common\Crypto\CryptoGen;
49 use OpenEMR\Common\Csrf\CsrfUtils;
50 use OpenEMR\Common\Utils\FormatMoney;
51 use OpenEMR\PaymentProcessing\Sphere\SpherePayment;
53 $cryptoGen = new CryptoGen();
55 $appsql = new ApplicationTable();
56 $pid = $_REQUEST['pid'] ?? $pid;
57 $pid = ($_REQUEST['hidden_patient_code'] ?? null) > 0 ? $_REQUEST['hidden_patient_code'] : $pid;
58 $recid = isset($_REQUEST['recid']) ? (int) $_REQUEST['recid'] : 0;
59 $adminUser = '';
60 $portalPatient = '';
62 $query = "SELECT pao.portal_username as recip_id, Concat_Ws(' ', patient_data.fname, patient_data.lname) as username FROM patient_data " .
63 "LEFT JOIN patient_access_onsite pao ON pao.pid = patient_data.pid " .
64 "WHERE patient_data.pid = ? AND pao.portal_pwd_status = 1";
65 $portalPatient = sqlQueryNoLog($query, $pid);
66 if ($_SESSION['authUserID'] ?? '') {
67 $query = "SELECT users.username as recip_id, users.authorized as dash, CONCAT(users.fname,' ',users.lname) as username " .
68 "FROM users WHERE id = ?";
69 $adminUser = sqlQueryNoLog($query, $_SESSION['authUserID']);
72 if ($recid) {
73 $edata = $appsql->getPortalAuditRec($recid);
74 } else {
75 $edata = $appsql->getPortalAudit($pid, 'review', 'payment');
77 $ccdata = array();
78 $invdata = array();
79 if ($edata) {
80 $ccdata = json_decode($cryptoGen->decryptStandard($edata['checksum']), true);
81 $invdata = json_decode($edata['table_args'], true);
82 echo "<script>var jsondata='" . $edata['table_args'] . "';var ccdata='" . $edata['checksum'] . "'</script>";
85 // Display a row of data for an encounter.
87 $var_index = 0;
88 $sum_charges = $sum_ptpaid = $sum_inspaid = $sum_duept = $sum_copay = $sum_patcopay = $sum_balance = 0;
89 function echoLine($iname, $date, $charges, $ptpaid, $inspaid, $duept, $encounter = 0, $copay = 0, $patcopay = 0)
91 global $sum_charges, $sum_ptpaid, $sum_inspaid, $sum_duept, $sum_copay, $sum_patcopay, $sum_balance;
92 global $var_index;
93 $var_index++;
94 $balance = FormatMoney::getBucks($charges - $ptpaid - $inspaid);
95 $balance = (round($duept, 2) != 0) ? 0 : $balance; // if balance is due from patient, then insurance balance is displayed as zero
96 $encounter = $encounter ? $encounter : '';
97 echo " <tr id='tr_" . attr($var_index) . "' >\n";
98 echo " <td class='detail'>" . text(oeFormatShortDate($date)) . "</td>\n";
99 echo " <td class='detail' id='" . attr($date) . "' align='left'>" . text($encounter) . "</td>\n";
100 echo " <td class='detail' align='center' id='td_charges_$var_index' >" . text(FormatMoney::getBucks($charges)) . "</td>\n";
101 echo " <td class='detail' align='center' id='td_inspaid_$var_index' >" . text(FormatMoney::getBucks($inspaid * -1)) . "</td>\n";
102 echo " <td class='detail' align='center' id='td_ptpaid_$var_index' >" . text(FormatMoney::getBucks($ptpaid * -1)) . "</td>\n";
103 echo " <td class='detail' align='center' id='td_patient_copay_$var_index' >" . text(FormatMoney::getBucks($patcopay)) . "</td>\n";
104 echo " <td class='detail' align='center' id='td_copay_$var_index' >" . text(FormatMoney::getBucks($copay)) . "</td>\n";
105 echo " <td class='detail' align='center' id='balance_$var_index'>" . text(FormatMoney::getBucks($balance)) . "</td>\n";
106 echo " <td class='detail' align='center' id='duept_$var_index'>" . text(FormatMoney::getBucks(round($duept, 2) * 1)) . "</td>\n";
107 echo " <td class='detail' align='center'><input class='form-control' name='" . attr($iname) . "' id='paying_" . attr($var_index) .
108 "' " . " value='" . '' . "' onchange='coloring();calctotal()' autocomplete='off' " . "onkeyup='calctotal()'/></td>\n";
109 echo " </tr>\n";
111 $sum_charges += (float)$charges * 1;
112 $sum_ptpaid += (float)$ptpaid * -1;
113 $sum_inspaid += (float)$inspaid * -1;
114 $sum_duept += (float)$duept * 1;
115 $sum_patcopay += (float)$patcopay * 1;
116 $sum_copay += (float)$copay * 1;
117 $sum_balance += (float)$balance * 1;
120 // We use this to put dashes, colons, etc. back into a timestamp.
122 function decorateString($fmt, $str)
124 $res = '';
125 while ($fmt) {
126 $fc = substr($fmt, 0, 1);
127 $fmt = substr($fmt, 1);
128 if ($fc == '.') {
129 $res .= substr($str, 0, 1);
130 $str = substr($str, 1);
131 } else {
132 $res .= $fc;
136 return $res;
139 // Compute taxes from a tax rate string and a possibly taxable amount.
141 function calcTaxes($row, $amount)
143 $total = 0;
144 if (empty($row['taxrates'])) {
145 return $total;
148 $arates = explode(':', $row['taxrates']);
149 if (empty($arates)) {
150 return $total;
153 foreach ($arates as $value) {
154 if (empty($value)) {
155 continue;
158 $trow = sqlQuery("SELECT option_value FROM list_options WHERE " . "list_id = 'taxrate' AND option_id = ? LIMIT 1", array($value
160 if (empty($trow['option_value'])) {
161 echo "<!-- Missing tax rate '" . text($value) . "'! -->\n";
162 continue;
165 $tax = sprintf("%01.2f", $amount * $trow['option_value']);
166 // echo "<!-- Rate = '$value', amount = '$amount', tax = '$tax' -->\n";
167 $total += $tax;
170 return $total;
173 $now = time();
174 $today = date('Y-m-d', $now);
175 $timestamp = date('Y-m-d H:i:s', $now);
177 $patdata = sqlQuery("SELECT " . "p.fname, p.mname, p.lname, p.postal_code, p.pubpid,p.pid, i.copay " . "FROM patient_data AS p " . "LEFT OUTER JOIN insurance_data AS i ON " . "i.pid = p.pid AND i.type = 'primary' " . "WHERE p.pid = ? ORDER BY i.date DESC LIMIT 1", array($pid
180 $alertmsg = ''; // anything here pops up in an alert box
182 // If the Save button was clicked...
183 if ($_POST['form_save'] ?? '') {
184 $form_pid = $_POST['form_pid'];
185 $form_method = trim($_POST['form_method']);
186 $form_source = trim($_POST['form_source']);
187 $patdata = getPatientData($form_pid, 'fname,mname,lname,pubpid');
188 $NameNew = $patdata['fname'] . " " . $patdata['lname'] . " " . $patdata['mname'];
190 if ($_REQUEST['radio_type_of_payment'] == 'pre_payment') {
191 $payment_id = sqlInsert(
192 "insert into ar_session set " .
193 "payer_id = ?" .
194 ", patient_id = ?" .
195 ", user_id = ?" .
196 ", closed = ?" .
197 ", reference = ?" .
198 ", check_date = now() , deposit_date = now() " .
199 ", pay_total = ?" .
200 ", payment_type = 'patient'" .
201 ", description = ?" .
202 ", adjustment_code = 'pre_payment'" .
203 ", post_to_date = now() " .
204 ", payment_method = ?",
205 array(0, $form_pid, $_SESSION['authUserID'], 0, $form_source, $_REQUEST['form_prepayment'], $NameNew, $form_method)
208 frontPayment($form_pid, 0, $form_method, $form_source, $_REQUEST['form_prepayment'], 0, $timestamp);//insertion to 'payments' table.
211 if ($_POST['form_upay'] && $_REQUEST['radio_type_of_payment'] != 'pre_payment') {
212 foreach ($_POST['form_upay'] as $enc => $payment) {
213 if ($amount = (float)$payment) {
214 $zero_enc = $enc;
216 //----------------------------------------------------------------------------------------------------
217 //Fetching the existing code and modifier
218 $ResultSearchNew = sqlStatement(
219 "SELECT * FROM billing LEFT JOIN code_types ON billing.code_type=code_types.ct_key " .
220 "WHERE code_types.ct_fee=1 AND billing.activity!=0 AND billing.pid =? AND encounter=? ORDER BY billing.code,billing.modifier",
221 array($form_pid, $enc)
223 if ($RowSearch = sqlFetchArray($ResultSearchNew)) {
224 $Codetype = $RowSearch['code_type'];
225 $Code = $RowSearch['code'];
226 $Modifier = $RowSearch['modifier'];
227 } else {
228 $Codetype = '';
229 $Code = '';
230 $Modifier = '';
233 //----------------------------------------------------------------------------------------------------
234 if ($_REQUEST['radio_type_of_payment'] == 'copay') {//copay saving to ar_session and ar_activity tables
235 $session_id = sqlInsert(
236 "INSERT INTO ar_session (payer_id,user_id,reference,check_date,deposit_date,pay_total," .
237 " global_amount,payment_type,description,patient_id,payment_method,adjustment_code,post_to_date) " .
238 " VALUES ('0',?,?,now(),now(),?,'','patient','COPAY',?,?,'patient_payment',now())",
239 array($_SESSION['authUserID'], $form_source, $amount, $form_pid, $form_method)
242 sqlBeginTrans();
243 $sequence_no = sqlQuery("SELECT IFNULL(MAX(sequence_no),0) + 1 AS increment FROM ar_activity WHERE pid = ? AND encounter = ?", array($form_pid, $enc));
244 $insrt_id = sqlInsert(
245 "INSERT INTO ar_activity (pid,encounter,sequence_no,code_type,code,modifier,payer_type,post_time,post_user,session_id,pay_amount,account_code)" .
246 " VALUES (?,?,?,?,?,?,0,now(),?,?,?,'PCP')",
247 array($form_pid, $enc, $sequence_no['increment'], $Codetype, $Code, $Modifier, $_SESSION['authUserID'], $session_id, $amount)
249 sqlCommitTrans();
251 frontPayment($form_pid, $enc, $form_method, $form_source, $amount, 0, $timestamp);//insertion to 'payments' table.
254 if ($_REQUEST['radio_type_of_payment'] == 'invoice_balance' || $_REQUEST['radio_type_of_payment'] == 'cash') { //Payment by patient after insurance paid, cash patients similar to do not bill insurance in feesheet.
255 if ($_REQUEST['radio_type_of_payment'] == 'cash') {
256 sqlStatement(
257 "update form_encounter set last_level_closed=? where encounter=? and pid=? ",
258 array(4, $enc, $form_pid)
260 sqlStatement(
261 "update billing set billed=? where encounter=? and pid=?",
262 array(1, $enc, $form_pid)
266 $adjustment_code = 'patient_payment';
267 $payment_id = sqlInsert(
268 "insert into ar_session set " .
269 "payer_id = ?" .
270 ", patient_id = ?" .
271 ", user_id = ?" .
272 ", closed = ?" .
273 ", reference = ?" .
274 ", check_date = now() , deposit_date = now() " .
275 ", pay_total = ?" .
276 ", payment_type = 'patient'" .
277 ", description = ?" .
278 ", adjustment_code = ?" .
279 ", post_to_date = now() " .
280 ", payment_method = ?",
281 array(0, $form_pid, $_SESSION['authUserID'], 0, $form_source, $amount, $NameNew, $adjustment_code, $form_method)
284 //--------------------------------------------------------------------------------------------------------------------
286 frontPayment($form_pid, $enc, $form_method, $form_source, 0, $amount, $timestamp);//insertion to 'payments' table.
288 //--------------------------------------------------------------------------------------------------------------------
290 $resMoneyGot = sqlStatement(
291 "SELECT sum(pay_amount) as PatientPay FROM ar_activity where deleted IS NULL AND pid =? and " .
292 "encounter =? and payer_type=0 and account_code='PCP'",
293 array($form_pid, $enc)
294 );//new fees screen copay gives account_code='PCP'
295 $rowMoneyGot = sqlFetchArray($resMoneyGot);
296 $Copay = $rowMoneyGot['PatientPay'];
298 //--------------------------------------------------------------------------------------------------------------------
300 //Looping the existing code and modifier
301 $ResultSearchNew = sqlStatement(
302 "SELECT * FROM billing LEFT JOIN code_types ON billing.code_type=code_types.ct_key WHERE code_types.ct_fee=1 " .
303 "AND billing.activity!=0 AND billing.pid =? AND encounter=? ORDER BY billing.code,billing.modifier",
304 array($form_pid, $enc)
306 while ($RowSearch = sqlFetchArray($ResultSearchNew)) {
307 $Codetype = $RowSearch['code_type'];
308 $Code = $RowSearch['code'];
309 $Modifier = $RowSearch['modifier'];
310 $Fee = $RowSearch['fee'];
312 $resMoneyGot = sqlStatement(
313 "SELECT sum(pay_amount) as MoneyGot FROM ar_activity where deleted IS NULL AND pid = ? " .
314 "and code_type=? and code=? and modifier=? and encounter =? and !(payer_type=0 and account_code='PCP')",
315 array($form_pid, $Codetype, $Code, $Modifier, $enc)
317 //new fees screen copay gives account_code='PCP'
318 $rowMoneyGot = sqlFetchArray($resMoneyGot);
319 $MoneyGot = $rowMoneyGot['MoneyGot'];
321 $resMoneyAdjusted = sqlStatement(
322 "SELECT sum(adj_amount) as MoneyAdjusted FROM ar_activity where deleted IS NULL AND " .
323 "pid =? and code_type=? and code=? and modifier=? and encounter =?",
324 array($form_pid, $Codetype, $Code, $Modifier, $enc)
326 $rowMoneyAdjusted = sqlFetchArray($resMoneyAdjusted);
327 $MoneyAdjusted = $rowMoneyAdjusted['MoneyAdjusted'];
329 $Remainder = $Fee - $Copay - $MoneyGot - $MoneyAdjusted;
330 $Copay = 0;
331 if (round($Remainder, 2) != 0 && $amount != 0) {
332 if ($amount - $Remainder >= 0) {
333 $insert_value = $Remainder;
334 $amount = $amount - $Remainder;
335 } else {
336 $insert_value = $amount;
337 $amount = 0;
340 sqlBeginTrans();
341 $sequence_no = sqlQuery("SELECT IFNULL(MAX(sequence_no),0) + 1 AS increment FROM ar_activity WHERE pid = ? AND encounter = ?", array($form_pid, $enc));
342 sqlStatement(
343 "insert into ar_activity set " .
344 "pid = ?" .
345 ", encounter = ?" .
346 ", sequence_no = ?" .
347 ", code_type = ?" .
348 ", code = ?" .
349 ", modifier = ?" .
350 ", payer_type = ?" .
351 ", post_time = now() " .
352 ", post_user = ?" .
353 ", session_id = ?" .
354 ", pay_amount = ?" .
355 ", adj_amount = ?" .
356 ", account_code = 'PP'",
357 array($form_pid, $enc, $sequence_no['increment'], $Codetype, $Code, $Modifier, 0, $_SESSION['authUserID'], $payment_id, $insert_value, 0)
359 sqlCommitTrans();
360 }//if
361 }//while
362 if ($amount != 0) {//if any excess is there.
363 sqlBeginTrans();
364 $sequence_no = sqlQuery("SELECT IFNULL(MAX(sequence_no),0) + 1 AS increment FROM ar_activity WHERE pid = ? AND encounter = ?", array($form_pid, $enc));
365 sqlStatement(
366 "insert into ar_activity set " .
367 "pid = ?" .
368 ", encounter = ?" .
369 ", sequence_no = ?" .
370 ", code_type = ?" .
371 ", code = ?" .
372 ", modifier = ?" .
373 ", payer_type = ?" .
374 ", post_time = now() " .
375 ", post_user = ?" .
376 ", session_id = ?" .
377 ", pay_amount = ?" .
378 ", adj_amount = ?" .
379 ", account_code = 'PP'",
380 array($form_pid, $enc, $sequence_no['increment'], $Codetype, $Code, $Modifier, 0, $_SESSION['authUserID'], $payment_id, $amount, 0)
382 sqlCommitTrans();
385 //--------------------------------------------------------------------------------------------------------------------
386 }//invoice_balance
387 }//if ($amount = 0 + $payment)
388 }//foreach
389 }//if ($_POST['form_upay'])
390 }//if ($_POST['form_save'])
392 if (($_POST['form_save'] ?? null) || ($_REQUEST['receipt'] ?? null)) {
393 if (($_REQUEST['receipt'] ?? null)) {
394 $form_pid = $_GET['patient'];
395 $timestamp = decorateString('....-..-.. ..:..:..', $_GET['time']);
398 // Get details for what we guess is the primary facility.
399 $frow = sqlQuery("SELECT * FROM facility " . "ORDER BY billing_location DESC, accepts_assignment DESC, id LIMIT 1");
401 // Get the patient's name and chart number.
402 $patdata = getPatientData($form_pid, 'fname,mname,lname,pubpid');
404 // Re-fetch payment info.
405 $payrow = sqlQuery("SELECT " . "SUM(amount1) AS amount1, " . "SUM(amount2) AS amount2, " . "MAX(method) AS method, " . "MAX(source) AS source, " . "MAX(dtime) AS dtime, " .
406 // "MAX(user) AS user " .
407 "MAX(user) AS user, " . "MAX(encounter) as encounter " . "FROM payments WHERE " . "pid = ? AND dtime = ?", array($form_pid, $timestamp
410 // Create key for deleting, just in case.
411 $ref_id = ($_REQUEST['radio_type_of_payment'] == 'copay') ? $session_id : $payment_id;
412 $payment_key = $form_pid . '.' . preg_replace('/[^0-9]/', '', $timestamp) . '.' . $ref_id;
414 // get facility from encounter
415 $tmprow = sqlQuery("SELECT facility_id FROM form_encounter WHERE encounter = ?", array($payrow['encounter']));
416 $frow = sqlQuery("SELECT * FROM facility " . " WHERE id = ?", array($tmprow['facility_id']
419 // Now proceed with printing the receipt.
422 <title><?php echo xlt('Receipt for Payment'); ?></title>
423 <script src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery/dist/jquery.min.js"></script>
424 <script>
426 function goHome() {
427 window.location.replace("./patient/onsiteactivityviews");
430 function notifyPatient() {
431 let pid = <?php echo js_escape($pid); ?>;
432 let note = $('#pop_receipt').html();
433 let formURL = './messaging/handle_note.php';
434 let owner = <?php echo js_escape($adminUser['recip_id']); ?>;
435 let sn = <?php echo js_escape($adminUser['username']); ?>;
436 let rid = <?php echo js_escape($portalPatient['recip_id']); ?>;
437 let rn = <?php echo js_escape($portalPatient['username']); ?>;
438 $.ajax({
439 url: formURL,
440 type: "POST",
441 data: {
442 'csrf_token_form': <?php echo js_escape(CsrfUtils::collectCsrfToken('messages-portal')); ?>,
443 'task': 'add',
444 'pid': pid,
445 'inputBody': note,
446 'title': 'Bill/Collect',
447 'recipient_name': rn,
448 'recipient_id': rid,
449 'sender_id': owner,
450 'sender_name': sn
452 success: function (data, textStatus, jqXHR) {
453 alert('Receipt sent to patient via Messages.')
455 error: function (jqXHR, status, error) {
456 console.log(status + ": " + error);
460 </script>
461 <?php
462 ob_start();
463 echo '<htlm><head></head><body style="text-align: center; margin: auto;">';
465 <div id='pop_receipt' style='display: block'>
467 <h2><?php echo xlt('Receipt for Payment'); ?></h2>
468 <p><?php echo text($frow['name']) ?>
469 <br /><?php echo text($frow['street']) ?>
470 <br /><?php echo text($frow['city'] . ', ' . $frow['state']) . ' ' . text($frow['postal_code']) ?>
471 <br /><?php echo text($frow['phone']) ?>
473 <div class="text-center" style="margin: auto;">
474 <table border='0' cellspacing='8' class="text-center" style="margin: auto;">
475 <tr>
476 <td><?php echo xlt('Date'); ?>:</td>
477 <td><?php echo text(oeFormatSDFT(strtotime($payrow['dtime']))) ?></td>
478 </tr>
479 <tr>
480 <td><?php echo xlt('Patient'); ?>:</td>
481 <td><?php echo text($patdata['fname']) . " " . text($patdata['mname']) . " " . text($patdata['lname']) . " (" . text($patdata['pubpid']) . ")" ?></td>
482 </tr>
483 <tr>
484 <td><?php echo xlt('Paid Via'); ?>:</td>
485 <td><?php echo generate_display_field(array('data_type' => '1', 'list_id' => 'payment_method'), $payrow['method']); ?></td>
486 </tr>
487 <tr>
488 <td><?php echo xlt('Authorized Id'); ?>:</td>
489 <td><?php echo text($payrow['source']) ?></td>
490 </tr>
491 <tr>
492 <td><?php echo xlt('Amount for This Visit'); ?>:</td>
493 <td><?php echo text(oeFormatMoney($payrow['amount1'])) ?></td>
494 </tr>
495 <tr>
496 <td><?php echo xlt('Amount for Past Balance'); ?>:</td>
497 <td><?php echo text(oeFormatMoney($payrow['amount2'])) ?></td>
498 </tr>
499 <tr>
500 <td><?php echo xlt('Received By'); ?>:</td>
501 <td><?php echo text($payrow['user']) ?></td>
502 </tr>
503 </table>
504 </div>
505 </div>
506 <button class='btn btn-sm' type='button' onclick='goHome()' id='returnhome'><?php echo xla('Return Home'); ?></button>
507 <button class='btn btn-sm' type='button' onclick="notifyPatient()"><?php echo xla('Notify Patient'); ?></button>
508 </body></html>
509 <?php
510 ob_end_flush();
511 } else {
513 // Here we display the form for data entry.
516 <title><?php echo xlt('Record Payment'); ?></title>
517 <style>
518 .dehead {
519 color: #000000;
520 font-weight: bold
522 .detail {
523 padding: 1px 1px;
524 color: #000000;
525 font-weight: normal
527 </style>
528 <script src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-creditcardvalidator/jquery.creditCardValidator.js"></script>
529 <script src="<?php echo $GLOBALS['webroot'] ?>/library/textformat.js?v=<?php echo $v_js_includes; ?>"></script>
530 <script>
531 var chargeMsg = <?php $amsg = xl('Payment was successfully authorized and your card is charged.') . "\n" .
532 xl("You will be notified when your payment is applied for this invoice.") . "\n" .
533 xl('Until then you will continue to see payment details here.') . "\n" . xl('Thank You.');
534 echo json_encode($amsg);
536 var publicKey = <?php echo json_encode($cryptoGen->decryptStandard($GLOBALS['gateway_public_key'])); ?>;
537 var apiKey = <?php echo json_encode($cryptoGen->decryptStandard($GLOBALS['gateway_api_key'])); ?>;
539 function calctotal() {
540 var flag = 0;
541 var f = document.forms["invoiceForm"];
542 var total = 0;
543 for (var i = 0; i < f.elements.length; ++i) {
544 var elem = f.elements[i];
545 var ename = elem.name;
546 if (ename.indexOf('form_upay[') == 0 || ename.indexOf('form_bpay[') == 0) {
547 if (elem.value.length > 0) {
548 total += Number(elem.value);
549 if (total < 0) flag = 1;
553 f.form_paytotal.value = Number(total).toFixed(2);
554 if (flag) {
555 $('#invoiceForm')[0].reset();
556 alert(<?php echo xlj('Negative payments not accepted'); ?>)
558 return true;
561 function coloring() {
562 for (var i = 1; ; ++i) {
563 if (document.getElementById('paying_' + i)) {
564 paying = document.getElementById('paying_' + i).value * 1;
565 patient_balance = document.getElementById('duept_' + i).innerHTML * 1;
566 if (patient_balance > 0 && paying > 0) {
567 if (paying > patient_balance) {
568 document.getElementById('paying_' + i).style.background = '#FF0000';
570 else if (paying < patient_balance) {
571 document.getElementById('paying_' + i).style.background = '#99CC00';
573 else if (paying == patient_balance) {
574 document.getElementById('paying_' + i).style.background = '#ffffff';
577 else {
578 document.getElementById('paying_' + i).style.background = '#ffffff';
581 else {
582 break;
587 function CheckVisible(MakeBlank) {//Displays and hides the check number text box.
588 if (document.getElementById('form_method').options[document.getElementById('form_method').selectedIndex].value == 'check_payment' ||
589 document.getElementById('form_method').options[document.getElementById('form_method').selectedIndex].value == 'bank_draft') {
590 document.getElementById('check_number').disabled = false;
592 else {
593 document.getElementById('check_number').disabled = true;
597 function validate() {
598 var f = document.forms["invoiceForm"];
599 ok = -1;
600 //no checks taken here....
601 issue = 'no';
602 if (document.getElementById('radio_type_of_payment_self1').checked == false &&
603 document.getElementById('radio_type_of_payment1').checked == false
604 && document.getElementById('radio_type_of_payment2').checked == false
605 && document.getElementById('radio_type_of_payment4').checked == false) {
606 alert("<?php //echo addslashes( xl('Please Select Type Of Payment.')) ?>");
607 return false;
609 if (document.getElementById('radio_type_of_payment_self1').checked == true || document.getElementById('radio_type_of_payment1').checked == true) {
610 for (var i = 0; i < f.elements.length; ++i) {
611 var elem = f.elements[i];
612 var ename = elem.name;
613 if (ename.indexOf('form_upay[0') == 0) //Today is this text box.
615 if (elem.value * 1 > 0) {//A warning message, if the amount is posted with out encounter.
616 if (confirm(<?php echo xlj('Are you sure to post for today?'); ?>)) {
617 ok = 1;
619 else {
620 elem.focus();
621 return false;
624 break;
628 else if (document.getElementsByName('form_paytotal')[0].value <= 0)//total 0
630 alert(<?php echo xlj('Invalid Total!'); ?>)
631 return false;
633 if (ok == -1) {
634 if (confirm(<?php echo xlj('Payment Validated: Save?'); ?>)) {
635 return true;
637 else {
638 return false;
643 function cursor_pointer() {//Point the cursor to the latest encounter(Today)
644 var f = document.forms["invoiceForm"];
645 var total = 0;
646 for (var i = 0; i < f.elements.length; ++i) {
647 var elem = f.elements[i];
648 var ename = elem.name;
649 if (ename.indexOf('form_upay[') == 0) {
650 elem.focus();
651 break;
656 function make_it_hide_enc_pay() {
657 document.getElementById('td_head_insurance_payment').style.display = "none";
658 document.getElementById('td_head_patient_co_pay').style.display = "none";
659 document.getElementById('td_head_co_pay').style.display = "none";
660 document.getElementById('td_head_insurance_balance').style.display = "none";
661 for (var i = 1; ; ++i) {
662 var td_inspaid_elem = document.getElementById('td_inspaid_' + i)
663 var td_patient_copay_elem = document.getElementById('td_patient_copay_' + i)
664 var td_copay_elem = document.getElementById('td_copay_' + i)
665 var balance_elem = document.getElementById('balance_' + i)
666 if (td_inspaid_elem) {
667 td_inspaid_elem.style.display = "none";
668 td_patient_copay_elem.style.display = "none";
669 td_copay_elem.style.display = "none";
670 balance_elem.style.display = "none";
672 else {
673 break;
676 document.getElementById('td_total_4').style.display = "none";
677 document.getElementById('td_total_7').style.display = "none";
678 document.getElementById('td_total_8').style.display = "none";
679 document.getElementById('td_total_6').style.display = "none";
681 document.getElementById('table_display').width = "420px";
684 function make_visible() {
685 document.getElementById('td_head_rep_doc').style.display = "";
686 document.getElementById('td_head_description').style.display = "";
687 document.getElementById('td_head_total_charge').style.display = "none";
688 document.getElementById('td_head_insurance_payment').style.display = "none";
689 document.getElementById('td_head_patient_payment').style.display = "none";
690 document.getElementById('td_head_patient_co_pay').style.display = "none";
691 document.getElementById('td_head_co_pay').style.display = "none";
692 document.getElementById('td_head_insurance_balance').style.display = "none";
693 document.getElementById('td_head_patient_balance').style.display = "none";
694 for (var i = 1; ; ++i) {
695 var td_charges_elem = document.getElementById('td_charges_' + i)
696 var td_inspaid_elem = document.getElementById('td_inspaid_' + i)
697 var td_ptpaid_elem = document.getElementById('td_ptpaid_' + i)
698 var td_patient_copay_elem = document.getElementById('td_patient_copay_' + i)
699 var td_copay_elem = document.getElementById('td_copay_' + i)
700 var balance_elem = document.getElementById('balance_' + i)
701 var duept_elem = document.getElementById('duept_' + i)
702 if (td_charges_elem) {
703 td_charges_elem.style.display = "none";
704 td_inspaid_elem.style.display = "none";
705 td_ptpaid_elem.style.display = "none";
706 td_patient_copay_elem.style.display = "none";
707 td_copay_elem.style.display = "none";
708 balance_elem.style.display = "none";
709 duept_elem.style.display = "none";
711 else {
712 break;
715 document.getElementById('td_total_7').style.display = "";
716 document.getElementById('td_total_8').style.display = "";
717 document.getElementById('td_total_1').style.display = "none";
718 document.getElementById('td_total_2').style.display = "none";
719 document.getElementById('td_total_3').style.display = "none";
720 document.getElementById('td_total_4').style.display = "none";
721 document.getElementById('td_total_5').style.display = "none";
722 document.getElementById('td_total_6').style.display = "none";
724 document.getElementById('table_display').width = "505px";
727 function make_it_hide() {
728 document.getElementById('td_head_rep_doc').style.display = "none";
729 document.getElementById('td_head_description').style.display = "none";
730 document.getElementById('td_head_total_charge').style.display = "";
731 document.getElementById('td_head_insurance_payment').style.display = "";
732 document.getElementById('td_head_patient_payment').style.display = "";
733 document.getElementById('td_head_patient_co_pay').style.display = "";
734 document.getElementById('td_head_co_pay').style.display = "";
735 document.getElementById('td_head_insurance_balance').style.display = "";
736 document.getElementById('td_head_patient_balance').style.display = "";
737 for (var i = 1; ; ++i) {
738 var td_charges_elem = document.getElementById('td_charges_' + i)
739 var td_inspaid_elem = document.getElementById('td_inspaid_' + i)
740 var td_ptpaid_elem = document.getElementById('td_ptpaid_' + i)
741 var td_patient_copay_elem = document.getElementById('td_patient_copay_' + i)
742 var td_copay_elem = document.getElementById('td_copay_' + i)
743 var balance_elem = document.getElementById('balance_' + i)
744 var duept_elem = document.getElementById('duept_' + i)
745 if (td_charges_elem) {
746 td_charges_elem.style.display = "";
747 td_inspaid_elem.style.display = "";
748 td_ptpaid_elem.style.display = "";
749 td_patient_copay_elem.style.display = "";
750 td_copay_elem.style.display = "";
751 balance_elem.style.display = "";
752 duept_elem.style.display = "";
754 else {
755 break;
758 document.getElementById('td_total_1').style.display = "";
759 document.getElementById('td_total_2').style.display = "";
760 document.getElementById('td_total_3').style.display = "";
761 document.getElementById('td_total_4').style.display = "";
762 document.getElementById('td_total_5').style.display = "";
763 document.getElementById('td_total_6').style.display = "";
764 document.getElementById('td_total_7').style.display = "";
765 document.getElementById('td_total_8').style.display = "";
767 document.getElementById('table_display').width = "100%";
770 function make_visible_radio() {
771 document.getElementById('tr_radio1').style.display = "";
772 document.getElementById('tr_radio2').style.display = "none";
775 function make_hide_radio() {
776 document.getElementById('tr_radio1').style.display = "none";
777 document.getElementById('tr_radio2').style.display = "";
780 function make_visible_row() {
781 document.getElementById('table_display').style.display = "";
782 document.getElementById('table_display_prepayment').style.display = "none";
785 function make_hide_row() {
786 document.getElementById('table_display').style.display = "none";
787 document.getElementById('table_display_prepayment').style.display = "";
790 function make_self() {
791 make_visible_row();
792 make_it_hide();
793 make_it_hide_enc_pay();
794 document.getElementById('radio_type_of_payment_self1').checked = true;
795 cursor_pointer();
798 function make_insurance() {
799 make_visible_row();
800 make_it_hide();
801 cursor_pointer();
802 document.getElementById('radio_type_of_payment1').checked = true;
805 $('#paySubmit').click(function (e) {
806 e.preventDefault();e.stopPropagation();
807 $("#mode").val("portal-save");
808 let inv_values = JSON.stringify(getFormObj('invoiceForm'));
809 let extra_values = JSON.stringify(getFormObj('paymentForm'));
810 let extra = "&inv_values=" + encodeURIComponent(inv_values) + "&extra_values=" + encodeURIComponent(extra_values);
811 let flag = 0
812 let liburl = './lib/paylib.php';
813 $.ajax({
814 type: "POST",
815 url: liburl,
816 data: $("#invoiceForm").serialize() + extra,
817 beforeSend: function (xhr) {
818 if (validateCC() !== true) return false;
819 if ($('#cardCode').val() == "" || $('#cardHolderName').val() == "" || $('#expYear').val() == "" || $('#expMonth').val() == "") {
820 alert(<?php echo xlj('Invalid Credit Card Values: Please correct'); ?>)
821 return false;
823 if (validate() != true) {
824 flag = 1;
825 alert(<?php echo xlj('Validation error: Fix and resubmit. This popup info is preserved!'); ?>)
826 return false;
828 $("#openPayModal .close").click()
830 error: function (qXHR, textStatus, errorThrow) {
831 console.log("There was an error:" + errorThrow);
833 success: function (templateHtml, textStatus, jqXHR) {
834 let msg = <?php $amsg = xl('Payment successfully sent for review and posting to your account.') . "\n" .
835 xl("You will be notified when the payment transaction is confirmed.") . "\n" .
836 xl('Until then you will continue to see payment details here.') . "\n" . xl('Thank You.');
837 echo json_encode($amsg); // backward compatable 5.0.1
839 alert(msg);
840 window.location.reload(false);
843 if (flag) {
844 $("#openPayModal .close").click();
848 $('#openPayModal').on('show.bs.modal', function () {
849 let total = $("#form_paytotal").val();
850 if(Number(total) < 1) {
851 let error = <?php echo json_encode("Please enter a payment amount"); ?>;
852 alert(error);
853 return false;
855 $("#payTotal").text(total);
856 $("#paymentAmount").val(total);
859 $("#invoiceForm").on('submit', function (e) {
860 e.preventDefault();
861 let thisform = this;
862 $("#mode").val("review-save");
863 let inv_values = JSON.stringify(getFormObj('invoiceForm'));
864 let extra_values = JSON.stringify(getFormObj('paymentForm'));
865 let extra = "&inv_values=" + inv_values + "&extra_values=" + extra_values;
867 let flag = 0
868 let liburl = '<?php echo $GLOBALS["webroot"] ?>/portal/lib/paylib.php';
869 $.ajax({
870 type: "POST",
871 url: liburl,
872 data: $("#invoiceForm").serialize() + extra,
873 beforeSend: function (xhr) {
874 if (validate() != true) {
875 flag = 1;
876 alert(<?php echo xlj('Validation error: Fix and resubmit.'); ?>)
877 return false;
880 error: function (xhr, textStatus, error) {
881 alert(<?php echo xlj('There is a Post error'); ?>)
882 console.log("There was an error:" + textStatus);
883 return false;
885 success: function (templateHtml, textStatus, jqXHR) {
886 thisform.submit();
891 function getFormObj(formId) {
892 let formObj = {};
893 let inputs = $('#' + formId).serializeArray();
894 $.each(inputs, function (i, input) {
895 formObj[input.name] = input.value;
897 return formObj;
900 function formRepopulate(jsondata) {
901 let data = $.parseJSON(jsondata);
902 $.each(data, function (name, val) {
903 let $el = $('[name="' + name + '"]'),
904 type = $el.attr('type');
905 switch (type) {
906 case 'checkbox':
907 $el.prop('checked', true);
908 break;
909 case 'radio':
910 $el.filter('[value="' + val + '"]').prop('checked', true);
911 break;
912 default:
913 $el.val(val);
918 function getAuth() {
919 let authnum = document.getElementById("check_number").value;
920 authnum = prompt(<?php echo xlj('Please enter card comfirmation authorization'); ?>, authnum);
921 if (authnum != null) {
922 document.getElementById("check_number").value = authnum;
925 </script>
927 <body class="skin-blue" onunload='imclosing()' onLoad="cursor_pointer();"
928 style="text-align: center; margin: auto;">
930 <form id="invoiceForm" method='post' action='<?php echo $GLOBALS["webroot"] ?>/portal/portal_payment.php'>
931 <input type='hidden' name='form_pid' value='<?php echo attr($pid) ?>'/>
932 <input type='hidden' name='form_save' value='<?php echo xla('Invoice'); ?>'/>
933 <table>
934 <tr height="10">
935 <td colspan="3">&nbsp;</td>
936 </tr>
937 <tr>
938 <td colspan='3' align='center' class='text'>
939 <b><?php echo xlt('Accept Payment for'); ?>&nbsp;:&nbsp;&nbsp;<?php
940 echo text($patdata['fname']) . " " .
941 text($patdata['lname']) . " " .
942 text($patdata['mname']) . " (" .
943 text($patdata['pid']) . ")" ?></b>
944 <?php $NameNew = $patdata['fname'] . " " . $patdata['lname'] . " " . $patdata['mname']; ?>
945 </td>
946 </tr>
947 <tr height="15">
948 <td colspan='3'></td>
949 </tr>
950 <tr>
951 <td class='text'>
952 <?php echo xlt('Payment Method'); ?>:
953 </td>
954 <td colspan='2'><select name="form_method" id="form_method" class="form-control" onChange='CheckVisible("yes")'>
955 <?php
956 $query1112 = "SELECT * FROM list_options where list_id=? ORDER BY seq, title ";
957 $bres1112 = sqlStatement($query1112, array('payment_method'));
958 while ($brow1112 = sqlFetchArray($bres1112)) {
959 if ($brow1112['option_id'] != 'credit_card' || $brow1112['option_id'] == 'debit' || $brow1112['option_id'] == 'bank_draft') {
960 continue;
962 echo "<option value='" . attr($brow1112['option_id']) . "'>" .
963 text(xl_list_label($brow1112['title'])) . "</option>";
966 </select></td>
967 </tr>
968 <?php if (isset($_SESSION['authUserID'])) { ?>
969 <tr height="5">
970 <td colspan='3'></td>
971 </tr>
972 <tr>
973 <td class='text'>
974 <?php echo xlt('Authorized'); ?>:
975 </td>
976 <td colspan='2'>
977 <?php if ($ccdata['authCode'] && empty($payrow['source'])) {
978 $payrow['source'] = $ccdata['authCode'] . " : " . $ccdata['transId'];
981 <input class="form-control form-control-sm" id='check_number' name='form_source' style='' value='<?php echo attr($payrow['source']) ?>' />
982 </td>
983 </tr>
984 <?php } ?>
985 <?php if (isset($_SESSION['authUserID'])) {
986 $hide = '';
987 echo '<tr height="5"><td colspan="3"></td></tr><tr">';
988 } else {
989 $hide = 'hidden';
990 echo '<tr class="hidden">';
993 <td class='text' valign="middle">
994 <?php echo xlt('Patient Coverage'); ?>:
995 </td>
996 <td class='text' colspan="2">
997 <input type="radio" name="radio_type_of_coverage" id="radio_type_of_coverage1"
998 value="self" onClick="make_visible_radio();make_self();"/>
999 <?php echo xlt('Self'); ?>
1000 <input type="radio" name="radio_type_of_coverage" id="radio_type_of_coverag2" value="insurance"
1001 checked="checked"
1002 onClick="make_hide_radio();make_insurance();"/>
1003 <?php echo xlt('Insurance'); ?>
1004 </td>
1005 </tr>
1006 <tr height="5">
1007 <td colspan='3'></td>
1008 </tr>
1009 <tr id="tr_radio1" style="display: none">
1010 <!-- For radio Insurance -->
1011 <td class='text' valign="top">
1012 <?php echo xlt('Payment against'); ?>:
1013 </td>
1014 <td class='text' colspan="2">
1015 <input type="radio" name="radio_type_of_payment" id="radio_type_of_payment_self1"
1016 value="cash" onClick="make_visible_row();make_it_hide_enc_pay();cursor_pointer();"/>
1017 <?php echo xlt('Encounter Payment'); ?>
1018 </td>
1019 </tr>
1020 <tr id="tr_radio2">
1021 <!-- For radio self -->
1022 <td class='text' valign="top"><?php echo xlt('Payment against'); ?>:</td>
1023 <td class='text' colspan="2">
1024 <input type="radio" name="radio_type_of_payment" id="radio_type_of_payment1" class="<?php echo $hide ? $hide : ''; ?>"
1025 value="copay" onClick="make_visible_row();cursor_pointer();"/><?php echo !$hide ? xlt('Co Pay') : ''; ?>
1026 <input type="radio" name="radio_type_of_payment" id="radio_type_of_payment2" checked="checked"
1027 value="invoice_balance" onClick="make_visible_row();"/><?php echo xlt('Invoice Balance'); ?>
1028 <input type="radio" name="radio_type_of_payment" id="radio_type_of_payment4" value="pre_payment"
1029 onClick="make_hide_row();"/><?php echo xlt('Pre Pay'); ?>
1030 </td>
1031 </tr>
1032 <tr height="15">
1033 <td colspan='3'></td>
1034 </tr>
1035 </table>
1036 <table width="20%" border="0" cellspacing="0" cellpadding="0" id="table_display_prepayment" style="margin-bottom: 10px; display: none">
1037 <tr>
1038 <td class='detail'><?php echo xlt('Pre Payment'); ?></td>
1039 <td><input class="form-control" type='text' id= 'form_prepayment' name='form_prepayment' style=''/></td>
1040 </tr>
1041 </table>
1042 <table id="table_display" style="background: #eee;" class="table table-sm table-striped table-bordered w-100">
1043 <thead>
1044 </thead>
1045 <tbody>
1046 <tr bgcolor="#cccccc" id="tr_head">
1047 <td class="dehead" width="60">
1048 <?php echo xlt('DOS') ?>
1049 </td>
1050 <td class="dehead" width="120">
1051 <?php echo xlt('Visit Reason') ?>
1052 </td>
1053 <td class="dehead" align="center" width="70" id="td_head_total_charge">
1054 <?php echo xlt('Total Charge') ?>
1055 </td>
1056 <td class="dehead" align="center" width="70" id="td_head_rep_doc" style='display: none'>
1057 <?php echo xlt('Report/ Form') ?>
1058 </td>
1059 <td class="dehead" align="center" width="200" id="td_head_description" style='display: none'>
1060 <?php echo xlt('Description') ?>
1061 </td>
1062 <td class="dehead" align="center" width="70" id="td_head_insurance_payment">
1063 <?php echo xlt('Insurance Payment') ?>
1064 </td>
1065 <td class="dehead" align="center" width="70" id="td_head_patient_payment">
1066 <?php echo xlt('Patient Payment') ?>
1067 </td>
1068 <td class="dehead" align="center" width="55" id="td_head_patient_co_pay">
1069 <?php echo xlt('Co Pay Paid') ?>
1070 </td>
1071 <td class="dehead" align="center" width="55" id="td_head_co_pay">
1072 <?php echo xlt('Required Co Pay') ?>
1073 </td>
1074 <td class="dehead" align="center" width="70" id="td_head_insurance_balance">
1075 <?php echo xlt('Insurance Balance') ?>
1076 </td>
1077 <td class="dehead" align="center" width="70" id="td_head_patient_balance">
1078 <?php echo xlt('Patient Balance') ?>
1079 </td>
1080 <td class="dehead" align="center" width="50">
1081 <?php echo xlt('Paying') ?>
1082 </td>
1083 </tr>
1084 <?php
1085 $encs = array();
1086 // Get the unbilled service charges and payments by encounter for this patient.
1088 $query = "SELECT fe.encounter, fe.reason, b.code_type, b.code, b.modifier, b.fee, " .
1089 "LEFT(fe.date, 10) AS encdate ,fe.last_level_closed " . "FROM form_encounter AS fe left join billing AS b on " .
1090 "b.pid = ? AND b.activity = 1 AND " . "b.code_type != 'TAX' AND b.fee != 0 " . "AND fe.pid = b.pid AND fe.encounter = b.encounter " .
1091 "where fe.pid = ? " . "ORDER BY b.encounter";
1092 $bres = sqlStatement($query, array($pid, $pid));
1094 while ($brow = sqlFetchArray($bres)) {
1095 $key = (int)$brow['encounter'];
1096 if (empty($encs[$key])) {
1097 $encs[$key] = array('encounter' => $brow['encounter'], 'date' => $brow['encdate'], 'last_level_closed' => $brow['last_level_closed'], 'charges' => 0, 'payments' => 0, 'reason' => $brow['reason']
1101 if ($brow['code_type'] !== 'COPAY') {
1102 $encs[$key]['charges'] += $brow['fee'];
1103 // Add taxes.
1104 $sql_array = array();
1105 $query = "SELECT taxrates FROM codes WHERE " . "code_type = ? AND " . "code = ? AND ";
1106 array_push($sql_array, $code_types[$brow['code_type']]['id'] ?? '', $brow['code'] ?? '');
1107 if ($brow['modifier'] ?? '') {
1108 $query .= "modifier = ?";
1109 $sql_array[] = $brow['modifier'] ?? '';
1110 } else {
1111 $query .= "(modifier IS NULL OR modifier = '')";
1114 $query .= " LIMIT 1";
1115 $trow = sqlQuery($query, $sql_array);
1116 $encs[$key]['charges'] += calcTaxes($trow, $brow['fee']);
1120 // Do the same for unbilled product sales.
1122 $query = "SELECT fe.encounter, fe.reason, s.drug_id, s.fee, " .
1123 "LEFT(fe.date, 10) AS encdate,fe.last_level_closed " .
1124 "FROM form_encounter AS fe left join drug_sales AS s " .
1125 "on s.pid = ? AND s.fee != 0 " .
1126 "AND fe.pid = s.pid AND fe.encounter = s.encounter " .
1127 "where fe.pid = ? " . "ORDER BY s.encounter";
1129 $dres = sqlStatement($query, array($pid, $pid));
1131 while ($drow = sqlFetchArray($dres)) {
1132 $key = (int)$drow['encounter'];
1133 if (empty($encs[$key])) {
1134 $encs[$key] = array(
1135 'encounter' => $drow['encounter'], 'date' => $drow['encdate'],
1136 'last_level_closed' => $drow['last_level_closed'],
1137 'charges' => 0, 'payments' => 0
1141 $encs[$key]['charges'] += $drow['fee'];
1142 // Add taxes.
1143 $trow = sqlQuery(
1144 "SELECT taxrates FROM drug_templates WHERE drug_id = ? " .
1145 "ORDER BY selector LIMIT 1",
1146 array($drow['drug_id'])
1148 $encs[$key]['charges'] += calcTaxes($trow, $drow['fee']);
1151 ksort($encs, SORT_NUMERIC);
1153 foreach ($encs as $key => $value) {
1154 $enc = $value['encounter'];
1155 $reason = $value['reason'];
1156 $dispdate = $value['date'];
1158 $inscopay = BillingUtilities::getCopay($pid, $dispdate);
1159 $patcopay = BillingUtilities::getPatientCopay($pid, $enc);
1160 // Insurance Payment
1162 $drow = sqlQuery(
1163 "SELECT SUM(pay_amount) AS payments, " .
1164 "SUM(adj_amount) AS adjustments FROM ar_activity WHERE " .
1165 "deleted IS NULL AND pid = ? and encounter = ? AND " .
1166 "payer_type != 0 AND account_code != 'PCP'",
1167 array($pid, $enc)
1169 $dpayment = $drow['payments'];
1170 $dadjustment = $drow['adjustments'];
1171 // Patient Payment
1173 $drow = sqlQuery(
1174 "SELECT SUM(pay_amount) AS payments, SUM(adj_amount) AS adjustments " .
1175 "FROM ar_activity WHERE deleted IS NULL AND pid = ? and encounter = ? and " .
1176 "payer_type = 0 and account_code != 'PCP'",
1177 array($pid, $enc)
1179 $dpayment_pat = $drow['payments'];
1181 // NumberOfInsurance
1183 $ResultNumberOfInsurance = sqlStatement(
1184 "SELECT COUNT( DISTINCT TYPE ) NumberOfInsurance FROM insurance_data where pid = ? and provider>0 ",
1185 array($pid)
1187 $RowNumberOfInsurance = sqlFetchArray($ResultNumberOfInsurance);
1188 $NumberOfInsurance = $RowNumberOfInsurance['NumberOfInsurance'] * 1;
1189 $duept = 0;
1190 if ((($NumberOfInsurance == 0 || $value['last_level_closed'] == 4 || $NumberOfInsurance == $value['last_level_closed']))) { // Patient balance
1191 $brow = sqlQuery("SELECT SUM(fee) AS amount FROM billing WHERE " . "pid = ? and encounter = ? AND activity = 1", array($pid, $enc
1193 $srow = sqlQuery("SELECT SUM(fee) AS amount FROM drug_sales WHERE " . "pid = ? and encounter = ? ", array($pid, $enc
1195 $drow = sqlQuery(
1196 "SELECT SUM(pay_amount) AS payments, SUM(adj_amount) AS adjustments " .
1197 "FROM ar_activity WHERE deleted IS NULL AND pid = ? and encounter = ? ",
1198 array($pid, $enc)
1200 $duept = $brow['amount'] + $srow['amount'] - $drow['payments'] - $drow['adjustments'];
1203 echoLine("form_upay[$enc]", $dispdate, $value['charges'], $dpayment_pat, ($dpayment + $dadjustment), $duept, ($enc . ': ' . $reason), $inscopay, $patcopay);
1206 // Continue with display of the data entry form.
1208 <tr>
1209 <td class="dehead" align="center"><?php echo xlt('Total'); ?></td>
1210 <td class="dehead" id='td_total_1' align="center"></td>
1211 <td class="dehead" id='td_total_2' align="center"><?php echo text(FormatMoney::getBucks($sum_charges)) ?></td>
1212 <td class="dehead" id='td_total_3' align="center"><?php echo text(FormatMoney::getBucks($sum_inspaid)) ?></td>
1213 <td class="dehead" id='td_total_4' align="center"><?php echo text(FormatMoney::getBucks($sum_ptpaid)) ?></td>
1214 <td class="dehead" id='td_total_5' align="center"><?php echo text(FormatMoney::getBucks($sum_patcopay)) ?></td>
1215 <td class="dehead" id='td_total_6' align="center"><?php echo text(FormatMoney::getBucks($sum_copay)) ?></td>
1216 <td class="dehead" id='td_total_7' align="center"><?php echo text(FormatMoney::getBucks($sum_balance)) ?></td>
1217 <td class="dehead" id='td_total_8' align="center"><?php echo text(FormatMoney::getBucks($sum_duept)) ?></td>
1218 <td class="dehead" align="center">
1219 <input class="form-control" name='form_paytotal' id='form_paytotal' value='' style='color: #3b9204;' readonly />
1220 </td>
1221 </tr>
1222 </table>
1223 <?php
1224 if (isset($ccdata["cardHolderName"])) {
1225 echo '<div class="col-5"><div class="card panel-default height">';
1226 if (!isset($_SESSION['authUserID'])) {
1227 echo '<div class="card-heading">' . xlt("Payment Information") .
1228 '<span style="color: #cc0000"><em> ' . xlt("Pending Auth since") . ': </em>' . text($edata["date"]) . '</span></div>';
1229 } else {
1230 echo '<div class="card-heading">' . xlt("Audit Payment") .
1231 '<span style="color: #cc0000"><em> ' . xlt("Pending since") . ': </em>' . text($edata["date"]) . '</span>' .
1232 ' <button type="button" class="btn btn-warning btn-sm" onclick="getAuth()">' . xlt("Authorize") . '</button></div>';
1234 } else {
1235 echo '<div style="display:none" class="col-6"><div class="card panel-default height">' .
1236 '<div class="card-heading">' . xlt("Payment Information") . ' </div>';
1239 <div class="card-body">
1240 <span class="font-weight-bold"><?php echo xlt('Card Name'); ?>: </span><span id="cn"><?php echo text($ccdata["cc_type"] ?? '') ?></span><br />
1241 <span class="font-weight-bold"><?php echo xlt('Name on Card'); ?>: </span><span id="nc"><?php echo text($ccdata["cardHolderName"] ?? '') ?></span>
1242 <span class="font-weight-bold"><?php echo xlt('Card Holder Zip'); ?>: </span><span id="czip"><?php echo text($ccdata["zip"] ?? '') ?></span><br />
1243 <span class="font-weight-bold"><?php echo xlt('Card Number'); ?>: </span><span id="ccn">
1244 <?php
1245 if (isset($_SESSION['authUserID']) || isset($ccdata["transId"])) {
1246 echo text($ccdata["cardNumber"]) . "</span><br />";
1247 } elseif (strlen($ccdata["cardNumber"] ?? '') > 4) {
1248 echo "********** " . text(substr($ccdata["cardNumber"], -4)) . "</span><br />";
1251 <?php
1252 if (!isset($ccdata["transId"])) { ?>
1253 <span class="font-weight-bold"><?php echo xlt('Exp Date'); ?>: </span><span id="ed"><?php echo text($ccdata["month"] ?? '') . "/" . text($ccdata["year"] ?? '') ?></span>
1254 <span class="font-weight-bold"><?php echo xlt('CVV'); ?>: </span><span id="cvvpin"><?php echo text($ccdata["cardCode"] ?? '') ?></span><br />
1255 <?php } else { ?>
1256 <span class="font-weight-bold"><?php echo xlt('Transaction Id'); ?>: </span><span id="ed"><?php echo text($ccdata["transId"] ?? '') . "/" . text($ccdata["year"]) ?></span>
1257 <span class="font-weight-bold"><?php echo xlt('Authorization'); ?>: </span><span id="cvvpin"><?php echo text($ccdata["authCode"] ?? '') ?></span><br />
1258 <?php } ?>
1259 <span class="font-weight-bold"><?php echo xlt('Charge Total'); ?>: </span><span id="ct"><?php echo text($invdata["form_paytotal"] ?? '') ?></span><br />
1260 </div>
1261 </div>
1262 </div>
1263 <div>
1264 <?php
1265 if (!isset($_SESSION['authUserID'])) {
1266 if (!isset($ccdata["cardHolderName"])) {
1267 if ($GLOBALS['payment_gateway'] == 'Sphere') {
1268 echo SpherePayment::renderSphereHtml('patient');
1269 } else {
1270 echo '<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#openPayModal">' . xlt("Pay Invoice") . '</button>';
1272 } else {
1273 echo '<h4><span class="bg-danger">' . xlt("Locked Payment Pending") . '</span></h4>';
1275 } else {
1276 echo "<button type='submit' class='btn btn-success' form='invoiceForm'>" . xlt('Post Payment') . "</button>";
1279 </div>
1280 <input type="hidden" name="hidden_patient_code" id="hidden_patient_code" value="<?php echo attr($pid); ?>"/>
1281 <input type='hidden' name='mode' id='mode' value=''/>
1282 </form>
1284 <script>
1285 if (typeof jsondata !== 'undefined') {
1286 formRepopulate(jsondata);
1288 calctotal();
1289 </script>
1290 <!-- credit payment modal -->
1291 <div id="openPayModal" class="modal fade" role="dialog">
1292 <div class="modal-dialog">
1293 <div class="modal-content">
1294 <div class="modal-header">
1295 <h4><?php echo xlt('Submit Payment for Authorization'); ?></h4>
1296 <!--<button type="button" class="close" data-dismiss="modal">&times;</button>-->
1297 </div>
1298 <div class="modal-body">
1299 <?php if ($GLOBALS['payment_gateway'] != 'Stripe' && $GLOBALS['payment_gateway'] != 'Sphere') { ?>
1300 <form id='paymentForm' method='post' action='<?php echo $GLOBALS["webroot"] ?>/portal/lib/paylib.php'>
1301 <fieldset>
1302 <div class="form-group">
1303 <label label-default="label-default"
1304 class="control-label"><?php echo xlt('Name on Card'); ?></label>
1305 <div class="controls">
1306 <input name="cardHolderName" id="cardHolderName" type="text" class="form-control" pattern="\w+ \w+.*" title="<?php echo xla('Fill your first and last name'); ?>" value="<?php echo attr($patdata['fname']) . ' ' . attr($patdata['lname']) ?>" />
1307 </div>
1308 </div>
1309 <div class="form-group">
1310 <label class="control-label"><?php echo xlt('Card Number'); ?></label>
1311 <div class="controls">
1312 <div class="row">
1313 <div class="col-sm-12">
1314 <input name="cardNumber" id="cardNumber" type="text" class="form-control inline col-sm-4" autocomplete="off" maxlength="19" pattern="\d" onchange="validateCC()" title="<?php echo xla('Card Number'); ?>" value="" />&nbsp;&nbsp;
1315 <h4 name="cardtype" id="cardtype" style="display: inline-block; color:#cc0000;"><?php echo xlt('Validating') ?></h4>
1316 </div>
1317 </div>
1318 </div>
1319 </div>
1320 <div class="form-group">
1321 <label label-default="label-default"><?php echo xlt('Card Expiry Date and Card Holders Zip'); ?></label>
1322 <div class="controls">
1323 <div class="row">
1324 <div class="col-md-4">
1325 <select name="month" id="expMonth" class="form-control">
1326 <option value=""><?php echo xlt('Select Month'); ?></option>
1327 <option value="01"><?php echo xlt('January'); ?></option>
1328 <option value="02"><?php echo xlt('February'); ?></option>
1329 <option value="03"><?php echo xlt('March'); ?></option>
1330 <option value="04"><?php echo xlt('April'); ?></option>
1331 <option value="05"><?php echo xlt('May'); ?></option>
1332 <option value="06"><?php echo xlt('June'); ?></option>
1333 <option value="07"><?php echo xlt('July'); ?></option>
1334 <option value="08"><?php echo xlt('August'); ?></option>
1335 <option value="09"><?php echo xlt('September'); ?></option>
1336 <option value="10"><?php echo xlt('October'); ?></option>
1337 <option value="11"><?php echo xlt('November'); ?></option>
1338 <option value="12"><?php echo xlt('December'); ?></option>
1339 </select>
1340 </div>
1341 <div class="col-md-4">
1342 <select name="year" id="expYear" class="form-control">
1343 <option value=""><?php echo xlt('Select Year'); ?></option>
1344 <option value="2019">2019</option>
1345 <option value="2020">2020</option>
1346 <option value="2021">2021</option>
1347 <option value="2022">2022</option>
1348 <option value="2023">2023</option>
1349 <option value="2024">2024</option>
1350 <option value="2025">2025</option>
1351 <option value="2026">2026</option>
1352 <option value="2027">2027</option>
1353 <option value="2028">2028</option>
1354 </select>
1355 </div>
1356 <div class="col-md-4">
1357 <input name="zip" id="cczip" type="text" class="form-control" pattern="\d" title="<?php echo xla('Enter Your Zip'); ?>" placeholder="<?php echo xla('Card Holder Zip'); ?>" value="<?php echo attr($patdata['postal_code']) ?>"/>
1358 </div>
1359 </div>
1360 </div>
1361 </div>
1362 <div class="form-group">
1363 <label label-default="label-default" class="control-label"><?php echo xlt('Card CVV'); ?></label>
1364 <div class="controls">
1365 <div class="row">
1366 <div class="col-md-3">
1367 <input name="cardCode" id="cardCode" type="text" class="form-control" autocomplete="off" maxlength="4" onfocus="validateCC()" title="<?php echo xla('Three or four digits at back of your card'); ?>" value="" />
1368 </div>
1369 <div class="col-md-3">
1370 <img src='./images/img_cvc.png' style='height: 40px; width: auto' />
1371 </div>
1372 <div class="col-md-6">
1373 <h4 style="display: inline-block;"><?php echo xlt('Payment Amount'); ?>:&nbsp;
1374 <span class="font-weight-bold"><span id="payTotal"></span></span></h4>
1375 </div>
1376 </div>
1377 </div>
1378 </div>
1379 <input type='hidden' name='pid' id='pid' value='<?php echo attr($pid) ?>'/>
1380 <input type='hidden' name='mode' id='mode' value=''/>
1381 <input type='hidden' name='cc_type' id='cc_type' value=''/>
1382 <input type='hidden' name='payment' id='paymentAmount' value=''/>
1383 <input type='hidden' name='invValues' id='invValues' value=''/>
1384 <input type="hidden" name="dataValue" id="dataValue" />
1385 <input type="hidden" name="dataDescriptor" id="dataDescriptor" />
1386 </fieldset>
1387 </form>
1388 <?php } else { ?>
1389 <form method="post" name="payment-form" id="payment-form">
1390 <fieldset>
1391 <div class="form-group">
1392 <label label-default="label-default"><?php echo xlt('Name on Card'); ?></label>
1393 <div class="controls">
1394 <input name="cardHolderName" id="cardHolderName" type="text" class="form-control" pattern="\w+ \w+.*" title="<?php echo xla('Fill your first and last name'); ?>" value="<?php echo attr($patdata['fname']) . ' ' . attr($patdata['lname']) ?>" />
1395 </div>
1396 </div>
1397 <div class="form-group">
1398 <label for="card-element"><?php echo xlt('Credit or Debit Card') ?></label>
1399 <div class="form-group" id="card-element"></div>
1400 <div id="card-errors" role="alert"></div>
1401 </div>
1402 <div class="col-md-6">
1403 <h4 style="display: inline-block;"><?php echo xlt('Payment Amount'); ?>:&nbsp;
1404 <strong><span id="payTotal"></span></strong></h4>
1405 </div>
1406 <input type='hidden' name='mode' id='mode' value=''/>
1407 <input type='hidden' name='cc_type' id='cc_type' value=''/>
1408 <input type='hidden' name='payment' id='paymentAmount' value=''/>
1409 <input type='hidden' name='invValues' id='invValues' value=''/>
1410 </fieldset>
1411 </form>
1412 <?php } ?>
1413 </div>
1414 <!-- Body -->
1415 <div class="modal-footer">
1416 <div class="button-group">
1417 <button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo xlt('Cancel'); ?></button>
1418 <?php
1419 if ($GLOBALS['payment_gateway'] == 'InHouse') { ?>
1420 <button id="paySubmit" class="btn btn-primary"><?php echo xlt('Send Payment'); ?></button>
1421 <?php } elseif ($GLOBALS['payment_gateway'] == 'AuthorizeNet') { ?>
1422 <button id="payAurhorizeNet" class="btn btn-primary"
1423 onclick="sendPaymentDataToAnet(event)"><?php echo xlt('Pay Now'); ?></button>
1424 <?php }
1425 if ($GLOBALS['payment_gateway'] == 'Stripe') { ?>
1426 <button id="stripeSubmit" class="btn btn-primary"><?php echo xlt('Pay Now'); ?></button>
1427 <?php } ?>
1428 </div>
1429 </div>
1430 </div>
1431 </div>
1432 </div>
1433 <script>
1434 var ccerr = <?php echo xlj('Invalid Credit Card Number'); ?>
1436 // In House CC number Validation
1437 /*$('#cardNumber').validateCreditCard(function (result) {
1438 var r = (result.card_type === null ? '' : result.card_type.name.toUpperCase())
1439 var v = (result.valid === true ? ' Valid Number' : ' Validating')
1440 if (result.valid === true) {
1441 document.getElementById("cardtype").style.color = "#00aa00";
1442 } else {
1443 document.getElementById("cardtype").style.color = "#aa0000";
1445 $('#cardtype').text(r + v);
1446 });*/
1448 // In House CC Validation
1449 function validateCC() {
1450 var result = $('#cardNumber').validateCreditCard();
1451 var r = (result.card_type == null ? '' : result.card_type.name.toUpperCase())
1452 var v = (result.valid == true ? ' Valid Card Number' : ' Invalid Card Number')
1453 if (result.valid === true) {
1454 document.getElementById("cardtype").style.color = "#00aa00";
1455 } else {
1456 document.getElementById("cardtype").style.color = "#aa0000";
1458 $('#cardtype').text(r + v);
1459 $('#cc_type').val(r);
1460 if (!result.valid) {
1461 alert(ccerr);
1462 return false;
1464 else {
1465 return true;
1468 </script>
1470 <?php if ($GLOBALS['payment_gateway'] == 'AuthorizeNet' && isset($_SESSION['patient_portal_onsite_two'])) {
1471 // Include Authorize.Net dependency to tokenize card.
1472 // Will return a token to use for payment request keeping
1473 // credit info off the server.
1475 <script>
1476 function sendPaymentDataToAnet(e) {
1477 e.preventDefault();
1478 const authData = {};
1479 authData.clientKey = publicKey;
1480 authData.apiLoginID = apiKey;
1482 const cardData = {};
1483 cardData.cardNumber = document.getElementById("cardNumber").value;
1484 cardData.month = document.getElementById("expMonth").value;
1485 cardData.year = document.getElementById("expYear").value;
1486 cardData.cardCode = document.getElementById("cardCode").value;
1487 cardData.fullName = document.getElementById("cardHolderName").value;
1488 cardData.zip = document.getElementById("cczip").value;
1490 const secureData = {};
1491 secureData.authData = authData;
1492 secureData.cardData = cardData;
1494 Accept.dispatchData(secureData, acceptResponseHandler);
1496 function acceptResponseHandler(response) {
1497 if (response.messages.resultCode === "Error") {
1498 let i = 0;
1499 let errorMsg = '';
1500 while (i < response.messages.message.length) {
1501 errorMsg = errorMsg + response.messages.message[i].code + ": " +response.messages.message[i].text;
1502 console.log(errorMsg);
1503 i = i + 1;
1505 alert(errorMsg);
1506 } else {
1507 paymentFormUpdate(response.opaqueData);
1512 function paymentFormUpdate(opaqueData) {
1513 // this is card tokenized
1514 document.getElementById("dataDescriptor").value = opaqueData.dataDescriptor;
1515 document.getElementById("dataValue").value = opaqueData.dataValue;
1516 let oForm = document.forms['paymentForm'];
1517 oForm.elements['mode'].value = "AuthorizeNet";
1518 let inv_values = JSON.stringify(getFormObj('invoiceForm'));
1519 document.getElementById("invValues").value = inv_values;
1521 // empty out the fields before submitting to server.
1522 document.getElementById("cardNumber").value = "";
1523 document.getElementById("expMonth").value = "";
1524 document.getElementById("expYear").value = "";
1525 document.getElementById("cardCode").value = "";
1527 // Submit payment to server
1528 fetch('./lib/paylib.php', {
1529 method: 'POST',
1530 body: new FormData(oForm)
1531 }).then(function(response) {
1532 if (!response.ok) {
1533 throw Error(response.statusText);
1535 return response.text();
1536 }).then(function(data) {
1537 if(data !== 'ok') {
1538 alert(data);
1539 return;
1541 alert(chargeMsg);
1542 window.location.reload(false);
1543 }).catch(function(error) {
1544 alert(error)
1547 </script>
1548 <?php } // end authorize.net ?>
1550 <?php if ($GLOBALS['payment_gateway'] == 'Stripe' && isset($_SESSION['patient_portal_onsite_two'])) { // Begin Include Stripe ?>
1551 <script>
1552 const stripe = Stripe(publicKey);
1553 const elements = stripe.elements();// Custom styling can be passed to options when creating an Element.
1554 const style = {
1555 base: {
1556 color: '#32325d',
1557 lineHeight: '1.2rem',
1558 fontSmoothing: 'antialiased',
1559 fontSize: '16px',
1560 '::placeholder': {
1561 color: '#8e8e8e'
1564 invalid: {
1565 color: '#fa755a',
1566 iconColor: '#fa755a'
1570 // Create an instance of the card Element.
1571 const card = elements.create('card', {style: style});
1572 // Add an instance of the card Element into the `card-element` <div>.
1573 card.mount('#card-element');
1574 // Handle real-time validation errors from the card Element.
1575 card.addEventListener('change', function (event) {
1576 let displayError = document.getElementById('card-errors');
1577 if (event.error) {
1578 displayError.textContent = event.error.message;
1579 } else {
1580 displayError.textContent = '';
1583 // Handle form submission.
1584 let form = document.getElementById('stripeSubmit');
1585 form.addEventListener('click', function (event) {
1586 event.preventDefault();
1587 stripe.createToken(card).then(function (result) {
1588 if (result.error) {
1589 // Inform the user if there was an error.
1590 let errorElement = document.getElementById('card-errors');
1591 errorElement.textContent = result.error.message;
1592 } else {
1593 // Send the token to server.
1594 stripeTokenHandler(result.token);
1598 // Submit the form with the token ID.
1599 function stripeTokenHandler(token) {
1600 // Insert the token ID into the form so it gets submitted to the server
1601 let oForm = document.forms['payment-form'];
1602 oForm.elements['mode'].value = "Stripe";
1604 let inv_values = JSON.stringify(getFormObj('invoiceForm'));
1605 document.getElementById("invValues").value = inv_values;
1607 let hiddenInput = document.createElement('input');
1608 hiddenInput.setAttribute('type', 'hidden');
1609 hiddenInput.setAttribute('name', 'stripeToken');
1610 hiddenInput.setAttribute('value', token.id);
1611 oForm.appendChild(hiddenInput);
1613 // Submit payment to server
1614 fetch('./lib/paylib.php', {
1615 method: 'POST',
1616 body: new FormData(oForm)
1617 }).then(function(response) {
1618 if (!response.ok) {
1619 throw Error(response.statusText);
1621 return response.text();
1622 }).then(function(data) {
1623 if(data !== 'ok') {
1624 alert(data);
1625 return;
1627 alert(chargeMsg);
1628 window.location.reload(false);
1629 }).catch(function(error) {
1630 alert(error)
1633 </script>
1634 <?php } ?>
1636 <?php
1637 if ($GLOBALS['payment_gateway'] == 'Sphere' && isset($_SESSION['patient_portal_onsite_two'])) {
1638 echo (new SpherePayment('patient', $pid))->renderSphereJs();
1642 </body>
1643 <?php } // end else display ?>