Merge pull request #7492 from sjpadgett/weno_updates
[openemr.git] / sites / default / statement.inc.php
blob2d5e137941789e358fea30593d44170b6e505174
1 <?php
3 /* This is a template for printing patient statements and collection
4 * letters. You must customize it to suit your practice. If your
5 * needs are simple then you do not need programming experience to do
6 * this - just read the comments and make appropriate substitutions.
7 * All you really need to do is replace the [strings in brackets].
9 * @package OpenEMR
10 * @author Rod Roark <rod@sunsetsystems.com>
11 * @copyright Copyright (c) 2006 Rod Roark <rod@sunsetsystems.com>
12 * @author Bill Cernansky <bill@mi-squared.com>
13 * @copyright Copyright (c) 2009 Bill Cernansky <bill@mi-squared.com>
14 * @author Tony McCormick <tony@mi-squared.com>
15 * @copyright Copyright (c) 2009 Tony McCormick <tony@mi-squared.com>
16 * @author Raymond Magauran <magauran@medfetch.com>
17 * @copyright Copyright (c) 2016 Raymond Magauran <magauran@medfetch.com>
18 * @author Jerry Padgett <sjpadgett@gmail.com>
19 * @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com>
20 * @author Stephen Waite <stephen.waite@cmsvt.com>
21 * @copyright Copyright (c) 2020 Stephen Waite <stephen.waite@cmsvt.com>
22 * @author Daniel Pflieger <daniel@growlingflea.com>
23 * @copyright Copyright (c) 2018 Daniel Pflieger <daniel@growlingflea.com>
24 * @link https://github.com/openemr/openemr/tree/master
25 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
28 use OpenEMR\Common\Crypto\CryptoGen;
30 // The location/name of a temporary file to hold printable statements.
31 // May want to alter these names to allow multi-site installs out-of-the-box
33 $STMT_TEMP_FILE = $GLOBALS['temporary_files_dir'] . "/openemr_statements.txt";
34 $STMT_TEMP_FILE_PDF = $GLOBALS['temporary_files_dir'] . "/openemr_statements.pdf";
35 $STMT_PRINT_CMD = (new CryptoGen())->decryptStandard($GLOBALS['more_secure']['print_command']);
37 /** There are two options to print a batch of PDF statements:
38 * 1. The original statement, a text based statement, using CezPDF
39 * Altering this statement is labor intensive, but capable of being altered any way desired...
41 * 2. Branded Statement, whose core is build from 1., the original statement, using mPDF.
43 * To customize 2., add your practice location/images/practice_logo.gif
44 * In the base/default install this is located at '/openemr/sites/default/images/practice_logo.gif',
45 * Adjust directory paths per your installation.
46 * Further customize 2. manually in functions report_2() and create_HTML_statement(), below.
49 function make_statement($stmt)
51 if ($GLOBALS['statement_appearance'] == "1") {
52 if (!empty($_POST['form_portalnotify']) && is_auth_portal($stmt['pid'])) {
53 return osp_create_HTML_statement($stmt);
54 } else {
55 return create_HTML_statement($stmt);
57 } else {
58 return create_statement($stmt);
61 /**
62 * This prints a header for documents. Keeps the brand uniform...
63 * @param string $pid patient_id
64 * @param string $direction, options "web" or anything else. Web provides apache-friendly url links.
65 * @return outputs to be displayed however requested
67 function report_header_2($stmt, $providerID = '1')
69 $titleres = getPatientData($stmt['pid'], "fname,lname,DOB");
70 //Author Daniel Pflieger - daniel@growlingflea.com
71 //We get the service facility from the encounter. In cases with multiple service facilities
72 //OpenEMR sends the correct facility
74 $service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.facility_id = f.id where fe.id = ?", array($stmt['fid']));
75 $facility = sqlFetchArray($service_query);
77 $DOB = oeFormatShortDate($titleres['DOB']);
78 /******************************************************************/
79 ob_start();
80 // Use logo if it exists as 'practice_logo.gif' in the site dir
81 // old code used the global custom dir which is no longer a valid
83 <table style="width:100%;">
84 <tr>
85 <?php
86 $haveLogo = false;
87 if (empty(!$GLOBALS['statement_logo'])) {
88 $practice_logo = $GLOBALS['OE_SITE_DIR'] . "/images/" . convert_safe_file_dir_name($GLOBALS['statement_logo']);
89 } else { // 'ya never know.
90 $practice_logo = $GLOBALS['OE_SITE_DIR'] . "/images/practice_logo.gif"; // can see is safe...
93 //Author Daniel Pflieger - daniel@growlingflea.com
94 //We only put space for a logo if it exists.
95 //if it does we put the patient name and the service facility on a separate line.
96 //Patients with long names cause formatting issues and it makes the statement look
97 //unprofessional. Additionally, the end user should be able to choose the
98 //statement logo from Administration -> statement.
100 if (is_file($practice_logo)) { // note: file_exist() will return true if path exist but not file. a truly function name misnomer.
101 echo "<td style='width:15%; height: auto; text-align:center;'>\n";
102 // restrain logo proportionally
103 echo "<img src='" . attr($practice_logo) . "' align='left' style='width:100%; height: auto; margin:0px;'><br />\n";
104 echo "</td>\n";
105 $haveLogo = true;
108 <td align='center' style='<?php echo ($haveLogo ? text("width:40%;max-width:50%;") : text("width:50%;") ) ?>'> <!--adds some growing room-->
109 <em style="font-weight:bold;font-size:1.4em;"><?php echo text($facility['name']); ?></em><br />
110 <?php echo text($facility['street']); ?><br />
111 <?php echo text($facility['city']); ?>, <?php echo text($facility['state']); ?> <?php echo text($facility['postal_code']); ?><br />
112 <?php echo xlt('Phone') . ': ' . text($facility['phone']); ?><br />
113 <?php echo xlt('Fax') . ': ' . text($facility['fax']); ?><br />
114 <br clear='all' />
115 </td>
116 <td align='center'>
117 <em style="font-weight:bold;font-size:1.4em;"><?php echo text($titleres['fname']) . " " . text($titleres['lname']); ?></em><br />
118 <b style="font-weight:bold;"><?php echo xlt('Chart Number'); ?>:</b> <?php echo text($stmt['pid']); ?><br />
119 <b style="font-weight:bold;"><?php echo xlt('Generated on'); ?>:</b> <?php echo text(oeFormatShortDate()); ?><br />
120 <b><?php echo xlt('Provider') . ':</b> '; ?><?php echo text(getProviderName($providerID)); ?> <br />
121 </td>
122 </tr>
123 </table>
124 <?php
125 $output = ob_get_contents();
126 ob_end_clean();
127 return $output;
130 function create_HTML_statement($stmt)
132 if (! $stmt['pid']) {
133 return ""; // get out if no data
136 #minimum_amount_due_to _print
137 if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion'] && ($_POST['form_category'] !== "All")) {
138 return "";
141 // Facility (service location) modified by Daniel Pflieger at Growlingflea Software
142 $service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.facility_id = f.id where fe.id = ? ", array($stmt['fid']));
143 $row = sqlFetchArray($service_query);
144 $clinic_name = "{$row['name']}";
145 $clinic_addr = "{$row['street']}";
146 $clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
149 // Billing location modified by Daniel Pflieger at Growlingflea Software
150 $service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.billing_facility = f.id where fe.id = ?", array($stmt['fid']));
151 $row = sqlFetchArray($service_query);
152 $remit_name = "{$row['name']}";
153 $remit_addr = "{$row['street']}";
154 $remit_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
156 ob_start();
157 ?><div style="padding-left:25px; page-break-after:always;">
158 <?php
159 $find_provider = sqlQuery("SELECT * FROM form_encounter " .
160 "WHERE pid = ? AND encounter = ? " .
161 "ORDER BY id DESC LIMIT 1", array($stmt['pid'],$stmt['encounter']));
162 $providerID = $find_provider['provider_id'];
163 echo report_header_2($stmt, $providerID);
165 // dunning message setup
167 // insurance has paid something
168 // $stmt['age'] how old is the invoice
169 // $stmt['dun_count'] number of statements run
170 // $stmt['level_closed'] <= 3 insurance 4 = patient
172 if ($GLOBALS['use_dunning_message']) {
173 if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
174 // do collection messages
175 switch ($stmt['age']) {
176 case $stmt['age'] <= $GLOBALS['first_dun_msg_set']:
177 $dun_message = $GLOBALS['first_dun_msg_text'];
178 break;
179 case $stmt['age'] <= $GLOBALS['second_dun_msg_set']:
180 $dun_message = $GLOBALS['second_dun_msg_text'];
181 break;
182 case $stmt['age'] <= $GLOBALS['third_dun_msg_set']:
183 $dun_message = $GLOBALS['third_dun_msg_text'];
184 break;
185 case $stmt['age'] <= $GLOBALS['fourth_dun_msg_set']:
186 $dun_message = $GLOBALS['fourth_dun_msg_text'];
187 break;
188 case $stmt['age'] >= $GLOBALS['fifth_dun_msg_set']:
189 $dun_message = $GLOBALS['fifth_dun_msg_text'];
190 break;
195 // Text only labels
197 $label_addressee = xl('ADDRESSED TO');
198 $label_remitto = xl('REMIT TO');
199 $label_chartnum = xl('Chart Number');
200 $label_insinfo = xl('Insurance information on file');
201 $label_totaldue = xl('Total amount due');
202 $label_payby = xl('If paying by');
203 $label_cards = xl('VISA/MC/Discovery/HSA');
204 $label_cardnum = xl('Card');
205 $label_expiry = xl('Exp');
206 $label_cvv = xl('CVV');
207 $label_sign = xl('Signature');
208 $label_retpay = xl('Please return this bottom part with your payment');
209 $label_pgbrk = xl('STATEMENT SUMMARY');
210 $label_visit = xl('Visit Date');
211 $label_desc = xl('Description');
212 $label_amt = xl('Amount');
214 // This is the text for the top part of the page, up to but not
215 // including the detail lines. Some examples of variable fields are:
216 // %s = string with no minimum width
217 // %9s = right-justified string of 9 characters padded with spaces
218 // %-25s = left-justified string of 25 characters padded with spaces
219 // Note that "\n" is a line feed (new line) character.
220 // reformatted to handle i8n by tony
222 $out = "<div style='margin-left:60px;margin-top:20px;'><pre>";
223 $out .= "\n";
224 $out .= sprintf("_______________________ %s _______________________\n", $label_pgbrk);
225 $out .= "\n";
226 $out .= sprintf("%-11s %-46s %s\n", $label_visit, $label_desc, $label_amt);
228 // This must be set to the number of lines generated above.
229 $count = 5;
231 $num_ages = 4;
232 $aging = array();
233 for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
234 $aging[$age_index] = 0.00;
237 $todays_time = strtotime(date('Y-m-d'));
239 // This generates the detail lines. Again, note that the values must be specified in the order used.
240 foreach ($stmt['lines'] as $line) {
241 if ($GLOBALS['use_custom_statement']) {
242 $description = substr($line['desc'], 0, 30);
243 } else {
244 $description = $line['desc'];
247 $tmp = substr($description, 0, 14);
248 if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201') {
249 $description = str_replace("Procedure", xl('Office Visit') . ":", $description);
252 //92002-14 are Eye Office Visit Codes
254 $dos = $line['dos'];
255 ksort($line['detail']);
256 // suppressing individual adjustments = improved statement printing
257 $adj_flag = false;
258 $note_flag = false;
259 $pt_paid_flag = false;
260 $prev_ddate = '';
261 $last_activity_date = $dos;
262 foreach ($line['detail'] as $dkey => $ddata) {
263 $ddate = substr($dkey, 0, 10);
264 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
265 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
268 if ($ddate && $ddate > $last_activity_date) {
269 $last_activity_date = $ddate;
272 $amount = '';
274 if (!empty($ddata['pmt'])) {
275 $amount = sprintf("%.2f", 0 - $ddata['pmt']);
276 $desc = xl('Paid') . ' ' . substr(oeFormatShortDate($ddate), 0, 6) .
277 substr(oeFormatShortDate($ddate), 8, 2) .
278 ': ' . $ddata['src'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
279 // $ddata['plv'] is the 'payer_type' field in `ar_activity`, passed in via InvoiceSummary
280 if ($ddata['src'] == 'Pt Paid' || $ddata['plv'] == '0') {
281 $pt_paid_flag = true;
282 $desc = xl('Pt paid') . ' ' . substr(oeFormatShortDate($ddate), 0, 6) .
283 substr(oeFormatShortDate($ddate), 8, 2);
285 } elseif (!empty($ddata['rsn'])) {
286 if ($ddata['chg']) {
287 // this is where the adjustments used to be printed individually
288 $adj_flag = true;
289 } else {
290 if ($ddate == $prev_ddate) {
291 if ($note_flag) {
292 // only 1 note per item or results in too much detail
293 continue;
294 } else {
295 $desc = xl('Note') . ' ' . substr(oeFormatShortDate($ddate), 0, 6) .
296 substr(oeFormatShortDate($ddate), 8, 2) .
297 ': ' . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
298 $note_flag = true;
300 } else {
301 continue; // no need to print notes for 2nd insurances
304 } elseif ($ddata['chg'] < 0) {
305 $amount = sprintf("%.2f", $ddata['chg']);
306 $desc = xl('Patient Payment');
307 } else {
308 $amount = sprintf("%.2f", $ddata['chg']);
309 $desc = $description;
312 if (!$adj_flag) {
313 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
314 ++$count;
317 $dos = '';
318 $adj_flag = false;
319 $note_flag = false;
320 $prev_ddate = $ddate;
322 // print the adjustments summed after all other postings
323 if ($line['adjust'] !== '0.00') {
324 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), "Insurance adjusted", sprintf("%.2f", 0 - $line['adjust']));
325 ++$count;
328 // don't print a balance after a "Paidpatient payment since it's on it's own line
329 if (!$pt_paid_flag) {
330 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), "Item balance ", sprintf("%.2f", ($line['amount'] - $line['paid'])));
331 ++$count;
334 # Compute the aging bucket index and accumulate into that bucket.
335 $last_activity_date = ($line['bill_date'] > $last_activity_date) ? $line['bill_date'] : $last_activity_date;
336 // If first bill then make the amount due current and reset aging date
337 if ($stmt['dun_count'] == '0') {
338 $last_activity_date = date('Y-m-d');
339 sqlStatement("UPDATE billing SET bill_date = ? WHERE pid = ? AND encounter = ?", array(date('Y-m-d'), $row['pid'], $row['encounter']));
341 $age_in_days = (int) (($todays_time - strtotime($last_activity_date)) / (60 * 60 * 24));
342 $age_index = (int) (($age_in_days - 1) / 30);
343 $age_index = max(0, min($num_ages - 1, $age_index));
344 $aging[$age_index] += $line['amount'] - $line['paid'];
347 // This generates blank lines until we are at line 20.
348 // At line 20 we start middle third.
350 while ($count++ < 16) {
351 $out .= "\n";
354 # Generate the string of aging text. This will look like:
355 # Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
356 # ....+....1....+....2....+....3....+....4....+....5....+....6....+
358 $ageline = xl('Current') . ': ' . sprintf("%.2f", $aging[0]);
359 for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
360 $ageline .= ' | ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) . ':' .
361 sprintf(" %.2f", $GLOBALS['gbl_currency_symbol'] . '' . $aging[$age_index]);
364 // Fixed text labels
365 $label_ptname = xl('Name');
366 $label_today = xl('Date');
367 $label_due = xl('Due');
368 $label_thanks = xl('Thank you for choosing');
369 $label_call = xl('Please call if any of the above information is incorrect.');
370 $label_prompt = xl('We appreciate prompt payment of balances due.');
371 $label_dept = xl('Billing Department');
372 $label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $row['phone'] );
373 $label_appointments = xl('Future Appointments') . ':';
375 // This is the top portion of the page.
376 $out .= "\n\n\n";
377 if (strlen($stmt['bill_note']) != 0 && $GLOBALS['statement_bill_note_print']) {
378 $out .= sprintf("%-46s\n", $stmt['bill_note']);
379 $count++;
382 if ($GLOBALS['use_dunning_message']) {
383 $out .= sprintf("%-46s\n", $dun_message);
384 $count++;
387 $out .= "\n";
388 $out .= sprintf(
389 "%-s: %-25s %-s: %-14s %-s: %8s\n",
390 $label_ptname,
391 $stmt['patient'],
392 $label_today,
393 oeFormatShortDate($stmt['today']),
394 $label_due,
395 $stmt['amount']
397 $out .= sprintf("__________________________________________________________________\n");
398 $out .= "\n";
399 $out .= sprintf("%-s\n", $label_call);
400 $out .= sprintf("%-s\n", $label_prompt);
401 $out .= "\n";
402 // $out .= sprintf("%-s\n", $billing_contact);
403 $out .= sprintf(" %-s %-25s\n", $label_dept, $label_bill_phone);
404 if ($GLOBALS['statement_message_to_patient']) {
405 $out .= "\n";
406 $statement_message = $GLOBALS['statement_msg_text'];
407 $out .= sprintf("%-40s\n", $statement_message);
408 $count++;
411 if ($GLOBALS['show_aging_on_custom_statement']) {
412 # code for ageing
413 $ageline .= ' | ' . xl('Over') . ' ' . ($age_index * 30) . ':' .
414 sprintf(" %.2f", $aging[$age_index]);
415 $out .= "\n" . $ageline . "\n\n";
416 $count++;
419 if ($GLOBALS['number_appointments_on_statement'] != 0) {
420 $out .= "\n";
421 $num_appts = $GLOBALS['number_appointments_on_statement'];
422 $next_day = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y'));
423 # add one day to date so it will not get todays appointment
424 $current_date2 = date('Y-m-d', $next_day);
425 $events = fetchNextXAppts($current_date2, $stmt['pid'], $num_appts);
426 $j = 0;
427 $out .= sprintf("%-s\n", $label_appointments);
428 #loop to add the appointments
429 for ($x = 1; $x <= $num_appts; $x++) {
430 $next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
431 $next_appoint_time = substr($events[$j]['pc_startTime'], 0, 5);
432 if (strlen(umname) != 0) {
433 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] . ' ' . $events[$j]['ulname'];
434 } else {
435 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
438 if (strlen($next_appoint_time) != 0) {
439 $label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') . ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
440 $out .= sprintf("%-s\n", $label_plsnote[$j]);
443 $j++;
444 $count++;
448 while ($count++ < 29) {
449 $out .= "\n";
452 $out .= sprintf("%-10s %s\n", null, $label_retpay);
453 $out .= '</pre></div>';
454 $out .= '<div style="width:7.0in;border-top:1pt dotted black;font-size:12px;margin:0px;"><br /><br />
455 <table style="width:7in;margin-left:20px;"><tr><td style="width:4.5in;"><br />
457 $out .= $label_payby . ' ' . $label_cards;
458 $out .= "<br /><br />";
459 $out .= $label_cardnum . ': __________________________________ ' . $label_expiry . ': ___ / ____ ' . $label_cvv . ':____<br /><br />';
460 $out .= $label_sign . ' ______________________________________________<br />';
461 $out .= "</td><td style='width:2.0in;vertical-align:middle;'>";
462 $practice_cards = $GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif";
463 if (file_exists($GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif")) {
464 $out .= "<img src='$practice_cards' style='width:90px;height:auto; margin:4px auto;'><br /><p>\n<b>" .
465 $label_totaldue . "</b>: " . $stmt['amount'] . "<br/>" . xlt('Payment Tracking Id') . ": " .
466 text($stmt['pid']);
467 $out .= "<br />" . xlt('Amount Paid') . ": _______ " . xlt('Check') . " #:</p>";
468 } else {
469 $out .= "<br /><p><b>" . $label_totaldue . "</b>: " . $stmt['amount'] . "<br/>" .
470 xlt('Payment Tracking Id') . ": " . text($stmt['pid']) . "</p>";
471 $out .= "<br /><p>" . xlt('Amount Paid') . ": _______ " . xlt('Check') . " #:</p>";
474 $out .= "</td></tr></table>";
476 $out .= '</div><br />
477 <pre>';
478 if (!empty($stmt['to'][3])) { //to avoid double blank lines the if condition is put.
479 $out .= sprintf(" %-32s\n", $stmt['to'][3]);
482 $out .= ' </pre>
483 <div style="width:7.0in;border-top:1pt solid black;"><br />';
484 $out .= " <table style='width:7.0in;margin:auto;'><tr>";
485 $out .= '<td style="margin:auto;"></td><td style="width:3.0in;"><b>'
486 . $label_addressee . '</b><br />'
487 . $stmt['to'][0] . '<br />'
488 . $stmt['to'][1] . '<br />'
489 . ($stmt['to'][2] ?? '') . '
490 </td><td style="width:0.5in;"></td>
491 <td style="margin:auto;"><b>' . $label_remitto . '</b><br />'
492 . $remit_name . '<br />'
493 . $remit_addr . '<br />'
494 . $remit_csz . '
495 </td>
496 </tr></table>';
498 $out .= " </div></div>";
499 $out .= "\014";
500 echo $out;
501 $output = ob_get_clean();
502 return $output;
505 // This function builds a printable statement or collection letter from
506 // an associative array having the following keys:
508 // today = statement date yyyy-mm-dd
509 // pid = patient ID
510 // patient = patient name
511 // amount = total amount due
512 // to = array of addressee name/address lines
513 // lines = array of lines, each with the following keys:
514 // dos = date of service yyyy-mm-dd
515 // desc = description
516 // amount = charge less adjustments
517 // paid = amount paid
518 // notice = 1 for first notice, 2 for second, etc.
519 // detail = associative array of details
521 // Each detail array is keyed on a string beginning with a date in
522 // yyyy-mm-dd format, or blanks in the case of the original charge
523 // items. Its values are associative arrays like this:
525 // pmt - payment amount as a positive number, only for payments
526 // src - check number or other source, only for payments
527 // chg - invoice line item amount amount, only for charges or
528 // adjustments (adjustments may be zero)
529 // rsn - adjustment reason, only for adjustments
531 // The returned value is a string that can be sent to a printer.
532 // This example is plain text, but if you are a hotshot programmer
533 // then you could make a PDF or PostScript or whatever peels your
534 // banana. These strings are sent in succession, so append a form
535 // feed if that is appropriate.
538 // A sample of the text based format follows:
540 //[Your Clinic Name] Patient Name 2009-12-29
541 //[Your Clinic Address] Chart Number: 1848
542 //[City, State Zip] Insurance information on file
545 //ADDRESSEE REMIT TO
546 //Patient Name [Your Clinic Name]
547 //patient address [Your Clinic Address]
548 //city, state zipcode [City, State Zip]
549 // If paying by VISA/MC/AMEX/Dis
551 //Card_____________________ Exp______ Signature___________________
552 // Return above part with your payment
553 //-----------------------------------------------------------------
555 //_______________________ STATEMENT SUMMARY _______________________
557 //Visit Date Description Amount
559 //2009-08-20 Procedure 99345 198.90
560 // Paid 2009-12-15: -51.50
561 //... more details ...
562 //...
563 //...
564 // skipping blanks in example
567 //Name: Patient Name Date: 2009-12-29 Due: 147.40
568 //_________________________________________________________________
570 //Please call if any of the above information is incorrect
571 //We appreciate prompt payment of balances due
573 //[Your billing contact name]
574 // Billing Department
575 // [Your billing dept phone]
577 function create_statement($stmt)
579 if (! $stmt['pid']) {
580 return ""; // get out if no data
583 #minimum_amount_to _print
584 if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion']) {
585 return "";
588 // These are your clinics return address, contact etc. Edit them.
589 // TBD: read this from the facility table
591 // Facility (service location) modified by Daniel Pflieger at Growlingflea Software
592 $service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.facility_id = f.id where fe.id = ?", array($stmt['fid']));
593 $row = sqlFetchArray($service_query);
594 $clinic_name = "{$row['name']}";
595 $clinic_addr = "{$row['street']}";
596 $clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
599 // Billing location modified by Daniel Pflieger at Growlingflea Software
600 $service_query = sqlStatement("SELECT * FROM `form_encounter` fe join facility f on fe.billing_facility = f.id where fe.id = ?", array($stmt['fid']));
601 $row = sqlFetchArray($service_query);
602 $remit_name = "{$row['name']}";
603 $remit_addr = "{$row['street']}";
604 $remit_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
607 // Contacts
608 $atres = sqlStatement("select f.attn,f.phone from facility f " .
609 " left join users u on f.id=u.facility_id " .
610 " left join billing b on b.provider_id=u.id and b.pid = ? " .
611 " where billing_location=1", [$stmt['pid']]);
612 $row = sqlFetchArray($atres);
613 $billing_contact = "{$row['attn']}";
614 $billing_phone = "{$row['phone']}";
616 // dunning message setup
618 // insurance has paid something
619 // $stmt['age'] how old is the invoice
620 // $stmt['dun_count'] number of statements run
621 // $stmt['level_closed'] <= 3 insurance 4 = patient
623 if ($GLOBALS['use_dunning_message']) {
624 if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
625 // do collection messages
626 switch ($stmt['age']) {
627 case $stmt['age'] <= $GLOBALS['first_dun_msg_set']:
628 $dun_message = $GLOBALS['first_dun_msg_text'];
629 break;
630 case $stmt['age'] <= $GLOBALS['second_dun_msg_set']:
631 $dun_message = $GLOBALS['second_dun_msg_text'];
632 break;
633 case $stmt['age'] <= $GLOBALS['third_dun_msg_set']:
634 $dun_message = $GLOBALS['third_dun_msg_text'];
635 break;
636 case $stmt['age'] <= $GLOBALS['fourth_dun_msg_set']:
637 $dun_message = $GLOBALS['fourth_dun_msg_text'];
638 break;
639 case $stmt['age'] >= $GLOBALS['fifth_dun_msg_set']:
640 $dun_message = $GLOBALS['fifth_dun_msg_text'];
641 break;
646 // Text only labels
648 $label_addressee = xl('ADDRESSED TO');
649 $label_remitto = xl('REMIT TO');
650 $label_chartnum = xl('Chart Number');
651 $label_insinfo = xl('Insurance information on file');
652 $label_totaldue = xl('Total amount due');
653 $label_payby = xl('If paying by');
654 $label_cards = xl('VISA/MC/Discovery/HSA');
655 $label_cardnum = xl('Card');
656 $label_expiry = xl('Exp');
657 $label_cvv = xl('CVV');
658 $label_sign = xl('Signature');
659 $label_retpay = xl('Return above part with your payment');
660 $label_pgbrk = xl('STATEMENT SUMMARY');
661 $label_visit = xl('Visit Date');
662 $label_desc = xl('Description');
663 $label_amt = xl('Amount');
665 // This is the text for the top part of the page, up to but not
666 // including the detail lines. Some examples of variable fields are:
667 // %s = string with no minimum width
668 // %9s = right-justified string of 9 characters padded with spaces
669 // %-25s = left-justified string of 25 characters padded with spaces
670 // Note that "\n" is a line feed (new line) character.
671 // reformatted to handle i8n by tony
672 $out = "\n\n";
673 $providerNAME = getProviderName($stmt['provider_id']);
674 $out .= sprintf("%-30s %s %-s\n", $clinic_name, $stmt['patient'], $stmt['today']);
675 $out .= sprintf("%-30s %s: %-s\n", $providerNAME, $label_chartnum, $stmt['pid']);
676 $out .= sprintf("%-30s %s\n", $clinic_addr, $label_insinfo);
677 $out .= sprintf("%-30s %-s: %-s\n", $clinic_csz, $label_totaldue, $stmt['amount']);
678 $out .= "\n";
679 $out .= sprintf(" %-30s %-s\n", $label_addressee, $label_remitto);
680 $out .= sprintf(" %-30s %s\n", $stmt['to'][0], $remit_name);
681 $out .= sprintf(" %-30s %s\n", $stmt['to'][1], $remit_addr);
682 $out .= sprintf(" %-30s %s\n", $stmt['to'][2], $remit_csz);
684 if ($stmt['to'][3] != '') { //to avoid double blank lines the if condition is put.
685 $out .= sprintf(" %-32s\n", $stmt['to'][3]);
688 $out .= sprintf("_________________________________________________________________\n");
689 $out .= "\n";
690 $out .= sprintf("%-32s\n", $label_payby . ' ' . $label_cards);
691 $out .= "\n";
692 $out .= sprintf(
693 "%s_____________________ %s______ %s______ %s___________________\n\n",
694 $label_cardnum,
695 $label_expiry,
696 $label_cvv,
697 $label_sign
699 $out .= sprintf("-----------------------------------------------------------------\n");
700 $out .= sprintf("%-20s %s\n", null, $label_retpay);
701 $out .= "\n";
702 $out .= sprintf("_______________________ %s _______________________\n", $label_pgbrk);
703 $out .= "\n";
704 $out .= sprintf("%-11s %-46s %s\n", $label_visit, $label_desc, $label_amt);
705 $out .= "\n";
707 // This must be set to the number of lines generated above.
709 $count = 25;
710 $num_ages = 4;
711 $aging = array();
712 for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
713 $aging[$age_index] = 0.00;
716 $todays_time = strtotime(date('Y-m-d'));
718 // This generates the detail lines. Again, note that the values must
719 // be specified in the order used.
723 foreach ($stmt['lines'] as $line) {
724 if ($GLOBALS['use_custom_statement']) {
725 $description = substr($line['desc'], 0, 30);
726 } else {
727 $description = $line['desc'];
730 $tmp = substr($description, 0, 14);
731 if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201') {
732 $description = str_replace("Procedure", xl('Office Visit') . ":", $description);
735 //92002-14 are Eye Office Visit Codes
737 $dos = $line['dos'];
738 ksort($line['detail']);
739 # Compute the aging bucket index and accumulate into that bucket.
741 $age_in_days = (int) (($todays_time - strtotime($dos)) / (60 * 60 * 24));
742 $age_index = (int) (($age_in_days - 1) / 30);
743 $age_index = max(0, min($num_ages - 1, $age_index));
744 $aging[$age_index] += $line['amount'] - $line['paid'];
746 foreach ($line['detail'] as $dkey => $ddata) {
747 $ddate = substr($dkey, 0, 10);
748 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
749 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
752 $amount = '';
754 if ($ddata['pmt']) {
755 $amount = sprintf("%.2f", 0 - $ddata['pmt']);
756 $desc = xl('Paid') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['src'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
757 } elseif ($ddata['rsn']) {
758 if ($ddata['chg']) {
759 $amount = sprintf("%.2f", $ddata['chg']);
760 $desc = xl('Adj') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
761 } else {
762 $desc = xl('Note') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
764 } elseif ($ddata['chg'] < 0) {
765 $amount = sprintf("%.2f", $ddata['chg']);
766 $desc = xl('Patient Payment');
767 } else {
768 $amount = sprintf("%.2f", $ddata['chg']);
769 $desc = $description;
772 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
773 $dos = '';
774 ++$count;
778 // This generates blank lines until we are at line 42.
780 while ($count++ < 42) {
781 $out .= "\n";
784 # Generate the string of aging text. This will look like:
785 # Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
786 # ....+....1....+....2....+....3....+....4....+....5....+....6....+
788 $ageline = xl('Current') . ' ' . sprintf("%.2f", $aging[0]);
789 for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
790 $ageline .= ' / ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) .
791 sprintf(" %.2f", $aging[$age_index]);
794 // Fixed text labels
795 $label_ptname = xl('Name');
796 $label_today = xl('Date');
797 $label_due = xl('Amount Due');
798 $label_thanks = xl('Thank you for choosing');
799 $label_call = xl('Please call if any of the above information is incorrect.');
800 $label_prompt = xl('We appreciate prompt payment of balances due.');
801 $label_dept = xl('Billing Department');
802 $label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $billing_phone );
803 $label_appointments = xl('Future Appointments') . ':';
805 // This is the bottom portion of the page.
806 $out .= "\n";
807 if (strlen($stmt['bill_note']) != 0 && $GLOBALS['statement_bill_note_print']) {
808 $out .= sprintf("%-46s\n", $stmt['bill_note']);
811 if ($GLOBALS['use_dunning_message']) {
812 $out .= sprintf("%-46s\n", $dun_message);
815 $out .= "\n";
816 $out .= sprintf(
817 "%-s: %-25s %-s: %-14s %-s: %8s\n",
818 $label_ptname,
819 $stmt['patient'],
820 $label_today,
821 oeFormatShortDate($stmt['today']),
822 $label_due,
823 $stmt['amount']
825 $out .= sprintf("__________________________________________________________________\n");
826 $out .= "\n";
827 $out .= sprintf("%-s\n", $label_call);
828 $out .= sprintf("%-s\n", $label_prompt);
829 $out .= "\n";
830 $out .= sprintf("%-s\n", $billing_contact);
831 $out .= sprintf(" %-s %-25s\n", $label_dept, $label_bill_phone);
832 if ($GLOBALS['statement_message_to_patient']) {
833 $out .= "\n";
834 $statement_message = $GLOBALS['statement_msg_text'];
835 $out .= sprintf("%-40s\n", $statement_message);
838 if ($GLOBALS['show_aging_on_custom_statement']) {
839 # code for ageing
840 $ageline .= ' / ' . xl('Over') . '-' . ($age_index * 30) .
841 sprintf(" %.2f", $aging[$age_index]);
842 $out .= "\n" . $ageline . "\n\n";
845 if ($GLOBALS['number_appointments_on_statement'] != 0) {
846 $out .= "\n";
847 $num_appts = $GLOBALS['number_appointments_on_statement'];
848 $next_day = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y'));
849 # add one day to date so it will not get todays appointment
850 $current_date2 = date('Y-m-d', $next_day);
851 $events = fetchNextXAppts($current_date2, $stmt['pid'], $num_appts);
852 $j = 0;
853 $out .= sprintf("%-s\n", $label_appointments);
854 #loop to add the appointments
855 for ($x = 1; $x <= $num_appts; $x++) {
856 $next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
857 $next_appoint_time = substr($events[$j]['pc_startTime'], 0, 5);
858 if (strlen(umname) != 0) {
859 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] .
860 ' ' . $events[$j]['ulname'];
861 } else {
862 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
865 if (strlen($next_appoint_time) != 0) {
866 $label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') .
867 ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
868 $out .= sprintf("%-s\n", $label_plsnote[$j]);
871 $j++;
875 $out .= "\014"; // this is a form feed
877 return $out;
880 function osp_create_HTML_statement($stmt)
882 if (! $stmt['pid']) {
883 return ""; // get out if no data
886 #minimum_amount_due_to _print
887 if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion']) {
888 return "";
891 // Facility (service location)
892 $atres = sqlStatement("select f.name,f.street,f.city,f.state,f.postal_code,f.attn,f.phone from facility f " .
893 " left join users u on f.id=u.facility_id " .
894 " left join billing b on b.provider_id=u.id and b.pid = ? " .
895 " where service_location=1", array($stmt['pid']));
896 $row = sqlFetchArray($atres);
897 $clinic_name = "{$row['name']}";
898 $clinic_addr = "{$row['street']}";
899 $clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
900 // Contacts
901 $billing_contact = "{$row['attn']}";
902 $billing_phone = "{$row['phone']}";
903 // Billing location
904 $remit_name = $clinic_name;
905 $remit_addr = $clinic_addr;
906 $remit_csz = $clinic_csz;
908 ob_start();
909 ?><div style="padding-left:25px;">
910 <?php
911 $find_provider = sqlQuery("SELECT * FROM form_encounter " .
912 "WHERE pid = ? AND encounter = ? " .
913 "ORDER BY id DESC LIMIT 1", array($stmt['pid'],$stmt['encounter']));
914 $providerID = $find_provider['provider_id'];
915 echo report_header_2($stmt, $providerID);
917 // dunning message setup
919 // insurance has paid something
920 // $stmt['age'] how old is the invoice
921 // $stmt['dun_count'] number of statements run
922 // $stmt['level_closed'] <= 3 insurance 4 = patient
924 if ($GLOBALS['use_dunning_message']) {
925 if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
926 // do collection messages
927 switch ($stmt['age']) {
928 case $stmt['age'] <= $GLOBALS['first_dun_msg_set']:
929 $dun_message = $GLOBALS['first_dun_msg_text'];
930 break;
931 case $stmt['age'] <= $GLOBALS['second_dun_msg_set']:
932 $dun_message = $GLOBALS['second_dun_msg_text'];
933 break;
934 case $stmt['age'] <= $GLOBALS['third_dun_msg_set']:
935 $dun_message = $GLOBALS['third_dun_msg_text'];
936 break;
937 case $stmt['age'] <= $GLOBALS['fourth_dun_msg_set']:
938 $dun_message = $GLOBALS['fourth_dun_msg_text'];
939 break;
940 case $stmt['age'] >= $GLOBALS['fifth_dun_msg_set']:
941 $dun_message = $GLOBALS['fifth_dun_msg_text'];
942 break;
947 // Text only labels
949 $label_addressee = xl('ADDRESSED TO');
950 $label_remitto = xl('REMIT TO');
951 $label_chartnum = xl('Chart Number');
952 $label_insinfo = xl('Insurance information on file');
953 $label_totaldue = xl('Total amount due');
954 $label_payby = xl('If paying by');
955 $label_cards = xl('VISA/MC/Discovery/HSA');
956 $label_cardnum = xl('Card');
957 $label_expiry = xl('Exp');
958 $label_sign = xl('Signature');
959 $label_retpay = xl('Please fill in credit information and send for review.');
960 $label_pgbrk = xl('STATEMENT SUMMARY');
961 $label_visit = xl('Visit Date');
962 $label_desc = xl('Description');
963 $label_amt = xl('Amount');
965 // This is the text for the top part of the page, up to but not
966 // including the detail lines. Some examples of variable fields are:
967 // %s = string with no minimum width
968 // %9s = right-justified string of 9 characters padded with spaces
969 // %-25s = left-justified string of 25 characters padded with spaces
970 // Note that "\n" is a line feed (new line) character.
971 // reformatted to handle i8n by tony
973 $out = "<div style='margin-left:60px;margin-top:0px;'>";
974 $out .= "\n";
975 $out .= sprintf("_______________________ %s _______________________\n", $label_pgbrk);
976 $out .= "\n";
977 $out .= sprintf("%-11s %-46s %s\n", $label_visit, $label_desc, $label_amt);
978 $out .= "\n";
980 // This must be set to the number of lines generated above.
982 $count = 6;
983 $num_ages = 4;
984 $aging = array();
985 for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
986 $aging[$age_index] = 0.00;
989 $todays_time = strtotime(date('Y-m-d'));
991 // This generates the detail lines. Again, note that the values must be specified in the order used.
992 foreach ($stmt['lines'] as $line) {
993 if ($GLOBALS['use_custom_statement']) {
994 $description = substr($line['desc'], 0, 30);
995 } else {
996 $description = $line['desc'];
999 $tmp = substr($description, 0, 14);
1000 if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201') {
1001 $description = str_replace("Procedure", xl('Office Visit') . ":", $description);
1004 //92002-14 are Eye Office Visit Codes
1006 $dos = $line['dos'];
1007 ksort($line['detail']);
1008 # Compute the aging bucket index and accumulate into that bucket.
1009 $age_in_days = (int) (($todays_time - strtotime($dos)) / (60 * 60 * 24));
1010 $age_index = (int) (($age_in_days - 1) / 30);
1011 $age_index = max(0, min($num_ages - 1, $age_index));
1012 $aging[$age_index] += $line['amount'] - $line['paid'];
1014 foreach ($line['detail'] as $dkey => $ddata) {
1015 $ddate = substr($dkey, 0, 10);
1016 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
1017 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
1020 $amount = '';
1022 if ($ddata['pmt']) {
1023 $amount = sprintf("%.2f", 0 - $ddata['pmt']);
1024 $desc = xl('Paid') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['src'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
1025 } elseif ($ddata['rsn']) {
1026 if ($ddata['chg']) {
1027 $amount = sprintf("%.2f", $ddata['chg']);
1028 $desc = xl('Adj') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
1029 } else {
1030 $desc = xl('Note') . ' ' . oeFormatShortDate($ddate) . ': ' . $ddata['rsn'] . ' ' . $ddata['pmt_method'] . ' ' . $ddata['insurance_company'];
1032 } elseif ($ddata['chg'] < 0) {
1033 $amount = sprintf("%.2f", $ddata['chg']);
1034 $desc = xl('Patient Payment');
1035 } else {
1036 $amount = sprintf("%.2f", $ddata['chg']);
1037 $desc = $description;
1040 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
1041 $dos = '';
1042 ++$count;
1046 // This generates blank lines until we are at line 20.
1047 // At line 20 we start middle third.
1049 //while ($count++ < 16) $out .= "\n";
1050 # Generate the string of aging text. This will look like:
1051 # Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
1052 # ....+....1....+....2....+....3....+....4....+....5....+....6....+
1054 $ageline = xl('Current') . ': ' . sprintf("%.2f", $aging[0]);
1055 for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
1056 $ageline .= ' | ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) . ':' .
1057 sprintf(" %.2f", $GLOBALS['gbl_currency_symbol'] . '' . $aging[$age_index]);
1060 // Fixed text labels
1061 $label_ptname = xl('Name');
1062 $label_today = xl('Date');
1063 $label_due = xl('Due');
1064 $label_thanks = xl('Thank you for choosing');
1065 $label_call = xl('Please call or message if any of the above information is incorrect.');
1066 $label_prompt = xl('We appreciate prompt payment of balances due.');
1067 $label_dept = xl('Billing Department');
1068 $label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $billing_phone );
1069 $label_appointments = xl('Future Appointments') . ':';
1071 // This is the top portion of the page.
1072 $out .= "\n";
1073 if (strlen($stmt['bill_note']) != 0 && $GLOBALS['statement_bill_note_print']) {
1074 $out .= sprintf("%-46s\n", $stmt['bill_note']);
1075 $count++;
1078 if ($GLOBALS['use_dunning_message']) {
1079 $out .= sprintf("%-46s\n", $dun_message);
1080 $count++;
1083 $out .= "\n";
1084 $out .= sprintf(
1085 "%-s: %-25s %-s: %-14s %-s: %8s\n",
1086 $label_ptname,
1087 $stmt['patient'],
1088 $label_today,
1089 oeFormatShortDate($stmt['today']),
1090 $label_due,
1091 $stmt['amount']
1093 $out .= sprintf("__________________________________________________________________\n");
1094 $out .= "\n";
1095 $out .= sprintf("%-s\n", $label_call);
1096 $out .= sprintf("%-s\n", $label_prompt);
1097 $out .= "\n";
1098 $out .= sprintf("%-s\n", $billing_contact);
1099 $out .= sprintf(" %-s %-25s\n", $label_dept, $label_bill_phone);
1100 if ($GLOBALS['statement_message_to_patient']) {
1101 $out .= "\n";
1102 $statement_message = $GLOBALS['statement_msg_text'];
1103 $out .= sprintf("%-40s\n", $statement_message);
1104 $count++;
1107 if ($GLOBALS['show_aging_on_custom_statement']) {
1108 # code for ageing
1109 $ageline .= ' | ' . xl('Over') . ' ' . ($age_index * 30) . ':' .
1110 sprintf(" %.2f", $aging[$age_index]);
1111 $out .= "\n" . $ageline . "\n\n";
1112 $count++;
1115 if ($GLOBALS['number_appointments_on_statement'] != 0) {
1116 $out .= "\n";
1117 $num_appts = $GLOBALS['number_appointments_on_statement'];
1118 $next_day = mktime(0, 0, 0, date('m'), date('d') + 1, date('Y'));
1119 # add one day to date so it will not get todays appointment
1120 $current_date2 = date('Y-m-d', $next_day);
1121 $events = fetchNextXAppts($current_date2, $stmt['pid'], $num_appts);
1122 $j = 0;
1123 $out .= sprintf("%-s\n", $label_appointments);
1124 #loop to add the appointments
1125 for ($x = 1; $x <= $num_appts; $x++) {
1126 $next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
1127 $next_appoint_time = substr($events[$j]['pc_startTime'], 0, 5);
1128 if (strlen(umname) != 0) {
1129 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] . ' ' . $events[$j]['ulname'];
1130 } else {
1131 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
1134 if (strlen($next_appoint_time) != 0) {
1135 $label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') . ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
1136 $out .= sprintf("%-s\n", $label_plsnote[$j]);
1139 $j++;
1140 $count++;
1144 // while ($count++ < 29) $out .= "\n";
1145 $out .= sprintf("%-10s %s\n", null, $label_retpay);
1146 $out .= '</pre></div>';
1147 $out .= '<div style="width:7.0in;border-top:1pt dotted black;font-size:12px;margin:0px;"><br /><br />
1148 <table style="width:8in;margin-left:20px;"><tr><td style="width:4.5in;"><br />
1150 $out .= $label_payby . ' ' . $label_cards;
1151 $out .= "<br /><br />";
1152 $out .= $label_cardnum . ': {TextInput} ' . $label_expiry . ': {smTextInput} / {smTextInput} <br /><br />';
1153 $out .= $label_sign . ' {PatientSignature}<br />';
1154 $out .= " </td><td style=width:2.0in;vertical-align:middle;'>";
1155 $practice_cards = $GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif";
1156 if (file_exists($GLOBALS['OE_SITE_DIR'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif")) {
1157 //$out .= "<img onclick='getPayment()' src='$practice_cards' style='width:100%;margin:4px auto;'><br /><p>\n".$label_totaldue.": ".$stmt['amount']."</p>";
1158 $out .= "<br /><p>" . $label_totaldue . ": " . $stmt['amount'] . "</p>";
1161 $out .= "</td></tr></table>";
1163 $out .= '</div><br />';
1164 if ($stmt['to'][3] != '') { //to avoid double blank lines the if condition is put.
1165 $out .= sprintf(" %-32s\n", $stmt['to'][3]);
1168 $out .= ' </pre>
1169 <div style="width:8in;border-top:1pt solid black;"><br />';
1170 $out .= " <table style='width:6.0in;margin-left:40px;'><tr>";
1171 $out .= '<td style="width:3.0in;"><b>'
1172 . $label_addressee . '</b><br />'
1173 . $stmt['to'][0] . '<br />'
1174 . $stmt['to'][1] . '<br />'
1175 . $stmt['to'][2] . '
1176 </td>
1177 <td style="width:3.0in;"><b>' . $label_remitto . '</b><br />'
1178 . $remit_name . '<br />'
1179 . $remit_addr . '<br />'
1180 . $remit_csz . '
1181 </td>
1182 </tr></table>';
1184 $out .= " </div></div>";
1185 $out .= "\014
1186 <br /><br />"; // this is a form feed
1187 echo $out;
1188 $output = ob_get_clean();
1189 return $output;