Fixing accounting/billing bugs
[openemr.git] / interface / patient_file / pos_checkout.php
blob32ee33a7bb0879d10fae9196542f287894fc8386
1 <?php
2 // Copyright (C) 2006-2010 Rod Roark <rod@sunsetsystems.com>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 // This module supports a popup window to handle patient checkout
10 // as a point-of-sale transaction. Support for in-house drug sales
11 // is included.
13 // Important notes about system design:
15 // (1) Drug sales may or may not be associated with an encounter;
16 // they are if they are paid for concurrently with an encounter, or
17 // if they are "product" (non-prescription) sales via the Fee Sheet.
18 // (2) Drug sales without an encounter will have 20YYMMDD, possibly
19 // with a suffix, as the encounter-number portion of their invoice
20 // number.
21 // (3) Payments are saved as AR only, don't mess with the billing table.
22 // See library/classes/WSClaim.class.php for posting code.
23 // (4) On checkout, the billing and drug_sales table entries are marked
24 // as billed and so become unavailable for further billing.
25 // (5) Receipt printing must be a separate operation from payment,
26 // and repeatable.
29 // TBD:
30 // If this user has 'irnpool' set
31 // on display of checkout form
32 // show pending next invoice number
33 // on applying checkout
34 // save next invoice number to form_encounter
35 // compute new next invoice number
36 // on receipt display
37 // show invoice number
39 $fake_register_globals=false;
40 $sanitize_all_escapes=true;
42 require_once("../globals.php");
43 require_once("$srcdir/acl.inc");
44 require_once("$srcdir/patient.inc");
45 require_once("$srcdir/billing.inc");
46 require_once("$srcdir/sql-ledger.inc");
47 require_once("$srcdir/freeb/xmlrpc.inc");
48 require_once("$srcdir/freeb/xmlrpcs.inc");
49 require_once("$srcdir/formatting.inc.php");
50 require_once("$srcdir/formdata.inc.php");
51 require_once("../../custom/code_types.inc.php");
53 $currdecimals = $GLOBALS['currency_decimals'];
55 $INTEGRATED_AR = $GLOBALS['oer_config']['ws_accounting']['enabled'] === 2;
57 $details = empty($_GET['details']) ? 0 : 1;
59 $patient_id = empty($_GET['ptid']) ? $pid : 0 + $_GET['ptid'];
61 // Get the patient's name and chart number.
62 $patdata = getPatientData($patient_id, 'fname,mname,lname,pubpid,street,city,state,postal_code');
64 // Get the "next invoice reference number" from this user's pool.
66 function getInvoiceRefNumber() {
67 $trow = sqlQuery("SELECT lo.notes " .
68 "FROM users AS u, list_options AS lo " .
69 "WHERE u.username = ? AND " .
70 "lo.list_id = 'irnpool' AND lo.option_id = u.irnpool LIMIT 1", array($_SESSION['authUser']) );
71 return empty($trow['notes']) ? '' : $trow['notes'];
74 // Increment the "next invoice reference number" of this user's pool.
75 // This identifies the "digits" portion of that number and adds 1 to it.
76 // If it contains more than one string of digits, the last is used.
78 function updateInvoiceRefNumber() {
79 $irnumber = getInvoiceRefNumber();
80 // Here "?" specifies a minimal match, to get the most digits possible:
81 if (preg_match('/^(.*?)(\d+)(\D*)$/', $irnumber, $matches)) {
82 $newdigs = sprintf('%0' . strlen($matches[2]) . 'd', $matches[2] + 1);
83 $newnumber = $matches[1] . $newdigs . $matches[3];
84 sqlStatement("UPDATE users AS u, list_options AS lo " .
85 "SET lo.notes = ? WHERE " .
86 "u.username = ? AND " .
87 "lo.list_id = 'irnpool' AND lo.option_id = u.irnpool", array($newnumber,$_SESSION['authUser']) );
89 return $irnumber;
92 //////////////////////////////////////////////////////////////////////
93 // The following functions are inline here temporarily, and should be
94 // moved to an includable module for common use. In particular
95 // WSClaim.class.php should be rewritten to use them.
96 //////////////////////////////////////////////////////////////////////
98 // Initialize the array of invoice information for posting to the
99 // accounting system.
101 function invoice_initialize(& $invoice_info, $patient_id, $provider_id,
102 $payer_id = 0, $encounter = 0, $dosdate = '')
104 $db = $GLOBALS['adodb']['db'];
106 // Get foreign ID (customer) for patient.
107 $sql = "SELECT foreign_id from integration_mapping as im " .
108 "LEFT JOIN patient_data as pd on im.local_id=pd.id " .
109 "where pd.pid = ? and im.local_table='patient_data' and im.foreign_table='customer'";
110 $result = $db->Execute($sql, array($patient_id) );
111 if($result && !$result->EOF) {
112 $foreign_patient_id = $result->fields['foreign_id'];
114 else {
115 return "Patient '" . $patient_id . "' has not yet been posted to the accounting system.";
118 // Get foreign ID (salesman) for provider.
119 $sql = "SELECT foreign_id from integration_mapping WHERE " .
120 "local_id = ? AND local_table='users' and foreign_table='salesman'";
121 $result = $db->Execute($sql, array($provider_id) );
122 if($result && !$result->EOF) {
123 $foreign_provider_id = $result->fields['foreign_id'];
125 else {
126 return "Provider '" . $provider_id . "' has not yet been posted to the accounting system.";
129 // Get foreign ID (customer) for insurance payer.
130 if ($payer_id && ! $GLOBALS['insurance_companies_are_not_customers']) {
131 $sql = "SELECT foreign_id from integration_mapping WHERE " .
132 "local_id = ? AND local_table = 'insurance_companies' AND foreign_table='customer'";
133 $result = $db->Execute($sql, array($payer_id) );
134 if($result && !$result->EOF) {
135 $foreign_payer_id = $result->fields['foreign_id'];
137 else {
138 return "Payer '" . $payer_id . "' has not yet been posted to the accounting system.";
140 } else {
141 $foreign_payer_id = $payer_id;
144 // Create invoice notes for the new invoice that list the patient's
145 // insurance plans. This is so that when payments are posted, the user
146 // can easily see if a secondary claim needs to be submitted.
148 $insnotes = "";
149 $insno = 0;
150 foreach (array("primary", "secondary", "tertiary") as $instype) {
151 ++$insno;
152 $sql = "SELECT insurance_companies.name " .
153 "FROM insurance_data, insurance_companies WHERE " .
154 "insurance_data.pid = ? AND " .
155 "insurance_data.type = ? AND " .
156 "insurance_companies.id = insurance_data.provider " .
157 "ORDER BY insurance_data.date DESC LIMIT 1";
158 $result = $db->Execute($sql, array($patient_id,$instype) );
159 if ($result && !$result->EOF && $result->fields['name']) {
160 if ($insnotes) $insnotes .= "\n";
161 $insnotes .= "Ins$insno: " . $result->fields['name'];
164 $invoice_info['notes'] = $insnotes;
166 if (preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/", $dosdate, $matches)) {
167 $dosdate = $matches[2] . '-' . $matches[3] . '-' . $matches[1];
168 } else {
169 $dosdate = date("m-d-Y");
172 $invoice_info['salesman'] = $foreign_provider_id;
173 $invoice_info['customerid'] = $foreign_patient_id;
174 $invoice_info['payer_id'] = $foreign_payer_id;
175 $invoice_info['invoicenumber'] = $patient_id . "." . $encounter;
176 $invoice_info['dosdate'] = $dosdate;
177 $invoice_info['items'] = array();
178 $invoice_info['total'] = '0.00';
180 return '';
183 function invoice_add_line_item(& $invoice_info, $code_type, $code,
184 $code_text, $amount, $units=1)
186 $units = max(1, intval(trim($units)));
187 $amount = sprintf("%01.2f", $amount);
188 $price = $amount / $units;
189 $tmp = sprintf("%01.2f", $price);
190 if (abs($price - $tmp) < 0.000001) $price = $tmp;
191 $tii = array();
192 $tii['maincode'] = $code;
193 $tii['itemtext'] = "$code_type:$code";
194 if ($code_text) $tii['itemtext'] .= " $code_text";
195 $tii['qty'] = $units;
196 $tii['price'] = $price;
197 $tii['glaccountid'] = $GLOBALS['oer_config']['ws_accounting']['income_acct'];
198 $invoice_info['total'] = sprintf("%01.2f", $invoice_info['total'] + $amount);
199 $invoice_info['items'][] = $tii;
200 return '';
203 function invoice_post(& $invoice_info)
205 $function['ezybiz.add_invoice'] = array(new xmlrpcval($invoice_info, "struct"));
207 list($name, $var) = each($function);
208 $f = new xmlrpcmsg($name, $var);
210 $c = new xmlrpc_client($GLOBALS['oer_config']['ws_accounting']['url'],
211 $GLOBALS['oer_config']['ws_accounting']['server'],
212 $GLOBALS['oer_config']['ws_accounting']['port']);
214 $c->setCredentials($GLOBALS['oer_config']['ws_accounting']['username'],
215 $GLOBALS['oer_config']['ws_accounting']['password']);
217 $r = $c->send($f);
218 if (!$r) return "XMLRPC send failed";
220 // We are not doing anything with the return value yet... should we?
221 $tv = $r->value();
222 if (is_object($tv)) {
223 $value = $tv->getval();
225 else {
226 $value = null;
229 if ($r->faultCode()) {
230 return "Fault: Code: " . $r->faultCode() . " Reason '" . $r->faultString() . "'";
233 return '';
236 ///////////// End of SQL-Ledger invoice posting functions ////////////
238 // Output HTML for an invoice line item.
240 $prevsvcdate = '';
241 function receiptDetailLine($svcdate, $description, $amount, $quantity) {
242 global $prevsvcdate, $details;
243 if (!$details) return;
244 $amount = sprintf('%01.2f', $amount);
245 if (empty($quantity)) $quantity = 1;
246 $price = sprintf('%01.4f', $amount / $quantity);
247 $tmp = sprintf('%01.2f', $price);
248 if ($price == $tmp) $price = $tmp;
249 echo " <tr>\n";
250 echo " <td>" . ($svcdate == $prevsvcdate ? '&nbsp;' : text(oeFormatShortDate($svcdate))) . "</td>\n";
251 echo " <td>" . text($description) . "</td>\n";
252 echo " <td align='right'>" . text(oeFormatMoney($price)) . "</td>\n";
253 echo " <td align='right'>" . text($quantity) . "</td>\n";
254 echo " <td align='right'>" . text(oeFormatMoney($amount)) . "</td>\n";
255 echo " </tr>\n";
256 $prevsvcdate = $svcdate;
259 // Output HTML for an invoice payment.
261 function receiptPaymentLine($paydate, $amount, $description='') {
262 $amount = sprintf('%01.2f', 0 - $amount); // make it negative
263 echo " <tr>\n";
264 echo " <td>" . text(oeFormatShortDate($paydate)) . "</td>\n";
265 echo " <td>" . xlt('Payment') . " " . text($description) . "</td>\n";
266 echo " <td colspan='2'>&nbsp;</td>\n";
267 echo " <td align='right'>" . text(oeFormatMoney($amount)) . "</td>\n";
268 echo " </tr>\n";
271 // Generate a receipt from the last-billed invoice for this patient,
272 // or for the encounter specified as a GET parameter.
274 function generate_receipt($patient_id, $encounter=0) {
275 global $sl_err, $sl_cash_acc, $css_header, $details, $INTEGRATED_AR;
277 // Get details for what we guess is the primary facility.
278 $frow = sqlQuery("SELECT * FROM facility " .
279 "ORDER BY billing_location DESC, accepts_assignment DESC, id LIMIT 1");
281 $patdata = getPatientData($patient_id, 'fname,mname,lname,pubpid,street,city,state,postal_code,providerID');
283 // Get the most recent invoice data or that for the specified encounter.
285 // Adding a provider check so that their info can be displayed on receipts
286 if ($INTEGRATED_AR) {
287 if ($encounter) {
288 $ferow = sqlQuery("SELECT id, date, encounter, provider_id FROM form_encounter " .
289 "WHERE pid = ? AND encounter = ?", array($patient_id,$encounter) );
290 } else {
291 $ferow = sqlQuery("SELECT id, date, encounter, provider_id FROM form_encounter " .
292 "WHERE pid = ? " .
293 "ORDER BY id DESC LIMIT 1", array($patient_id) );
295 if (empty($ferow)) die(xlt("This patient has no activity."));
296 $trans_id = $ferow['id'];
297 $encounter = $ferow['encounter'];
298 $svcdate = substr($ferow['date'], 0, 10);
300 if ($GLOBALS['receipts_by_provider']){
301 if (isset($ferow['provider_id']) ) {
302 $encprovider = $ferow['provider_id'];
303 } else if (isset($patdata['providerID'])){
304 $encprovider = $patdata['providerID'];
305 } else { $encprovider = -1; }
308 if ($encprovider){
309 $providerrow = sqlQuery("SELECT fname, mname, lname, title, street, streetb, " .
310 "city, state, zip, phone, fax FROM users WHERE id = ?", array($encprovider) );
313 else {
314 SLConnect();
316 $arres = SLQuery("SELECT * FROM ar WHERE " .
317 "invnumber LIKE '$patient_id.%' " .
318 "ORDER BY id DESC LIMIT 1");
319 if ($sl_err) die(text($sl_err));
320 if (!SLRowCount($arres)) die(xlt("This patient has no activity."));
321 $arrow = SLGetRow($arres, 0);
323 $trans_id = $arrow['id'];
325 // Determine the date of service. An 8-digit encounter number is
326 // presumed to be a date of service imported during conversion or
327 // associated with prescriptions only. Otherwise look it up in the
328 // form_encounter table.
330 $svcdate = "";
331 list($trash, $encounter) = explode(".", $arrow['invnumber']);
332 if (strlen($encounter) >= 8) {
333 $svcdate = substr($encounter, 0, 4) . "-" . substr($encounter, 4, 2) .
334 "-" . substr($encounter, 6, 2);
336 else if ($encounter) {
337 $tmp = sqlQuery("SELECT date FROM form_encounter WHERE " .
338 "encounter = ?", array($encounter) );
339 $svcdate = substr($tmp['date'], 0, 10);
341 } // end not $INTEGRATED_AR
343 // Get invoice reference number.
344 $encrow = sqlQuery("SELECT invoice_refno FROM form_encounter WHERE " .
345 "pid = ? AND encounter = ? LIMIT 1", array($patient_id,$encounter) );
346 $invoice_refno = $encrow['invoice_refno'];
348 <html>
349 <head>
350 <?php html_header_show(); ?>
351 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
352 <title><?php echo xlt('Receipt for Payment'); ?></title>
353 <script type="text/javascript" src="../../library/dialog.js"></script>
354 <script language="JavaScript">
356 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
358 // Process click on Print button.
359 function printme() {
360 var divstyle = document.getElementById('hideonprint').style;
361 divstyle.display = 'none';
362 window.print();
363 return false;
366 // Process click on Delete button.
367 function deleteme() {
368 dlgopen('deleter.php?billing=<?php echo attr("$patient_id.$encounter"); ?>', '_blank', 500, 450);
369 return false;
372 // Called by the deleteme.php window on a successful delete.
373 function imdeleted() {
374 window.close();
377 </script>
378 </head>
379 <body class="body_top">
380 <center>
381 <?php
382 if ( $GLOBALS['receipts_by_provider'] && !empty($providerrow) ) { printProviderHeader($providerrow); }
383 else { printFacilityHeader($frow); }
385 <?php
386 echo xlt("Receipt Generated") . ":" . text(date(' F j, Y'));
387 if ($invoice_refno) echo " " . xlt("Invoice Number") . ": " . text($invoice_refno) . " " . xlt("Service Date") . ": " . text($svcdate);
389 <br>&nbsp;
390 </b></p>
391 </center>
393 <?php echo text($patdata['fname']) . ' ' . text($patdata['mname']) . ' ' . text($patdata['lname']) ?>
394 <br><?php echo text($patdata['street']) ?>
395 <br><?php echo text($patdata['city']) . ', ' . text($patdata['state']) . ' ' . text($patdata['postal_code']) ?>
396 <br>&nbsp;
397 </p>
398 <center>
399 <table cellpadding='5'>
400 <tr>
401 <td><b><?php echo xlt('Date'); ?></b></td>
402 <td><b><?php echo xlt('Description'); ?></b></td>
403 <td align='right'><b><?php echo $details ? xlt('Price') : '&nbsp;'; ?></b></td>
404 <td align='right'><b><?php echo $details ? xlt('Qty' ) : '&nbsp;'; ?></b></td>
405 <td align='right'><b><?php echo xlt('Total'); ?></b></td>
406 </tr>
408 <?php
409 $charges = 0.00;
411 if ($INTEGRATED_AR) {
412 // Product sales
413 $inres = sqlStatement("SELECT s.sale_id, s.sale_date, s.fee, " .
414 "s.quantity, s.drug_id, d.name " .
415 "FROM drug_sales AS s LEFT JOIN drugs AS d ON d.drug_id = s.drug_id " .
416 // "WHERE s.pid = '$patient_id' AND s.encounter = '$encounter' AND s.fee != 0 " .
417 "WHERE s.pid = ? AND s.encounter = ? " .
418 "ORDER BY s.sale_id", array($patient_id,$encounter) );
419 while ($inrow = sqlFetchArray($inres)) {
420 $charges += sprintf('%01.2f', $inrow['fee']);
421 receiptDetailLine($inrow['sale_date'], $inrow['name'],
422 $inrow['fee'], $inrow['quantity']);
424 // Service and tax items
425 $inres = sqlStatement("SELECT * FROM billing WHERE " .
426 "pid = ? AND encounter = ? AND " .
427 // "code_type != 'COPAY' AND activity = 1 AND fee != 0 " .
428 "code_type != 'COPAY' AND activity = 1 " .
429 "ORDER BY id", array($patient_id,$encounter) );
430 while ($inrow = sqlFetchArray($inres)) {
431 $charges += sprintf('%01.2f', $inrow['fee']);
432 receiptDetailLine($svcdate, $inrow['code_text'],
433 $inrow['fee'], $inrow['units']);
435 // Adjustments.
436 $inres = sqlStatement("SELECT " .
437 "a.code_type, a.code, a.modifier, a.memo, a.payer_type, a.adj_amount, a.pay_amount, " .
438 "s.payer_id, s.reference, s.check_date, s.deposit_date " .
439 "FROM ar_activity AS a " .
440 "LEFT JOIN ar_session AS s ON s.session_id = a.session_id WHERE " .
441 "a.pid = ? AND a.encounter = ? AND " .
442 "a.adj_amount != 0 " .
443 "ORDER BY s.check_date, a.sequence_no", array($patient_id,$encounter) );
444 while ($inrow = sqlFetchArray($inres)) {
445 $charges -= sprintf('%01.2f', $inrow['adj_amount']);
446 $payer = empty($inrow['payer_type']) ? 'Pt' : ('Ins' . $inrow['payer_type']);
447 receiptDetailLine($svcdate, $payer . ' ' . $inrow['memo'],
448 0 - $inrow['adj_amount'], 1);
450 } // end $INTEGRATED_AR
451 else {
452 // Request all line items with money belonging to the invoice.
453 $inres = SLQuery("SELECT * FROM invoice WHERE " .
454 "trans_id = $trans_id AND sellprice != 0 ORDER BY id");
455 if ($sl_err) die($sl_err);
456 for ($irow = 0; $irow < SLRowCount($inres); ++$irow) {
457 $row = SLGetRow($inres, $irow);
458 $amount = sprintf('%01.2f', $row['sellprice'] * $row['qty']);
459 $charges += $amount;
460 $desc = preg_replace('/^.{1,6}:/', '', $row['description']);
461 receiptDetailLine($svcdate, $desc, $amount, $row['qty']);
463 } // end not $INTEGRATED_AR
466 <tr>
467 <td colspan='5'>&nbsp;</td>
468 </tr>
469 <tr>
470 <td><?php echo text(oeFormatShortDate($svcdispdate)); ?></td>
471 <td><b><?php echo xlt('Total Charges'); ?></b></td>
472 <td align='right'>&nbsp;</td>
473 <td align='right'>&nbsp;</td>
474 <td align='right'><?php echo text(oeFormatMoney($charges, true)) ?></td>
475 </tr>
476 <tr>
477 <td colspan='5'>&nbsp;</td>
478 </tr>
480 <?php
481 if ($INTEGRATED_AR) {
482 // Get co-pays.
483 $inres = sqlStatement("SELECT fee, code_text FROM billing WHERE " .
484 "pid = ? AND encounter = ? AND " .
485 "code_type = 'COPAY' AND activity = 1 AND fee != 0 " .
486 "ORDER BY id", array($patient_id,$encounter) );
487 while ($inrow = sqlFetchArray($inres)) {
488 $charges += sprintf('%01.2f', $inrow['fee']);
489 receiptPaymentLine($svcdate, 0 - $inrow['fee'], $inrow['code_text']);
491 // Get other payments.
492 $inres = sqlStatement("SELECT " .
493 "a.code_type, a.code, a.modifier, a.memo, a.payer_type, a.adj_amount, a.pay_amount, " .
494 "s.payer_id, s.reference, s.check_date, s.deposit_date " .
495 "FROM ar_activity AS a " .
496 "LEFT JOIN ar_session AS s ON s.session_id = a.session_id WHERE " .
497 "a.pid = ? AND a.encounter = ? AND " .
498 "a.pay_amount != 0 " .
499 "ORDER BY s.check_date, a.sequence_no", array($patient_id,$encounter) );
500 while ($inrow = sqlFetchArray($inres)) {
501 $payer = empty($inrow['payer_type']) ? 'Pt' : ('Ins' . $inrow['payer_type']);
502 $charges -= sprintf('%01.2f', $inrow['pay_amount']);
503 receiptPaymentLine($svcdate, $inrow['pay_amount'],
504 $payer . ' ' . $inrow['reference']);
506 } // end $INTEGRATED_AR
507 else {
508 $chart_id_cash = SLQueryValue("select id from chart where accno = '$sl_cash_acc'");
509 if ($sl_err) die($sl_err);
510 if (! $chart_id_cash) die("There is no COA entry for cash account '$sl_cash_acc'");
512 // Request all cash entries belonging to the invoice.
513 $atres = SLQuery("SELECT * FROM acc_trans WHERE " .
514 "trans_id = $trans_id AND chart_id = $chart_id_cash ORDER BY transdate");
515 if ($sl_err) die($sl_err);
517 for ($irow = 0; $irow < SLRowCount($atres); ++$irow) {
518 $row = SLGetRow($atres, $irow);
519 $amount = sprintf('%01.2f', $row['amount']); // negative
520 $charges += $amount;
521 $rowsource = $row['source'];
522 if (strtolower($rowsource) == 'co-pay') $rowsource = '';
523 receiptPaymentLine($row['transdate'], 0 - $amount, $rowsource);
525 } // end not $INTEGRATED_AR
527 <tr>
528 <td colspan='5'>&nbsp;</td>
529 </tr>
530 <tr>
531 <td>&nbsp;</td>
532 <td><b><?php echo xlt('Balance Due'); ?></b></td>
533 <td colspan='2'>&nbsp;</td>
534 <td align='right'><?php echo text(oeFormatMoney($charges, true)) ?></td>
535 </tr>
536 </table>
537 </center>
538 <div id='hideonprint'>
540 &nbsp;
541 <a href='#' onclick='return printme();'><?php echo xlt('Print'); ?></a>
542 <?php if (acl_check('acct','disc')) { ?>
543 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
544 <a href='#' onclick='return deleteme();'><?php echo xlt('Undo Checkout'); ?></a>
545 <?php } ?>
546 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
547 <?php if ($details) { ?>
548 <a href='pos_checkout.php?details=0&ptid=<?php echo attr($patient_id); ?>&enc=<?php echo attr($encounter); ?>'><?php echo xlt('Hide Details'); ?></a>
549 <?php } else { ?>
550 <a href='pos_checkout.php?details=1&ptid=<?php echo attr($patient_id); ?>&enc=<?php echo attr($encounter); ?>'><?php echo xlt('Show Details'); ?></a>
551 <?php } ?>
552 </p>
553 </div>
554 </body>
555 </html>
556 <?php
557 if (!$INTEGRATED_AR) SLClose();
558 } // end function generate_receipt()
560 // Function to output a line item for the input form.
562 $lino = 0;
563 function write_form_line($code_type, $code, $id, $date, $description,
564 $amount, $units, $taxrates) {
565 global $lino;
566 $amount = sprintf("%01.2f", $amount);
567 if (empty($units)) $units = 1;
568 $price = $amount / $units; // should be even cents, but ok here if not
569 if ($code_type == 'COPAY' && !$description) $description = xl('Payment');
570 echo " <tr>\n";
571 echo " <td>" . text(oeFormatShortDate($date));
572 echo "<input type='hidden' name='line[$lino][code_type]' value='" . attr($code_type) . "'>";
573 echo "<input type='hidden' name='line[$lino][code]' value='" . attr($code) . "'>";
574 echo "<input type='hidden' name='line[$lino][id]' value='" . attr($id) . "'>";
575 echo "<input type='hidden' name='line[$lino][description]' value='" . attr($description) . "'>";
576 echo "<input type='hidden' name='line[$lino][taxrates]' value='" . attr($taxrates) . "'>";
577 echo "<input type='hidden' name='line[$lino][price]' value='" . attr($price) . "'>";
578 echo "<input type='hidden' name='line[$lino][units]' value='" . attr($units) . "'>";
579 echo "</td>\n";
580 echo " <td>" . text($description) . "</td>";
581 echo " <td align='right'>" . text($units) . "</td>";
582 echo " <td align='right'><input type='text' name='line[$lino][amount]' " .
583 "value='" . attr($amount) . "' size='6' maxlength='8'";
584 // Modifying prices requires the acct/disc permission.
585 // if ($code_type == 'TAX' || ($code_type != 'COPAY' && !acl_check('acct','disc')))
586 echo " style='text-align:right;background-color:transparent' readonly";
587 // else echo " style='text-align:right' onkeyup='computeTotals()'";
588 echo "></td>\n";
589 echo " </tr>\n";
590 ++$lino;
593 // Create the taxes array. Key is tax id, value is
594 // (description, rate, accumulated total).
595 $taxes = array();
596 $pres = sqlStatement("SELECT option_id, title, option_value " .
597 "FROM list_options WHERE list_id = 'taxrate' ORDER BY seq");
598 while ($prow = sqlFetchArray($pres)) {
599 $taxes[$prow['option_id']] = array($prow['title'], $prow['option_value'], 0);
602 // Print receipt header for facility
603 function printFacilityHeader($frow){
604 echo "<p><b>" . text($frow['name']) .
605 "<br>" . text($frow['street']) .
606 "<br>" . text($frow['city']) . ', ' . text($frow['state']) . ' ' . text($frow['postal_code']) .
607 "<br>" . text($frow['phone']) .
608 "<br>&nbsp" .
609 "<br>";
612 // Pring receipt header for Provider
613 function printProviderHeader($pvdrow){
614 echo "<p><b>" . text($pvdrow['title']) . " " . text($pvdrow['fname']) . " " . text($pvdrow['mname']) . " " . text($pvdrow['lname']) . " " .
615 "<br>" . text($pvdrow['street']) .
616 "<br>" . text($pvdrow['city']) . ', ' . text($pvdrow['state']) . ' ' . text($pvdrow['postal_code']) .
617 "<br>" . text($pvdrow['phone']) .
618 "<br>&nbsp" .
619 "<br>";
622 // Mark the tax rates that are referenced in this invoice.
623 function markTaxes($taxrates) {
624 global $taxes;
625 $arates = explode(':', $taxrates);
626 if (empty($arates)) return;
627 foreach ($arates as $value) {
628 if (!empty($taxes[$value])) $taxes[$value][2] = '1';
632 $payment_methods = array(
633 'Cash',
634 'Check',
635 'MC',
636 'VISA',
637 'AMEX',
638 'DISC',
639 'Other');
641 $alertmsg = ''; // anything here pops up in an alert box
643 // If the Save button was clicked...
645 if ($_POST['form_save']) {
647 // On a save, do the following:
648 // Flag drug_sales and billing items as billed.
649 // Post the corresponding invoice with its payment(s) to sql-ledger
650 // and be careful to use a unique invoice number.
651 // Call the generate-receipt function.
652 // Exit.
654 $form_pid = $_POST['form_pid'];
655 $form_encounter = $_POST['form_encounter'];
657 // Get the posting date from the form as yyyy-mm-dd.
658 $dosdate = date("Y-m-d");
659 if (preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/", $_POST['form_date'], $matches)) {
660 $dosdate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
663 // If there is no associated encounter (i.e. this invoice has only
664 // prescriptions) then assign an encounter number of the service
665 // date, with an optional suffix to ensure that it's unique.
667 if (! $form_encounter) {
668 $form_encounter = substr($dosdate,0,4) . substr($dosdate,5,2) . substr($dosdate,8,2);
669 $tmp = '';
670 if ($INTEGRATED_AR) {
671 while (true) {
672 $ferow = sqlQuery("SELECT id FROM form_encounter WHERE " .
673 "pid = ? AND encounter = ?", array($form_pid, $form_encounter.$tmp) );
674 if (empty($ferow)) break;
675 $tmp = $tmp ? $tmp + 1 : 1;
678 else {
679 SLConnect();
680 while (SLQueryValue("select id from ar where " .
681 "invnumber = '$form_pid.$form_encounter$tmp'")) {
682 $tmp = $tmp ? $tmp + 1 : 1;
684 SLClose();
686 $form_encounter .= $tmp;
689 if ($INTEGRATED_AR) {
690 // Delete any TAX rows from billing because they will be recalculated.
691 sqlStatement("UPDATE billing SET activity = 0 WHERE " .
692 "pid = ? AND encounter = ? AND " .
693 "code_type = 'TAX'", array($form_pid,$form_encounter) );
695 else {
696 // Initialize an array of invoice information for posting.
697 $invoice_info = array();
698 $msg = invoice_initialize($invoice_info, $form_pid,
699 $_POST['form_provider'], $_POST['form_payer'], $form_encounter, $dosdate);
700 if ($msg) die($msg);
703 $form_amount = $_POST['form_amount'];
704 $lines = $_POST['line'];
706 for ($lino = 0; $lines[$lino]['code_type']; ++$lino) {
707 $line = $lines[$lino];
708 $code_type = $line['code_type'];
709 $id = $line['id'];
710 $amount = sprintf('%01.2f', trim($line['amount']));
712 if (!$INTEGRATED_AR) {
713 $msg = invoice_add_line_item($invoice_info, $code_type,
714 $line['code'], $line['description'], $amount, $line['units']);
715 if ($msg) die($msg);
718 if ($code_type == 'PROD') {
719 // Product sales. The fee and encounter ID may have changed.
720 $query = "update drug_sales SET fee = ?, " .
721 "encounter = ?, billed = 1 WHERE " .
722 "sale_id = ?";
723 sqlQuery($query, array($amount,$form_encounter,$id) );
725 else if ($code_type == 'TAX') {
726 // In the SL case taxes show up on the invoice as line items.
727 // Otherwise we gotta save them somewhere, and in the billing
728 // table with a code type of TAX seems easiest.
729 // They will have to be stripped back out when building this
730 // script's input form.
731 addBilling($form_encounter, 'TAX', 'TAX', 'Taxes', $form_pid, 0, 0,
732 '', '', $amount, '', '', 1);
734 else {
735 // Because there is no insurance here, there is no need for a claims
736 // table entry and so we do not call updateClaim(). Note we should not
737 // eliminate billed and bill_date from the billing table!
738 $query = "UPDATE billing SET fee = ?, billed = 1, " .
739 "bill_date = NOW() WHERE id = ?";
740 sqlQuery($query, array($amount,$id) );
744 // Post discount.
745 if ($_POST['form_discount']) {
746 if ($GLOBALS['discount_by_money']) {
747 $amount = sprintf('%01.2f', trim($_POST['form_discount']));
749 else {
750 $amount = sprintf('%01.2f', trim($_POST['form_discount']) * $form_amount / 100);
752 $memo = xl('Discount');
753 if ($INTEGRATED_AR) {
754 $time = date('Y-m-d H:i:s');
755 $query = "INSERT INTO ar_activity ( " .
756 "pid, encounter, code, modifier, payer_type, post_user, post_time, " .
757 "session_id, memo, adj_amount " .
758 ") VALUES ( " .
759 "?, " .
760 "?, " .
761 "'', " .
762 "'', " .
763 "'0', " .
764 "?, " .
765 "?, " .
766 "'0', " .
767 "?, " .
768 "? " .
769 ")";
770 sqlStatement($query, array($form_pid,$form_encounter,$_SESSION['authUserID'],$time,$memo,$amount) );
772 else {
773 $msg = invoice_add_line_item($invoice_info, 'DISCOUNT',
774 '', $memo, 0 - $amount);
775 if ($msg) die($msg);
779 // Post payment.
780 if ($_POST['form_amount']) {
781 $amount = sprintf('%01.2f', trim($_POST['form_amount']));
782 $form_source = trim($_POST['form_source']);
783 $paydesc = trim($_POST['form_method']);
784 if ($INTEGRATED_AR) {
785 //Fetching the existing code and modifier
786 $ResultSearchNew = sqlStatement("SELECT * FROM billing LEFT JOIN code_types ON billing.code_type=code_types.ct_key ".
787 "WHERE code_types.ct_fee=1 AND billing.activity!=0 AND billing.pid =? AND encounter=? ORDER BY billing.code,billing.modifier",
788 array($form_pid,$form_encounter));
789 if($RowSearch = sqlFetchArray($ResultSearchNew))
791 $Codetype=$RowSearch['code_type'];
792 $Code=$RowSearch['code'];
793 $Modifier=$RowSearch['modifier'];
794 }else{
795 $Codetype='';
796 $Code='';
797 $Modifier='';
799 $session_id=idSqlStatement("INSERT INTO ar_session (payer_id,user_id,reference,check_date,deposit_date,pay_total,".
800 " global_amount,payment_type,description,patient_id,payment_method,adjustment_code,post_to_date) ".
801 " VALUES ('0',?,?,now(),?,?,'','patient','COPAY',?,?,'patient_payment',now())",
802 array($_SESSION['authId'],$form_source,$dosdate,$amount,$form_pid,$paydesc));
803 $insrt_id=idSqlStatement("INSERT INTO ar_activity (pid,encounter,code_type,code,modifier,payer_type,post_time,post_user,session_id,pay_amount,account_code)".
804 " VALUES (?,?,?,?,?,0,?,?,?,?,'PCP')",
805 array($form_pid,$form_encounter,$Codetype,$Code,$Modifier,$dosdate,$_SESSION['authId'],$session_id,$amount));
807 else {
808 $msg = invoice_add_line_item($invoice_info, 'COPAY',
809 $paydesc, $form_source, 0 - $amount);
810 if ($msg) die($msg);
814 if (!$INTEGRATED_AR) {
815 $msg = invoice_post($invoice_info);
816 if ($msg) die($msg);
819 // If applicable, set the invoice reference number.
820 $invoice_refno = '';
821 if (isset($_POST['form_irnumber'])) {
822 $invoice_refno = trim($_POST['form_irnumber']);
824 else {
825 $invoice_refno = updateInvoiceRefNumber();
827 if ($invoice_refno) {
828 sqlStatement("UPDATE form_encounter " .
829 "SET invoice_refno = ? " .
830 "WHERE pid = ? AND encounter = ?", array($invoice_refno,$form_pid,$form_encounter) );
833 generate_receipt($form_pid, $form_encounter);
834 exit();
837 // If an encounter ID was given, then we must generate a receipt.
839 if (!empty($_GET['enc'])) {
840 generate_receipt($patient_id, $_GET['enc']);
841 exit();
844 // Get the unbilled billing table items for this patient.
845 $query = "SELECT id, date, code_type, code, modifier, code_text, " .
846 "provider_id, payer_id, units, fee, encounter " .
847 "FROM billing WHERE pid = ? AND activity = 1 AND " .
848 "billed = 0 AND code_type != 'TAX' " .
849 "ORDER BY encounter DESC, id ASC";
850 $bres = sqlStatement($query, array($patient_id) );
852 // Get the product sales for this patient.
853 $query = "SELECT s.sale_id, s.sale_date, s.prescription_id, s.fee, " .
854 "s.quantity, s.encounter, s.drug_id, d.name, r.provider_id " .
855 "FROM drug_sales AS s " .
856 "LEFT JOIN drugs AS d ON d.drug_id = s.drug_id " .
857 "LEFT OUTER JOIN prescriptions AS r ON r.id = s.prescription_id " .
858 "WHERE s.pid = ? AND s.billed = 0 " .
859 "ORDER BY s.encounter DESC, s.sale_id ASC";
860 $dres = sqlStatement($query, array($patient_id) );
862 // If there are none, just redisplay the last receipt and exit.
864 if (sqlNumRows($bres) == 0 && sqlNumRows($dres) == 0) {
865 generate_receipt($patient_id);
866 exit();
869 // Get the valid practitioners, including those not active.
870 $arr_users = array();
871 $ures = sqlStatement("SELECT id, username FROM users WHERE " .
872 "( authorized = 1 OR info LIKE '%provider%' ) AND username != ''");
873 while ($urow = sqlFetchArray($ures)) {
874 $arr_users[$urow['id']] = '1';
877 // Now write a data entry form:
878 // List unbilled billing items (cpt, hcpcs, copays) for the patient.
879 // List unbilled product sales for the patient.
880 // Present an editable dollar amount for each line item, a total
881 // which is also the default value of the input payment amount,
882 // and OK and Cancel buttons.
884 <html>
885 <head>
886 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
887 <title><?php echo xlt('Patient Checkout'); ?></title>
888 <style>
889 </style>
890 <style type="text/css">@import url(../../library/dynarch_calendar.css);</style>
891 <script type="text/javascript" src="../../library/textformat.js"></script>
892 <script type="text/javascript" src="../../library/dynarch_calendar.js"></script>
893 <?php include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?>
894 <script type="text/javascript" src="../../library/dynarch_calendar_setup.js"></script>
895 <script type="text/javascript" src="../../library/dialog.js"></script>
896 <script type="text/javascript" src="../../library/js/jquery-1.2.2.min.js"></script>
897 <script language="JavaScript">
898 var mypcc = '<?php echo $GLOBALS['phone_country_code'] ?>';
900 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
902 // This clears the tax line items in preparation for recomputing taxes.
903 function clearTax(visible) {
904 var f = document.forms[0];
905 for (var lino = 0; true; ++lino) {
906 var pfx = 'line[' + lino + ']';
907 if (! f[pfx + '[code_type]']) break;
908 if (f[pfx + '[code_type]'].value != 'TAX') continue;
909 f[pfx + '[price]'].value = '0.00';
910 if (visible) f[pfx + '[amount]'].value = '0.00';
914 // For a given tax ID and amount, compute the tax on that amount and add it
915 // to the "price" (same as "amount") of the corresponding tax line item.
916 // Note the tax line items include their "taxrate" to make this easy.
917 function addTax(rateid, amount, visible) {
918 if (rateid.length == 0) return 0;
919 var f = document.forms[0];
920 for (var lino = 0; true; ++lino) {
921 var pfx = 'line[' + lino + ']';
922 if (! f[pfx + '[code_type]']) break;
923 if (f[pfx + '[code_type]'].value != 'TAX') continue;
924 if (f[pfx + '[code]'].value != rateid) continue;
925 var tax = amount * parseFloat(f[pfx + '[taxrates]'].value);
926 tax = parseFloat(tax.toFixed(<?php echo $currdecimals ?>));
927 var cumtax = parseFloat(f[pfx + '[price]'].value) + tax;
928 f[pfx + '[price]'].value = cumtax.toFixed(<?php echo $currdecimals ?>); // requires JS 1.5
929 if (visible) f[pfx + '[amount]'].value = cumtax.toFixed(<?php echo $currdecimals ?>); // requires JS 1.5
930 if (isNaN(tax)) alert('Tax rate not numeric at line ' + lino);
931 return tax;
933 return 0;
936 // This mess recomputes the invoice total and optionally applies a discount.
937 function computeDiscountedTotals(discount, visible) {
938 clearTax(visible);
939 var f = document.forms[0];
940 var total = 0.00;
941 for (var lino = 0; f['line[' + lino + '][code_type]']; ++lino) {
942 var code_type = f['line[' + lino + '][code_type]'].value;
943 // price is price per unit when the form was originally generated.
944 // By contrast, amount is the dynamically-generated discounted line total.
945 var price = parseFloat(f['line[' + lino + '][price]'].value);
946 if (isNaN(price)) alert('Price not numeric at line ' + lino);
947 if (code_type == 'COPAY' || code_type == 'TAX') {
948 // This works because the tax lines come last.
949 total += parseFloat(price.toFixed(<?php echo $currdecimals ?>));
950 continue;
952 var units = f['line[' + lino + '][units]'].value;
953 var amount = price * units;
954 amount = parseFloat(amount.toFixed(<?php echo $currdecimals ?>));
955 if (visible) f['line[' + lino + '][amount]'].value = amount.toFixed(<?php echo $currdecimals ?>);
956 total += amount;
957 var taxrates = f['line[' + lino + '][taxrates]'].value;
958 var taxids = taxrates.split(':');
959 for (var j = 0; j < taxids.length; ++j) {
960 addTax(taxids[j], amount, visible);
963 return total - discount;
966 // Recompute displayed amounts with any discount applied.
967 function computeTotals() {
968 var f = document.forms[0];
969 var discount = parseFloat(f.form_discount.value);
970 if (isNaN(discount)) discount = 0;
971 <?php if (!$GLOBALS['discount_by_money']) { ?>
972 // This site discounts by percentage, so convert it to a money amount.
973 if (discount > 100) discount = 100;
974 if (discount < 0 ) discount = 0;
975 discount = 0.01 * discount * computeDiscountedTotals(0, false);
976 <?php } ?>
977 var total = computeDiscountedTotals(discount, true);
978 f.form_amount.value = total.toFixed(<?php echo $currdecimals ?>);
979 return true;
982 </script>
983 </head>
985 <body class="body_top">
987 <form method='post' action='pos_checkout.php'>
988 <input type='hidden' name='form_pid' value='<?php echo attr($patient_id) ?>' />
990 <center>
993 <table cellspacing='5'>
994 <tr>
995 <td colspan='3' align='center'>
996 <b><?php echo xlt('Patient Checkout for '); ?><?php echo text($patdata['fname']) . " " .
997 text($patdata['lname']) . " (" . text($patdata['pubpid']) . ")" ?></b>
998 </td>
999 </tr>
1000 <tr>
1001 <td><b><?php echo xlt('Date'); ?></b></td>
1002 <td><b><?php echo xlt('Description'); ?></b></td>
1003 <td align='right'><b><?php echo xlt('Qty'); ?></b></td>
1004 <td align='right'><b><?php echo xlt('Amount'); ?></b></td>
1005 </tr>
1006 <?php
1007 $inv_encounter = '';
1008 $inv_date = '';
1009 $inv_provider = 0;
1010 $inv_payer = 0;
1011 $gcac_related_visit = false;
1012 $gcac_service_provided = false;
1014 // Process billing table items.
1015 // Items that are not allowed to have a fee are skipped.
1017 while ($brow = sqlFetchArray($bres)) {
1018 // Skip all but the most recent encounter.
1019 if ($inv_encounter && $brow['encounter'] != $inv_encounter) continue;
1021 $thisdate = substr($brow['date'], 0, 10);
1022 $code_type = $brow['code_type'];
1024 // Collect tax rates, related code and provider ID.
1025 $taxrates = '';
1026 $related_code = '';
1027 $sqlBindArray = array();
1028 if (!empty($code_types[$code_type]['fee'])) {
1029 $query = "SELECT taxrates, related_code FROM codes WHERE code_type = ? " .
1030 " AND " .
1031 "code = ? AND ";
1032 array_push($sqlBindArray,$code_types[$code_type]['id'],$brow['code']);
1033 if ($brow['modifier']) {
1034 $query .= "modifier = ?";
1035 array_push($sqlBindArray,$brow['modifier']);
1036 } else {
1037 $query .= "(modifier IS NULL OR modifier = '')";
1039 $query .= " LIMIT 1";
1040 $tmp = sqlQuery($query,$sqlBindArray);
1041 $taxrates = $tmp['taxrates'];
1042 $related_code = $tmp['related_code'];
1043 markTaxes($taxrates);
1046 write_form_line($code_type, $brow['code'], $brow['id'], $thisdate,
1047 $brow['code_text'], $brow['fee'], $brow['units'],
1048 $taxrates);
1049 if (!$inv_encounter) $inv_encounter = $brow['encounter'];
1050 $inv_payer = $brow['payer_id'];
1051 if (!$inv_date || $inv_date < $thisdate) $inv_date = $thisdate;
1053 // Custom logic for IPPF to determine if a GCAC issue applies.
1054 if ($GLOBALS['ippf_specific'] && $related_code) {
1055 $relcodes = explode(';', $related_code);
1056 foreach ($relcodes as $codestring) {
1057 if ($codestring === '') continue;
1058 list($codetype, $code) = explode(':', $codestring);
1059 if ($codetype !== 'IPPF') continue;
1060 if (preg_match('/^25222/', $code)) {
1061 $gcac_related_visit = true;
1062 if (preg_match('/^25222[34]/', $code))
1063 $gcac_service_provided = true;
1069 // Process copays
1071 $totalCopay = getPatientCopay($patient_id,$encounter);
1072 if ($totalCopay < 0) {
1073 write_form_line("COPAY", "", "", "", "", $totalCopay, "", "");
1076 // Process drug sales / products.
1078 while ($drow = sqlFetchArray($dres)) {
1079 if ($inv_encounter && $drow['encounter'] && $drow['encounter'] != $inv_encounter) continue;
1081 $thisdate = $drow['sale_date'];
1082 if (!$inv_encounter) $inv_encounter = $drow['encounter'];
1084 if (!$inv_provider && !empty($arr_users[$drow['provider_id']]))
1085 $inv_provider = $drow['provider_id'] + 0;
1087 if (!$inv_date || $inv_date < $thisdate) $inv_date = $thisdate;
1089 // Accumulate taxes for this product.
1090 $tmp = sqlQuery("SELECT taxrates FROM drug_templates WHERE drug_id = ? " .
1091 " ORDER BY selector LIMIT 1", array($drow['drug_id']) );
1092 // accumTaxes($drow['fee'], $tmp['taxrates']);
1093 $taxrates = $tmp['taxrates'];
1094 markTaxes($taxrates);
1096 write_form_line('PROD', $drow['drug_id'], $drow['sale_id'],
1097 $thisdate, $drow['name'], $drow['fee'], $drow['quantity'], $taxrates);
1100 // Write a form line for each tax that has money, adding to $total.
1101 foreach ($taxes as $key => $value) {
1102 if ($value[2]) {
1103 write_form_line('TAX', $key, $key, date('Y-m-d'), $value[0], 0, 1, $value[1]);
1107 // Besides copays, do not collect any other information from ar_activity,
1108 // since this is for appt checkout.
1110 if ($inv_encounter) {
1111 $erow = sqlQuery("SELECT provider_id FROM form_encounter WHERE " .
1112 "pid = ? AND encounter = ? " .
1113 "ORDER BY id DESC LIMIT 1", array($patient_id,$inv_encounter) );
1114 $inv_provider = $erow['provider_id'] + 0;
1117 </table>
1120 <table border='0' cellspacing='4'>
1122 <tr>
1123 <td>
1124 <?php echo $GLOBALS['discount_by_money'] ? xlt('Discount Amount') : xlt('Discount Percentage'); ?>:
1125 </td>
1126 <td>
1127 <input type='text' name='form_discount' size='6' maxlength='8' value=''
1128 style='text-align:right' onkeyup='computeTotals()'>
1129 </td>
1130 </tr>
1132 <tr>
1133 <td>
1134 <?php echo xlt('Payment Method'); ?>:
1135 </td>
1136 <td>
1137 <select name='form_method'>
1138 <?php
1139 $query1112 = "SELECT * FROM list_options where list_id=? ORDER BY seq, title ";
1140 $bres1112 = sqlStatement($query1112,array('payment_method'));
1141 while ($brow1112 = sqlFetchArray($bres1112))
1143 if($brow1112['option_id']=='electronic' || $brow1112['option_id']=='bank_draft')
1144 continue;
1145 echo "<option value='".attr($brow1112['option_id'])."'>".text(xl_list_label($brow1112['title']))."</option>";
1148 </select>
1149 </td>
1150 </tr>
1152 <tr>
1153 <td>
1154 <?php echo xlt('Check/Reference Number'); ?>:
1155 </td>
1156 <td>
1157 <input type='text' name='form_source' size='10' value=''>
1158 </td>
1159 </tr>
1161 <tr>
1162 <td>
1163 <?php echo xlt('Amount Paid'); ?>:
1164 </td>
1165 <td>
1166 <input type='text' name='form_amount' size='10' value='0.00'>
1167 </td>
1168 </tr>
1170 <tr>
1171 <td>
1172 <?php echo xlt('Posting Date'); ?>:
1173 </td>
1174 <td>
1175 <input type='text' size='10' name='form_date' id='form_date'
1176 value='<?php echo attr($inv_date) ?>'
1177 title='yyyy-mm-dd date of service'
1178 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' />
1179 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
1180 id='img_date' border='0' alt='[?]' style='cursor:pointer'
1181 title='<?php echo xla("Click here to choose a date"); ?>'>
1182 </td>
1183 </tr>
1185 <?php
1186 // If this user has a non-empty irnpool assigned, show the pending
1187 // invoice reference number.
1188 $irnumber = getInvoiceRefNumber();
1189 if (!empty($irnumber)) {
1191 <tr>
1192 <td>
1193 <?php echo xlt('Tentative Invoice Ref No'); ?>:
1194 </td>
1195 <td>
1196 <?php echo text($irnumber); ?>
1197 </td>
1198 </tr>
1199 <?php
1201 // Otherwise if there is an invoice reference number mask, ask for the refno.
1202 else if (!empty($GLOBALS['gbl_mask_invoice_number'])) {
1204 <tr>
1205 <td>
1206 <?php echo xlt('Invoice Reference Number'); ?>:
1207 </td>
1208 <td>
1209 <input type='text' name='form_irnumber' size='10' value=''
1210 onkeyup='maskkeyup(this,"<?php echo addslashes($GLOBALS['gbl_mask_invoice_number']); ?>")'
1211 onblur='maskblur(this,"<?php echo addslashes($GLOBALS['gbl_mask_invoice_number']); ?>")'
1213 </td>
1214 </tr>
1215 <?php
1219 <tr>
1220 <td colspan='2' align='center'>
1221 &nbsp;<br>
1222 <input type='submit' name='form_save' value='<?php echo xla('Save'); ?>' /> &nbsp;
1223 <?php if (empty($_GET['framed'])) { ?>
1224 <input type='button' value='<?php echo xla('Cancel'); ?>' onclick='window.close()' />
1225 <?php } ?>
1226 <input type='hidden' name='form_provider' value='<?php echo attr($inv_provider) ?>' />
1227 <input type='hidden' name='form_payer' value='<?php echo attr($inv_payer) ?>' />
1228 <input type='hidden' name='form_encounter' value='<?php echo attr($inv_encounter) ?>' />
1229 </td>
1230 </tr>
1232 </table>
1233 </center>
1235 </form>
1237 <script language='JavaScript'>
1238 Calendar.setup({inputField:"form_date", ifFormat:"%Y-%m-%d", button:"img_date"});
1239 computeTotals();
1240 <?php
1241 // The following is removed, perhaps temporarily, because gcac reporting
1242 // no longer depends on gcac issues. -- Rod 2009-08-11
1243 /*********************************************************************
1244 // Custom code for IPPF. Try to make sure that a GCAC issue is linked to this
1245 // visit if it contains GCAC-related services.
1246 if ($gcac_related_visit) {
1247 $grow = sqlQuery("SELECT l.id, l.title, l.begdate, ie.pid " .
1248 "FROM lists AS l " .
1249 "LEFT JOIN issue_encounter AS ie ON ie.pid = l.pid AND " .
1250 "ie.encounter = '$inv_encounter' AND ie.list_id = l.id " .
1251 "WHERE l.pid = '$pid' AND " .
1252 "l.activity = 1 AND l.type = 'ippf_gcac' " .
1253 "ORDER BY ie.pid DESC, l.begdate DESC LIMIT 1");
1254 // Note that reverse-ordering by ie.pid is a trick for sorting
1255 // issues linked to the encounter (non-null values) first.
1256 if (empty($grow['pid'])) { // if there is no linked GCAC issue
1257 if (!empty($grow)) { // there is one that is not linked
1258 echo " if (confirm('" . xl('OK to link the GCAC issue dated') . " " .
1259 $grow['begdate'] . " " . xl('to this visit?') . "')) {\n";
1260 echo " $.getScript('link_issue_to_encounter.php?issue=" . $grow['id'] .
1261 "&thisenc=$inv_encounter');\n";
1262 echo " } else";
1264 echo " if (confirm('" . xl('Are you prepared to complete a new GCAC issue for this visit?') . "')) {\n";
1265 echo " dlgopen('summary/add_edit_issue.php?thisenc=$inv_encounter" .
1266 "&thistype=ippf_gcac', '_blank', 700, 600);\n";
1267 echo " } else {\n";
1268 echo " $.getScript('link_issue_to_encounter.php?thisenc=$inv_encounter');\n";
1269 echo " }\n";
1271 } // end if ($gcac_related_visit)
1272 *********************************************************************/
1274 if ($gcac_related_visit && !$gcac_service_provided) {
1275 // Skip this warning if the GCAC visit form is not allowed.
1276 $grow = sqlQuery("SELECT COUNT(*) AS count FROM list_options " .
1277 "WHERE list_id = 'lbfnames' AND option_id = 'LBFgcac'");
1278 if (!empty($grow['count'])) { // if gcac is used
1279 // Skip this warning if referral or abortion in TS.
1280 $grow = sqlQuery("SELECT COUNT(*) AS count FROM transactions " .
1281 "WHERE title = 'Referral' AND refer_date IS NOT NULL AND " .
1282 "refer_date = ? AND pid = ?", array($inv_date,$patient_id) );
1283 if (empty($grow['count'])) { // if there is no referral
1284 $grow = sqlQuery("SELECT COUNT(*) AS count FROM forms " .
1285 "WHERE pid = ? AND encounter = ? AND " .
1286 "deleted = 0 AND formdir = 'LBFgcac'", array($patient_id,$inv_encounter) );
1287 if (empty($grow['count'])) { // if there is no gcac form
1288 echo " alert('" . addslashes(xl('This visit will need a GCAC form, referral or procedure service.')) . "');\n";
1292 } // end if ($gcac_related_visit)
1294 </script>
1296 </body>
1297 </html>