fixes to prior statements improvements
[openemr.git] / sites / default / statement.inc.php
blob4fc17c4fd22354ae9590efc3b9351a0cb9952497
1 <?php
3 // Copyright (C) 2005-2006 Rod Roark <rod@sunsetsystems.com>
4 // Copyright (C) 2016 Raymond Magauran <magauran@medfetch.com>
5 //
6 // Windows compatibility mods 2009 Bill Cernansky [mi-squared.com]
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
13 // Updated by Medical Information Integration, LLC to support download
14 // and multi OS use - tony@mi-squared..com 12-2009
16 //////////////////////////////////////////////////////////////////////
17 // This is a template for printing patient statements and collection
18 // letters. You must customize it to suit your practice. If your
19 // needs are simple then you do not need programming experience to do
20 // this - just read the comments and make appropriate substitutions.
21 // All you really need to do is replace the [strings in brackets].
22 //////////////////////////////////////////////////////////////////////
24 // The location/name of a temporary file to hold printable statements.
25 // May want to alter these names to allow multi-site installs out-of-the-box
27 $STMT_TEMP_FILE = $GLOBALS['temporary_files_dir'] . "/openemr_statements.txt";
28 $STMT_TEMP_FILE_PDF = $GLOBALS['temporary_files_dir'] . "/openemr_statements.pdf";
29 $STMT_PRINT_CMD = $GLOBALS['print_command'];
31 /** There are two options to print a batch of PDF statements:
32 * 1. The original statement, a text based statement, using CezPDF
33 * Altering this statement is labor intensive, but capable of being altered any way desired...
35 * 2. Branded Statement, whose core is build from 1., the original statement, using HTML2PDF.
37 * To customize 2., add your practice location/images/practice_logo.gif
38 * In the base/default install this is located at '/openemr/sites/default/images/practice_logo.gif',
39 * Adjust directory paths per your installation.
40 * Further customize 2. manually in functions report_2() and create_HTML_statement(), below.
43 function make_statement($stmt) {
44 if ($GLOBALS['statement_appearance'] == "1") {
45 return create_HTML_statement($stmt);
46 } else {
47 return create_statement($stmt);
50 /**
51 * This prints a header for documents. Keeps the brand uniform...
52 * @param string $pid patient_id
53 * @param string $direction, options "web" or anything else. Web provides apache-friendly url links.
54 * @return outputs to be displayed however requested
56 function report_header_2($stmt,$direction='',$providerID='1') {
57 $titleres = getPatientData($stmt['pid'], "fname,lname,DOB");
58 if ($_SESSION['pc_facility']) {
59 $sql = "select * from facility where id=?";
60 $facility = sqlQuery($sql,array($_SESSION['pc_facility']));
61 } else {
62 $sql = "SELECT * FROM facility ORDER BY billing_location DESC LIMIT 1";
63 $facility = sqlQuery($sql);
65 $DOB = oeFormatShortDate($titleres['DOB']);
66 /******************************************************************/
67 ob_start();
68 // Use logo if it exists as 'practice_logo.gif' in the site dir
69 // old code used the global custom dir which is no longer a valid
71 <table style="width:7in;">
72 <tr>
73 <td style='width:100px;text-align:top;'>
74 <?php
75 $practice_logo = $GLOBALS['OE_SITE_DIR']."/images/practice_logo.gif";
76 if (file_exists($practice_logo)) {
77 echo "<img src='$practice_logo' align='left' style='width:125px;margin:0px;'><br />\n";
80 </td>
81 <td style='width:40%;'>
82 <em style="font-weight:bold;font-size:1.4em;"><?php echo text($facility['name']); ?></em><br />
83 <?php echo text($facility['street']); ?><br />
84 <?php echo text($facility['city']); ?>, <?php echo text($facility['state']); ?> <?php echo text($facility['postal_code']); ?><br />
85 <?php echo xlt('Phone').': ' .text($facility['phone']); ?><br />
86 <?php echo xlt('Fax').': ' .text($facility['fax']); ?><br />
87 <br clear='all' />
88 </td>
89 <td>
90 <em style="font-weight:bold;font-size:1.4em;"><?php echo text($titleres['fname']) . " " . text($titleres['lname']); ?></em><br />
91 <b style="font-weight:bold;"><?php echo xlt('Chart Number'); ?>:</b> <?php echo text($stmt['pid']); ?><br />
92 <b style="font-weight:bold;"><?php echo xlt('Generated on'); ?>:</b> <?php echo oeFormatShortDate(); ?><br />
93 <b><?php echo xlt('Provider') . ':</b> '; ?><?php echo text(getProviderName($providerID)); ?> <br />
94 </td>
95 </tr>
96 </table>
97 <?php
98 $output = ob_get_contents();
99 ob_end_clean();
100 return $output;
103 function create_HTML_statement($stmt) {
104 if (! $stmt['pid']) return ""; // get out if no data
106 #minimum_amount_due_to _print
107 if ($stmt['amount'] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion']) return "";
109 // Facility (service location)
110 $atres = sqlStatement("select f.name,f.street,f.city,f.state,f.postal_code,f.attn,f.phone from facility f " .
111 " left join users u on f.id=u.facility_id " .
112 " left join billing b on b.provider_id=u.id and b.pid = ? ".
113 " where service_location=1",array($stmt['pid']));
114 $row = sqlFetchArray($atres);
115 $clinic_name = "{$row['name']}";
116 $clinic_addr = "{$row['street']}";
117 $clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
118 // Contacts
119 $billing_contact = "{$row['attn']}";
120 $billing_phone = "{$row['phone']}";
121 // Billing location
122 $remit_name = $clinic_name;
123 $remit_addr = $clinic_addr;
124 $remit_csz = $clinic_csz;
126 ob_start();
127 ?><div style="padding-left:25px;">
128 <?php
129 $find_provider = sqlQuery("SELECT * FROM form_encounter " .
130 "WHERE pid = ? AND encounter = ? " .
131 "ORDER BY id DESC LIMIT 1", array($stmt['pid'],$stmt['encounter']) );
132 $providerID = $find_provider['provider_id'];
133 echo report_header_2($stmt,$direction,$providerID);
135 // dunning message setup
137 // insurance has paid something
138 // $stmt['age'] how old is the invoice
139 // $stmt['dun_count'] number of statements run
140 // $stmt['level_closed'] <= 3 insurance 4 = patient
142 if ($GLOBALS['use_dunning_message']) {
143 if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
145 // do collection messages
146 switch ($stmt{'age'}) {
147 case $stmt{'age'} <= $GLOBALS['first_dun_msg_set']:
148 $dun_message = $GLOBALS['first_dun_msg_text'];
149 break;
150 case $stmt{'age'} <= $GLOBALS['second_dun_msg_set']:
151 $dun_message = $GLOBALS['second_dun_msg_text'];
152 break;
153 case $stmt{'age'} <= $GLOBALS['third_dun_msg_set']:
154 $dun_message = $GLOBALS['third_dun_msg_text'];
155 break;
156 case $stmt{'age'} <= $GLOBALS['fourth_dun_msg_set']:
157 $dun_message = $GLOBALS['fourth_dun_msg_text'];
158 break;
159 case $stmt{'age'} >= $GLOBALS['fifth_dun_msg_set']:
160 $dun_message = $GLOBALS['fifth_dun_msg_text'];
161 break;
165 // Text only labels
167 $label_addressee = xl('ADDRESSEE');
168 $label_remitto = xl('REMIT TO');
169 $label_chartnum = xl('Chart Number');
170 $label_insinfo = xl('Insurance information on file');
171 $label_totaldue = xl('Total amount due');
172 $label_payby = xl('If paying by');
173 $label_cards = xl('VISA/MC/Discovery/HSA');
174 $label_cardnum = xl('Card');
175 $label_expiry = xl('Exp');
176 $label_sign = xl('Signature');
177 $label_retpay = xl('Please return this bottom part with your payment');
178 $label_pgbrk = xl('STATEMENT SUMMARY');
179 $label_visit = xl('Visit Date');
180 $label_desc = xl('Description');
181 $label_amt = xl('Amount');
183 // This is the text for the top part of the page, up to but not
184 // including the detail lines. Some examples of variable fields are:
185 // %s = string with no minimum width
186 // %9s = right-justified string of 9 characters padded with spaces
187 // %-25s = left-justified string of 25 characters padded with spaces
188 // Note that "\n" is a line feed (new line) character.
189 // reformatted to handle i8n by tony
191 $out = "<div style='margin-left:60px;margin-top:20px;'><pre>";
192 $out .= "\n";
193 $out .= sprintf("_______________________ %s _______________________\n",$label_pgbrk);
194 $out .= "\n";
195 $out .= sprintf("%-11s %-46s %s\n",$label_visit,$label_desc,$label_amt);
196 $out .= "\n";
198 // This must be set to the number of lines generated above.
200 $count = 6;
201 $num_ages = 4;
202 $aging = array();
203 for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
204 $aging[$age_index] = 0.00;
206 $todays_time = strtotime(date('Y-m-d'));
208 // This generates the detail lines. Again, note that the values must be specified in the order used.
209 foreach ($stmt['lines'] as $line) {
210 if ($GLOBALS['use_custom_statement']) {
211 $description = substr($line['desc'],0,30);
212 } else {
213 $description = $line['desc'];
216 $tmp = substr($description, 0, 14);
217 if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201')
218 $description = str_replace("Procedure",xl('Office Visit').":",$description);
219 //92002-14 are Eye Office Visit Codes
221 $dos = $line['dos'];
222 ksort($line['detail']);
223 # Compute the aging bucket index and accumulate into that bucket.
224 $age_in_days = (int) (($todays_time - strtotime($dos)) / (60 * 60 * 24));
225 $age_index = (int) (($age_in_days - 1) / 30);
226 $age_index = max(0, min($num_ages - 1, $age_index));
227 $aging[$age_index] += $line['amount'] - $line['paid'];
229 foreach ($line['detail'] as $dkey => $ddata) {
230 $ddate = substr($dkey, 0, 10);
231 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
232 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
234 $amount = '';
236 if ($ddata['pmt']) {
237 $amount = sprintf("%.2f", 0 - $ddata['pmt']);
238 $desc = xl('Paid') .' '. oeFormatShortDate($ddate) .': '. $ddata['src'].' '. $ddata['pmt_method'].' '. $ddata['insurance_company'];
239 } else if ($ddata['rsn']) {
240 if ($ddata['chg']) {
241 $amount = sprintf("%.2f", $ddata['chg']);
242 $desc = xl('Adj') .' '. oeFormatShortDate($ddate) .': ' . $ddata['rsn'].' '.$ddata['pmt_method'].' '. $ddata['insurance_company'];
243 } else {
244 $desc = xl('Note') .' '. oeFormatShortDate($ddate) .': '. $ddata['rsn'].' '.$ddata['pmt_method'].' '. $ddata['insurance_company'];
246 } else if ($ddata['chg'] < 0) {
247 $amount = sprintf("%.2f", $ddata['chg']);
248 $desc = xl('Patient Payment');
249 } else {
250 $amount = sprintf("%.2f", $ddata['chg']);
251 $desc = $description;
255 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
256 $dos = '';
257 ++$count;
261 // This generates blank lines until we are at line 20.
262 // At line 20 we start middle third.
264 while ($count++ < 16) $out .= "\n";
265 # Generate the string of aging text. This will look like:
266 # Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
267 # ....+....1....+....2....+....3....+....4....+....5....+....6....+
269 $ageline = xl('Current') .': ' . sprintf("%.2f", $aging[0]);
270 for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
271 $ageline .= ' | ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) . ':' .
272 sprintf(" %.2f", $GLOBALS['gbl_currency_symbol'].''.$aging[$age_index]);
275 // Fixed text labels
276 $label_ptname = xl('Name');
277 $label_today = xl('Date');
278 $label_due = xl('Due');
279 $label_thanks = xl('Thank you for choosing');
280 $label_call = xl('Please call if any of the above information is incorrect.');
281 $label_prompt = xl('We appreciate prompt payment of balances due.');
282 $label_dept = xl('Billing Department');
283 $label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $billing_phone );
284 $label_appointments = xl('Future Appointments').':';
286 // This is the top portion of the page.
287 $out .= "\n\n\n";
288 if(strlen($stmt['bill_note']) !=0 && $GLOBALS['statement_bill_note_print']) {
289 $out .= sprintf("%-46s\n",$stmt['bill_note']);
290 $count++;
292 if ($GLOBALS['use_dunning_message']) {
293 $out .= sprintf("%-46s\n",$dun_message);
294 $count++;
296 $out .= "\n";
297 $out .= sprintf("%-s: %-25s %-s: %-14s %-s: %8s\n",$label_ptname,$stmt['patient'],
298 $label_today,oeFormatShortDate($stmt['today']),$label_due,$stmt['amount']);
299 $out .= sprintf("__________________________________________________________________\n");
300 $out .= "\n";
301 $out .= sprintf("%-s\n",$label_call);
302 $out .= sprintf("%-s\n",$label_prompt);
303 $out .= "\n";
304 $out .= sprintf("%-s\n",$billing_contact);
305 $out .= sprintf(" %-s %-25s\n",$label_dept,$label_bill_phone);
306 if($GLOBALS['statement_message_to_patient']) {
307 $out .= "\n";
308 $statement_message = $GLOBALS['statement_msg_text'];
309 $out .= sprintf("%-40s\n",$statement_message);
310 $count++;
312 if($GLOBALS['show_aging_on_custom_statement']) {
313 # code for ageing
314 $ageline .= ' | ' . xl('Over') . ' ' . ($age_index * 30) .':'.
315 sprintf(" %.2f", $aging[$age_index]);
316 $out .= "\n" . $ageline . "\n\n";
317 $count++;
319 if($GLOBALS['number_appointments_on_statement']!=0) {
320 $out .= "\n";
321 $num_appts = $GLOBALS['number_appointments_on_statement'];
322 $next_day = mktime(0,0,0,date('m'),date('d')+1,date('Y'));
323 # add one day to date so it will not get todays appointment
324 $current_date2 = date('Y-m-d', $next_day);
325 $events = fetchNextXAppts($current_date2,$stmt['pid'],$num_appts);
326 $j=0;
327 $out .= sprintf("%-s\n",$label_appointments);
328 #loop to add the appointments
329 for ($x = 1; $x <= $num_appts; $x++) {
330 $next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
331 $next_appoint_time = substr($events[$j]['pc_startTime'],0,5);
332 if(strlen(umname) != 0 ) {
333 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] . ' ' . $events[$j]['ulname'];
335 else
337 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
339 if(strlen($next_appoint_time) != 0) {
340 $label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') . ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
341 $out .= sprintf("%-s\n",$label_plsnote[$j]);
343 $j++;
344 $count++;
347 while ($count++ < 29) $out .= "\n";
348 $out .= sprintf("%-10s %s\n",null,$label_retpay);
349 $out .= '</pre></div>';
350 $out .= '<div style="width:7.0in;border-top:1pt dotted black;font-size:12px;margin:0px;"><br /><br />
351 <table style="width:7in;margin-left:20px;"><tr><td style="width:4.5in;"><br />
353 $out .= $label_payby.' '.$label_cards;
354 $out .= "<br /><br />";
355 $out .= $label_cardnum .': __________________________________ '.$label_expiry.': ___ / _____ <br /><br />';
356 $out .= $label_sign .' ____________________________<br />';
357 $out .=" </td><td style=width:2.0in;vertical-align:middle;'>";
358 $practice_cards = $GLOBALS['webroot']."/sites/" . $_SESSION['site_id'] . "/images/visa_mc_disc_credit_card_logos_176x35.gif";
359 if (file_exists($GLOBALS['OE_SITE_DIR']."/images/visa_mc_disc_credit_card_logos_176x35.gif")) {
360 $out .= "<img src='$practice_cards' style='width:100%;margin:4px auto;'><br /><p>\n".$label_totaldue.": ".$stmt['amount']."</p>";
363 $out .="</td></tr></table>";
365 $out .= '</div><br />
366 <pre>';
367 if($stmt['to'][3]!='')//to avoid double blank lines the if condition is put.
368 $out .= sprintf(" %-32s\n",$stmt['to'][3]);
369 $out .= ' </pre>
370 <div style="width:7in;border-top:1pt solid black;"><br />';
371 $out .= " <table style='width:6.0in;margin-left:40px;'><tr>";
372 $out .= '<td style="width:3.0in;"><b>'
373 .$label_addressee.'</b><br />'
374 .$stmt['to'][0].'<br />'
375 .$stmt['to'][1].'<br />'
376 .$stmt['to'][2].'
377 </td>
378 <td style="width:3.0in;"><b>'.$label_remitto.'</b><br />'
379 .$remit_name.'<br />'
380 .$remit_addr.'<br />'
381 .$remit_csz.'
382 </td>
383 </tr></table>';
385 $out .= " </div></div>";
386 $out .= "\014
387 <br /><br />"; // this is a form feed
388 echo $out;
389 $output = ob_get_clean();
390 return $output;
393 // This function builds a printable statement or collection letter from
394 // an associative array having the following keys:
396 // today = statement date yyyy-mm-dd
397 // pid = patient ID
398 // patient = patient name
399 // amount = total amount due
400 // to = array of addressee name/address lines
401 // lines = array of lines, each with the following keys:
402 // dos = date of service yyyy-mm-dd
403 // desc = description
404 // amount = charge less adjustments
405 // paid = amount paid
406 // notice = 1 for first notice, 2 for second, etc.
407 // detail = associative array of details
409 // Each detail array is keyed on a string beginning with a date in
410 // yyyy-mm-dd format, or blanks in the case of the original charge
411 // items. Its values are associative arrays like this:
413 // pmt - payment amount as a positive number, only for payments
414 // src - check number or other source, only for payments
415 // chg - invoice line item amount amount, only for charges or
416 // adjustments (adjustments may be zero)
417 // rsn - adjustment reason, only for adjustments
419 // The returned value is a string that can be sent to a printer.
420 // This example is plain text, but if you are a hotshot programmer
421 // then you could make a PDF or PostScript or whatever peels your
422 // banana. These strings are sent in succession, so append a form
423 // feed if that is appropriate.
426 // A sample of the text based format follows:
428 //[Your Clinic Name] Patient Name 2009-12-29
429 //[Your Clinic Address] Chart Number: 1848
430 //[City, State Zip] Insurance information on file
433 //ADDRESSEE REMIT TO
434 //Patient Name [Your Clinic Name]
435 //patient address [Your Clinic Address]
436 //city, state zipcode [City, State Zip]
437 // If paying by VISA/MC/AMEX/Dis
439 //Card_____________________ Exp______ Signature___________________
440 // Return above part with your payment
441 //-----------------------------------------------------------------
443 //_______________________ STATEMENT SUMMARY _______________________
445 //Visit Date Description Amount
447 //2009-08-20 Procedure 99345 198.90
448 // Paid 2009-12-15: -51.50
449 //... more details ...
450 //...
451 //...
452 // skipping blanks in example
455 //Name: Patient Name Date: 2009-12-29 Due: 147.40
456 //_________________________________________________________________
458 //Please call if any of the above information is incorrect
459 //We appreciate prompt payment of balances due
461 //[Your billing contact name]
462 // Billing Department
463 // [Your billing dept phone]
465 function create_statement($stmt) {
466 if (! $stmt['pid']) return ""; // get out if no data
468 #minimum_amount_to _print
469 if ($stmt[amount] <= ($GLOBALS['minimum_amount_to_print']) && $GLOBALS['use_statement_print_exclusion']) return "";
471 // These are your clinics return address, contact etc. Edit them.
472 // TBD: read this from the facility table
474 // Facility (service location)
475 $atres = sqlStatement("select f.name,f.street,f.city,f.state,f.postal_code from facility f " .
476 " left join users u on f.id=u.facility_id " .
477 " left join billing b on b.provider_id=u.id and b.pid = '".$stmt['pid']."' " .
478 " where service_location=1");
479 $row = sqlFetchArray($atres);
481 // Facility (service location)
483 $clinic_name = "{$row['name']}";
484 $clinic_addr = "{$row['street']}";
485 $clinic_csz = "{$row['city']}, {$row['state']}, {$row['postal_code']}";
488 // Billing location
489 $remit_name = $clinic_name;
490 $remit_addr = $clinic_addr;
491 $remit_csz = $clinic_csz;
493 // Contacts
494 $atres = sqlStatement("select f.attn,f.phone from facility f " .
495 " left join users u on f.id=u.facility_id " .
496 " left join billing b on b.provider_id=u.id and b.pid = '".$stmt['pid']."' " .
497 " where billing_location=1");
498 $row = sqlFetchArray($atres);
499 $billing_contact = "{$row['attn']}";
500 $billing_phone = "{$row['phone']}";
502 // dunning message setup
504 // insurance has paid something
505 // $stmt['age'] how old is the invoice
506 // $stmt['dun_count'] number of statements run
507 // $stmt['level_closed'] <= 3 insurance 4 = patient
509 if ($GLOBALS['use_dunning_message']) {
510 if ($stmt['ins_paid'] != 0 || $stmt['level_closed'] == 4) {
512 // do collection messages
513 switch ($stmt{'age'}) {
514 case $stmt{'age'} <= $GLOBALS['first_dun_msg_set']:
515 $dun_message = $GLOBALS['first_dun_msg_text'];
516 break;
517 case $stmt{'age'} <= $GLOBALS['second_dun_msg_set']:
518 $dun_message = $GLOBALS['second_dun_msg_text'];
519 break;
520 case $stmt{'age'} <= $GLOBALS['third_dun_msg_set']:
521 $dun_message = $GLOBALS['third_dun_msg_text'];
522 break;
523 case $stmt{'age'} <= $GLOBALS['fourth_dun_msg_set']:
524 $dun_message = $GLOBALS['fourth_dun_msg_text'];
525 break;
526 case $stmt{'age'} >= $GLOBALS['fifth_dun_msg_set']:
527 $dun_message = $GLOBALS['fifth_dun_msg_text'];
528 break;
532 // Text only labels
534 $label_addressee = xl('ADDRESSEE');
535 $label_remitto = xl('REMIT TO');
536 $label_chartnum = xl('Chart Number');
537 $label_insinfo = xl('Insurance information on file');
538 $label_totaldue = xl('Total amount due');
539 $label_payby = xl('If paying by');
540 $label_cards = xl('VISA/MC/Discovery/HSA');
541 $label_cardnum = xl('Card');
542 $label_expiry = xl('Exp');
543 $label_sign = xl('Signature');
544 $label_retpay = xl('Return above part with your payment');
545 $label_pgbrk = xl('STATEMENT SUMMARY');
546 $label_visit = xl('Visit Date');
547 $label_desc = xl('Description');
548 $label_amt = xl('Amount');
550 // This is the text for the top part of the page, up to but not
551 // including the detail lines. Some examples of variable fields are:
552 // %s = string with no minimum width
553 // %9s = right-justified string of 9 characters padded with spaces
554 // %-25s = left-justified string of 25 characters padded with spaces
555 // Note that "\n" is a line feed (new line) character.
556 // reformatted to handle i8n by tony
557 $out = "\n\n";
558 $providerNAME = getProviderName($stmt['providerID']);
559 $out .= sprintf("%-30s %s %-s\n",$clinic_name,$stmt['patient'],$stmt['today']);
560 $out .= sprintf("%-30s %s: %-s\n",$providerNAME,$label_chartnum,$stmt['pid']);
561 $out .= sprintf("%-30s %s\n",$clinic_addr,$label_insinfo);
562 $out .= sprintf("%-30s %-s: %-s\n",$clinic_csz,$label_totaldue,$stmt['amount']);
563 $out .= "\n";
564 $out .= sprintf(" %-30s %-s\n",$label_addressee,$label_remitto);
565 $out .= sprintf(" %-30s %s\n",$stmt['to'][0],$remit_name);
566 $out .= sprintf(" %-30s %s\n",$stmt['to'][1],$remit_addr);
567 $out .= sprintf(" %-30s %s\n",$stmt['to'][2],$remit_csz);
569 if($stmt['to'][3]!='')//to avoid double blank lines the if condition is put.
570 $out .= sprintf(" %-32s\n",$stmt['to'][3]);
571 $out .= sprintf("_________________________________________________________________\n");
572 $out .= "\n";
573 $out .= sprintf("%-32s\n",$label_payby.' '.$label_cards);
574 $out .= "\n";
575 $out .= sprintf("%s_____________________ %s______ %s___________________%s\n\n",
576 $label_cardnum,$label_expiry,$label_sign);
577 $out .= sprintf("-----------------------------------------------------------------\n");
578 $out .= sprintf("%-20s %s\n",null,$label_retpay);
579 $out .= "\n";
580 $out .= sprintf("_______________________ %s _______________________\n",$label_pgbrk);
581 $out .= "\n";
582 $out .= sprintf("%-11s %-46s %s\n",$label_visit,$label_desc,$label_amt);
583 $out .= "\n";
585 // This must be set to the number of lines generated above.
587 $count = 25;
588 $num_ages = 4;
589 $aging = array();
590 for ($age_index = 0; $age_index < $num_ages; ++$age_index) {
591 $aging[$age_index] = 0.00;
593 $todays_time = strtotime(date('Y-m-d'));
595 // This generates the detail lines. Again, note that the values must
596 // be specified in the order used.
600 foreach ($stmt['lines'] as $line) {
601 if ($GLOBALS['use_custom_statement']) {
602 $description = substr($line['desc'],0,30);
605 else {
606 $description = $line['desc'];
610 $tmp = substr($description, 0, 14);
611 if ($tmp == 'Procedure 9920' || $tmp == 'Procedure 9921' || $tmp == 'Procedure 9200' || $tmp == 'Procedure 9201')
612 $description = str_replace("Procedure",xl('Office Visit').":",$description);
613 //92002-14 are Eye Office Visit Codes
615 $dos = $line['dos'];
616 ksort($line['detail']);
617 # Compute the aging bucket index and accumulate into that bucket.
619 $age_in_days = (int) (($todays_time - strtotime($dos)) / (60 * 60 * 24));
620 $age_index = (int) (($age_in_days - 1) / 30);
621 $age_index = max(0, min($num_ages - 1, $age_index));
622 $aging[$age_index] += $line['amount'] - $line['paid'];
624 foreach ($line['detail'] as $dkey => $ddata) {
625 $ddate = substr($dkey, 0, 10);
626 if (preg_match('/^(\d\d\d\d)(\d\d)(\d\d)\s*$/', $ddate, $matches)) {
627 $ddate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
629 $amount = '';
631 if ($ddata['pmt']) {
632 $amount = sprintf("%.2f", 0 - $ddata['pmt']);
633 $desc = xl('Paid') .' '. oeFormatShortDate($ddate) .': '. $ddata['src'].' '. $ddata['pmt_method'].' '. $ddata['insurance_company'];
634 } else if ($ddata['rsn']) {
635 if ($ddata['chg']) {
636 $amount = sprintf("%.2f", $ddata['chg']);
637 $desc = xl('Adj') .' '. oeFormatShortDate($ddate) .': ' . $ddata['rsn'].' '.$ddata['pmt_method'].' '. $ddata['insurance_company'];
638 } else {
639 $desc = xl('Note') .' '. oeFormatShortDate($ddate) .': '. $ddata['rsn'].' '.$ddata['pmt_method'].' '. $ddata['insurance_company'];
641 } else if ($ddata['chg'] < 0) {
642 $amount = sprintf("%.2f", $ddata['chg']);
643 $desc = xl('Patient Payment');
644 } else {
645 $amount = sprintf("%.2f", $ddata['chg']);
646 $desc = $description;
650 $out .= sprintf("%-10s %-45s%8s\n", oeFormatShortDate($dos), $desc, $amount);
651 $dos = '';
652 ++$count;
656 // This generates blank lines until we are at line 42.
658 while ($count++ < 42) $out .= "\n";
659 # Generate the string of aging text. This will look like:
660 # Current xxx.xx / 31-60 x.xx / 61-90 x.xx / Over-90 xxx.xx
661 # ....+....1....+....2....+....3....+....4....+....5....+....6....+
663 $ageline = xl('Current') .' ' . sprintf("%.2f", $aging[0]);
664 for ($age_index = 1; $age_index < ($num_ages - 1); ++$age_index) {
665 $ageline .= ' / ' . ($age_index * 30 + 1) . '-' . ($age_index * 30 + 30) .
666 sprintf(" %.2f", $aging[$age_index]);
669 // Fixed text labels
670 $label_ptname = xl('Name');
671 $label_today = xl('Date');
672 $label_due = xl('Amount Due');
673 $label_thanks = xl('Thank you for choosing');
674 $label_call = xl('Please call if any of the above information is incorrect.');
675 $label_prompt = xl('We appreciate prompt payment of balances due.');
676 $label_dept = xl('Billing Department');
677 $label_bill_phone = (!empty($GLOBALS['billing_phone_number']) ? $GLOBALS['billing_phone_number'] : $billing_phone );
678 $label_appointments = xl('Future Appointments').':';
680 // This is the bottom portion of the page.
681 $out .= "\n";
682 if(strlen($stmt['bill_note']) !=0 && $GLOBALS['statement_bill_note_print']) {
683 $out .= sprintf("%-46s\n",$stmt['bill_note']);
685 if ($GLOBALS['use_dunning_message']) {
686 $out .= sprintf("%-46s\n",$dun_message);
688 $out .= "\n";
689 $out .= sprintf("%-s: %-25s %-s: %-14s %-s: %8s\n",$label_ptname,$stmt['patient'],
690 $label_today,oeFormatShortDate($stmt['today']),$label_due,$stmt['amount']);
691 $out .= sprintf("__________________________________________________________________\n");
692 $out .= "\n";
693 $out .= sprintf("%-s\n",$label_call);
694 $out .= sprintf("%-s\n",$label_prompt);
695 $out .= "\n";
696 $out .= sprintf("%-s\n",$billing_contact);
697 $out .= sprintf(" %-s %-25s\n",$label_dept,$label_bill_phone);
698 if($GLOBALS['statement_message_to_patient']) {
699 $out .= "\n";
700 $statement_message = $GLOBALS['statement_msg_text'];
701 $out .= sprintf("%-40s\n",$statement_message);
703 if($GLOBALS['show_aging_on_custom_statement']) {
704 # code for ageing
705 $ageline .= ' / ' . xl('Over') . '-' . ($age_index * 30) .
706 sprintf(" %.2f", $aging[$age_index]);
707 $out .= "\n" . $ageline . "\n\n";
710 if($GLOBALS['number_appointments_on_statement']!=0) {
711 $out .= "\n";
712 $num_appts = $GLOBALS['number_appointments_on_statement'];
713 $next_day = mktime(0,0,0,date('m'),date('d')+1,date('Y'));
714 # add one day to date so it will not get todays appointment
715 $current_date2 = date('Y-m-d', $next_day);
716 $events = fetchNextXAppts($current_date2,$stmt['pid'],$num_appts);
717 $j=0;
718 $out .= sprintf("%-s\n",$label_appointments);
719 #loop to add the appointments
720 for ($x = 1; $x <= $num_appts; $x++) {
721 $next_appoint_date = oeFormatShortDate($events[$j]['pc_eventDate']);
722 $next_appoint_time = substr($events[$j]['pc_startTime'],0,5);
723 if(strlen(umname) != 0 ) {
724 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['umname'] . ' ' . $events[$j]['ulname'];
726 else
728 $next_appoint_provider = $events[$j]['ufname'] . ' ' . $events[$j]['ulname'];
730 if(strlen($next_appoint_time) != 0) {
731 $label_plsnote[$j] = xlt('Date') . ': ' . text($next_appoint_date) . ' ' . xlt('Time') . ' ' . text($next_appoint_time) . ' ' . xlt('Provider') . ' ' . text($next_appoint_provider);
732 $out .= sprintf("%-s\n",$label_plsnote[$j]);
734 $j++;
737 $out .= "\014"; // this is a form feed
739 return $out;