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.
1191 lines
50 KiB
1191 lines
50 KiB
2 years ago
|
<?php
|
||
|
|
||
|
/* This is a template for printing patient statements and collection
|
||
|
* letters. You must customize it to suit your practice. If your
|
||
|
* needs are simple then you do not need programming experience to do
|
||
|
* this - just read the comments and make appropriate substitutions.
|
||
|
* All you really need to do is replace the [strings in brackets].
|
||
|
*
|
||
|
* @package OpenEMR
|
||
|
* @author Rod Roark <rod@sunsetsystems.com>
|
||
|
* @copyright Copyright (c) 2006 Rod Roark <rod@sunsetsystems.com>
|
||
|
* @author Bill Cernansky <bill@mi-squared.com>
|
||
|
* @copyright Copyright (c) 2009 Bill Cernansky <bill@mi-squared.com>
|
||
|
* @author Tony McCormick <tony@mi-squared.com>
|
||
|
* @copyright Copyright (c) 2009 Tony McCormick <tony@mi-squared.com>
|
||
|
* @author Raymond Magauran <magauran@medfetch.com>
|
||
|
* @copyright Copyright (c) 2016 Raymond Magauran <magauran@medfetch.com>
|
||
|
* @author Jerry Padgett <sjpadgett@gmail.com>
|
||
|
* @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com>
|
||
|
* @author Stephen Waite <stephen.waite@cmsvt.com>
|
||
|
* @copyright Copyright (c) 2020 Stephen Waite <stephen.waite@cmsvt.com>
|
||
|
* @author Daniel Pflieger <daniel@growlingflea.com>
|
||
|
* @copyright Copyright (c) 2018 Daniel Pflieger <daniel@growlingflea.com>
|
||
|
* @link https://github.com/openemr/openemr/tree/master
|
||
|
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
|
||
|
*/
|
||
|
|
||
|
use OpenEMR\Common\Crypto\CryptoGen;
|
||
|
|
||
|
// The location/name of a temporary file to hold printable statements.
|
||
|
// May want to alter these names to allow multi-site installs out-of-the-box
|
||
|
|
||
|
$STMT_TEMP_FILE = $GLOBALS['temporary_files_dir'] . "/openemr_statements.txt";
|
||
|
$STMT_TEMP_FILE_PDF = $GLOBALS['temporary_files_dir'] . "/openemr_statements.pdf";
|
||
|
$STMT_PRINT_CMD = (new CryptoGen())->decryptStandard($GLOBALS['more_secure']['print_command']);
|
||
|
|
||
|
/** There are two options to print a batch of PDF statements:
|
||
|
* 1. The original statement, a text based statement, using CezPDF
|
||
|
* Altering this statement is labor intensive, but capable of being altered any way desired...
|
||
|
*
|
||
|
* 2. Branded Statement, whose core is build from 1., the original statement, using mPDF.
|
||
|
*
|
||
|
* To customize 2., add your practice location/images/practice_logo.gif
|
||
|
* In the base/default install this is located at '/openemr/sites/default/images/practice_logo.gif',
|
||
|
* Adjust directory paths per your installation.
|
||
|
* Further customize 2. manually in functions report_2() and create_HTML_statement(), below.
|
||
|
*
|
||
|
*/
|
||
|
function make_statement($stmt)
|
||
|
{
|
||
|
if ($GLOBALS['statement_appearance'] == "1") {
|
||
|
if (!empty($_POST['form_portalnotify']) && is_auth_portal($stmt['pid'])) {
|
||
|
return osp_create_HTML_statement($stmt);
|
||
|
} else {
|
||
|
return create_HTML_statement($stmt);
|
||
|
}
|
||
|
} else {
|
||
|
return create_statement($stmt);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* This prints a header for documents. Keeps the brand uniform...
|
||
|
* @param string $pid patient_id
|
||
|
* @param string $direction, options "web" or anything else. Web provides apache-friendly url links.
|
||
|
* @return outputs to be displayed however requested
|
||
|
*/
|
||
|
function report_header_2($stmt, $providerID = '1')
|
||
|
{
|
||
|
$titleres = getPatientData($stmt['pid'], "fname,lname,DOB");
|
||
|
//Author Daniel Pflieger - daniel@growlingflea.com
|
||
|
//We get the service facility from the encounter. In cases with multiple service facilities
|
||
|
//OpenEMR sends the correct facility
|
||
|
|
||
|
$service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.facility_id = f.id where fe.id = ?", array($stmt['fid']));
|
||
|
$facility = sqlFetchArray($service_query);
|
||
|
|
||
|
$DOB = oeFormatShortDate($titleres['DOB']);
|
||
|
/******************************************************************/
|
||
|
ob_start();
|
||
|
// Use logo if it exists as 'practice_logo.gif' in the site dir
|
||
|
// old code used the global custom dir which is no longer a valid
|
||
|
?>
|
||
|
<table style="width:100%;">
|
||
|
<tr>
|
||
|
<?php
|
||
|
$haveLogo = false;
|
||
|
if (empty(!$GLOBALS['statement_logo'])) {
|
||
|
$practice_logo = $GLOBALS['OE_SITE_DIR'] . "/images/" . convert_safe_file_dir_name($GLOBALS['statement_logo']);
|
||
|
} else { // 'ya never know.
|
||
|
$practice_logo = $GLOBALS['OE_SITE_DIR'] . "/images/practice_logo.gif"; // can see is safe...
|
||
|
}
|
||
|
|
||
|
//Author Daniel Pflieger - daniel@growlingflea.com
|
||
|
//We only put space for a logo if it exists.
|
||
|
//if it does we put the patient name and the service facility on a separate line.
|
||
|
//Patients with long names cause formatting issues and it makes the statement look
|
||
|
//unprofessional. Additionally, the end user should be able to choose the
|
||
|
//statement logo from Administration -> statement.
|
||
|
//
|
||
|
if (is_file($practice_logo)) { // note: file_exist() will return true if path exist but not file. a truly function name misnomer.
|
||
|
echo "<td style='width:15%; height: auto; text-align:center;'>\n";
|
||
|
// restrain logo proportionally
|
||
|
echo "<img src='" . attr($practice_logo) . "' align='left' style='width:100%; height: auto; margin:0px;'><br />\n";
|
||
|
echo "</td>\n";
|
||
|
$haveLogo = true;
|
||
|
}
|
||
|
?>
|
||
|
<td align='center' style='<?php echo ($haveLogo ? text("width:40%;max-width:50%;") : text("width:50%;") ) ?>'> <!--adds some growing room-->
|
||
|
<em style="font-weight:bold;font-size:1.4em;"><?php echo text($facility['name']); ?></em><br />
|
||
|
<?php echo text($facility['street']); ?><br />
|
||
|
<?php echo text($facility['city']); ?>, <?php echo text($facility['state']); ?> <?php echo text($facility['postal_code']); ?><br />
|
||
|
<?php echo xlt('Phone') . ': ' . text($facility['phone']); ?><br />
|
||
|
<?php echo xlt('Fax') . ': ' . text($facility['fax']); ?><br />
|
||
|
<br clear='all' />
|
||
|
</td>
|
||
|
<td align='center'>
|
||
|
<em style="font-weight:bold;font-size:1.4em;"><?php echo text($titleres['fname']) . " " . text($titleres['lname']); ?></em><br />
|
||
|
<b style="font-weight:bold;"><?php echo xlt('Chart Number'); ?>:</b> <?php echo text($stmt['pid']); ?><br />
|
||
|
<b style="font-weight:bold;"><?php echo xlt('Generated on'); ?>:</b> <?php echo text(oeFormatShortDate()); ?><br />
|
||
|
<b><?php echo xlt('Provider') . ':</b> '; ?><?php echo text(getProviderName($providerID)); ?> <br />
|
||
|
</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
<?php
|
||
|
$output = ob_get_contents();
|
||
|
ob_end_clean();
|
||
|
return $output;
|
||
|
}
|
||
|
|
||
|
function create_HTML_statement($stmt)
|
||
|
{
|
||
|
if (! $stmt['pid']) {
|
||
|
return ""; // get out if no data
|
||
|
}
|
||
|
|
||
|
#minimum_amount_due_to _print
|
||
|
if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion'] && ($_POST['form_category'] !== "All")) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
// Facility (service location) modified by Daniel Pflieger at Growlingflea Software
|
||
|
$service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.facility_id = f.id where fe.id = ? ", array($stmt['fid']));
|
||
|
$row = sqlFetchArray($service_query);
|
||
|
$clinic_name = "{$row['name']}";
|
||
|
$clinic_addr = "{$row['street']}";
|
||
|
$clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
|
||
|
|
||
|
|
||
|
// Billing location modified by Daniel Pflieger at Growlingflea Software
|
||
|
$service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.billing_facility = f.id where fe.id = ?", array($stmt['fid']));
|
||
|
$row = sqlFetchArray($service_query);
|
||
|
$remit_name = "{$row['name']}";
|
||
|
$remit_addr = "{$row['street']}";
|
||
|
$remit_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
|
||
|
|
||
|
ob_start();
|
||
|
?><div style="padding-left:25px; page-break-after:always;">
|
||
|
<?php
|
||
|
$find_provider = sqlQuery("SELECT * FROM form_encounter " .
|
||
|
"WHERE pid = ? AND encounter = ? " .
|
||
|
"ORDER BY id DESC LIMIT 1", array($stmt['pid'],$stmt['encounter']));
|
||
|
$providerID = $find_provider['provider_id'];
|
||
|
echo report_header_2($stmt, $providerID);
|
||
|
|
||
|
// dunning message setup
|
||
|
|
||
|
// insurance has paid something
|
||
|
// $stmt['age'] how old is the invoice
|
||
|
// $stmt['dun_count'] number of statements run
|
||
|
// $stmt['level_closed'] <= 3 insurance 4 = patient
|
||
|
|
||
|
if ($GLOBALS['use_dunning_message']) {
|
||
|
if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
|
||
|
// do collection messages
|
||
|
switch ($stmt['age']) {
|
||
|
case $stmt['age'] <= $GLOBALS['first_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['first_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['second_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['second_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['third_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['third_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['fourth_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['fourth_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] >= $GLOBALS['fifth_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['fifth_dun_msg_text'];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Text only labels
|
||
|
|
||
|
$label_addressee = xl('ADDRESSED TO');
|
||
|
$label_remitto = xl('REMIT TO');
|
||
|
$label_chartnum = xl('Chart Number');
|
||
|
$label_insinfo = xl('Insurance information on file');
|
||
|
$label_totaldue = xl('Total amount due');
|
||
|
$label_payby = xl('If paying by');
|
||
|
$label_cards = xl('VISA/MC/Discovery/HSA');
|
||
|
$label_cardnum = xl('Card');
|
||
|
$label_expiry = xl('Exp');
|
||
|
$label_cvv = xl('CVV');
|
||
|
$label_sign = xl('Signature');
|
||
|
$label_retpay = xl('Please return this bottom part with your payment');
|
||
|
$label_pgbrk = xl('STATEMENT SUMMARY');
|
||
|
$label_visit = xl('Visit Date');
|
||
|
$label_desc = xl('Description');
|
||
|
$label_amt = xl('Amount');
|
||
|
|
||
|
// This is the text for the top part of the page, up to but not
|
||
|
// including the detail lines. Some examples of variable fields are:
|
||
|
// %s = string with no minimum width
|
||
|
// %9s = right-justified string of 9 characters padded with spaces
|
||
|
// %-25s = left-justified string of 25 characters padded with spaces
|
||
|
// Note that "\n" is a line feed (new line) character.
|
||
|
// reformatted to handle i8n by tony
|
||
|
|
||
|
$out = "<div style='margin-left:60px;margin-top:20px;'><pre>";
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("_______________________ %s _______________________\n", $label_pgbrk);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-11s %-46s %s\n", $label_visit, $label_desc, $label_amt);
|
||
|
|
||
|
// This must be set to the number of lines generated above.
|
||
|
$count = 5;
|
||
|
|
||
|
$num_ages = 4;
|
||
|
$aging = array();
|
||
|
for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
|
||
|
$aging[$age_index] = 0.00;
|
||
|
}
|
||
|
|
||
|
$todays_time = strtotime(date('Y-m-d'));
|
||
|
|
||
|
// This generates the detail lines. Again, note that the values must be specified in the order used.
|
||
|
foreach ($stmt['lines'] as $line) {
|
||
|
if ($GLOBALS['use_custom_statement']) {
|
||
|
$description = substr($line['desc'], 0, 30);
|
||
|
} else {
|
||
|
$description = $line['desc'];
|
||
|
}
|
||
|
|
||
|
$tmp = substr($description, 0, 14);
|
||
|
if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201') {
|
||
|
$description = str_replace("Procedure", xl('Office Visit') . ":", $description);
|
||
|
}
|
||
|
|
||
|
//92002-14 are Eye Office Visit Codes
|
||
|
|
||
|
$dos = $line['dos'];
|
||
|
ksort($line['detail']);
|
||
|
// suppressing individual adjustments = improved statement printing
|
||
|
$adj_flag = false;
|
||
|
$note_flag = false;
|
||
|
$pt_paid_flag = false;
|
||
|
$prev_ddate = '';
|
||
|
$last_activity_date = $dos;
|
||
|
foreach ($line['detail'] 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];
|
||
|
}
|
||
|
|
||
|
if ($ddate && $ddate > $last_activity_date) {
|
||
|
$last_activity_date = $ddate;
|
||
|
}
|
||
|
|
||
|
$amount = '';
|
||
|
|
||
|
if (!empty($ddata['pmt'])) {
|
||
|
$amount = sprintf("%.2f", 0 - $ddata['pmt']);
|
||
|
$desc = xl('Paid') . ' ' . substr(oeFormatShortDate($ddate), 0, 6) .
|
||
|
substr(oeFormatShortDate($ddate), 8, 2) .
|
||
|
': ' . $ddata['src'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
// $ddata['plv'] is the 'payer_type' field in `ar_activity`, passed in via InvoiceSummary
|
||
|
if ($ddata['src'] == 'Pt Paid' || $ddata['plv'] == '0') {
|
||
|
$pt_paid_flag = true;
|
||
|
$desc = xl('Pt paid') . ' ' . substr(oeFormatShortDate($ddate), 0, 6) .
|
||
|
substr(oeFormatShortDate($ddate), 8, 2);
|
||
|
}
|
||
|
} elseif (!empty($ddata['rsn'])) {
|
||
|
if ($ddata['chg']) {
|
||
|
// this is where the adjustments used to be printed individually
|
||
|
$adj_flag = true;
|
||
|
} else {
|
||
|
if ($ddate == $prev_ddate) {
|
||
|
if ($note_flag) {
|
||
|
// only 1 note per item or results in too much detail
|
||
|
continue;
|
||
|
} else {
|
||
|
$desc = xl('Note') . ' ' . substr(oeFormatShortDate($ddate), 0, 6) .
|
||
|
substr(oeFormatShortDate($ddate), 8, 2) .
|
||
|
': ' . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
$note_flag = true;
|
||
|
}
|
||
|
} else {
|
||
|
continue; // no need to print notes for 2nd insurances
|
||
|
}
|
||
|
}
|
||
|
} elseif ($ddata['chg'] < 0) {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = xl('Patient Payment');
|
||
|
} else {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = $description;
|
||
|
}
|
||
|
|
||
|
if (!$adj_flag) {
|
||
|
$out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
|
||
|
++$count;
|
||
|
}
|
||
|
|
||
|
$dos = '';
|
||
|
$adj_flag = false;
|
||
|
$note_flag = false;
|
||
|
$prev_ddate = $ddate;
|
||
|
}
|
||
|
// print the adjustments summed after all other postings
|
||
|
if ($line['adjust'] !== '0.00') {
|
||
|
$out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), "Insurance adjusted", sprintf("%.2f", 0 - $line['adjust']));
|
||
|
++$count;
|
||
|
}
|
||
|
|
||
|
// don't print a balance after a "Paidpatient payment since it's on it's own line
|
||
|
if (!$pt_paid_flag) {
|
||
|
$out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), "Item balance ", sprintf("%.2f", ($line['amount'] - $line['paid'])));
|
||
|
++$count;
|
||
|
}
|
||
|
|
||
|
# Compute the aging bucket index and accumulate into that bucket.
|
||
|
$last_activity_date = ($line['bill_date'] > $last_activity_date) ? $line['bill_date'] : $last_activity_date;
|
||
|
// If first bill then make the amount due current and reset aging date
|
||
|
if ($stmt['dun_count'] == '0') {
|
||
|
$last_activity_date = date('Y-m-d');
|
||
|
sqlStatement("UPDATE billing SET bill_date = ? WHERE pid = ? AND encounter = ?", array(date('Y-m-d'), $patient_id, $encounter_id));
|
||
|
}
|
||
|
$age_in_days = (int) (($todays_time - strtotime($last_activity_date)) / (60 * 60 * 24));
|
||
|
$age_index = (int) (($age_in_days - 1) / 30);
|
||
|
$age_index = max(0, min($num_ages - 1, $age_index));
|
||
|
$aging[$age_index] += $line['amount'] - $line['paid'];
|
||
|
}
|
||
|
|
||
|
// This generates blank lines until we are at line 20.
|
||
|
// At line 20 we start middle third.
|
||
|
|
||
|
while ($count++ < 16) {
|
||
|
$out .= "\n";
|
||
|
}
|
||
|
|
||
|
# Generate the string of aging text. This will look like:
|
||
|
# Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
|
||
|
# ....+....1....+....2....+....3....+....4....+....5....+....6....+
|
||
|
#
|
||
|
$ageline = xl('Current') . ': ' . sprintf("%.2f", $aging[0]);
|
||
|
for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
|
||
|
$ageline .= ' | ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) . ':' .
|
||
|
sprintf(" %.2f", $GLOBALS['gbl_currency_symbol'] . '' . $aging[$age_index]);
|
||
|
}
|
||
|
|
||
|
// Fixed text labels
|
||
|
$label_ptname = xl('Name');
|
||
|
$label_today = xl('Date');
|
||
|
$label_due = xl('Due');
|
||
|
$label_thanks = xl('Thank you for choosing');
|
||
|
$label_call = xl('Please call if any of the above information is incorrect.');
|
||
|
$label_prompt = xl('We appreciate prompt payment of balances due.');
|
||
|
$label_dept = xl('Billing Department');
|
||
|
$label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $row['phone'] );
|
||
|
$label_appointments = xl('Future Appointments') . ':';
|
||
|
|
||
|
// This is the top portion of the page.
|
||
|
$out .= "\n\n\n";
|
||
|
if (strlen($stmt['bill_note']) != 0 && $GLOBALS['statement_bill_note_print']) {
|
||
|
$out .= sprintf("%-46s\n", $stmt['bill_note']);
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['use_dunning_message']) {
|
||
|
$out .= sprintf("%-46s\n", $dun_message);
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf(
|
||
|
"%-s: %-25s %-s: %-14s %-s: %8s\n",
|
||
|
$label_ptname,
|
||
|
$stmt['patient'],
|
||
|
$label_today,
|
||
|
oeFormatShortDate($stmt['today']),
|
||
|
$label_due,
|
||
|
$stmt['amount']
|
||
|
);
|
||
|
$out .= sprintf("__________________________________________________________________\n");
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-s\n", $label_call);
|
||
|
$out .= sprintf("%-s\n", $label_prompt);
|
||
|
$out .= "\n";
|
||
|
// $out .= sprintf("%-s\n", $billing_contact);
|
||
|
$out .= sprintf(" %-s %-25s\n", $label_dept, $label_bill_phone);
|
||
|
if ($GLOBALS['statement_message_to_patient']) {
|
||
|
$out .= "\n";
|
||
|
$statement_message = $GLOBALS['statement_msg_text'];
|
||
|
$out .= sprintf("%-40s\n", $statement_message);
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['show_aging_on_custom_statement']) {
|
||
|
# code for ageing
|
||
|
$ageline .= ' | ' . xl('Over') . ' ' . ($age_index * 30) . ':' .
|
||
|
sprintf(" %.2f", $aging[$age_index]);
|
||
|
$out .= "\n" . $ageline . "\n\n";
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['number_appointments_on_statement'] != 0) {
|
||
|
$out .= "\n";
|
||
|
$num_appts = $GLOBALS['number_appointments_on_statement'];
|
||
|
$next_day = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y'));
|
||
|
# add one day to date so it will not get todays appointment
|
||
|
$current_date2 = date('Y-m-d', $next_day);
|
||
|
$events = fetchNextXAppts($current_date2, $stmt['pid'], $num_appts);
|
||
|
$j = 0;
|
||
|
$out .= sprintf("%-s\n", $label_appointments);
|
||
|
#loop to add the appointments
|
||
|
for ($x = 1; $x <= $num_appts; $x++) {
|
||
|
$next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
|
||
|
$next_appoint_time = substr($events[$j]['pc_startTime'], 0, 5);
|
||
|
if (strlen(umname) != 0) {
|
||
|
$next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] . ' ' . $events[$j]['ulname'];
|
||
|
} else {
|
||
|
$next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
|
||
|
}
|
||
|
|
||
|
if (strlen($next_appoint_time) != 0) {
|
||
|
$label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') . ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
|
||
|
$out .= sprintf("%-s\n", $label_plsnote[$j]);
|
||
|
}
|
||
|
|
||
|
$j++;
|
||
|
$count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while ($count++ < 29) {
|
||
|
$out .= "\n";
|
||
|
}
|
||
|
|
||
|
$out .= sprintf("%-10s %s\n", null, $label_retpay);
|
||
|
$out .= '</pre></div>';
|
||
|
$out .= '<div style="width:7.0in;border-top:1pt dotted black;font-size:12px;margin:0px;"><br /><br />
|
||
|
<table style="width:7in;margin-left:20px;"><tr><td style="width:4.5in;"><br />
|
||
|
';
|
||
|
$out .= $label_payby . ' ' . $label_cards;
|
||
|
$out .= "<br /><br />";
|
||
|
$out .= $label_cardnum . ': __________________________________ ' . $label_expiry . ': ___ / ____ ' . $label_cvv . ':____<br /><br />';
|
||
|
$out .= $label_sign . ' ______________________________________________<br />';
|
||
|
$out .= "</td><td style='width:2.0in;vertical-align:middle;'>";
|
||
|
$practice_cards = $GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif";
|
||
|
if (file_exists($GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif")) {
|
||
|
$out .= "<img src='$practice_cards' style='width:90px;height:auto; margin:4px auto;'><br /><p>\n<b>" .
|
||
|
$label_totaldue . "</b>: " . $stmt['amount'] . "<br/>" . xlt('Payment Tracking Id') . ": " .
|
||
|
text($stmt['pid']);
|
||
|
$out .= "<br />" . xlt('Amount Paid') . ": _______ " . xlt('Check') . " #:</p>";
|
||
|
} else {
|
||
|
$out .= "<br /><p><b>" . $label_totaldue . "</b>: " . $stmt['amount'] . "<br/>" .
|
||
|
xlt('Payment Tracking Id') . ": " . text($stmt['pid']) . "</p>";
|
||
|
$out .= "<br /><p>" . xlt('Amount Paid') . ": _______ " . xlt('Check') . " #:</p>";
|
||
|
}
|
||
|
|
||
|
$out .= "</td></tr></table>";
|
||
|
|
||
|
$out .= '</div><br />
|
||
|
<pre>';
|
||
|
if (!empty($stmt['to'][3])) { //to avoid double blank lines the if condition is put.
|
||
|
$out .= sprintf(" %-32s\n", $stmt['to'][3]);
|
||
|
}
|
||
|
|
||
|
$out .= ' </pre>
|
||
|
<div style="width:7.0in;border-top:1pt solid black;"><br />';
|
||
|
$out .= " <table style='width:7.0in;margin:auto;'><tr>";
|
||
|
$out .= '<td style="margin:auto;"></td><td style="width:3.0in;"><b>'
|
||
|
. $label_addressee . '</b><br />'
|
||
|
. $stmt['to'][0] . '<br />'
|
||
|
. $stmt['to'][1] . '<br />'
|
||
|
. ($stmt['to'][2] ?? '') . '
|
||
|
</td><td style="width:0.5in;"></td>
|
||
|
<td style="margin:auto;"><b>' . $label_remitto . '</b><br />'
|
||
|
. $remit_name . '<br />'
|
||
|
. $remit_addr . '<br />'
|
||
|
. $remit_csz . '
|
||
|
</td>
|
||
|
</tr></table>';
|
||
|
|
||
|
$out .= " </div></div>";
|
||
|
$out .= "\014";
|
||
|
echo $out;
|
||
|
$output = ob_get_clean();
|
||
|
return $output;
|
||
|
}
|
||
|
|
||
|
// This function builds a printable statement or collection letter from
|
||
|
// an associative array having the following keys:
|
||
|
//
|
||
|
// today = statement date yyyy-mm-dd
|
||
|
// pid = patient ID
|
||
|
// patient = patient name
|
||
|
// amount = total amount due
|
||
|
// to = array of addressee name/address lines
|
||
|
// lines = array of lines, each with the following keys:
|
||
|
// dos = date of service yyyy-mm-dd
|
||
|
// desc = description
|
||
|
// amount = charge less adjustments
|
||
|
// paid = amount paid
|
||
|
// notice = 1 for first notice, 2 for second, etc.
|
||
|
// detail = associative array of details
|
||
|
//
|
||
|
// Each detail array is keyed on a string beginning with a date in
|
||
|
// yyyy-mm-dd format, or blanks in the case of the original charge
|
||
|
// items. Its values are associative arrays like this:
|
||
|
//
|
||
|
// pmt - payment amount as a positive number, only for payments
|
||
|
// src - check number or other source, only for payments
|
||
|
// chg - invoice line item amount amount, only for charges or
|
||
|
// adjustments (adjustments may be zero)
|
||
|
// rsn - adjustment reason, only for adjustments
|
||
|
//
|
||
|
// The returned value is a string that can be sent to a printer.
|
||
|
// This example is plain text, but if you are a hotshot programmer
|
||
|
// then you could make a PDF or PostScript or whatever peels your
|
||
|
// banana. These strings are sent in succession, so append a form
|
||
|
// feed if that is appropriate.
|
||
|
//
|
||
|
|
||
|
// A sample of the text based format follows:
|
||
|
|
||
|
//[Your Clinic Name] Patient Name 2009-12-29
|
||
|
//[Your Clinic Address] Chart Number: 1848
|
||
|
//[City, State Zip] Insurance information on file
|
||
|
//
|
||
|
//
|
||
|
//ADDRESSEE REMIT TO
|
||
|
//Patient Name [Your Clinic Name]
|
||
|
//patient address [Your Clinic Address]
|
||
|
//city, state zipcode [City, State Zip]
|
||
|
// If paying by VISA/MC/AMEX/Dis
|
||
|
//
|
||
|
//Card_____________________ Exp______ Signature___________________
|
||
|
// Return above part with your payment
|
||
|
//-----------------------------------------------------------------
|
||
|
//
|
||
|
//_______________________ STATEMENT SUMMARY _______________________
|
||
|
//
|
||
|
//Visit Date Description Amount
|
||
|
//
|
||
|
//2009-08-20 Procedure 99345 198.90
|
||
|
// Paid 2009-12-15: -51.50
|
||
|
//... more details ...
|
||
|
//...
|
||
|
//...
|
||
|
// skipping blanks in example
|
||
|
//
|
||
|
//
|
||
|
//Name: Patient Name Date: 2009-12-29 Due: 147.40
|
||
|
//_________________________________________________________________
|
||
|
//
|
||
|
//Please call if any of the above information is incorrect
|
||
|
//We appreciate prompt payment of balances due
|
||
|
//
|
||
|
//[Your billing contact name]
|
||
|
// Billing Department
|
||
|
// [Your billing dept phone]
|
||
|
|
||
|
function create_statement($stmt)
|
||
|
{
|
||
|
if (! $stmt['pid']) {
|
||
|
return ""; // get out if no data
|
||
|
}
|
||
|
|
||
|
#minimum_amount_to _print
|
||
|
if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion']) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
// These are your clinics return address, contact etc. Edit them.
|
||
|
// TBD: read this from the facility table
|
||
|
|
||
|
// Facility (service location) modified by Daniel Pflieger at Growlingflea Software
|
||
|
$service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.facility_id = f.id where fe.id = ?", array($stmt['fid']));
|
||
|
$row = sqlFetchArray($service_query);
|
||
|
$clinic_name = "{$row['name']}";
|
||
|
$clinic_addr = "{$row['street']}";
|
||
|
$clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
|
||
|
|
||
|
|
||
|
// Billing location modified by Daniel Pflieger at Growlingflea Software
|
||
|
$service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.billing_facility = f.id where fe.id = ?", array($stmt['fid']));
|
||
|
$row = sqlFetchArray($service_query);
|
||
|
$remit_name = "{$row['name']}";
|
||
|
$remit_addr = "{$row['street']}";
|
||
|
$remit_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
|
||
|
|
||
|
|
||
|
// Contacts
|
||
|
$atres = sqlStatement("select f.attn,f.phone from facility f " .
|
||
|
" left join users u on f.id=u.facility_id " .
|
||
|
" left join billing b on b.provider_id=u.id and b.pid = ? " .
|
||
|
" where billing_location=1", [$stmt['pid']]);
|
||
|
$row = sqlFetchArray($atres);
|
||
|
$billing_contact = "{$row['attn']}";
|
||
|
$billing_phone = "{$row['phone']}";
|
||
|
|
||
|
// dunning message setup
|
||
|
|
||
|
// insurance has paid something
|
||
|
// $stmt['age'] how old is the invoice
|
||
|
// $stmt['dun_count'] number of statements run
|
||
|
// $stmt['level_closed'] <= 3 insurance 4 = patient
|
||
|
|
||
|
if ($GLOBALS['use_dunning_message']) {
|
||
|
if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
|
||
|
// do collection messages
|
||
|
switch ($stmt['age']) {
|
||
|
case $stmt['age'] <= $GLOBALS['first_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['first_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['second_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['second_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['third_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['third_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['fourth_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['fourth_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] >= $GLOBALS['fifth_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['fifth_dun_msg_text'];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Text only labels
|
||
|
|
||
|
$label_addressee = xl('ADDRESSED TO');
|
||
|
$label_remitto = xl('REMIT TO');
|
||
|
$label_chartnum = xl('Chart Number');
|
||
|
$label_insinfo = xl('Insurance information on file');
|
||
|
$label_totaldue = xl('Total amount due');
|
||
|
$label_payby = xl('If paying by');
|
||
|
$label_cards = xl('VISA/MC/Discovery/HSA');
|
||
|
$label_cardnum = xl('Card');
|
||
|
$label_expiry = xl('Exp');
|
||
|
$label_cvv = xl('CVV');
|
||
|
$label_sign = xl('Signature');
|
||
|
$label_retpay = xl('Return above part with your payment');
|
||
|
$label_pgbrk = xl('STATEMENT SUMMARY');
|
||
|
$label_visit = xl('Visit Date');
|
||
|
$label_desc = xl('Description');
|
||
|
$label_amt = xl('Amount');
|
||
|
|
||
|
// This is the text for the top part of the page, up to but not
|
||
|
// including the detail lines. Some examples of variable fields are:
|
||
|
// %s = string with no minimum width
|
||
|
// %9s = right-justified string of 9 characters padded with spaces
|
||
|
// %-25s = left-justified string of 25 characters padded with spaces
|
||
|
// Note that "\n" is a line feed (new line) character.
|
||
|
// reformatted to handle i8n by tony
|
||
|
$out = "\n\n";
|
||
|
$providerNAME = getProviderName($stmt['provider_id']);
|
||
|
$out .= sprintf("%-30s %s %-s\n", $clinic_name, $stmt['patient'], $stmt['today']);
|
||
|
$out .= sprintf("%-30s %s: %-s\n", $providerNAME, $label_chartnum, $stmt['pid']);
|
||
|
$out .= sprintf("%-30s %s\n", $clinic_addr, $label_insinfo);
|
||
|
$out .= sprintf("%-30s %-s: %-s\n", $clinic_csz, $label_totaldue, $stmt['amount']);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf(" %-30s %-s\n", $label_addressee, $label_remitto);
|
||
|
$out .= sprintf(" %-30s %s\n", $stmt['to'][0], $remit_name);
|
||
|
$out .= sprintf(" %-30s %s\n", $stmt['to'][1], $remit_addr);
|
||
|
$out .= sprintf(" %-30s %s\n", $stmt['to'][2], $remit_csz);
|
||
|
|
||
|
if ($stmt['to'][3] != '') { //to avoid double blank lines the if condition is put.
|
||
|
$out .= sprintf(" %-32s\n", $stmt['to'][3]);
|
||
|
}
|
||
|
|
||
|
$out .= sprintf("_________________________________________________________________\n");
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-32s\n", $label_payby . ' ' . $label_cards);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf(
|
||
|
"%s_____________________ %s______ %s______ %s___________________\n\n",
|
||
|
$label_cardnum,
|
||
|
$label_expiry,
|
||
|
$label_cvv,
|
||
|
$label_sign
|
||
|
);
|
||
|
$out .= sprintf("-----------------------------------------------------------------\n");
|
||
|
$out .= sprintf("%-20s %s\n", null, $label_retpay);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("_______________________ %s _______________________\n", $label_pgbrk);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-11s %-46s %s\n", $label_visit, $label_desc, $label_amt);
|
||
|
$out .= "\n";
|
||
|
|
||
|
// This must be set to the number of lines generated above.
|
||
|
//
|
||
|
$count = 25;
|
||
|
$num_ages = 4;
|
||
|
$aging = array();
|
||
|
for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
|
||
|
$aging[$age_index] = 0.00;
|
||
|
}
|
||
|
|
||
|
$todays_time = strtotime(date('Y-m-d'));
|
||
|
|
||
|
// This generates the detail lines. Again, note that the values must
|
||
|
// be specified in the order used.
|
||
|
//
|
||
|
|
||
|
|
||
|
foreach ($stmt['lines'] as $line) {
|
||
|
if ($GLOBALS['use_custom_statement']) {
|
||
|
$description = substr($line['desc'], 0, 30);
|
||
|
} else {
|
||
|
$description = $line['desc'];
|
||
|
}
|
||
|
|
||
|
$tmp = substr($description, 0, 14);
|
||
|
if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201') {
|
||
|
$description = str_replace("Procedure", xl('Office Visit') . ":", $description);
|
||
|
}
|
||
|
|
||
|
//92002-14 are Eye Office Visit Codes
|
||
|
|
||
|
$dos = $line['dos'];
|
||
|
ksort($line['detail']);
|
||
|
# Compute the aging bucket index and accumulate into that bucket.
|
||
|
#
|
||
|
$age_in_days = (int) (($todays_time - strtotime($dos)) / (60 * 60 * 24));
|
||
|
$age_index = (int) (($age_in_days - 1) / 30);
|
||
|
$age_index = max(0, min($num_ages - 1, $age_index));
|
||
|
$aging[$age_index] += $line['amount'] - $line['paid'];
|
||
|
|
||
|
foreach ($line['detail'] 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];
|
||
|
}
|
||
|
|
||
|
$amount = '';
|
||
|
|
||
|
if ($ddata['pmt']) {
|
||
|
$amount = sprintf("%.2f", 0 - $ddata['pmt']);
|
||
|
$desc = xl('Paid') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['src'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
} elseif ($ddata['rsn']) {
|
||
|
if ($ddata['chg']) {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = xl('Adj') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
} else {
|
||
|
$desc = xl('Note') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
}
|
||
|
} elseif ($ddata['chg'] < 0) {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = xl('Patient Payment');
|
||
|
} else {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = $description;
|
||
|
}
|
||
|
|
||
|
$out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
|
||
|
$dos = '';
|
||
|
++$count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This generates blank lines until we are at line 42.
|
||
|
//
|
||
|
while ($count++ < 42) {
|
||
|
$out .= "\n";
|
||
|
}
|
||
|
|
||
|
# Generate the string of aging text. This will look like:
|
||
|
# Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
|
||
|
# ....+....1....+....2....+....3....+....4....+....5....+....6....+
|
||
|
#
|
||
|
$ageline = xl('Current') . ' ' . sprintf("%.2f", $aging[0]);
|
||
|
for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
|
||
|
$ageline .= ' / ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) .
|
||
|
sprintf(" %.2f", $aging[$age_index]);
|
||
|
}
|
||
|
|
||
|
// Fixed text labels
|
||
|
$label_ptname = xl('Name');
|
||
|
$label_today = xl('Date');
|
||
|
$label_due = xl('Amount Due');
|
||
|
$label_thanks = xl('Thank you for choosing');
|
||
|
$label_call = xl('Please call if any of the above information is incorrect.');
|
||
|
$label_prompt = xl('We appreciate prompt payment of balances due.');
|
||
|
$label_dept = xl('Billing Department');
|
||
|
$label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $billing_phone );
|
||
|
$label_appointments = xl('Future Appointments') . ':';
|
||
|
|
||
|
// This is the bottom portion of the page.
|
||
|
$out .= "\n";
|
||
|
if (strlen($stmt['bill_note']) != 0 && $GLOBALS['statement_bill_note_print']) {
|
||
|
$out .= sprintf("%-46s\n", $stmt['bill_note']);
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['use_dunning_message']) {
|
||
|
$out .= sprintf("%-46s\n", $dun_message);
|
||
|
}
|
||
|
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf(
|
||
|
"%-s: %-25s %-s: %-14s %-s: %8s\n",
|
||
|
$label_ptname,
|
||
|
$stmt['patient'],
|
||
|
$label_today,
|
||
|
oeFormatShortDate($stmt['today']),
|
||
|
$label_due,
|
||
|
$stmt['amount']
|
||
|
);
|
||
|
$out .= sprintf("__________________________________________________________________\n");
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-s\n", $label_call);
|
||
|
$out .= sprintf("%-s\n", $label_prompt);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-s\n", $billing_contact);
|
||
|
$out .= sprintf(" %-s %-25s\n", $label_dept, $label_bill_phone);
|
||
|
if ($GLOBALS['statement_message_to_patient']) {
|
||
|
$out .= "\n";
|
||
|
$statement_message = $GLOBALS['statement_msg_text'];
|
||
|
$out .= sprintf("%-40s\n", $statement_message);
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['show_aging_on_custom_statement']) {
|
||
|
# code for ageing
|
||
|
$ageline .= ' / ' . xl('Over') . '-' . ($age_index * 30) .
|
||
|
sprintf(" %.2f", $aging[$age_index]);
|
||
|
$out .= "\n" . $ageline . "\n\n";
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['number_appointments_on_statement'] != 0) {
|
||
|
$out .= "\n";
|
||
|
$num_appts = $GLOBALS['number_appointments_on_statement'];
|
||
|
$next_day = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y'));
|
||
|
# add one day to date so it will not get todays appointment
|
||
|
$current_date2 = date('Y-m-d', $next_day);
|
||
|
$events = fetchNextXAppts($current_date2, $stmt['pid'], $num_appts);
|
||
|
$j = 0;
|
||
|
$out .= sprintf("%-s\n", $label_appointments);
|
||
|
#loop to add the appointments
|
||
|
for ($x = 1; $x <= $num_appts; $x++) {
|
||
|
$next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
|
||
|
$next_appoint_time = substr($events[$j]['pc_startTime'], 0, 5);
|
||
|
if (strlen(umname) != 0) {
|
||
|
$next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] .
|
||
|
' ' . $events[$j]['ulname'];
|
||
|
} else {
|
||
|
$next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
|
||
|
}
|
||
|
|
||
|
if (strlen($next_appoint_time) != 0) {
|
||
|
$label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') .
|
||
|
' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
|
||
|
$out .= sprintf("%-s\n", $label_plsnote[$j]);
|
||
|
}
|
||
|
|
||
|
$j++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$out .= "\014"; // this is a form feed
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
function osp_create_HTML_statement($stmt)
|
||
|
{
|
||
|
if (! $stmt['pid']) {
|
||
|
return ""; // get out if no data
|
||
|
}
|
||
|
|
||
|
#minimum_amount_due_to _print
|
||
|
if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion']) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
// Facility (service location)
|
||
|
$atres = sqlStatement("select f.name,f.street,f.city,f.state,f.postal_code,f.attn,f.phone from facility f " .
|
||
|
" left join users u on f.id=u.facility_id " .
|
||
|
" left join billing b on b.provider_id=u.id and b.pid = ? " .
|
||
|
" where service_location=1", array($stmt['pid']));
|
||
|
$row = sqlFetchArray($atres);
|
||
|
$clinic_name = "{$row['name']}";
|
||
|
$clinic_addr = "{$row['street']}";
|
||
|
$clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
|
||
|
// Contacts
|
||
|
$billing_contact = "{$row['attn']}";
|
||
|
$billing_phone = "{$row['phone']}";
|
||
|
// Billing location
|
||
|
$remit_name = $clinic_name;
|
||
|
$remit_addr = $clinic_addr;
|
||
|
$remit_csz = $clinic_csz;
|
||
|
|
||
|
ob_start();
|
||
|
?><div style="padding-left:25px;">
|
||
|
<?php
|
||
|
$find_provider = sqlQuery("SELECT * FROM form_encounter " .
|
||
|
"WHERE pid = ? AND encounter = ? " .
|
||
|
"ORDER BY id DESC LIMIT 1", array($stmt['pid'],$stmt['encounter']));
|
||
|
$providerID = $find_provider['provider_id'];
|
||
|
echo report_header_2($stmt, $providerID);
|
||
|
|
||
|
// dunning message setup
|
||
|
|
||
|
// insurance has paid something
|
||
|
// $stmt['age'] how old is the invoice
|
||
|
// $stmt['dun_count'] number of statements run
|
||
|
// $stmt['level_closed'] <= 3 insurance 4 = patient
|
||
|
|
||
|
if ($GLOBALS['use_dunning_message']) {
|
||
|
if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
|
||
|
// do collection messages
|
||
|
switch ($stmt['age']) {
|
||
|
case $stmt['age'] <= $GLOBALS['first_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['first_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['second_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['second_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['third_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['third_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] <= $GLOBALS['fourth_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['fourth_dun_msg_text'];
|
||
|
break;
|
||
|
case $stmt['age'] >= $GLOBALS['fifth_dun_msg_set']:
|
||
|
$dun_message = $GLOBALS['fifth_dun_msg_text'];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Text only labels
|
||
|
|
||
|
$label_addressee = xl('ADDRESSED TO');
|
||
|
$label_remitto = xl('REMIT TO');
|
||
|
$label_chartnum = xl('Chart Number');
|
||
|
$label_insinfo = xl('Insurance information on file');
|
||
|
$label_totaldue = xl('Total amount due');
|
||
|
$label_payby = xl('If paying by');
|
||
|
$label_cards = xl('VISA/MC/Discovery/HSA');
|
||
|
$label_cardnum = xl('Card');
|
||
|
$label_expiry = xl('Exp');
|
||
|
$label_sign = xl('Signature');
|
||
|
$label_retpay = xl('Please fill in credit information and send for review.');
|
||
|
$label_pgbrk = xl('STATEMENT SUMMARY');
|
||
|
$label_visit = xl('Visit Date');
|
||
|
$label_desc = xl('Description');
|
||
|
$label_amt = xl('Amount');
|
||
|
|
||
|
// This is the text for the top part of the page, up to but not
|
||
|
// including the detail lines. Some examples of variable fields are:
|
||
|
// %s = string with no minimum width
|
||
|
// %9s = right-justified string of 9 characters padded with spaces
|
||
|
// %-25s = left-justified string of 25 characters padded with spaces
|
||
|
// Note that "\n" is a line feed (new line) character.
|
||
|
// reformatted to handle i8n by tony
|
||
|
|
||
|
$out = "<div style='margin-left:60px;margin-top:0px;'>";
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("_______________________ %s _______________________\n", $label_pgbrk);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-11s %-46s %s\n", $label_visit, $label_desc, $label_amt);
|
||
|
$out .= "\n";
|
||
|
|
||
|
// This must be set to the number of lines generated above.
|
||
|
//
|
||
|
$count = 6;
|
||
|
$num_ages = 4;
|
||
|
$aging = array();
|
||
|
for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
|
||
|
$aging[$age_index] = 0.00;
|
||
|
}
|
||
|
|
||
|
$todays_time = strtotime(date('Y-m-d'));
|
||
|
|
||
|
// This generates the detail lines. Again, note that the values must be specified in the order used.
|
||
|
foreach ($stmt['lines'] as $line) {
|
||
|
if ($GLOBALS['use_custom_statement']) {
|
||
|
$description = substr($line['desc'], 0, 30);
|
||
|
} else {
|
||
|
$description = $line['desc'];
|
||
|
}
|
||
|
|
||
|
$tmp = substr($description, 0, 14);
|
||
|
if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201') {
|
||
|
$description = str_replace("Procedure", xl('Office Visit') . ":", $description);
|
||
|
}
|
||
|
|
||
|
//92002-14 are Eye Office Visit Codes
|
||
|
|
||
|
$dos = $line['dos'];
|
||
|
ksort($line['detail']);
|
||
|
# Compute the aging bucket index and accumulate into that bucket.
|
||
|
$age_in_days = (int) (($todays_time - strtotime($dos)) / (60 * 60 * 24));
|
||
|
$age_index = (int) (($age_in_days - 1) / 30);
|
||
|
$age_index = max(0, min($num_ages - 1, $age_index));
|
||
|
$aging[$age_index] += $line['amount'] - $line['paid'];
|
||
|
|
||
|
foreach ($line['detail'] 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];
|
||
|
}
|
||
|
|
||
|
$amount = '';
|
||
|
|
||
|
if ($ddata['pmt']) {
|
||
|
$amount = sprintf("%.2f", 0 - $ddata['pmt']);
|
||
|
$desc = xl('Paid') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['src'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
} elseif ($ddata['rsn']) {
|
||
|
if ($ddata['chg']) {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = xl('Adj') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
} else {
|
||
|
$desc = xl('Note') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
|
||
|
}
|
||
|
} elseif ($ddata['chg'] < 0) {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = xl('Patient Payment');
|
||
|
} else {
|
||
|
$amount = sprintf("%.2f", $ddata['chg']);
|
||
|
$desc = $description;
|
||
|
}
|
||
|
|
||
|
$out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
|
||
|
$dos = '';
|
||
|
++$count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This generates blank lines until we are at line 20.
|
||
|
// At line 20 we start middle third.
|
||
|
|
||
|
//while ($count++ < 16) $out .= "\n";
|
||
|
# Generate the string of aging text. This will look like:
|
||
|
# Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
|
||
|
# ....+....1....+....2....+....3....+....4....+....5....+....6....+
|
||
|
#
|
||
|
$ageline = xl('Current') . ': ' . sprintf("%.2f", $aging[0]);
|
||
|
for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
|
||
|
$ageline .= ' | ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) . ':' .
|
||
|
sprintf(" %.2f", $GLOBALS['gbl_currency_symbol'] . '' . $aging[$age_index]);
|
||
|
}
|
||
|
|
||
|
// Fixed text labels
|
||
|
$label_ptname = xl('Name');
|
||
|
$label_today = xl('Date');
|
||
|
$label_due = xl('Due');
|
||
|
$label_thanks = xl('Thank you for choosing');
|
||
|
$label_call = xl('Please call or message if any of the above information is incorrect.');
|
||
|
$label_prompt = xl('We appreciate prompt payment of balances due.');
|
||
|
$label_dept = xl('Billing Department');
|
||
|
$label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $billing_phone );
|
||
|
$label_appointments = xl('Future Appointments') . ':';
|
||
|
|
||
|
// This is the top portion of the page.
|
||
|
$out .= "\n";
|
||
|
if (strlen($stmt['bill_note']) != 0 && $GLOBALS['statement_bill_note_print']) {
|
||
|
$out .= sprintf("%-46s\n", $stmt['bill_note']);
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['use_dunning_message']) {
|
||
|
$out .= sprintf("%-46s\n", $dun_message);
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf(
|
||
|
"%-s: %-25s %-s: %-14s %-s: %8s\n",
|
||
|
$label_ptname,
|
||
|
$stmt['patient'],
|
||
|
$label_today,
|
||
|
oeFormatShortDate($stmt['today']),
|
||
|
$label_due,
|
||
|
$stmt['amount']
|
||
|
);
|
||
|
$out .= sprintf("__________________________________________________________________\n");
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-s\n", $label_call);
|
||
|
$out .= sprintf("%-s\n", $label_prompt);
|
||
|
$out .= "\n";
|
||
|
$out .= sprintf("%-s\n", $billing_contact);
|
||
|
$out .= sprintf(" %-s %-25s\n", $label_dept, $label_bill_phone);
|
||
|
if ($GLOBALS['statement_message_to_patient']) {
|
||
|
$out .= "\n";
|
||
|
$statement_message = $GLOBALS['statement_msg_text'];
|
||
|
$out .= sprintf("%-40s\n", $statement_message);
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['show_aging_on_custom_statement']) {
|
||
|
# code for ageing
|
||
|
$ageline .= ' | ' . xl('Over') . ' ' . ($age_index * 30) . ':' .
|
||
|
sprintf(" %.2f", $aging[$age_index]);
|
||
|
$out .= "\n" . $ageline . "\n\n";
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
if ($GLOBALS['number_appointments_on_statement'] != 0) {
|
||
|
$out .= "\n";
|
||
|
$num_appts = $GLOBALS['number_appointments_on_statement'];
|
||
|
$next_day = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y'));
|
||
|
# add one day to date so it will not get todays appointment
|
||
|
$current_date2 = date('Y-m-d', $next_day);
|
||
|
$events = fetchNextXAppts($current_date2, $stmt['pid'], $num_appts);
|
||
|
$j = 0;
|
||
|
$out .= sprintf("%-s\n", $label_appointments);
|
||
|
#loop to add the appointments
|
||
|
for ($x = 1; $x <= $num_appts; $x++) {
|
||
|
$next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
|
||
|
$next_appoint_time = substr($events[$j]['pc_startTime'], 0, 5);
|
||
|
if (strlen(umname) != 0) {
|
||
|
$next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] . ' ' . $events[$j]['ulname'];
|
||
|
} else {
|
||
|
$next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
|
||
|
}
|
||
|
|
||
|
if (strlen($next_appoint_time) != 0) {
|
||
|
$label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') . ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
|
||
|
$out .= sprintf("%-s\n", $label_plsnote[$j]);
|
||
|
}
|
||
|
|
||
|
$j++;
|
||
|
$count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// while ($count++ < 29) $out .= "\n";
|
||
|
$out .= sprintf("%-10s %s\n", null, $label_retpay);
|
||
|
$out .= '</pre></div>';
|
||
|
$out .= '<div style="width:7.0in;border-top:1pt dotted black;font-size:12px;margin:0px;"><br /><br />
|
||
|
<table style="width:8in;margin-left:20px;"><tr><td style="width:4.5in;"><br />
|
||
|
';
|
||
|
$out .= $label_payby . ' ' . $label_cards;
|
||
|
$out .= "<br /><br />";
|
||
|
$out .= $label_cardnum . ': {TextInput} ' . $label_expiry . ': {smTextInput} / {smTextInput} <br /><br />';
|
||
|
$out .= $label_sign . ' {PatientSignature}<br />';
|
||
|
$out .= " </td><td style=width:2.0in;vertical-align:middle;'>";
|
||
|
$practice_cards = $GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif";
|
||
|
if (file_exists($GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif")) {
|
||
|
//$out .= "<img onclick='getPayment()' src='$practice_cards' style='width:100%;margin:4px auto;'><br /><p>\n".$label_totaldue.": ".$stmt['amount']."</p>";
|
||
|
$out .= "<br /><p>" . $label_totaldue . ": " . $stmt['amount'] . "</p>";
|
||
|
}
|
||
|
|
||
|
$out .= "</td></tr></table>";
|
||
|
|
||
|
$out .= '</div><br />';
|
||
|
if ($stmt['to'][3] != '') { //to avoid double blank lines the if condition is put.
|
||
|
$out .= sprintf(" %-32s\n", $stmt['to'][3]);
|
||
|
}
|
||
|
|
||
|
$out .= ' </pre>
|
||
|
<div style="width:8in;border-top:1pt solid black;"><br />';
|
||
|
$out .= " <table style='width:6.0in;margin-left:40px;'><tr>";
|
||
|
$out .= '<td style="width:3.0in;"><b>'
|
||
|
. $label_addressee . '</b><br />'
|
||
|
. $stmt['to'][0] . '<br />'
|
||
|
. $stmt['to'][1] . '<br />'
|
||
|
. $stmt['to'][2] . '
|
||
|
</td>
|
||
|
<td style="width:3.0in;"><b>' . $label_remitto . '</b><br />'
|
||
|
. $remit_name . '<br />'
|
||
|
. $remit_addr . '<br />'
|
||
|
. $remit_csz . '
|
||
|
</td>
|
||
|
</tr></table>';
|
||
|
|
||
|
$out .= " </div></div>";
|
||
|
$out .= "\014
|
||
|
<br /><br />"; // this is a form feed
|
||
|
echo $out;
|
||
|
$output = ob_get_clean();
|
||
|
return $output;
|
||
|
}
|