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.
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\Logging\EventAuditLogger
;
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' : '';
40 $posting_adj_disable = prevSetting('sl_eob_search.', 'posting_adj_disable', 'posting_adj_disable', $g_posting_adj_disable);
42 $posting_adj_disable = $g_posting_adj_disable;
45 // If we permit deletion of transactions. Might change this later.
50 // Format money for display.
52 function bucks($amount)
55 return sprintf("%.2f", $amount);
62 <?php Header
::setupHeader(['datetime-picker', 'opener', 'no_dialog']); ?
>
63 <title
><?php
echo xlt('EOB Posting - Invoice') ?
></title
>
66 const adjDisable
= <?php
echo js_escape($posting_adj_disable); ?
>;
67 // An insurance radio button is selected.
68 function setins(istr
) {
72 function goEncounterSummary(e
, pid
) {
74 if(typeof opener
.toEncSummary
=== 'function') {
75 opener
.toEncSummary(e
, pid
);
85 // Compute an adjustment that writes off the balance:
86 function writeoff(code
) {
87 const f
= document
.forms
[0];
88 const belement
= f
['form_line[' + code +
'][bal]'];
89 const pelement
= f
['form_line[' + code +
'][pay]'];
90 const aelement
= f
['form_line[' + code +
'][adj]'];
91 const relement
= f
['form_line[' + code +
'][reason]'];
92 const tmp
= belement
.value
- pelement
.value
;
93 aelement
.value
= Number(tmp
).toFixed(2);
94 if (aelement
.value
&& !relement
.value
) {
95 relement
.selectedIndex
= 1;
100 // Onsubmit handler. A good excuse to write some JavaScript.
101 function validate(f
) {
105 for (let i
= 0; i
< f
.elements
.length
; ++i
) {
106 let ename
= f
.elements
[i
].name
;
108 if (ename
.substring(0, 9) == 'form_del[') {
109 if (f
.elements
[i
].checked
) {
114 let pfxlen
= ename
.indexOf('[pay]');
118 let pfx
= ename
.substring(0, pfxlen
);
119 let code
= pfx
.substring(pfx
.indexOf('[') +
1, pfxlen
- 1);
120 let cPay
= parseFloat(f
[pfx +
'[pay]'].value
).toFixed(2);
121 let cAdjust
= parseFloat(f
[pfx +
'[adj]'].value
).toFixed(2);
123 if ((cPay
!== 0) || cAdjust
!== 0) {
127 if ((cAdjust
== 0 && ins_done
.value
== 'changed')) {
131 if ((cPay
!== 0) && isNaN(parseFloat(f
[pfx +
'[pay]'].value
))) {
132 let message
= <?php
echo xlj('Payment value for code') ?
> +
" " + code +
" " +
<?php
echo xlj('is not a number') ?
>;
133 (async (message
, time
) => {
134 await
asyncAlertMsg(message
, time
, 'danger', 'lg');
139 if ((cAdjust
!== 0) && isNaN(parseFloat(f
[pfx +
'[adj]'].value
))) {
140 let message
= <?php
echo xlj('Adjustment value for code') ?
> +
" " + code +
" " +
<?php
echo xlj('is not a number') ?
>;
141 (async (message
, time
) => {
142 await
asyncAlertMsg(message
, time
, 'danger', 'lg');
147 if ((cAdjust
!== 0) && !f
[pfx +
'[reason]'].value
&& !adjDisable
) {
148 let message
= <?php
echo xlj('Please select an adjustment reason for code') ?
> +
" " + code
;
149 (async (message
, time
) => {
150 await
asyncAlertMsg(message
, time
, 'danger', 'lg');
155 // TBD: validate the date format
157 // Check if save is clicked with nothing to post.
158 if (allempty
&& delcount
=== 0) {
159 let message
= <?php
echo xlj('Nothing to Post! Please review entries or use Cancel to exit transaction') ?
>;
160 (async (message
, time
) => {
161 await
asyncAlertMsg(message
, time
, 'danger', 'lg');
166 // Demand confirmation if deleting anything.
168 if (!confirm(<?php
echo xlj('Really delete'); ?
> +
' ' + delcount +
169 ' ' +
<?php
echo xlj('transactions'); ?
> +
'?' +
170 ' ' +
<?php
echo xlj('This action will be logged'); ?
> +
'!')
177 function getFormattedToday() {
178 let today
= new Date();
179 let dd
= today
.getDate();
180 let mm
= today
.getMonth() +
1; //January is 0!
181 let yyyy
= today
.getFullYear();
188 return (yyyy +
'-' + mm +
'-' + dd
);
191 // Update Payment Fields
192 function updateFields(payField
, adjField
, balField
, coPayField
, isFirstProcCode
) {
196 let coPayAmount
= 0.0;
198 // coPayFiled will be null if there is no co-pay entry in the fee sheet
200 coPayAmount
= coPayField
.value
;
203 // if balance field is 0.00, its value comes back as null, so check for nul-ness first
205 balAmount
= (balField
.value
) ? balField
.value
: 0;
209 payAmount
= (payField
.value
) ? payField
.value
: 0;
212 // alert('balance = >' + balAmount +'< payAmount = ' + payAmount + ' copay = ' + coPayAmount + ' isFirstProcCode = ' + isFirstProcCode);
214 // subtract the co-pay only from the first procedure code
215 if (isFirstProcCode
== 1) {
216 balAmount
= parseFloat(balAmount
) +
parseFloat(coPayAmount
);
223 adjAmount
= balAmount
- payAmount
;
224 // Assign rounded adjustment value back to TextField
225 adjField
.value
= adjAmount
= Math
.round(adjAmount
* 100) / 100;
229 $
('.datepicker').datetimepicker({
230 <?php
$datetimepicker_timepicker = false; ?
>
231 <?php
$datetimepicker_showseconds = false; ?
>
232 <?php
$datetimepicker_formatInput = true; ?
>
233 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
234 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
238 $
("#ins_done").on("change", function() {
239 $
("#ins_done").val('changed');
244 @media only screen
and (max
-width
: 768px
) {
247 text
-align
: left
!Important
;
256 .table
> tbody
> tr
> td
{
261 border
-bottom
: 1px
var(--black
) solid
;
265 @media
(min
-width
: 992px
) {
267 width
: 1000px
!Important
;
274 $trans_id = (int) $_GET['id'];
276 die(xlt("You cannot access this page directly."));
279 // A/R case, $trans_id matches form_encounter.id.
280 $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));
282 die("There is no encounter with form_encounter.id = '" . text($trans_id) . "'.");
284 $patient_id = (int) $ferow['pid'];
285 $encounter_id = (int) $ferow['encounter'];
286 $svcdate = substr($ferow['date'], 0, 10);
287 $form_payer_id = (!empty($_POST['form_payer_id'])) ?
(0 +
$_POST['form_payer_id']) : 0;
288 $form_reference = $_POST['form_reference'] ??
null;
289 $form_check_date = fixDate(($_POST['form_check_date'] ??
''), date('Y-m-d'));
290 $form_deposit_date = fixDate(($_POST['form_deposit_date'] ??
''), $form_check_date);
291 $form_pay_total = (!empty($_POST['form_pay_total'])) ?
(0 +
$_POST['form_pay_total']) : 0;
294 if (preg_match('/^Ins(\d)/i', ($_POST['form_insurance'] ??
''), $matches)) {
295 $payer_type = $matches[1];
298 if (!empty($_POST['form_save']) ||
!empty($_POST['form_cancel']) ||
!empty($_POST['isLastClosed']) ||
!empty($_POST['billing_note'])) {
299 if (!empty($_POST['form_save'])) {
300 if (!CsrfUtils
::verifyCsrfToken($_POST["csrf_token_form"])) {
301 CsrfUtils
::csrfNotVerified();
305 echo "<p><b>" . xlt("This module is in test mode. The database will not be changed.") . "</b><p>\n";
308 $session_id = SLEOB
::arGetSession($form_payer_id, $form_reference, $form_check_date, $form_deposit_date, $form_pay_total);
309 // The sl_eob_search page needs its invoice links modified to invoke
310 // javascript to load form parms for all the above and submit.
311 // At the same time that page would be modified to work off the
312 // openemr database exclusively.
313 // And back to the sl_eob_invoice page, I think we may want to move
314 // the source input fields from row level to header level.
316 // Handle deletes. row_delete() is borrowed from deleter.php.
317 if ($ALLOW_DELETE && !$debug) {
318 if (!empty($_POST['form_del']) && is_array($_POST['form_del'])) {
319 foreach ($_POST['form_del'] as $arseq => $dummy) {
323 "pid = '" . add_escape_custom($patient_id) .
324 "' AND encounter = '" . add_escape_custom($encounter_id) .
325 "' AND sequence_no = '" . add_escape_custom($arseq) .
326 "' AND deleted IS NULL"
333 foreach ($_POST['form_line'] as $code => $cdata) {
334 $thispay = trim($cdata['pay']);
335 $thisadj = trim($cdata['adj']);
336 $thisins = trim($cdata['ins']);
337 $thiscodetype = trim($cdata['code_type']);
338 $reason = $cdata['reason'];
340 // Get the adjustment reason type. Possible values are:
341 // 1 = Charge adjustment
348 $tmp = sqlQuery("SELECT option_value FROM list_options WHERE list_id = 'adjreason' AND activity = 1 AND option_id = ?", array($reason));
349 if (empty($tmp['option_value'])) {
350 // This should not happen but if it does, apply old logic.
351 if (preg_match("/To copay/", $reason)) {
353 } elseif (preg_match("/To ded'ble/", $reason)) {
356 $info_msg .= xl("No adjustment reason type found for") . " \"$reason\". ";
358 $reason_type = $tmp['option_value'];
366 if (0.0 +
$thispay) {
367 SLEOB
::arPostPayment($patient_id, $encounter_id, $session_id, $thispay, $code, $payer_type, '', $debug, '', $thiscodetype);
368 $paytotal +
= $thispay;
371 // Be sure to record adjustment reasons, even for zero adjustments if
372 // they happen to be comments.
375 ($reason && $reason_type == 5) ||
376 ($reason && ($reason_type > 1 && $reason_type < 6))
378 // "To copay" and "To ded'ble" need to become a comment in a zero
379 // adjustment, formatted just like sl_eob_process.php.
380 if ($reason_type == '2') {
381 $reason = $_POST['form_insurance'] . " coins: $thisadj";
383 } elseif ($reason_type == '3') {
384 $reason = $_POST['form_insurance'] . " dedbl: $thisadj";
386 } elseif ($reason_type == '4') {
387 $reason = $_POST['form_insurance'] . " ptresp: $thisadj $reason";
389 } elseif ($reason_type == '5') {
390 $reason = $_POST['form_insurance'] . " note: $thisadj $reason";
393 // An adjustment reason including "Ins" is assumed to be assigned by
394 // insurance, and in that case we identify which one by appending
395 // Ins1, Ins2 or Ins3.
396 if (strpos(strtolower($reason), 'ins') != false) {
397 $reason .= ' ' . $_POST['form_insurance'];
400 SLEOB
::arPostAdjustment($patient_id, $encounter_id, $session_id, $thisadj, $code, $payer_type, $reason, $debug, '', $thiscodetype);
404 // Maintain which insurances are marked as finished.
406 $form_done = 0 +
$_POST['form_done'];
407 $form_stmt_count = 0 +
$_POST['form_stmt_count'];
408 sqlStatement("UPDATE form_encounter SET last_level_closed = ?, stmt_count = ? WHERE pid = ? AND encounter = ?", array($form_done, $form_stmt_count, $patient_id, $encounter_id));
410 if (!empty($_POST['form_secondary'])) {
411 SLEOB
::arSetupSecondary($patient_id, $encounter_id, $debug);
414 echo " if (opener.document.forms[0] != undefined) {\n";
415 echo " if (opener.document.forms[0].form_amount) {\n";
416 echo " var tmp = opener.document.forms[0].form_amount.value - " . attr($paytotal) . ";\n";
417 echo " opener.document.forms[0].form_amount.value = Number(tmp).toFixed(2);\n";
424 echo " alert(" . js_escape($info_msg) . ");\n";
426 if (!$debug && !$save_stay && !$_POST['isLastClosed']) {
429 if (!$debug && ($save_stay ||
$_POST['isLastClosed'] ||
$_POST['billing_note'])) {
430 if ($_POST['isLastClosed']) {
431 // save last closed level
432 $form_done = 0 +
$_POST['form_done'];
433 $form_stmt_count = 0 +
$_POST['form_stmt_count'];
434 sqlStatement("UPDATE form_encounter SET last_level_closed = ?, stmt_count = ? WHERE pid = ? AND encounter = ?", array($form_done, $form_stmt_count, $patient_id, $encounter_id));
435 // also update billing for aging
436 sqlStatement("UPDATE billing SET bill_date = ? WHERE pid = ? AND encounter = ?", array($form_deposit_date, $patient_id, $encounter_id));
437 if (!empty($_POST['form_secondary'])) {
438 SLEOB
::arSetupSecondary($patient_id, $encounter_id, $debug);
442 if ($_POST['billing_note']) {
443 // save last closed level
444 sqlStatement("UPDATE form_encounter SET billing_note = ? WHERE pid = ? AND encounter = ?", array($_POST['billing_note'], $patient_id, $encounter_id));
447 // will reload page w/o reposting
448 echo "location.replace(location)\n";
451 if (!$save_stay && !$_POST['isLastClosed']) {
456 // Get invoice charge details.
457 $codes = InvoiceSummary
::arGetInvoiceSummary($patient_id, $encounter_id, true);
458 $pdrow = sqlQuery("select billing_note from patient_data where pid = ? limit 1", array($patient_id));
459 $bnrow = sqlQuery("select billing_note from form_encounter where pid = ? AND encounter = ? limit 1", array($patient_id, $encounter_id));
462 <div
class="container-fluid">
464 <h2
><?php
echo xlt('EOB Invoice'); ?
></h2
>
466 <div
class="container-fluid">
467 <form
class="form" action
='sl_eob_invoice.php?id=<?php echo attr_url($trans_id); ?>' method
='post' onsubmit
='return validate(this)'>
468 <input type
="hidden" name
="csrf_token_form" value
="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>"/>
469 <input type
="hidden" name
="isPosting" value
="<?php echo attr($from_posting); ?>"/>
470 <input type
="hidden" name
="isLastClosed" value
="" />
472 <legend
><?php
echo xlt('Invoice Actions'); ?
></legend
>
473 <div
class="form-row">
474 <div
class="form-group col-lg">
475 <label
class="col-form-label" for="form_name"><?php
echo xlt('Patient'); ?
>:</label
>
476 <input type
="text" class="form-control" id
='form_name'
478 value
="<?php echo attr($ferow['fname']) . ' ' . attr($ferow['mname']) . ' ' . attr($ferow['lname']); ?>"
481 <div
class="form-group col-lg">
482 <label
class="col-form-label" for="form_provider"><?php
echo xlt('Provider'); ?
>:</label
>
484 $tmp = sqlQuery("SELECT fname, mname, lname " .
485 "FROM users WHERE id = ?", array($ferow['provider_id']));
486 $provider = text($tmp['fname']) . ' ' . text($tmp['mname']) . ' ' . text($tmp['lname']);
487 $tmp = sqlQuery("SELECT bill_date FROM billing WHERE " .
488 "pid = ? AND encounter = ? AND " .
489 "activity = 1 ORDER BY fee DESC, id ASC LIMIT 1", array($patient_id, $encounter_id));
490 $billdate = substr(($tmp['bill_date'] ??
'' . "Not Billed"), 0, 10);
492 <input type
="text" class="form-control" id
='form_provider'
493 name
='form_provider' value
="<?php echo attr($provider); ?>" disabled
/>
495 <div
class="form-group col-lg">
496 <label
class="col-form-label" for="form_invoice"><?php
echo xlt('Invoice'); ?
>:</label
>
497 <input type
="text" class="form-control" id
='form_provider'
498 name
='form_provider' value
='<?php echo attr($patient_id) . "-" . attr($encounter_id); ?>'
501 <div
class="form-group col-lg">
502 <label
class="col-form-label" for="svc_date"><?php
echo xlt('Svc Date'); ?
>:</label
>
503 <input type
="text" class="form-control" id
='svc_date' name
='form_provider'
504 value
='<?php echo attr($svcdate); ?>' disabled
/>
506 <div
class="card bg-light col-lg-4">
507 <div
class="card-title mx-auto"><?php
echo xlt('Insurance'); ?
></div
>
509 for ($i = 1; $i <= 3; ++
$i) {
510 $payerid = SLEOB
::arGetPayerID($patient_id, $svcdate, $i);
512 $tmp = sqlQuery("SELECT name FROM insurance_companies WHERE id = ?", array($payerid));
513 echo "$i: " . $tmp['name'] . "<br />";
519 <div
class="form-row">
520 <div
class="form-group col-lg">
521 <label
class="col-form-label" for="billing_note"><?php
echo xlt('Billing Note'); ?
>:</label
>
522 <textarea name
="billing_note" id
="billing_note" class="form-control" cols
="5" rows
="2"><?php
echo text(($pdrow['billing_note'] ??
'')) . "\n" . text(($bnrow['billing_note'] ??
'')); ?
></textarea
>
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'); ?
>:</label
>
528 <input type
='text' name
='form_stmt_count' id
='form_stmt_count' class="form-control" value
='<?php echo attr((0 + $ferow['stmt_count
'])); ?>' />
530 <div
class="form-group col-lg">
531 <label
class="col-form-label" for="form_last_bill"><?php
echo xlt('Last Bill Date'); ?
>:</label
>
532 <input type
='text' name
="form_last_bill" id
='form_last_bill' class="form-control"
533 value
='<?php echo attr($billdate); ?>' disabled
/>
535 <div
class="form-group col-lg">
536 <label
class="col-form-label" for="form_reference"><?php
echo xlt('Check/EOB No.'); ?
>:</label
>
537 <input type
='text' name
='form_reference' id
='form_reference' class="form-control" value
='' />
539 <div
class="form-group col-lg">
540 <label
class="col-form-label" for="form_check_date"><?php
echo xlt('Check/EOB Date'); ?
>:</label
>
541 <input type
='text' name
='form_check_date' id
='form_check_date' class='form-control datepicker' value
='' />
543 <div
class="form-group col-lg">
544 <label
class="col-form-label" for="form_deposit_date"><?php
echo xlt('Deposit Date'); ?
>:</label
>
545 <input type
='text' name
='form_deposit_date' id
='form_deposit_date' class='form-control datepicker' value
='' />
546 <input type
='hidden' name
='form_payer_id' value
='' />
547 <input type
='hidden' name
='form_orig_reference' value
='' />
548 <input type
='hidden' name
='form_orig_check_date' value
='' />
549 <input type
='hidden' name
='form_orig_deposit_date' value
='' />
550 <input type
='hidden' name
='form_pay_total' value
='' />
553 <div
class="form-row">
554 <div
class="form-group col-lg">
555 <label
class="col-form-label" for="type_code"><?php
echo xlt('Now posting for'); ?
>:</label
>
558 $last_level_closed = 0 +
$ferow['last_level_closed'];
560 <label
class="radio-inline">
561 <input
<?php
echo $last_level_closed === 0 ?
attr('checked') : ''; ?
> name
='form_insurance' onclick
='setins("Ins1")' type
='radio'
562 value
='Ins1' /><?php
echo xlt('Ins1') ?
>
564 <label
class="radio-inline">
565 <input
<?php
echo $last_level_closed === 1 ?
attr('checked') : ''; ?
> name
='form_insurance' onclick
='setins("Ins2")' type
='radio'
566 value
='Ins2' /><?php
echo xlt('Ins2') ?
>
568 <label
class="radio-inline">
569 <input
<?php
echo $last_level_closed === 2 ?
attr('checked') : ''; ?
> name
='form_insurance' onclick
='setins("Ins3")' type
='radio'
570 value
='Ins3' /><?php
echo xlt('Ins3') ?
>
572 <label
class="radio-inline">
573 <input
<?php
echo $last_level_closed === 3 ?
attr('checked') : ''; ?
> name
='form_insurance' onclick
='setins("Pt")' type
='radio'
574 value
='Pt' /><?php
echo xlt('Patient') ?
>
577 // TBD: I think the following is unused and can be removed.
579 <input name
='form_eobs' type
='hidden' value
='<?php echo attr($arrow['shipvia
'] ?? '') ?>'/>
582 <div
class="form-group col-lg" id
='ins_done'>
583 <label
class="col-form-label" for=""><?php
echo xlt('Done with'); ?
>:</label
>
584 <a
class="btn btn-save bg-light text-primary"
585 onclick
="document.forms[0].isLastClosed.value='3'; document.forms[0].submit()"><?php
echo xlt("Save Level"); ?
>
589 // Write a checkbox for each insurance. It is to be checked when
590 // we no longer expect any payments from that company for the claim.
591 $last_level_closed = 0 +
$ferow['last_level_closed'];
592 foreach (array(0 => 'None', 1 => 'Ins1', 2 => 'Ins2', 3 => 'Ins3') as $key => $value) {
593 if ($key && !SLEOB
::arGetPayerID($patient_id, $svcdate, $key)) {
596 $checked = ($last_level_closed == $key) ?
" checked" : "";
597 echo "<label class='radio-inline'>";
598 echo "<input type='radio' name='form_done' value='" . attr($key) . "'$checked />" . text($value);
604 <div
class="form-group col-lg">
605 <label
class="col-form-label" for=""><?php
echo xlt('Secondary billing'); ?
>:</label
>
607 <label
class="checkbox-inline">
608 <input name
="form_secondary" type
="checkbox" value
="1" /><?php
echo xlt('Needs secondary billing') ?
>
615 <legend
><?php
echo xlt('Invoice Details'); ?
></legend
>
616 <div
class="table-responsive">
617 <table
class="table table-sm">
620 <th
><?php
echo xlt('Code') ?
></th
>
621 <th
class="text-left"><?php
echo xlt('Charge') ?
></th
>
622 <th
class="text-left"><?php
echo xlt('Balance') ?
> 
;</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
>
628 <th
><?php
echo xlt('Reason') ?
></th
>
630 if ($ALLOW_DELETE) { ?
>
631 <th
><?php
echo xlt('Del') ?
></th
>
637 $firstProcCodeIndex = -1;
639 foreach ($codes as $code => $cdata) {
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];
657 if (!empty($ddata['chg']) && ($ddata['chg'] != 0)) {
658 if (isset($ddata['rsn'])) {
659 $tmpadj = 0 - $ddata['chg'];
661 $tmpchg = $ddata['chg'];
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"> 
;</td
>
671 if (isset($ddata['plv'])) {
672 if (!$ddata['plv']) {
675 echo 'Ins' . text($ddata['plv']) . '/';
678 echo text($ddata['src'] ??
'');
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"> 
;</td
>
685 <td
class="detail"><?php
echo text($ddata['rsn'] ??
''); ?
></td
>
687 if ($ALLOW_DELETE) { ?
>
690 if (!empty($ddata['arseq'])) { ?
>
691 <input name
="form_del[<?php echo attr($ddata['arseq']); ?>]"
701 <?php
} // end of prior detail line ?>
703 <td
class="last_detail"><?php
echo text($dispcode);
706 <td
class="last_detail"> 
;</td
>
707 <td
class="last_detail">
708 <input name
="form_line[<?php echo attr($code); ?>][bal]" type
="hidden"
709 value
="<?php echo attr(bucks($cdata['bal'])); ?>" />
710 <input name
="form_line[<?php echo attr($code); ?>][ins]" type
="hidden"
711 value
="<?php echo attr($cdata['ins'] ?? ''); ?>" />
712 <input name
="form_line[<?php echo attr($code); ?>][code_type]" type
="hidden"
713 value
="<?php echo attr($cdata['code_type'] ?? ''); ?>" /> <?php
echo text(sprintf("%.2f", $cdata['bal'])); ?
>
716 <td
class="last_detail"></td
>
717 <td
class="last_detail"></td
>
718 <td
class="last_detail">
719 <input name
="form_line[<?php echo attr($code); ?>][pay]"
720 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 ?>)"
721 onfocus
="this.select()" autofocus size
="10" type
="text" class="form-control"
724 <td
class="last_detail">
725 <input name
="form_line[<?php echo attr($code); ?>][adj]" size
="10" type
="text"
727 value
='<?php echo attr((!empty($totalAdjAmount)) ? $totalAdjAmount : '0.00'); ?>'
728 onclick
="this.select()" />
730 <td
class="last_detail text-center">
731 <a href
="#" class="text-decoration-none" onclick
="return writeoff(<?php echo attr_js($code); ?>)">WO
</a
>
733 <td
class="last_detail">
734 <select
class="form-control" name
="form_line[<?php echo attr($code); ?>][reason]">
736 // Adjustment reasons are now taken from the list_options table.
737 echo " <option value=''></option>\n";
738 $ores = sqlStatement("SELECT option_id, title, is_default FROM list_options " .
739 "WHERE list_id = 'adjreason' AND activity = 1 ORDER BY seq, title");
740 while ($orow = sqlFetchArray($ores)) {
741 echo " <option value='" . attr($orow['option_id']) . "'";
742 if ($orow['is_default']) {
745 echo ">" . text($orow['title']) . "</option>\n";
750 // TBD: Maybe a comment field would be good here, for appending
754 <?php
if ($ALLOW_DELETE) { ?
>
755 <td
class="last_detail"> 
;</td
>
758 <?php
} // end of code ?>
762 <?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 ?>
763 <div
class="form-group col-lg clearfix">
764 <div
class="col-sm-12 text-left position-override" id
="search-btn">
765 <div
class="btn-group" role
="group">
766 <!-- @todo leave
as I may still
use sjp
08/2020 -->
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"); ?
></button
>
771 <button type
='button' class="btn btn-secondary btn-cancel" name
='form_cancel'
772 id
="btn-cancel" onclick
='doClose()'><?php
echo xlt("Close"); ?
></button
>
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(event, <?php echo attr_js($patient_id) ?>)"><?php
echo xlt("Past Encounters"); ?
></button
>
782 </div
><!--End of container div
-->
783 <?php
if ($from_posting) { ?
>
785 var f1
= opener
.document
.forms
[0];
786 var f2
= document
.forms
[0];
787 if (f1
.form_source
) {
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";
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.