You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
16 KiB
387 lines
16 KiB
<?php |
|
|
|
/** |
|
* UB04 Functions |
|
* |
|
* @package OpenEMR |
|
* @link http://www.open-emr.org |
|
* @author Jerry Padgett <sjpadgett@gmail.com> |
|
* @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com> |
|
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 |
|
*/ |
|
|
|
require_once("../globals.php"); |
|
|
|
use OpenEMR\Billing\BillingUtilities; |
|
use OpenEMR\Billing\Claim; |
|
use OpenEMR\Billing\X125010837I; |
|
use OpenEMR\Pdf\PdfCreator; |
|
|
|
function ub04_dispose() |
|
{ |
|
$dispose = isset($_POST['handler']) ? $_POST['handler'] : $_GET['handler']; |
|
if ($dispose) { |
|
if ($dispose == "edit_save") { |
|
$ub04id = isset($_POST['ub04id']) ? $_POST['ub04id'] : $_GET['ub04id']; |
|
$pid = isset($_POST['pid']) ? $_POST['pid'] : $_GET['pid']; |
|
$encounter = isset($_POST['encounter']) ? $_POST['encounter'] : $_GET['encounter']; |
|
$action = $_REQUEST['action']; |
|
$ub04id = json_decode($ub04id, true); |
|
saveTemplate($encounter, $pid, $ub04id, $action); |
|
exit(); |
|
} elseif ($dispose == "payer_save") { |
|
$ub04id = isset($_POST['ub04id']) ? $_POST['ub04id'] : $_GET['ub04id']; |
|
$payerid = isset($_POST['payerid']) ? $_POST['payerid'] : $_GET['payerid']; |
|
savePayerTemplate($payerid, $ub04id); |
|
exit("done"); |
|
} elseif ($dispose == "batch_save") { |
|
$pid = isset($_POST['pid']) ? $_POST['pid'] : $_GET['pid']; |
|
$encounter = isset($_POST['encounter']) ? $_POST['encounter'] : $_GET['encounter']; |
|
$ub04id = isset($_POST['ub04id']) ? $_POST['ub04id'] : $_GET['ub04id']; |
|
saveTemplate($encounter, $pid, $ub04id, $dispose); |
|
exit("done"); |
|
} elseif ($dispose == "reset_claim") { |
|
$pid = isset($_POST['pid']) ? $_POST['pid'] : $_GET['pid']; |
|
$encounter = isset($_POST['encounter']) ? $_POST['encounter'] : $_GET['encounter']; |
|
// clear claim first otherwise get ub04 returns cuurent version. |
|
// |
|
$flg = exist_ub04_claim($pid, $encounter, true); |
|
if ($flg === true) { |
|
BillingUtilities::updateClaim(false, $pid, $encounter, -1, -1, -1, -1, '', 'ub04', -1, 0, ""); |
|
} |
|
$ub04id = get_ub04_array($pid, $encounter); |
|
$ub04id = json_encode($ub04id); |
|
|
|
echo $ub04id; |
|
exit(); |
|
} |
|
die(xlt('Do not know what to do!')); |
|
} |
|
} |
|
|
|
function get_payer_defaults($payerid) |
|
{ |
|
$p = sqlQuery("SELECT insurance_companies.* FROM insurance_companies WHERE insurance_companies.id = ?", array($payerid)); |
|
if ($p['claim_template']) { |
|
return $p['claim_template']; |
|
} else { |
|
return json_encode(array()); |
|
} |
|
} |
|
|
|
function savePayerTemplate($payerid, $ubo4id) |
|
{ |
|
$ub04id = json_encode($ub04id); |
|
sqlStatement("update insurance_companies set claim_template= ? where id = ?", array( |
|
$ubo4id, |
|
$payerid |
|
)); |
|
} |
|
|
|
function saveTemplate($encounter, $pid, $ub04id, $action = 'form') |
|
{ |
|
global $isAuthorized; |
|
if ($action != 'batch_save') { |
|
$ub04id = json_encode($ub04id); |
|
$isAuthorized = true; |
|
ob_start(); |
|
require(dirname(__file__) . "/ub04_form.php"); |
|
$htmlin = ob_get_clean(); |
|
$isAuthorized = false; |
|
ub04Dispose('download', $htmlin, "ub04_download.pdf", $action); |
|
} |
|
$flg = exist_ub04_claim($pid, $encounter, true); |
|
if ($flg === true) { |
|
BillingUtilities::updateClaim(false, $pid, $encounter, - 1, - 1, - 1, - 1, '', 'ub04', - 1, 0, $ub04id); |
|
} else { |
|
BillingUtilities::updateClaim(true, $pid, $encounter, - 1, - 1, 1, 1, '', 'ub04', - 1, 0, $ub04id); |
|
} |
|
} |
|
|
|
function buildTemplate(string $pid = null, string $encounter = null, $htmlin, string $action = null, &$log) |
|
{ |
|
global $srcdir, $isAuthorized; |
|
|
|
if (!$action) { |
|
$action = 'form'; |
|
} |
|
$ub04id = get_ub04_array($pid, $encounter, $log); |
|
|
|
$ub04id = json_encode($ub04id); |
|
|
|
$isAuthorized = true; |
|
ob_start(); |
|
require $srcdir . "/../interface/billing/ub04_form.php"; |
|
$htmlin = ob_get_clean(); |
|
$isAuthorized = false; |
|
|
|
return $htmlin; |
|
} |
|
|
|
function ub04Dispose($dispose = 'download', $htmlin = "", $filename = "ub04.pdf", $form_action = "") |
|
{ |
|
$top = isset($_POST["left_ubmargin"]) ? $_POST["left_ubmargin"] : $GLOBALS['left_ubmargin_default']; |
|
$side = isset($_POST["top_ubmargin"]) ? $_POST["top_ubmargin"] : $GLOBALS['top_ubmargin_default']; |
|
$form_filename = $GLOBALS['OE_SITE_DIR'] . "/documents/edi/$filename"; |
|
// convert points to inches-some tricky calculus here! 72 pts/inch |
|
$top = round($top / 72.00, 2) . "in"; |
|
$side = round($side / 72.00, 2) . "in"; |
|
|
|
try { |
|
if ($dispose == 'download') { |
|
$isnotform = false; |
|
if ($form_action == "noform") { |
|
$isnotform = true; |
|
} |
|
$options = array( |
|
'margin-top' => $top, |
|
'margin-bottom' => '0in', |
|
'margin-left' => $side, |
|
'margin-right' => $side, |
|
'zoom' => '1.045', |
|
'print-media-type' => true, |
|
'lowquality' => true, |
|
'no-outline' => true, |
|
'keep-relative-links' => true, |
|
'no-images' => $isnotform, |
|
'grayscale' => true, |
|
'page-size' => 'Letter', |
|
'orientation' => 'Portrait' |
|
); |
|
|
|
$PdfCreator = new PdfCreator(); |
|
$pdfwkout = $PdfCreator->getPdf($htmlin, $options); |
|
|
|
/* |
|
* $fh = @fopen($form_filename, 'w'); // Future Use! |
|
* if ($fh) { |
|
* fwrite($fh, $pdfwkout); |
|
* fclose($fh); |
|
* } |
|
*/ |
|
|
|
header("Pragma: public"); |
|
header("Expires: 0"); |
|
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); |
|
header('Content-Type: application/pdf'); |
|
header("Content-Disposition: download; filename=$filename"); |
|
header("Content-Description: File Transfer"); |
|
echo $pdfwkout; |
|
} |
|
} catch (Exception $e) { |
|
echo xlt($e->getMessage()); |
|
} |
|
return true; |
|
} |
|
|
|
function exist_ub04_claim($pid, $encounter, $flag = false) |
|
{ |
|
$sql = "SELECT * FROM claims WHERE patient_id = ? AND encounter_id = ? AND status > 0 AND status < 4 "; |
|
$sql .= "ORDER BY version DESC LIMIT 1"; |
|
$row = sqlQuery($sql, array( |
|
$pid, |
|
$encounter |
|
)); |
|
if ($row) { |
|
if (! empty($row['submitted_claim'])) { |
|
if ($flag === false) { |
|
return $row['submitted_claim']; |
|
} else { |
|
return true; |
|
} |
|
} else { |
|
return false; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
function get_ub04_array($pid, $encounter, &$log = "") |
|
{ |
|
|
|
$exist_ub04 = exist_ub04_claim($pid, $encounter); |
|
if ($exist_ub04) { |
|
$log .= "*** Info: Using saved edited claim."; |
|
return json_decode($exist_ub04, true); |
|
} |
|
$log .= "*** Generating UB04 Claim."; |
|
$today = time(); |
|
$claim = new Claim($pid, $encounter); |
|
|
|
$ub04id = array(); |
|
$ub04id[0] = array(); |
|
// $ub04id[0] Is reserved for params |
|
$ub04id[2] = $claim->billingFacilityName(); |
|
$ub04id[4] = $claim->billingFacilityStreet(); |
|
$ub04id[8] = $claim->billingFacilityCity() . ', ' . $claim->billingFacilityState() . ', ' . $claim->billingFacilityZip(); /* 1. BILLING PROVIDER CITY, STATE, ZIP */ |
|
$tmp = $claim->billingContactPhone(); |
|
$ub04id[10] = substr($tmp, 0, 3) . '-' . substr($tmp, 3, 3) . '-' . substr($tmp, 6); |
|
$ub04id[3] = $pid . ' ' . $encounter; /* 3a. PATIENT CONTROL NUMBER */ |
|
$ub04id[6] = $pid; /* 3b. MEDICAL/HEALTH RECORD NUMBER */ |
|
$ub04id[7] = ! empty($ub04id[7]) ? $ub04id[7] : '831'; /* 4. TYPE OF BILL */ |
|
$ub04id[12] = $claim->facilityETIN(); /* 5. FEDERAL TAX NUMBER */ |
|
|
|
$tmp = $claim->serviceDate(); |
|
$ub04id[13] = substr($tmp, 4, 2) . substr($tmp, 6, 2) . substr($tmp, 2, 2); /* 6. STATEMENT COVERS PERIOD FROM DATE */ |
|
$ub04id[14] = ''; /* 6. STATEMENT COVERS PERIOD TO DATE */ |
|
// $ub04id[16] = ''; /* 8a. PATIENT IDENTIFIER */ |
|
$tmp = $claim->patientLastName() . ', ' . $claim->patientFirstName(); |
|
if ($claim->patientMiddleName()) { |
|
$tmp .= ', ' . substr($claim->patientMiddleName(), 0, 1); |
|
} |
|
$ub04id[18] = $tmp; /* 8b. PATIENT NAME */ |
|
$ub04id[17] = $claim->patientStreet(); /* 9a. PATIENT STREET ADDRESS */ |
|
$ub04id[19] = $claim->patientCity(); /* 9b. PATIENT CITY */ |
|
$ub04id[20] = $claim->patientState(); /* 9c. PATIENT STATE */ |
|
$ub04id[21] = $claim->patientZip(); /* 9d. PATIENT ZIP CODE */ |
|
$ub04id[22] = ''; /* 9e. PATIENT COUNTRY CODE */ |
|
$tmp = $claim->patientDOB(); |
|
$ub04id[23] = substr($tmp, 4, 2) . substr($tmp, 6, 2) . substr($tmp, 0, 4); /* 10. PATIENT BIRTH DATE (MMDDYYYY) */ |
|
$ub04id[24] = $claim->patientSex(); /* 11. PATIENT SEX */ |
|
$tmp = $claim->onsetDate(); |
|
$ub04id[25] = substr($tmp, 4, 2) . substr($tmp, 6, 2) . substr($tmp, 2, 2); /* 12. PATIENT ADMISSION/START OF CARE DATE (MMDDYY) */ |
|
|
|
$ub04_proc_index = 0; // Test for second page of charges. |
|
$proccount = $claim->procCount(); |
|
$clm_total_charges = 0; |
|
$clm_amount_adjusted = 0; |
|
$clm_amount_paid = $ub04_proc_index ? 0 : $claim->patientPaidAmount(); |
|
for ($tlh = 0; $tlh < $proccount; ++$tlh) { |
|
$tmp = $claim->procs[$tlh][code_text]; |
|
if ($claim->procs[$tlh][code_type] == 'HCPCS') { |
|
$tmpcode = '3'; |
|
} else { |
|
$tmpcode = '1'; |
|
} |
|
$getrevcd = $claim->cptCode($tlh); |
|
$sql = "SELECT * FROM codes WHERE code_type = ? and code = ? ORDER BY revenue_code DESC"; |
|
$revcode[$tlh] = sqlQuery($sql, array( |
|
$tmpcode, |
|
$getrevcd |
|
)); |
|
if (!empty($revcode[$tlh])) { |
|
$claim->procs[$tlh]['revenue_code'] = $claim->procs[$tlh]['revenue_code'] ? $claim->procs[$tlh]['revenue_code'] : $revcode[$tlh]['revenue_code']; |
|
$revcode2[$tlh] = array_merge($revcode[$tlh], $claim->procs[$tlh]); |
|
} |
|
} |
|
foreach ($revcode as $key => $row) { |
|
$revcod[$key] = $row['revenue_code']; |
|
} |
|
array_multisort($revcod, SORT_ASC, $revcode2); |
|
// Procedure loop starts here. |
|
$os = 99; // Line 1 - 23 offset |
|
$dos = 382; |
|
$pcnt = 0; |
|
for ($svccount = 0; $svccount < 22 && $ub04_proc_index < $proccount; ++$ub04_proc_index) { |
|
$dia = $claim->diagIndexArray($ub04_proc_index); |
|
if (! $claim->cptCharges($ub04_proc_index)) { |
|
$log .= "*** Procedure '" . $claim->cptKey($ub04_proc_index) . "' has no charges!\n"; |
|
} |
|
if (empty($dia)) { |
|
$log .= "*** Procedure '" . $claim->cptKey($ub04_proc_index) . "' is not justified!\n"; |
|
} |
|
$clm_total_charges += $claim->cptCharges($ub04_proc_index); |
|
// Compute prior payments and "hard" adjustments. |
|
for ($ins = 1; $ins < $claim->payerCount(); ++$ins) { |
|
if ($claim->payerSequence($ins) > $claim->payerSequence()) { |
|
continue; // skip future payers |
|
} |
|
$payerpaid = $claim->payerTotals($ins, $claim->cptKey($ub04_proc_index)); |
|
$clm_amount_paid += $payerpaid[1]; |
|
$clm_amount_adjusted += $payerpaid[2]; |
|
} |
|
++$svccount; |
|
$mcnt = $ub04_proc_index; |
|
|
|
// @todo need if inpatient or out patient for box 74 - 74e |
|
$tmp = $claim->cleanDate($revcode2[$mcnt][date]); |
|
$sdate = substr($tmp, 4, 2) . substr($tmp, 6, 2) . substr($tmp, 2, 2); |
|
if ($pcnt < 6) { |
|
$ub04id[$dos++] = $revcode2[$mcnt][code]; /* 74. PRINCIPAL PROCEDURE CODE */ |
|
$ub04id[$dos++] = $sdate; /* 74. PRINCIPAL PROCEDURE DATE */ |
|
if ($dos == 388) { |
|
$dos = 393; |
|
} |
|
$pcnt++; |
|
} |
|
// @todo Deal with code modifiers $revcode2[$mcnt][modifier] |
|
$tmp = $claim->serviceDate(); |
|
$sdate = substr($tmp, 4, 2) . substr($tmp, 6, 2) . substr($tmp, 2, 2); |
|
$ub04id[$os] = $claim->procs[$mcnt][revenue_code]; // 42. REVENUE CODE, Line 1-23 */ |
|
$ub04id[++$os] = strtoupper($revcode2[$mcnt][code_text]); /* 43. REVENUE DESCRIPTION, Line 1-23 */ |
|
$ub04id[++$os] = trim($revcode2[$mcnt][code] . ' ' . $revcode2[$mcnt][modifier]); /* 44. HCPCS/ACCOMMODATION RATES/HIPPS RATE CODES, Line 1-23 */ |
|
$ub04id[++$os] = $sdate; /* 45. SERVICE DATE, Line 1-23 */ |
|
$ub04id[++$os] = $revcode2[$mcnt][units]; /* 46. SERVICE UNITS, Line 1-23 */ |
|
$ub04id[++$os] = str_replace('.', ' ', sprintf('%8.2f', $revcode2[$mcnt][fee])); /* 47. TOTAL CHARGES, Line 1-23 */ |
|
$ub04id[++$os] = ''; /* 48. NON-COVERED CHARGES, Line 1-23 */ |
|
$os += 2; |
|
} |
|
$ub04id[275] = '0001'; /* 42. REVENUE CODE, Line 23 */ |
|
$ub04id[276] = '1'; /* 43. CLAIM PAGE NUMBER */ |
|
$ub04id[277] = '1'; /* 43. TOTAL NUMBER OF CLAIM PAGES */ |
|
$ub04id[278] = date('mdy', $today); /* 45. CREATION DATE, Line 23 */ |
|
$ub04id[279] = str_replace('.', ' ', sprintf('%8.2f', $clm_total_charges)); /* 47. TOTAL OF TOTAL CHARGES, Line 23 */ |
|
if (! $clm_total_charges) { |
|
$log .= "* Claim total is zero charges!\n"; |
|
} |
|
// Diagnosis Should be ICD10 |
|
$ub04id[347] = '0'; /* 66. DIAGNOSIS AND PROCEDURE CODE QUALIFIER (ICD VERSION INDICATOR) */ |
|
$os = 328; /* 67. PRINCIPAL DIAGNOSIS CODE AND POA INDICATOR */ |
|
$diagnosis = array(); |
|
foreach ($claim->diagArray() as $diag) { |
|
$diagnosis[] = $diag; |
|
if (! empty($diag)) { |
|
if ($os == 362) { |
|
$ub04id[$os++] = substr($diag, 0, 7); |
|
$ub04id[366] = ""; |
|
continue; |
|
} |
|
$ub04id[$os++] = substr($diag, 0, 7); |
|
$ub04id[$os++] = ""; |
|
} |
|
if ($os == 346) { |
|
$os = 348; |
|
} |
|
if ($os == 365) { |
|
break; |
|
} |
|
} |
|
// @todo Not sure |
|
$ub04id[367] = $diagnosis[0] ? substr($diagnosis[0], 0, 7) : ''; /* 69. ADMITTING DIAGNOSIS CODE */ |
|
$ub04id[368] = $diagnosis[1] ? substr($diagnosis[1], 0, 7) : ''; /* 70a. PATIENT'S REASON FOR VISIT */ |
|
$ub04id[369] = $diagnosis[2] ? substr($diagnosis[2], 0, 7) : ''; /* 70b. PATIENT'S REASON FOR VISIT */ |
|
$ub04id[370] = $diagnosis[3] ? substr($diagnosis[3], 0, 7) : ''; /* 70c. PATIENT'S REASON FOR VISIT */ |
|
|
|
$payer_os = 0; |
|
if (empty($claim->payerName(0))) { |
|
$payer_os = 1; |
|
} |
|
$ub04id[282] = $claim->facilityNPI(); /* 56. NATIONAL PROVIDER IDENTIFIER - BILLING PROVIDER */ |
|
$ub04id[283] = $claim->payerName($payer_os); /* 50a. PRIMARY PAYER NAME */ |
|
$ub04id[284] = $claim->planName($payer_os); /* 51a. PRIMARY PAYER HEALTH PLAN ID */ |
|
$ub04id[285] = 'Y'; /* 52a. RELEASE OF INFORMATION CERTIFICATION INDICATOR, PRIMARY PAYER */ |
|
$tmp = $claim->billingFacilityAssignment() ? 'Y' : 'N'; |
|
$ub04id[286] = $tmp; /* 53a. ASSIGNMENT OF BENEFITS CERTIFICATION INDICATOR, PRIMARY PAYER */ |
|
//$ub04id[287] = ''; /* 54a. PRIMARY PAYER PRIOR PAYMENTS */ |
|
//$ub04id[288] = ''; /* 55a. PRIMARY PAYER ESTIMATED AMOUNT DUE */ |
|
if (!empty($claim->payerName($payer_os + 1))) { |
|
$ub04id[290] = $claim->payerName($payer_os + 1); /* 50b. SECONDARY PAYER NAME */ |
|
$ub04id[291] = $claim->planName($payer_os + 1); /* 51b. SECONDARY PAYER HEALTH PLAN ID */ |
|
$ub04id[292] = 'Y'; /* 52b. RELEASE OF INFORMATION CERTIFICATION INDICATOR, SECONDARY PAYER */ |
|
$tmp = (null !== $claim->payerName($payer_os + 1)) && $claim->billingFacilityAssignment() ? 'Y' : 'N'; |
|
$ub04id[293] = $tmp; /* 53b. ASSIGNMENT OF BENEFITS CERTIFICATION INDICATOR, SECONDARY PAYER */ |
|
} |
|
|
|
if ($claim->insuredMiddleName()) { |
|
$tmp = $claim->insuredLastName() . ', ' . $claim->insuredFirstName() . ' ' . substr($claim->insuredMiddleName(), 0, 1); |
|
} else { |
|
$tmp = $claim->insuredLastName() . ', ' . $claim->insuredFirstName(); |
|
} |
|
$ub04id[304] = $tmp; /* 58a. INSURED'S NAME - PRIMARY PLAN */ |
|
$ub04id[305] = $claim->insuredRelationship(); /* 59a. PATIENT'S RELATIONSHIP TO INSURED - PRIMARY PLAN */ |
|
$ub04id[306] = $claim->policyNumber(); /* 60a. INSURED'S UNIQUE IDENTIFIER - PRIMARY PLAN */ |
|
$ub04id[307] = $claim->groupName(); /* 61a. INSURED'S GROUP NAME - PRIMARY PLAN */ |
|
$ub04id[308] = $claim->groupNumber(); /* 62a. INSURANCE GROUP NUMBER - PRIMARY PLAN */ |
|
|
|
return $ub04id; |
|
}
|
|
|