add missing id attr for check date (#3600)
[openemr.git] / interface / billing / sl_eob_invoice.php
blob8c768e6ebd0ae17ab5d171ec1bebbd7ca7510e2f
1 <?php
3 /**
4 * This provides for manual posting of EOBs. It is invoked from
5 * sl_eob_search.php. For automated (X12 835) remittance posting
6 * see sl_eob_process.php.
8 * @package OpenEMR
9 * @link http://www.open-emr.org
10 * @author Rod Roark <rod@sunsetsystems.com>
11 * @author Roberto Vasquez <robertogagliotta@gmail.com>
12 * @author Terry Hill <terry@lillysystems.com>
13 * @author Jerry Padgett <sjpadgett@gmail.com>
14 * @author Stephen Waite <stephen.waite@cmsvt.com>
15 * @author Brady Miller <brady.g.miller@gmail.com>
16 * @copyright Copyright (c) 2005-2016 Rod Roark <rod@sunsetsystems.com>
17 * @copyright Copyright (c) 2018-2020 Stephen Waite <stephen.waite@cmsvt.com>
18 * @copyright Copyright (c) 2019-2020 Brady Miller <brady.g.miller@gmail.com>
19 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
22 require_once("../globals.php");
23 require_once("$srcdir/patient.inc");
24 require_once("$srcdir/forms.inc");
25 require_once("../../custom/code_types.inc.php");
26 require_once "$srcdir/user.inc";
28 use OpenEMR\Billing\InvoiceSummary;
29 use OpenEMR\Billing\SLEOB;
30 use OpenEMR\Common\Csrf\CsrfUtils;
31 use OpenEMR\Common\Logging\EventAuditLogger;
32 use OpenEMR\Core\Header;
34 $debug = 0; // set to 1 for debugging mode
35 $save_stay = $_REQUEST['form_save'] == '1' ? true : false;
36 $from_posting = (0 + $_REQUEST['isPosting']) ? 1 : 0;
37 $g_posting_adj_disable = $GLOBALS['posting_adj_disable'] ? 'checked' : '';
38 if ($from_posting) {
39 $posting_adj_disable = prevSetting('sl_eob_search.', 'posting_adj_disable', 'posting_adj_disable', $g_posting_adj_disable);
40 } else {
41 $posting_adj_disable = $g_posting_adj_disable;
44 // If we permit deletion of transactions. Might change this later.
45 $ALLOW_DELETE = true;
47 $info_msg = "";
49 // Format money for display.
51 function bucks($amount)
53 if ($amount) {
54 return sprintf("%.2f", $amount);
58 // Delete rows, with logging, for the specified table using the
59 // specified WHERE clause. Borrowed from deleter.php.
61 function row_delete($table, $where)
63 $tres = sqlStatement("SELECT * FROM " . escape_table_name($table) . " WHERE $where");
64 $count = 0;
65 while ($trow = sqlFetchArray($tres)) {
66 $logstring = "";
67 foreach ($trow as $key => $value) {
68 if (!$value || $value == '0000-00-00 00:00:00') {
69 continue;
72 if ($logstring) {
73 $logstring .= " ";
76 $logstring .= $key . "='" . addslashes($value) . "'";
79 EventAuditLogger::instance()->newEvent("delete", $_SESSION['authUser'], $_SESSION['authProvider'], 1, "$table: $logstring");
80 ++$count;
83 if ($count) { // Lets not echo the query for stay and save
84 $query = "DELETE FROM " . escape_table_name($table) . " WHERE $where";
85 sqlStatement($query);
90 <html>
91 <head>
92 <?php Header::setupHeader(['datetime-picker', 'opener']); ?>
93 <title><?php echo xlt('EOB Posting - Invoice') ?></title>
94 <script>
96 const adjDisable = <?php echo js_escape($posting_adj_disable); ?>;
97 // An insurance radio button is selected.
98 function setins(istr) {
99 return true;
102 function goEncounterSummary(pid) {
103 if(pid) {
104 if(typeof opener.toEncSummary === 'function') {
105 opener.toEncSummary(pid);
108 doClose();
111 function doClose() {
112 window.close();
115 // Compute an adjustment that writes off the balance:
116 function writeoff(code) {
117 const f = document.forms[0];
118 const belement = f['form_line[' + code + '][bal]'];
119 const pelement = f['form_line[' + code + '][pay]'];
120 const aelement = f['form_line[' + code + '][adj]'];
121 const relement = f['form_line[' + code + '][reason]'];
122 const tmp = belement.value - pelement.value;
123 aelement.value = Number(tmp).toFixed(2);
124 if (aelement.value && !relement.value) {
125 relement.selectedIndex = 1;
127 return false;
130 // Onsubmit handler. A good excuse to write some JavaScript.
131 function validate(f) {
132 let delcount = 0;
133 let allempty = true;
135 for (let i = 0; i < f.elements.length; ++i) {
136 let ename = f.elements[i].name;
137 // Count deletes.
138 if (ename.substring(0, 9) == 'form_del[') {
139 if (f.elements[i].checked) {
140 ++delcount;
142 continue;
144 let pfxlen = ename.indexOf('[pay]');
145 if (pfxlen < 0) {
146 continue
148 let pfx = ename.substring(0, pfxlen);
149 let code = pfx.substring(pfx.indexOf('[') + 1, pfxlen - 1);
150 let cPay = parseFloat(f[pfx + '[pay]'].value).toFixed(2);
151 let cAdjust = parseFloat(f[pfx + '[adj]'].value).toFixed(2);
153 if ((cPay !== 0) || cAdjust !== 0) {
154 allempty = false;
156 if(adjDisable) {
157 if ((cAdjust == 0 && ins_done.value == 'changed')) {
158 allempty = false;
161 if ((cPay !== 0) && isNaN(parseFloat(f[pfx + '[pay]'].value))) {
162 let message = <?php echo xlj('Payment value for code') ?> + " " + code + " " + <?php echo xlj('is not a number') ?>;
163 (async (message, time) => {
164 await asyncAlertMsg(message, time, 'danger', 'lg');
165 })(message, 3000)
166 .then(res => { });
167 return false;
169 if ((cAdjust !== 0) && isNaN(parseFloat(f[pfx + '[adj]'].value))) {
170 let message = <?php echo xlj('Adjustment value for code') ?> + " " + code + " " <?php echo xlj('is not a number') ?>;
171 (async (message, time) => {
172 await asyncAlertMsg(message, time, 'danger', 'lg');
173 })(message, 3000)
174 .then(res => { });
175 return false;
177 if ((cAdjust !== 0) && !f[pfx + '[reason]'].value && !adjDisable) {
178 let message = <?php echo xlj('Please select an adjustment reason for code') ?> + " " + code;
179 (async (message, time) => {
180 await asyncAlertMsg(message, time, 'danger', 'lg');
181 })(message, 3000)
182 .then(res => { });
183 return false;
185 // TBD: validate the date format
187 // Check if save is clicked with nothing to post.
188 if (allempty && delcount === 0) {
189 let message = <?php echo xlj('Nothing to Post! Please review entries or use Cancel to exit transaction') ?>;
190 (async (message, time) => {
191 await asyncAlertMsg(message, time, 'danger', 'lg');
192 })(message, 3000)
193 .then(res => { });
194 return false;
196 // Demand confirmation if deleting anything.
197 if (delcount > 0) {
198 if (!confirm(<?php echo xlj('Really delete'); ?> + ' ' + delcount +
199 ' ' + <?php echo xlj('transactions'); ?> + '?' +
200 ' ' + <?php echo xlj('This action will be logged'); ?> + '!')
201 ) return false;
203 return true;
206 // Get current date
207 function getFormattedToday() {
208 let today = new Date();
209 let dd = today.getDate();
210 let mm = today.getMonth() + 1; //January is 0!
211 let yyyy = today.getFullYear();
212 if (dd < 10) {
213 dd = '0' + dd;
215 if (mm < 10) {
216 mm = '0' + mm;
218 return (yyyy + '-' + mm + '-' + dd);
221 // Update Payment Fields
222 function updateFields(payField, adjField, balField, coPayField, isFirstProcCode) {
223 let payAmount = 0.0;
224 let adjAmount = 0.0;
225 let balAmount = 0.0;
226 let coPayAmount = 0.0;
228 // coPayFiled will be null if there is no co-pay entry in the fee sheet
229 if (coPayField) {
230 coPayAmount = coPayField.value;
233 // if balance field is 0.00, its value comes back as null, so check for nul-ness first
234 if (balField) {
235 balAmount = (balField.value) ? balField.value : 0;
238 if (payField) {
239 payAmount = (payField.value) ? payField.value : 0;
242 // alert('balance = >' + balAmount +'< payAmount = ' + payAmount + ' copay = ' + coPayAmount + ' isFirstProcCode = ' + isFirstProcCode);
244 // subtract the co-pay only from the first procedure code
245 if (isFirstProcCode == 1) {
246 balAmount = parseFloat(balAmount) + parseFloat(coPayAmount);
249 if (adjDisable) {
250 return;
253 adjAmount = balAmount - payAmount;
254 // Assign rounded adjustment value back to TextField
255 adjField.value = adjAmount = Math.round(adjAmount * 100) / 100;
258 $(function () {
259 $('.datepicker').datetimepicker({
260 <?php $datetimepicker_timepicker = false; ?>
261 <?php $datetimepicker_showseconds = false; ?>
262 <?php $datetimepicker_formatInput = true; ?>
263 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
264 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
268 $("#ins_done").on("change", function() {
269 $("#ins_done").val('changed');
272 </script>
273 <style>
274 @media only screen and (max-width: 768px) {
275 [class*="col-"] {
276 width: 100%;
277 text-align: left !Important;
281 .table {
282 margin: auto;
283 width: 99%;
286 .table > tbody > tr > td {
287 border-top: none;
290 .last_detail {
291 border-bottom: 1px var(--black) solid;
292 margin-top: 2px;
295 @media (min-width: 992px) {
296 .modal-lg {
297 width: 1000px !Important;
300 </style>
301 </head>
302 <body>
303 <?php
304 $trans_id = 0 + $_GET['id'];
305 if (!$trans_id) {
306 die(xlt("You cannot access this page directly."));
309 // A/R case, $trans_id matches form_encounter.id.
310 $ferow = sqlQuery("SELECT e.*, p.fname, p.mname, p.lname FROM form_encounter AS e, patient_data AS p WHERE e.id = ? AND p.pid = e.pid", array($trans_id));
311 if (empty($ferow)) {
312 die("There is no encounter with form_encounter.id = '" . text($trans_id) . "'.");
314 $patient_id = 0 + $ferow['pid'];
315 $encounter_id = 0 + $ferow['encounter'];
316 $svcdate = substr($ferow['date'], 0, 10);
317 $form_payer_id = ($_POST['$form_payer_id']) ? (0 + $_POST['form_payer_id']) : 0;
318 $form_reference = $_POST['form_reference'];
319 $form_check_date = ($_POST['form_check_date']) ? DateToYYYYMMDD($_POST['form_check_date']) : date('Y-m-d');
320 $form_deposit_date = ($_POST['form_deposit_date']) ? DateToYYYYMMDD($_POST['form_deposit_date']) : date('Y-m-d');
321 $form_pay_total = ($_POST['form_pay_total']) ? (0 + $_POST['form_pay_total']) : 0;
324 $payer_type = 0;
325 if (preg_match('/^Ins(\d)/i', $_POST['form_insurance'], $matches)) {
326 $payer_type = $matches[1];
329 if (($_POST['form_save'] || $_POST['form_cancel'])) {
330 if ($_POST['form_save']) {
331 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
332 CsrfUtils::csrfNotVerified();
335 if ($debug) {
336 echo "<p><b>" . xlt("This module is in test mode. The database will not be changed.") . "</b><p>\n";
339 $session_id = SLEOB::arGetSession($form_payer_id, $form_reference, $form_check_date, $form_deposit_date, $form_pay_total);
340 // The sl_eob_search page needs its invoice links modified to invoke
341 // javascript to load form parms for all the above and submit.
342 // At the same time that page would be modified to work off the
343 // openemr database exclusively.
344 // And back to the sl_eob_invoice page, I think we may want to move
345 // the source input fields from row level to header level.
347 // Handle deletes. row_delete() is borrowed from deleter.php.
348 if ($ALLOW_DELETE && !$debug) {
349 if (is_array($_POST['form_del'])) {
350 foreach ($_POST['form_del'] as $arseq => $dummy) {
351 row_delete("ar_activity", "pid = '" . add_escape_custom($patient_id) . "' AND " . "encounter = '" . add_escape_custom($encounter_id) . "' AND sequence_no = '" . add_escape_custom($arseq) . "'");
356 $paytotal = 0;
357 foreach ($_POST['form_line'] as $code => $cdata) {
358 $thispay = trim($cdata['pay']);
359 $thisadj = trim($cdata['adj']);
360 $thisins = trim($cdata['ins']);
361 $thiscodetype = trim($cdata['code_type']);
362 $reason = $cdata['reason'];
364 // Get the adjustment reason type. Possible values are:
365 // 1 = Charge adjustment
366 // 2 = Coinsurance
367 // 3 = Deductible
368 // 4 = Other pt resp
369 // 5 = Comment
370 $reason_type = '1';
371 if ($reason) {
372 $tmp = sqlQuery("SELECT option_value FROM list_options WHERE list_id = 'adjreason' AND activity = 1 AND option_id = ?", array($reason));
373 if (empty($tmp['option_value'])) {
374 // This should not happen but if it does, apply old logic.
375 if (preg_match("/To copay/", $reason)) {
376 $reason_type = 2;
377 } elseif (preg_match("/To ded'ble/", $reason)) {
378 $reason_type = 3;
380 $info_msg .= xl("No adjustment reason type found for") . " \"$reason\". ";
381 } else {
382 $reason_type = $tmp['option_value'];
386 if (!$thisins) {
387 $thisins = 0;
390 if (0.0 + $thispay) {
391 SLEOB::arPostPayment($patient_id, $encounter_id, $session_id, $thispay, $code, $payer_type, '', $debug, '', $thiscodetype);
392 $paytotal += $thispay;
395 // Be sure to record adjustment reasons, even for zero adjustments if
396 // they happen to be comments.
397 if (
398 (0.0 + $thisadj) ||
399 ($reason && $reason_type == 5) ||
400 ($reason && ($reason_type > 1 && $reason_type < 6))
402 // "To copay" and "To ded'ble" need to become a comment in a zero
403 // adjustment, formatted just like sl_eob_process.php.
404 if ($reason_type == '2') {
405 $reason = $_POST['form_insurance'] . " coins: $thisadj";
406 $thisadj = 0;
407 } elseif ($reason_type == '3') {
408 $reason = $_POST['form_insurance'] . " dedbl: $thisadj";
409 $thisadj = 0;
410 } elseif ($reason_type == '4') {
411 $reason = $_POST['form_insurance'] . " ptresp: $thisadj $reason";
412 $thisadj = 0;
413 } elseif ($reason_type == '5') {
414 $reason = $_POST['form_insurance'] . " note: $thisadj $reason";
415 $thisadj = 0;
416 } else {
417 // An adjustment reason including "Ins" is assumed to be assigned by
418 // insurance, and in that case we identify which one by appending
419 // Ins1, Ins2 or Ins3.
420 if (strpos(strtolower($reason), 'ins') != false) {
421 $reason .= ' ' . $_POST['form_insurance'];
424 SLEOB::arPostAdjustment($patient_id, $encounter_id, $session_id, $thisadj, $code, $payer_type, $reason, $debug, '', $thiscodetype);
428 // Maintain which insurances are marked as finished.
430 $form_done = 0 + $_POST['form_done'];
431 $form_stmt_count = 0 + $_POST['form_stmt_count'];
432 sqlStatement("UPDATE form_encounter SET last_level_closed = ?, stmt_count = ? WHERE pid = ? AND encounter = ?", array($form_done, $form_stmt_count, $patient_id, $encounter_id));
434 if ($_POST['form_secondary']) {
435 SLEOB::arSetupSecondary($patient_id, $encounter_id, $debug);
437 echo "<script>\n";
438 echo " if (opener.document.forms[0] != undefined) {\n";
439 echo " if (opener.document.forms[0].form_amount) {\n";
440 echo " var tmp = opener.document.forms[0].form_amount.value - " . attr($paytotal) . ";\n";
441 echo " opener.document.forms[0].form_amount.value = Number(tmp).toFixed(2);\n";
442 echo " }\n";
443 echo " }\n";
444 } else {
445 echo "<script>\n";
447 if ($info_msg) {
448 echo " alert(" . js_escape($info_msg) . ");\n";
450 if (!$debug && !$save_stay) {
451 echo "doClose();\n";
453 echo "</script></body></html>\n";
454 if (!$save_stay) {
455 exit();
459 // Get invoice charge details.
460 $codes = InvoiceSummary::arGetInvoiceSummary($patient_id, $encounter_id, true);
461 $pdrow = sqlQuery("select billing_note from patient_data where pid = ? limit 1", array($patient_id));
464 <div class="container-fluid">
465 <div class="row">
466 <div class="page-header">
467 <h2><?php echo xlt('EOB Invoice'); ?></h2>
468 </div>
469 </div>
470 <div class="container-fluid">
471 <form class="form" action='sl_eob_invoice.php?id=<?php echo attr_url($trans_id); ?>' method='post' onsubmit='return validate(this)'>
472 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>"/>
473 <input type="hidden" name="isPosting" value="<?php echo attr($from_posting); ?>"/>
474 <fieldset class="px-2">
475 <legend><?php echo xlt('Invoice Actions'); ?></legend>
476 <div class="form-row">
477 <div class="form-group col-lg">
478 <label class="col-form-label" for="form_name"><?php echo xlt('Patient'); ?>:</label>
479 <input type="text" class="form-control" id='form_name'
480 name='form_name'
481 value="<?php echo attr($ferow['fname']) . ' ' . attr($ferow['mname']) . ' ' . attr($ferow['lname']); ?>"
482 disabled>
483 </div>
484 <div class="form-group col-lg">
485 <label class="col-form-label" for="form_provider"><?php echo xlt('Provider'); ?>:</label>
486 <?php
487 $tmp = sqlQuery("SELECT fname, mname, lname " .
488 "FROM users WHERE id = ?", array($ferow['provider_id']));
489 $provider = text($tmp['fname']) . ' ' . text($tmp['mname']) . ' ' . text($tmp['lname']);
490 $tmp = sqlQuery("SELECT bill_date FROM billing WHERE " .
491 "pid = ? AND encounter = ? AND " .
492 "activity = 1 ORDER BY fee DESC, id ASC LIMIT 1", array($patient_id, $encounter_id));
493 $billdate = substr(($tmp['bill_date'] . "Not Billed"), 0, 10);
495 <input type="text" class="form-control" id='form_provider'
496 name='form_provider' value="<?php echo attr($provider); ?>" disabled>
497 </div>
498 <div class="form-group col-lg">
499 <label class="col-form-label" for="form_invoice"><?php echo xlt('Invoice'); ?>:</label>
500 <input type="text" class="form-control" id='form_provider'
501 name='form_provider' value='<?php echo attr($patient_id) . "." . attr($encounter_id); ?>'
502 disabled>
503 </div>
504 <div class="form-group col-lg">
505 <label class="col-form-label" for="svc_date"><?php echo xlt('Svc Date'); ?>:</label>
506 <input type="text" class="form-control" id='svc_date' name='form_provider'
507 value='<?php echo attr($svcdate); ?>' disabled>
508 </div>
509 <div class="card bg-light col-lg-4">
510 <div class="card-title mx-auto"><?php echo xlt('Insurance'); ?></div>
511 <?php
512 for ($i = 1; $i <= 3; ++$i) {
513 $payerid = SLEOB::arGetPayerID($patient_id, $svcdate, $i);
514 if ($payerid) {
515 $tmp = sqlQuery("SELECT name FROM insurance_companies WHERE id = ?", array($payerid));
516 echo "$i: " . $tmp['name'] . "<br />";
520 </div>
521 </div>
522 <div class="form-group mt-3">
523 <textarea name="insurance_name" id="insurance_name" class="form-control" cols="5" rows="2" readonly><?php echo attr($insurance); ?></textarea>
524 </div>
525 <div class="form-row">
526 <div class="form-group col-lg">
527 <label class="col-form-label" for="form_stmt_count"><?php echo xlt('Statements Sent'); ?>
528 :</label>
529 <input type='text' name='form_stmt_count' id='form_stmt_count' class="form-control" value='<?php echo attr((0 + $ferow['stmt_count'])); ?>'/>
530 </div>
531 <div class="form-group col-lg">
532 <label class="col-form-label" for="form_last_bill"><?php echo xlt('Last Bill Date'); ?>
533 :</label>
534 <input type='text' name="form_last_bill" id='form_last_bill' class="form-control"
535 value ='<?php echo attr($billdate); ?>' disabled/>
536 </div>
537 <div class="form-group col-lg">
538 <label class="col-form-label" for="form_reference"><?php echo xlt('Check/EOB No.'); ?>:</label>
539 <input type='text' name='form_reference' id='form_reference' class="form-control" value=''/>
540 </div>
541 <div class="form-group col-lg">
542 <label class="col-form-label" for="form_check_date"><?php echo xlt('Check/EOB Date'); ?>:</label>
543 <input type='text' name='form_check_date' id='form_check_date" class='form-control datepicker' value=''/>
544 </div>
545 <div class="form-group col-lg">
546 <label class="col-form-label" for="form_deposit_date"><?php echo xlt('Deposit Date'); ?>:</label>
547 <input type='text' name='form_deposit_date' id='form_deposit_date' class='form-control datepicker' value=''/>
548 <input type='hidden' name='form_payer_id' value=''/>
549 <input type='hidden' name='form_orig_reference' value=''/>
550 <input type='hidden' name='form_orig_check_date' value=''/>
551 <input type='hidden' name='form_orig_deposit_date' value=''/>
552 <input type='hidden' name='form_pay_total' value=''/>
553 </div>
554 </div>
555 <div class="form-row">
556 <div class="form-group col-lg">
557 <label class="col-form-label" for="type_code"><?php echo xlt('Now posting for'); ?>:</label>
558 <div style="padding-left: 15px">
559 <?php
560 $last_level_closed = 0 + $ferow['last_level_closed'];
562 <label class="radio-inline">
563 <input <?php echo $last_level_closed === 0 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Ins1")' type='radio'
564 value='Ins1'><?php echo xlt('Ins1') ?>
565 </label>
566 <label class="radio-inline">
567 <input <?php echo $last_level_closed === 1 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Ins2")' type='radio'
568 value='Ins2'><?php echo xlt('Ins2') ?>
569 </label>
570 <label class="radio-inline">
571 <input <?php echo $last_level_closed === 2 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Ins3")' type='radio'
572 value='Ins3'><?php echo xlt('Ins3') ?>
573 </label>
574 <label class="radio-inline">
575 <input <?php echo $last_level_closed === 3 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Pt")' type='radio'
576 value='Pt'><?php echo xlt('Patient') ?>
577 </label>
578 <?php
579 // TBD: I think the following is unused and can be removed.
581 <input name='form_eobs' type='hidden' value='<?php echo attr($arrow['shipvia']) ?>'/>
582 </div>
583 </div>
584 <div class="form-group col-lg" id='ins_done'>
585 <label class="col-form-label" for=""><?php echo xlt('Done with'); ?>:</label>
586 <div style="padding-left:15px">
587 <?php
588 // Write a checkbox for each insurance. It is to be checked when
589 // we no longer expect any payments from that company for the claim.
590 $last_level_closed = 0 + $ferow['last_level_closed'];
591 foreach (array(0 => 'None', 1 => 'Ins1', 2 => 'Ins2', 3 => 'Ins3') as $key => $value) {
592 if ($key && !SLEOB::arGetPayerID($patient_id, $svcdate, $key)) {
593 continue;
595 $checked = ($last_level_closed == $key) ? " checked" : "";
596 echo "<label class='radio-inline'>";
597 echo "<input type='radio' name='form_done' value='" . attr($key) . "'$checked />" . text($value);
598 echo "</label>";
601 </div>
602 </div>
603 <div class="form-group col-lg">
604 <label class="col-form-label" for=""><?php echo xlt('Secondary billing'); ?>:</label>
605 <div style="padding-left:15px">
606 <label class="checkbox-inline">
607 <input name="form_secondary" type="checkbox" value="1"><?php echo xlt('Needs secondary billing') ?>
608 </label>
609 </div>
610 </div>
611 </div>
613 </fieldset>
614 <fieldset>
615 <legend><?php echo xlt('Invoice Details'); ?></legend>
616 <div class="table-responsive">
617 <table class="table table-sm">
618 <thead>
619 <tr>
620 <th><?php echo xlt('Code') ?></th>
621 <th class="text-right"><?php echo xlt('Charge') ?></th>
622 <th class="text-right"><?php echo xlt('Balance') ?>&nbsp;</th>
623 <th><?php echo xlt('By/Source') ?></th>
624 <th><?php echo xlt('Date') ?></th>
625 <th><?php echo xlt('Pay') ?></th>
626 <th><?php echo xlt('Adjust') ?></th>
627 <th>&nbsp;</th>
628 <th><?php echo xlt('Reason') ?></th>
629 <?php
630 if ($ALLOW_DELETE) { ?>
631 <th><?php echo xlt('Del') ?></th>
632 <?php
633 } ?>
634 </tr>
635 </thead>
636 <?php
637 $firstProcCodeIndex = -1;
638 $encount = 0;
639 foreach ($codes as $code => $cdata) {
640 ++$encount;
641 $dispcode = $code;
643 // remember the index of the first entry whose code is not "CO-PAY", i.e. it's a legitimate proc code
644 if ($firstProcCodeIndex == -1 && strcmp($code, "CO-PAY") != 0) {
645 $firstProcCodeIndex = $encount;
648 // this sorts the details more or less chronologically:
649 ksort($cdata['dtl']);
650 foreach ($cdata['dtl'] as $dkey => $ddata) {
651 $ddate = substr($dkey, 0, 10);
652 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
653 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
655 $tmpchg = "";
656 $tmpadj = "";
657 if ($ddata['chg'] != 0) {
658 if (isset($ddata['rsn'])) {
659 $tmpadj = 0 - $ddata['chg'];
660 } else {
661 $tmpchg = $ddata['chg'];
665 <tr>
666 <td class="detail" style="background:<?php echo $dispcode ? 'lightyellow' : ''; ?>"><?php echo text($dispcode); $dispcode = "" ?></td>
667 <td class="detail"><?php echo text(bucks($tmpchg)); ?></td>
668 <td class="detail">&nbsp;</td>
669 <td class="detail">
670 <?php
671 if (isset($ddata['plv'])) {
672 if (!$ddata['plv']) {
673 echo 'Pt/';
674 } else {
675 echo 'Ins' . text($ddata['plv']) . '/';
678 echo text($ddata['src']);
680 </td>
681 <td class="detail"><?php echo text($ddate); ?></td>
682 <td class="detail"><?php echo text(bucks($ddata['pmt'])); ?></td>
683 <td class="detail"><?php echo text(bucks($tmpadj)); ?></td>
684 <td class="detail">&nbsp;</td>
685 <td class="detail"><?php echo text($ddata['rsn']); ?></td>
686 <?php
687 if ($ALLOW_DELETE) { ?>
688 <td class="detail">
689 <?php
690 if (!empty($ddata['arseq'])) { ?>
691 <input name="form_del[<?php echo attr($ddata['arseq']); ?>]"
692 type="checkbox">
693 <?php
694 } else {
695 ?> &nbsp;
696 <?php
697 } ?>
698 </td>
699 <?php } ?>
700 </tr>
701 <?php } // end of prior detail line ?>
702 <tr>
703 <td class="last_detail"><?php echo text($dispcode);
704 $dispcode = "" ?></td>
705 <td class="last_detail">&nbsp;</td>
706 <td class="last_detail">
707 <input name="form_line[<?php echo attr($code); ?>][bal]" type="hidden"
708 value="<?php echo attr(bucks($cdata['bal'])); ?>">
709 <input name="form_line[<?php echo attr($code); ?>][ins]" type="hidden"
710 value="<?php echo attr($cdata['ins']); ?>">
711 <input name="form_line[<?php echo attr($code); ?>][code_type]" type="hidden"
712 value="<?php echo attr($cdata['code_type']); ?>"> <?php echo text(sprintf("%.2f", $cdata['bal'])); ?>
713 &nbsp;
714 </td>
715 <td class="last_detail"></td>
716 <td class="last_detail"></td>
717 <td class="last_detail">
718 <input name="form_line[<?php echo attr($code); ?>][pay]"
719 onkeyup="updateFields(document.forms[0]['form_line[<?php echo attr($code); ?>][pay]'], document.forms[0]['form_line[<?php echo attr($code); ?>][adj]'], document.forms[0]['form_line[<?php echo attr($code); ?>][bal]'], document.forms[0]['form_line[CO-PAY][bal]'], <?php echo ($firstProcCodeIndex == $encount) ? 1 : 0 ?>)"
720 onfocus="this.select()" autofocus size="10" type="text" class="form-control"
721 value="0.00"></td>
722 <td class="last_detail">
723 <input name="form_line[<?php echo attr($code); ?>][adj]" size="10" type="text"
724 class="form-control"
725 value='<?php echo attr($totalAdjAmount ? $totalAdjAmount : '0.00'); ?>'
726 onclick="this.select()">
727 </td>
728 <td class="last_detail text-center">
729 <a href="#" class="text-decoration-none" onclick="return writeoff(<?php echo attr_js($code); ?>)">WO</a>
730 </td>
731 <td class="last_detail">
732 <select class="form-control" name="form_line[<?php echo attr($code); ?>][reason]">
733 <?php
734 // Adjustment reasons are now taken from the list_options table.
735 echo " <option value=''></option>\n";
736 $ores = sqlStatement("SELECT option_id, title, is_default FROM list_options " .
737 "WHERE list_id = 'adjreason' AND activity = 1 ORDER BY seq, title");
738 while ($orow = sqlFetchArray($ores)) {
739 echo " <option value='" . attr($orow['option_id']) . "'";
740 if ($orow['is_default']) {
741 echo " selected";
743 echo ">" . text($orow['title']) . "</option>\n";
746 </select>
747 <?php
748 // TBD: Maybe a comment field would be good here, for appending
749 // to the reason.
751 </td>
752 <?php if ($ALLOW_DELETE) { ?>
753 <td class="last_detail">&nbsp;</td>
754 <?php } ?>
755 </tr>
756 <?php } // end of code ?>
757 </table>
758 </div>
759 </fieldset>
760 </div>
762 </div>
763 <?php //can change position of buttons by creating a class 'position-override' and adding rule text-align:center or right as the case may be in individual stylesheets ?>
764 <div class="form-group col-lg clearfix">
765 <div class="col-sm-12 text-left position-override" id="search-btn">
766 <div class="btn-group" role="group">
767 <button type='submit' class="btn btn-primary btn-save" name='form_save' id="btn-save-stay"
768 onclick="this.value='1';"><?php echo xlt("Save Current"); ?></button>
769 <button type='submit' class="btn btn-primary btn-save" name='form_save' id="btn-save"
770 onclick="this.value='2';"><?php echo xlt("Save & Exit"); ?></button>
771 <button type='button' class="btn btn-secondary btn-cancel btn-separate-left" name='form_cancel'
772 id="btn-cancel" onclick='doClose()'><?php echo xlt("Close"); ?></button>
773 </div>
774 <?php if ($from_posting) { ?>
775 <button type='button' class="btn btn-secondary btn-view float-right" name='form_goto' id="btn-goto"
776 onclick="goEncounterSummary(<?php echo attr_js($patient_id) ?>)"><?php echo xlt("Past Encounters"); ?></button>
777 <?php } ?>
778 </div>
779 </div>
780 </form>
781 </div>
782 </div><!--End of container div-->
783 <?php if ($from_posting) { ?>
784 <script>
785 var f1 = opener.document.forms[0];
786 var f2 = document.forms[0];
787 if (f1.form_source) {
788 <?php
789 // These support creation and lookup of ar_session table entries:
790 echo " f2.form_reference.value = f1.form_source.value;\n";
791 echo " f2.form_check_date.value = f1.form_paydate.value;\n";
792 echo " //f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
793 echo " if (f1.form_deposit_date.value != '')\n";
794 echo " f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
795 echo " else\n";
796 echo " f2.form_deposit_date.value = getFormattedToday();\n";
797 echo " f2.form_payer_id.value = f1.form_payer_id.value;\n";
798 echo " f2.form_pay_total.value = f1.form_amount.value;\n";
799 echo " f2.form_orig_reference.value = f1.form_source.value;\n";
800 echo " f2.form_orig_check_date.value = f1.form_paydate.value;\n";
801 echo " f2.form_orig_deposit_date.value = f1.form_deposit_date.value;\n";
803 // While I'm thinking about it, some notes about eob sessions.
804 // If they do not have all of the session key fields in the search
805 // page, then show a warning at the top of the invoice page.
806 // Also when they go to save the invoice page and a session key
807 // field has changed, alert them to that and allow a cancel.
809 // Another point... when posting EOBs, the incoming payer ID might
810 // not match the payer ID for the patient's insurance. This is
811 // because the same payer might be entered more than once into the
812 // insurance_companies table. I don't think it matters much.
815 setins("Ins1");
816 </script>
817 <?php } ?>
818 </body>
819 </html>