chore(deps): bump twig/twig from 3.17.1 to 3.19.0 (#7951)
[openemr.git] / interface / billing / sl_eob_invoice.php
blob51d94f866ecc4db7c4bbeb783e74724c6e7927d0
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-2020 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.php");
24 require_once("$srcdir/forms.inc.php");
25 require_once("../../custom/code_types.inc.php");
26 require_once "$srcdir/user.inc.php";
27 require_once("$srcdir/payment.inc.php");
29 use OpenEMR\Billing\InvoiceSummary;
30 use OpenEMR\Billing\SLEOB;
31 use OpenEMR\Common\Csrf\CsrfUtils;
32 use OpenEMR\Common\Utils\FormatMoney;
33 use OpenEMR\Core\Header;
35 $debug = 0; // set to 1 for debugging mode
36 $save_stay = (!empty($_REQUEST['form_save']) && ($_REQUEST['form_save'] == '1')) ? true : false;
37 $from_posting = (0 + ($_REQUEST['isPosting'] ?? null)) ? 1 : 0;
38 $g_posting_adj_disable = $GLOBALS['posting_adj_disable'] ? 'checked' : '';
39 if ($from_posting) {
40 $posting_adj_disable = prevSetting('sl_eob_search.', 'posting_adj_disable', 'posting_adj_disable', $g_posting_adj_disable);
41 } else {
42 $posting_adj_disable = $g_posting_adj_disable;
45 // If we permit deletion of transactions. Might change this later.
46 $ALLOW_DELETE = true;
48 $info_msg = "";
51 <html>
52 <head>
53 <?php Header::setupHeader(['datetime-picker', 'opener', 'no_dialog']); ?>
54 <title><?php echo xlt('EOB Posting - Invoice') ?></title>
55 <script>
57 const adjDisable = <?php echo js_escape($posting_adj_disable); ?>;
58 // An insurance radio button is selected.
59 function setins(istr) {
60 return true;
63 function goEncounterSummary(e, pid) {
64 if(pid) {
65 if(typeof opener.toEncSummary === 'function') {
66 opener.toEncSummary(e, pid);
69 doClose();
72 function doClose() {
73 window.close();
76 // Compute an adjustment that writes off the balance:
77 function writeoff(code) {
78 const f = document.forms[0];
79 const belement = f['form_line[' + code + '][bal]'];
80 const pelement = f['form_line[' + code + '][pay]'];
81 const aelement = f['form_line[' + code + '][adj]'];
82 const relement = f['form_line[' + code + '][reason]'];
83 const tmp = belement.value - pelement.value;
84 aelement.value = Number(tmp).toFixed(2);
85 if (aelement.value && !relement.value) {
86 relement.selectedIndex = 1;
88 return false;
91 // Onsubmit handler. A good excuse to write some JavaScript.
92 function validate(f) {
93 let delcount = 0;
94 let allempty = true;
96 for (let i = 0; i < f.elements.length; ++i) {
97 let ename = f.elements[i].name;
98 // Count deletes.
99 if (ename.substring(0, 9) == 'form_del[') {
100 if (f.elements[i].checked) {
101 ++delcount;
103 continue;
105 let pfxlen = ename.indexOf('[pay]');
106 if (pfxlen < 0) {
107 continue
109 let pfx = ename.substring(0, pfxlen);
110 let code = pfx.substring(pfx.indexOf('[') + 1, pfxlen - 1);
111 let cPay = parseFloat(f[pfx + '[pay]'].value).toFixed(2);
112 let cAdjust = parseFloat(f[pfx + '[adj]'].value).toFixed(2);
114 if ((cPay !== 0) || cAdjust !== 0) {
115 allempty = false;
117 if(adjDisable) {
118 if ((cAdjust == 0 && ins_done.value == 'changed')) {
119 allempty = false;
122 if ((cPay !== 0) && isNaN(parseFloat(f[pfx + '[pay]'].value))) {
123 let message = <?php echo xlj('Payment value for code') ?> + " " + code + " " + <?php echo xlj('is not a number') ?>;
124 (async (message, time) => {
125 await asyncAlertMsg(message, time, 'danger', 'lg');
126 })(message, 3000)
127 .then(res => { });
128 return false;
130 if ((cAdjust !== 0) && isNaN(parseFloat(f[pfx + '[adj]'].value))) {
131 let message = <?php echo xlj('Adjustment value for code') ?> + " " + code + " " + <?php echo xlj('is not a number') ?>;
132 (async (message, time) => {
133 await asyncAlertMsg(message, time, 'danger', 'lg');
134 })(message, 3000)
135 .then(res => { });
136 return false;
138 if ((cAdjust !== 0) && !f[pfx + '[reason]'].value && !adjDisable) {
139 let message = <?php echo xlj('Please select an adjustment reason for code') ?> + " " + code;
140 (async (message, time) => {
141 await asyncAlertMsg(message, time, 'danger', 'lg');
142 })(message, 3000)
143 .then(res => { });
144 return false;
146 // TBD: validate the date format
148 // Check if save is clicked with nothing to post.
149 if (allempty && delcount === 0) {
150 let message = <?php echo xlj('Nothing to Post! Please review entries or use Cancel to exit transaction') ?>;
151 (async (message, time) => {
152 await asyncAlertMsg(message, time, 'danger', 'lg');
153 })(message, 3000)
154 .then(res => { });
155 return false;
157 // Demand confirmation if deleting anything.
158 if (delcount > 0) {
159 if (!confirm(<?php echo xlj('Really delete'); ?> + ' ' + delcount +
160 ' ' + <?php echo xlj('transactions'); ?> + '?' +
161 ' ' + <?php echo xlj('This action will be logged'); ?> + '!')
162 ) return false;
164 return true;
167 // Get current date
168 function getFormattedToday() {
169 let today = new Date();
170 let dd = today.getDate();
171 let mm = today.getMonth() + 1; //January is 0!
172 let yyyy = today.getFullYear();
173 if (dd < 10) {
174 dd = '0' + dd;
176 if (mm < 10) {
177 mm = '0' + mm;
179 return (yyyy + '-' + mm + '-' + dd);
182 // Update Payment Fields
183 function updateFields(payField, adjField, balField, coPayField, isFirstProcCode) {
184 let payAmount = 0.0;
185 let adjAmount = 0.0;
186 let balAmount = 0.0;
187 let coPayAmount = 0.0;
189 // coPayFiled will be null if there is no co-pay entry in the fee sheet
190 if (coPayField) {
191 coPayAmount = coPayField.value;
194 // if balance field is 0.00, its value comes back as null, so check for nul-ness first
195 if (balField) {
196 balAmount = (balField.value) ? balField.value : 0;
199 if (payField) {
200 payAmount = (payField.value) ? payField.value : 0;
203 // alert('balance = >' + balAmount +'< payAmount = ' + payAmount + ' copay = ' + coPayAmount + ' isFirstProcCode = ' + isFirstProcCode);
205 // subtract the co-pay only from the first procedure code
206 if (isFirstProcCode == 1) {
207 balAmount = parseFloat(balAmount) + parseFloat(coPayAmount);
210 if (adjDisable) {
211 return;
214 adjAmount = balAmount - payAmount;
215 // Assign rounded adjustment value back to TextField
216 adjField.value = adjAmount = Math.round(adjAmount * 100) / 100;
219 $(function () {
220 $('.datepicker').datetimepicker({
221 <?php $datetimepicker_timepicker = false; ?>
222 <?php $datetimepicker_showseconds = false; ?>
223 <?php $datetimepicker_formatInput = true; ?>
224 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
225 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
229 $("#ins_done").on("change", function() {
230 $("#ins_done").val('changed');
233 </script>
234 <style>
235 @media only screen and (max-width: 768px) {
236 [class*="col-"] {
237 width: 100%;
238 text-align: left !Important;
242 .table {
243 margin: auto;
244 width: 99%;
247 .table > tbody > tr > td {
248 border-top: none;
251 .last_detail {
252 border-bottom: 1px var(--black) solid;
253 margin-top: 2px;
256 @media (min-width: 992px) {
257 .modal-lg {
258 width: 1000px !Important;
261 </style>
262 </head>
263 <body>
264 <?php
265 $trans_id = (int) $_GET['id'];
266 if (!$trans_id) {
267 die(xlt("You cannot access this page directly."));
270 // A/R case, $trans_id matches form_encounter.id.
271 $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));
272 if (empty($ferow)) {
273 die("There is no encounter with form_encounter.id = '" . text($trans_id) . "'.");
275 $patient_id = (int) $ferow['pid'];
276 $encounter_id = (int) $ferow['encounter'];
277 $svcdate = substr($ferow['date'], 0, 10);
278 $form_payer_id = (!empty($_POST['form_payer_id'])) ? (0 + $_POST['form_payer_id']) : 0;
279 $form_reference = $_POST['form_reference'] ?? null;
280 $form_check_date = fixDate(($_POST['form_check_date'] ?? ''), date('Y-m-d'));
281 $form_deposit_date = fixDate(($_POST['form_deposit_date'] ?? ''), $form_check_date);
282 $form_pay_total = (!empty($_POST['form_pay_total'])) ? (0 + $_POST['form_pay_total']) : 0;
284 $payer_type = 0;
285 if (preg_match('/^Ins(\d)/i', ($_POST['form_insurance'] ?? ''), $matches)) {
286 $payer_type = $matches[1];
289 if (!empty($_POST['form_save']) || !empty($_POST['form_cancel']) || !empty($_POST['isLastClosed']) || !empty($_POST['enc_billing_note'])) {
290 if (!empty($_POST['form_save'])) {
291 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
292 CsrfUtils::csrfNotVerified();
295 if ($debug) {
296 echo "<p><b>" . xlt("This module is in test mode. The database will not be changed.") . "</b><p>\n";
299 $session_id = SLEOB::arGetSession($form_payer_id, $form_reference, $form_check_date, $form_deposit_date, $form_pay_total);
300 // The sl_eob_search page needs its invoice links modified to invoke
301 // javascript to load form parms for all the above and submit.
302 // At the same time that page would be modified to work off the
303 // openemr database exclusively.
304 // And back to the sl_eob_invoice page, I think we may want to move
305 // the source input fields from row level to header level.
307 // Handle deletes. row_delete() is borrowed from deleter.php.
308 if ($ALLOW_DELETE && !$debug) {
309 if (!empty($_POST['form_del']) && is_array($_POST['form_del'])) {
310 foreach ($_POST['form_del'] as $arseq => $dummy) {
311 row_modify(
312 "ar_activity",
313 "deleted = NOW()",
314 "pid = '" . add_escape_custom($patient_id) .
315 "' AND encounter = '" . add_escape_custom($encounter_id) .
316 "' AND sequence_no = '" . add_escape_custom($arseq) .
317 "' AND deleted IS NULL"
323 $paytotal = 0;
324 foreach ($_POST['form_line'] as $code => $cdata) {
325 $thispay = trim($cdata['pay']);
326 $thisadj = trim($cdata['adj']);
327 $thisins = trim($cdata['ins']);
328 $thiscodetype = trim($cdata['code_type']);
329 $reason = $cdata['reason'];
331 // Get the adjustment reason type. Possible values are:
332 // 1 = Charge adjustment
333 // 2 = Coinsurance
334 // 3 = Deductible
335 // 4 = Other pt resp
336 // 5 = Comment
337 $reason_type = '1';
338 if ($reason) {
339 $tmp = sqlQuery("SELECT option_value FROM list_options WHERE list_id = 'adjreason' AND activity = 1 AND option_id = ?", array($reason));
340 if (empty($tmp['option_value'])) {
341 // This should not happen but if it does, apply old logic.
342 if (preg_match("/To copay/", $reason)) {
343 $reason_type = 2;
344 } elseif (preg_match("/To ded'ble/", $reason)) {
345 $reason_type = 3;
347 $info_msg .= xl("No adjustment reason type found for") . " \"$reason\". ";
348 } else {
349 $reason_type = $tmp['option_value'];
353 if (!$thisins) {
354 $thisins = 0;
357 if (0.0 + $thispay) {
358 SLEOB::arPostPayment($patient_id, $encounter_id, $session_id, $thispay, $code, $payer_type, '', $debug, '', $thiscodetype);
359 $paytotal += $thispay;
362 // Be sure to record adjustment reasons, even for zero adjustments if
363 // they happen to be comments.
364 if (
365 (0.0 + $thisadj) ||
366 ($reason && $reason_type == 5) ||
367 ($reason && ($reason_type > 1 && $reason_type < 6))
369 // "To copay" and "To ded'ble" need to become a comment in a zero
370 // adjustment, formatted just like sl_eob_process.php.
371 if ($reason_type == '2') {
372 $reason = $_POST['form_insurance'] . " coins: $thisadj";
373 $thisadj = 0;
374 } elseif ($reason_type == '3') {
375 $reason = $_POST['form_insurance'] . " dedbl: $thisadj";
376 $thisadj = 0;
377 } elseif ($reason_type == '4') {
378 $reason = $_POST['form_insurance'] . " ptresp: $thisadj $reason";
379 $thisadj = 0;
380 } elseif ($reason_type == '5') {
381 $reason = $_POST['form_insurance'] . " note: $thisadj $reason";
382 $thisadj = 0;
383 } else {
384 // An adjustment reason including "Ins" is assumed to be assigned by
385 // insurance, and in that case we identify which one by appending
386 // Ins1, Ins2 or Ins3.
387 if (strpos(strtolower($reason), 'ins') != false) {
388 $reason .= ' ' . $_POST['form_insurance'];
391 SLEOB::arPostAdjustment($patient_id, $encounter_id, $session_id, $thisadj, $code, $payer_type, $reason, $debug, '', $thiscodetype);
395 // Maintain which insurances are marked as finished.
397 $form_done = 0 + $_POST['form_done'];
398 $form_stmt_count = 0 + (int) $_POST['form_stmt_count'];
399 sqlStatement("UPDATE form_encounter SET last_level_closed = ?, stmt_count = ? WHERE pid = ? AND encounter = ?", array($form_done, $form_stmt_count, $patient_id, $encounter_id));
401 if (!empty($_POST['form_secondary'])) {
402 SLEOB::arSetupSecondary($patient_id, $encounter_id, $debug);
404 echo "<script>\n";
405 echo " if (opener.document.forms[0] != undefined) {\n";
406 echo " if (opener.document.forms[0].form_amount) {\n";
407 echo " var tmp = opener.document.forms[0].form_amount.value - " . attr($paytotal) . ";\n";
408 echo " opener.document.forms[0].form_amount.value = Number(tmp).toFixed(2);\n";
409 echo " }\n";
410 echo " }\n";
411 } else {
412 echo "<script>\n";
414 if ($info_msg) {
415 echo " alert(" . js_escape($info_msg) . ");\n";
417 if (!$debug && !$save_stay && !$_POST['isLastClosed']) {
418 echo "doClose();\n";
420 if (!$debug && ($save_stay || $_POST['isLastClosed'] || $_POST['enc_billing_note'])) {
421 if ($_POST['isLastClosed']) {
422 // save last closed level
423 $form_done = 0 + $_POST['form_done'];
424 $form_stmt_count = 0 + $_POST['form_stmt_count'];
425 sqlStatement("UPDATE form_encounter SET last_level_closed = ?, stmt_count = ? WHERE pid = ? AND encounter = ?", array($form_done, $form_stmt_count, $patient_id, $encounter_id));
426 // also update billing for aging
427 sqlStatement("UPDATE billing SET bill_date = ? WHERE pid = ? AND encounter = ?", array($form_deposit_date, $patient_id, $encounter_id));
428 if (!empty($_POST['form_secondary'])) {
429 SLEOB::arSetupSecondary($patient_id, $encounter_id, $debug);
433 if ($_POST['enc_billing_note']) {
434 // save enc billing note
435 sqlStatement("UPDATE form_encounter SET billing_note = ? WHERE pid = ? AND encounter = ?", array($_POST['enc_billing_note'], $patient_id, $encounter_id));
438 // will reload page w/o reposting
439 echo "location.replace(location)\n";
441 echo "</script>\n";
442 if (!$save_stay && !$_POST['isLastClosed']) {
443 exit();
447 // Get invoice charge details.
448 $codes = InvoiceSummary::arGetInvoiceSummary($patient_id, $encounter_id, true);
449 $pdrow = sqlQuery("select billing_note from patient_data where pid = ? limit 1", array($patient_id));
450 $bnrow = sqlQuery("select billing_note from form_encounter where pid = ? AND encounter = ? limit 1", array($patient_id, $encounter_id));
453 <div class="container-fluid">
454 <div class="row">
455 <h2><?php echo xlt('EOB Invoice'); ?></h2>
456 </div>
457 <div class="container-fluid">
458 <form class="form" action='sl_eob_invoice.php?id=<?php echo attr_url($trans_id); ?>' method='post' onsubmit='return validate(this)'>
459 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>"/>
460 <input type="hidden" name="isPosting" value="<?php echo attr($from_posting); ?>"/>
461 <input type="hidden" name="isLastClosed" value="" />
462 <fieldset>
463 <legend><?php echo xlt('Invoice Actions'); ?></legend>
464 <div class="form-row">
465 <div class="form-group col-lg">
466 <label class="col-form-label" for="form_name"><?php echo xlt('Patient'); ?>:</label>
467 <input type="text" class="form-control" id='form_name'
468 name='form_name'
469 value="<?php echo attr($ferow['fname']) . ' ' . attr($ferow['mname']) . ' ' . attr($ferow['lname']); ?>"
470 disabled />
471 </div>
472 <div class="form-group col-lg">
473 <label class="col-form-label" for="form_provider"><?php echo xlt('Provider'); ?>:</label>
474 <?php
475 $tmp = sqlQuery("SELECT fname, mname, lname " .
476 "FROM users WHERE id = ?", array($ferow['provider_id']));
477 $provider = text($tmp['fname']) . ' ' . text($tmp['mname']) . ' ' . text($tmp['lname']);
478 $tmp = sqlQuery("SELECT bill_date FROM billing WHERE " .
479 "pid = ? AND encounter = ? AND " .
480 "activity = 1 ORDER BY fee DESC, id ASC LIMIT 1", array($patient_id, $encounter_id));
481 $billdate = substr(($tmp['bill_date'] ?? '' . "Not Billed"), 0, 10);
483 <input type="text" class="form-control" id='form_provider'
484 name='form_provider' value="<?php echo attr($provider); ?>" disabled />
485 </div>
486 <div class="form-group col-lg">
487 <label class="col-form-label" for="form_invoice"><?php echo xlt('Invoice'); ?>:</label>
488 <input type="text" class="form-control" id='form_provider'
489 name='form_provider' value='<?php echo attr($patient_id) . "-" . attr($encounter_id); ?>'
490 disabled />
491 </div>
492 <div class="form-group col-lg">
493 <label class="col-form-label" for="svc_date"><?php echo xlt('Svc Date'); ?>:</label>
494 <input type="text" class="form-control" id='svc_date' name='form_provider'
495 value='<?php echo attr($svcdate); ?>' disabled />
496 </div>
497 <div class="card bg-light col-lg-4">
498 <div class="card-title mx-auto"><?php echo xlt('Insurance'); ?></div>
499 <?php
500 for ($i = 1; $i <= 3; ++$i) {
501 $payerid = SLEOB::arGetPayerID($patient_id, $svcdate, $i);
502 if ($payerid) {
503 $tmp = sqlQuery("SELECT name FROM insurance_companies WHERE id = ?", array($payerid));
504 echo "$i: " . $tmp['name'] . "<br />";
508 </div>
509 </div>
510 <div class="form-row">
511 <div class="form-group col-lg">
512 <label class="col-form-label" for="pt_billing_note"><?php echo xlt('Patient Billing Note'); ?>:</label>
513 <textarea name="pt_billing_note" id="pt_billing_note" class="form-control" cols="5" rows="1" readonly><?php echo text($pdrow['billing_note'] ?? ''); ?></textarea>
514 </div>
515 </div>
516 <div class="form-row">
517 <div class="form-group col-lg">
518 <label class="col-form-label" for="enc_billing_note"><?php echo xlt('Encounter Billing Note'); ?>:</label>
519 <textarea name="enc_billing_note" id="enc_billing_note" class="form-control" cols="5" rows="2"><?php echo text($bnrow['billing_note'] ?? ''); ?></textarea>
520 </div>
521 </div>
522 <div class="form-row">
523 <div class="form-group col-lg">
524 <label class="col-form-label" for="form_stmt_count"><?php echo xlt('Statements Sent'); ?>:</label>
525 <input type='text' name='form_stmt_count' id='form_stmt_count' class="form-control" value='<?php echo attr((0 + $ferow['stmt_count'])); ?>' />
526 </div>
527 <div class="form-group col-lg">
528 <label class="col-form-label" for="form_last_bill"><?php echo xlt('Last Bill Date'); ?>:</label>
529 <input type='text' name="form_last_bill" id='form_last_bill' class="form-control"
530 value ='<?php echo attr($billdate); ?>' disabled />
531 </div>
532 <div class="form-group col-lg">
533 <label class="col-form-label" for="form_reference"><?php echo xlt('Check/EOB No.'); ?>:</label>
534 <input type='text' name='form_reference' id='form_reference' class="form-control" value='' />
535 </div>
536 <div class="form-group col-lg">
537 <label class="col-form-label" for="form_check_date"><?php echo xlt('Check/EOB Date'); ?>:</label>
538 <input type='text' name='form_check_date' id='form_check_date' class='form-control datepicker' value='' />
539 </div>
540 <div class="form-group col-lg">
541 <label class="col-form-label" for="form_deposit_date"><?php echo xlt('Deposit Date'); ?>:</label>
542 <input type='text' name='form_deposit_date' id='form_deposit_date' class='form-control datepicker' value='' />
543 <input type='hidden' name='form_payer_id' value='' />
544 <input type='hidden' name='form_orig_reference' value='' />
545 <input type='hidden' name='form_orig_check_date' value='' />
546 <input type='hidden' name='form_orig_deposit_date' value='' />
547 <input type='hidden' name='form_pay_total' value='' />
548 </div>
549 </div>
550 <div class="form-row">
551 <div class="form-group col-lg">
552 <label class="col-form-label" for="type_code"><?php echo xlt('Now posting for'); ?>:</label>
553 <div class="pl-3">
554 <?php
555 $last_level_closed = 0 + $ferow['last_level_closed'];
557 <label class="radio-inline">
558 <input <?php echo $last_level_closed === 0 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Ins1")' type='radio'
559 value='Ins1' /><?php echo xlt('Ins1') ?>
560 </label>
561 <label class="radio-inline">
562 <input <?php echo $last_level_closed === 1 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Ins2")' type='radio'
563 value='Ins2' /><?php echo xlt('Ins2') ?>
564 </label>
565 <label class="radio-inline">
566 <input <?php echo $last_level_closed === 2 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Ins3")' type='radio'
567 value='Ins3' /><?php echo xlt('Ins3') ?>
568 </label>
569 <label class="radio-inline">
570 <input <?php echo $last_level_closed === 3 ? attr('checked') : ''; ?> name='form_insurance' onclick='setins("Pt")' type='radio'
571 value='Pt' /><?php echo xlt('Patient') ?>
572 </label>
573 <?php
574 // TBD: I think the following is unused and can be removed.
576 <input name='form_eobs' type='hidden' value='<?php echo attr($arrow['shipvia'] ?? '') ?>'/>
577 </div>
578 </div>
579 <div class="form-group col-lg" id='ins_done'>
580 <label class="col-form-label" for=""><?php echo xlt('Done with'); ?>:</label>
581 <a class="btn btn-save bg-light text-primary"
582 onclick="document.forms[0].isLastClosed.value='3'; document.forms[0].submit()"><?php echo xlt("Save Level"); ?>
583 </a>
584 <div class="pl-3">
585 <?php
586 // Write a checkbox for each insurance. It is to be checked when
587 // we no longer expect any payments from that company for the claim.
588 $last_level_closed = 0 + $ferow['last_level_closed'];
589 foreach (array(0 => 'None', 1 => 'Ins1', 2 => 'Ins2', 3 => 'Ins3') as $key => $value) {
590 if ($key && !SLEOB::arGetPayerID($patient_id, $svcdate, $key)) {
591 continue;
593 $checked = ($last_level_closed == $key) ? " checked" : "";
594 echo "<label class='radio-inline'>";
595 echo "<input type='radio' name='form_done' value='" . attr($key) . "'$checked />" . text($value);
596 echo "</label>";
599 </div>
600 </div>
601 <div class="form-group col-lg">
602 <label class="col-form-label" for=""><?php echo xlt('Secondary billing'); ?>:</label>
603 <div class="pl-3">
604 <label class="checkbox-inline">
605 <input name="form_secondary" type="checkbox" value="1" /><?php echo xlt('Needs secondary billing') ?>
606 </label>
607 </div>
608 </div>
609 </div>
610 </fieldset>
611 <fieldset>
612 <legend><?php echo xlt('Invoice Details'); ?></legend>
613 <div class="table-responsive">
614 <table class="table table-sm">
615 <thead>
616 <tr>
617 <th><?php echo xlt('Code') ?></th>
618 <th class="text-left"><?php echo xlt('Charge') ?></th>
619 <th class="text-left"><?php echo xlt('Balance') ?>&nbsp;</th>
620 <th><?php echo xlt('By/Source') ?></th>
621 <th><?php echo xlt('Date') ?></th>
622 <th><?php echo xlt('Pay') ?></th>
623 <th><?php echo xlt('Adjust') ?></th>
624 <th>&nbsp;</th>
625 <th><?php echo xlt('Reason') ?></th>
626 <?php
627 if ($ALLOW_DELETE) { ?>
628 <th><?php echo xlt('Del') ?></th>
629 <?php
630 } ?>
631 </tr>
632 </thead>
633 <?php
634 $firstProcCodeIndex = -1;
635 $encount = 0;
636 foreach ($codes as $code => $cdata) {
637 ++$encount;
638 $dispcode = $code;
640 // remember the index of the first entry whose code is not "CO-PAY", i.e. it's a legitimate proc code
641 if ($firstProcCodeIndex == -1 && strcmp($code, "CO-PAY") != 0) {
642 $firstProcCodeIndex = $encount;
645 // this sorts the details more or less chronologically:
646 ksort($cdata['dtl']);
647 foreach ($cdata['dtl'] as $dkey => $ddata) {
648 $ddate = substr($dkey, 0, 10);
649 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
650 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
652 $tmpchg = "";
653 $tmpadj = "";
654 if (!empty($ddata['chg']) && ($ddata['chg'] != 0)) {
655 if (isset($ddata['rsn'])) {
656 $tmpadj = 0 - $ddata['chg'];
657 } else {
658 $tmpchg = $ddata['chg'];
662 <tr>
663 <td class="detail" style="background:<?php echo $dispcode ? 'lightyellow' : ''; ?>"><?php echo text($dispcode); $dispcode = "" ?></td>
664 <td class="detail"><?php echo text(FormatMoney::getBucks($tmpchg)); ?></td>
665 <td class="detail">&nbsp;</td>
666 <td class="detail">
667 <?php
668 if (isset($ddata['plv'])) {
669 if (!$ddata['plv']) {
670 echo 'Pt/';
671 } else {
672 echo 'Ins' . text($ddata['plv']) . '/';
675 echo text($ddata['src'] ?? '');
677 </td>
678 <td class="detail"><?php echo text($ddate); ?></td>
679 <td class="detail"><?php echo text(FormatMoney::getBucks($ddata['pmt'] ?? '')); ?></td>
680 <td class="detail"><?php echo text(FormatMoney::getBucks($tmpadj ?? '')); ?></td>
681 <td class="detail">&nbsp;</td>
682 <td class="detail"><?php echo text($ddata['rsn'] ?? ''); ?></td>
683 <?php
684 if ($ALLOW_DELETE) { ?>
685 <td class="detail">
686 <?php
687 if (!empty($ddata['arseq'])) { ?>
688 <input name="form_del[<?php echo attr($ddata['arseq']); ?>]"
689 type="checkbox" />
690 <?php
691 } else {
692 ?> &nbsp;
693 <?php
694 } ?>
695 </td>
696 <?php } ?>
697 </tr>
698 <?php } // end of prior detail line ?>
699 <tr>
700 <td class="last_detail"><?php echo text($dispcode);
701 $dispcode = "" ?>
702 </td>
703 <td class="last_detail">&nbsp;</td>
704 <td class="last_detail">
705 <input name="form_line[<?php echo attr($code); ?>][bal]" type="hidden"
706 value="<?php echo attr(FormatMoney::getBucks($cdata['bal'] ?? '')); ?>" />
707 <input name="form_line[<?php echo attr($code); ?>][ins]" type="hidden"
708 value="<?php echo attr($cdata['ins'] ?? ''); ?>" />
709 <input name="form_line[<?php echo attr($code); ?>][code_type]" type="hidden"
710 value="<?php echo attr($cdata['code_type'] ?? ''); ?>" /> <?php echo text(FormatMoney::getBucks($cdata['bal'], true)); ?>
711 &nbsp;
712 </td>
713 <td class="last_detail"></td>
714 <td class="last_detail"></td>
715 <td class="last_detail">
716 <input name="form_line[<?php echo attr($code); ?>][pay]"
717 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 ?>)"
718 onfocus="this.select()" autofocus size="10" type="text" class="form-control"
719 value="0.00" />
720 </td>
721 <td class="last_detail">
722 <input name="form_line[<?php echo attr($code); ?>][adj]" size="10" type="text"
723 class="form-control"
724 value='<?php echo attr((!empty($totalAdjAmount)) ? $totalAdjAmount : '0.00'); ?>'
725 onclick="this.select()" />
726 </td>
727 <td class="last_detail text-center">
728 <a href="#" class="text-decoration-none" onclick="return writeoff(<?php echo attr_js($code); ?>)">WO</a>
729 </td>
730 <td class="last_detail">
731 <select class="form-control" name="form_line[<?php echo attr($code); ?>][reason]">
732 <?php
733 // Adjustment reasons are now taken from the list_options table.
734 echo " <option value=''></option>\n";
735 $ores = sqlStatement("SELECT option_id, title, is_default FROM list_options " .
736 "WHERE list_id = 'adjreason' AND activity = 1 ORDER BY seq, title");
737 while ($orow = sqlFetchArray($ores)) {
738 echo " <option value='" . attr($orow['option_id']) . "'";
739 if ($orow['is_default']) {
740 echo " selected";
742 echo ">" . text($orow['title']) . "</option>\n";
745 </select>
746 <?php
747 // TBD: Maybe a comment field would be good here, for appending
748 // to the reason.
750 </td>
751 <?php if ($ALLOW_DELETE) { ?>
752 <td class="last_detail">&nbsp;</td>
753 <?php } ?>
754 </tr>
755 <?php } // end of code ?>
756 </table>
757 </div>
758 </fieldset>
759 <?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 ?>
760 <div class="form-group col-lg clearfix">
761 <div class="col-sm-12 text-left position-override" id="search-btn">
762 <div class="btn-group" role="group">
763 <!-- @todo leave as I may still use sjp 08/2020 -->
764 <!--<button type='submit' class="btn btn-primary btn-save" name='form_save' id="btn-save-stay"
765 onclick="this.value='1';"><?php /*echo xlt("Save Current"); */?></button>-->
766 <button type='submit' class="btn btn-primary btn-save" name='form_save' id="btn-save"
767 onclick="this.value='2';"><?php echo xlt("Save"); ?></button>
768 <button type='button' class="btn btn-secondary btn-cancel" name='form_cancel'
769 id="btn-cancel" onclick='doClose()'><?php echo xlt("Close"); ?></button>
770 </div>
771 <?php if ($from_posting) { ?>
772 <button type='button' class="btn btn-secondary btn-view float-right" name='form_goto' id="btn-goto"
773 onclick="goEncounterSummary(event, <?php echo attr_js($patient_id) ?>)"><?php echo xlt("Past Encounters"); ?></button>
774 <?php } ?>
775 </div>
776 </div>
777 </form>
778 </div>
779 </div><!--End of container div-->
780 <?php if ($from_posting) { ?>
781 <script>
782 var f1 = opener.document.forms[0];
783 var f2 = document.forms[0];
784 if (f1.form_source) {
785 <?php
786 // These support creation and lookup of ar_session table entries:
787 echo " f2.form_reference.value = f1.form_source.value;\n";
788 echo " f2.form_check_date.value = f1.form_paydate.value;\n";
789 echo " //f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
790 echo " if (f1.form_deposit_date.value != '')\n";
791 echo " f2.form_deposit_date.value = f1.form_deposit_date.value;\n";
792 echo " else\n";
793 echo " f2.form_deposit_date.value = getFormattedToday();\n";
794 echo " f2.form_payer_id.value = f1.form_payer_id.value;\n";
795 echo " f2.form_pay_total.value = f1.form_amount.value;\n";
796 echo " f2.form_orig_reference.value = f1.form_source.value;\n";
797 echo " f2.form_orig_check_date.value = f1.form_paydate.value;\n";
798 echo " f2.form_orig_deposit_date.value = f1.form_deposit_date.value;\n";
800 // While I'm thinking about it, some notes about eob sessions.
801 // If they do not have all of the session key fields in the search
802 // page, then show a warning at the top of the invoice page.
803 // Also when they go to save the invoice page and a session key
804 // field has changed, alert them to that and allow a cancel.
806 // Another point... when posting EOBs, the incoming payer ID might
807 // not match the payer ID for the patient's insurance. This is
808 // because the same payer might be entered more than once into the
809 // insurance_companies table. I don't think it matters much.
812 setins("Ins1");
813 </script>
814 <?php } ?>
815 </body>
816 </html>