* @author Roberto Vasquez * @author Terry Hill * @author Jerry Padgett * @author Stephen Waite * @author Brady Miller * @copyright Copyright (c) 2005-2020 Rod Roark * @copyright Copyright (c) 2018-2020 Stephen Waite * @copyright Copyright (c) 2019-2020 Brady Miller * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 */ require_once("../globals.php"); require_once("$srcdir/patient.inc"); require_once("$srcdir/forms.inc"); require_once("../../custom/code_types.inc.php"); require_once "$srcdir/user.inc"; require_once("$srcdir/payment.inc.php"); use OpenEMR\Billing\InvoiceSummary; use OpenEMR\Billing\SLEOB; use OpenEMR\Common\Csrf\CsrfUtils; use OpenEMR\Common\Logging\EventAuditLogger; use OpenEMR\Core\Header; $debug = 0; // set to 1 for debugging mode $save_stay = (!empty($_REQUEST['form_save']) && ($_REQUEST['form_save'] == '1')) ? true : false; $from_posting = (0 + ($_REQUEST['isPosting'] ?? null)) ? 1 : 0; $g_posting_adj_disable = $GLOBALS['posting_adj_disable'] ? 'checked' : ''; if ($from_posting) { $posting_adj_disable = prevSetting('sl_eob_search.', 'posting_adj_disable', 'posting_adj_disable', $g_posting_adj_disable); } else { $posting_adj_disable = $g_posting_adj_disable; } // If we permit deletion of transactions. Might change this later. $ALLOW_DELETE = true; $info_msg = ""; // Format money for display. // function bucks($amount) { if ($amount) { return sprintf("%.2f", $amount); } } ?> <?php echo xlt('EOB Posting - Invoice') ?> " . xlt("This module is in test mode. The database will not be changed.") . "

\n"; } $session_id = SLEOB::arGetSession($form_payer_id, $form_reference, $form_check_date, $form_deposit_date, $form_pay_total); // The sl_eob_search page needs its invoice links modified to invoke // javascript to load form parms for all the above and submit. // At the same time that page would be modified to work off the // openemr database exclusively. // And back to the sl_eob_invoice page, I think we may want to move // the source input fields from row level to header level. // Handle deletes. row_delete() is borrowed from deleter.php. if ($ALLOW_DELETE && !$debug) { if (!empty($_POST['form_del']) && is_array($_POST['form_del'])) { foreach ($_POST['form_del'] as $arseq => $dummy) { row_modify( "ar_activity", "deleted = NOW()", "pid = '" . add_escape_custom($patient_id) . "' AND encounter = '" . add_escape_custom($encounter_id) . "' AND sequence_no = '" . add_escape_custom($arseq) . "' AND deleted IS NULL" ); } } } $paytotal = 0; foreach ($_POST['form_line'] as $code => $cdata) { $thispay = trim($cdata['pay']); $thisadj = trim($cdata['adj']); $thisins = trim($cdata['ins']); $thiscodetype = trim($cdata['code_type']); $reason = $cdata['reason']; // Get the adjustment reason type. Possible values are: // 1 = Charge adjustment // 2 = Coinsurance // 3 = Deductible // 4 = Other pt resp // 5 = Comment $reason_type = '1'; if ($reason) { $tmp = sqlQuery("SELECT option_value FROM list_options WHERE list_id = 'adjreason' AND activity = 1 AND option_id = ?", array($reason)); if (empty($tmp['option_value'])) { // This should not happen but if it does, apply old logic. if (preg_match("/To copay/", $reason)) { $reason_type = 2; } elseif (preg_match("/To ded'ble/", $reason)) { $reason_type = 3; } $info_msg .= xl("No adjustment reason type found for") . " \"$reason\". "; } else { $reason_type = $tmp['option_value']; } } if (!$thisins) { $thisins = 0; } if (0.0 + $thispay) { SLEOB::arPostPayment($patient_id, $encounter_id, $session_id, $thispay, $code, $payer_type, '', $debug, '', $thiscodetype); $paytotal += $thispay; } // Be sure to record adjustment reasons, even for zero adjustments if // they happen to be comments. if ( (0.0 + $thisadj) || ($reason && $reason_type == 5) || ($reason && ($reason_type > 1 && $reason_type < 6)) ) { // "To copay" and "To ded'ble" need to become a comment in a zero // adjustment, formatted just like sl_eob_process.php. if ($reason_type == '2') { $reason = $_POST['form_insurance'] . " coins: $thisadj"; $thisadj = 0; } elseif ($reason_type == '3') { $reason = $_POST['form_insurance'] . " dedbl: $thisadj"; $thisadj = 0; } elseif ($reason_type == '4') { $reason = $_POST['form_insurance'] . " ptresp: $thisadj $reason"; $thisadj = 0; } elseif ($reason_type == '5') { $reason = $_POST['form_insurance'] . " note: $thisadj $reason"; $thisadj = 0; } else { // An adjustment reason including "Ins" is assumed to be assigned by // insurance, and in that case we identify which one by appending // Ins1, Ins2 or Ins3. if (strpos(strtolower($reason), 'ins') != false) { $reason .= ' ' . $_POST['form_insurance']; } } SLEOB::arPostAdjustment($patient_id, $encounter_id, $session_id, $thisadj, $code, $payer_type, $reason, $debug, '', $thiscodetype); } } // Maintain which insurances are marked as finished. $form_done = 0 + $_POST['form_done']; $form_stmt_count = 0 + $_POST['form_stmt_count']; sqlStatement("UPDATE form_encounter SET last_level_closed = ?, stmt_count = ? WHERE pid = ? AND encounter = ?", array($form_done, $form_stmt_count, $patient_id, $encounter_id)); if (!empty($_POST['form_secondary'])) { SLEOB::arSetupSecondary($patient_id, $encounter_id, $debug); } echo "\n"; if (!$save_stay && !$_POST['isLastClosed']) { exit(); } } // Get invoice charge details. $codes = InvoiceSummary::arGetInvoiceSummary($patient_id, $encounter_id, true); $pdrow = sqlQuery("select billing_note from patient_data where pid = ? limit 1", array($patient_id)); $bnrow = sqlQuery("select billing_note from form_encounter where pid = ? AND encounter = ? limit 1", array($patient_id, $encounter_id)); ?>

"; } } ?>
' />
'/>
'None', 1 => 'Ins1', 2 => 'Ins2', 3 => 'Ins3') as $key => $value) { if ($key && !SLEOB::arGetPayerID($patient_id, $svcdate, $key)) { continue; } $checked = ($last_level_closed == $key) ? " checked" : ""; echo ""; } ?>
$cdata) { ++$encount; $dispcode = $code; // remember the index of the first entry whose code is not "CO-PAY", i.e. it's a legitimate proc code if ($firstProcCodeIndex == -1 && strcmp($code, "CO-PAY") != 0) { $firstProcCodeIndex = $encount; } // this sorts the details more or less chronologically: ksort($cdata['dtl']); foreach ($cdata['dtl'] as $dkey => $ddata) { $ddate = substr($dkey, 0, 10); if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) { $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3]; } $tmpchg = ""; $tmpadj = ""; if (!empty($ddata['chg']) && ($ddata['chg'] != 0)) { if (isset($ddata['rsn'])) { $tmpadj = 0 - $ddata['chg']; } else { $tmpchg = $ddata['chg']; } } ?>
   
     
    ' onclick="this.select()" /> WO