Added a link to new prescription generator.
[openemr.git] / interface / patient_file / pos_checkout.php
blob13c7ed153b3b2242b9f5913bae81fa1c9d88b2c6
1 <?php
2 // Copyright (C) 2006, 2008 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 in SL 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, therefore driven from the SL database and
27 // mirroring the contents of the invoice.
29 require_once("../globals.php");
30 require_once("$srcdir/acl.inc");
31 require_once("$srcdir/patient.inc");
32 require_once("$srcdir/sql-ledger.inc");
33 require_once("$srcdir/freeb/xmlrpc.inc");
34 require_once("$srcdir/freeb/xmlrpcs.inc");
35 require_once("../../custom/code_types.inc.php");
37 // Get the patient's name and chart number.
38 $patdata = getPatientData($pid, 'fname,mname,lname,pubpid,street,city,state,postal_code');
40 //////////////////////////////////////////////////////////////////////
41 // The following functions are inline here temporarily, and should be
42 // moved to an includable module for common use. In particular
43 // WSClaim.class.php should be rewritten to use them.
44 //////////////////////////////////////////////////////////////////////
46 // Initialize the array of invoice information for posting to the
47 // accounting system.
49 function invoice_initialize(& $invoice_info, $patient_id, $provider_id,
50 $payer_id = 0, $encounter = 0, $dosdate = '')
52 $db = $GLOBALS['adodb']['db'];
54 // Get foreign ID (customer) for patient.
55 $sql = "SELECT foreign_id from integration_mapping as im " .
56 "LEFT JOIN patient_data as pd on im.local_id=pd.id " .
57 "where pd.pid = '" .
58 $patient_id .
59 "' and im.local_table='patient_data' and im.foreign_table='customer'";
60 $result = $db->Execute($sql);
61 if($result && !$result->EOF) {
62 $foreign_patient_id = $result->fields['foreign_id'];
64 else {
65 return "Patient '" . $patient_id . "' has not yet been posted to the accounting system.";
68 // Get foreign ID (salesman) for provider.
69 $sql = "SELECT foreign_id from integration_mapping WHERE " .
70 "local_id = $provider_id AND local_table='users' and foreign_table='salesman'";
71 $result = $db->Execute($sql);
72 if($result && !$result->EOF) {
73 $foreign_provider_id = $result->fields['foreign_id'];
75 else {
76 return "Provider '" . $provider_id . "' has not yet been posted to the accounting system.";
79 // Get foreign ID (customer) for insurance payer.
80 if ($payer_id && ! $GLOBALS['insurance_companies_are_not_customers']) {
81 $sql = "SELECT foreign_id from integration_mapping WHERE " .
82 "local_id = $payer_id AND local_table = 'insurance_companies' AND foreign_table='customer'";
83 $result = $db->Execute($sql);
84 if($result && !$result->EOF) {
85 $foreign_payer_id = $result->fields['foreign_id'];
87 else {
88 return "Payer '" . $payer_id . "' has not yet been posted to the accounting system.";
90 } else {
91 $foreign_payer_id = $payer_id;
94 // Create invoice notes for the new invoice that list the patient's
95 // insurance plans. This is so that when payments are posted, the user
96 // can easily see if a secondary claim needs to be submitted.
98 $insnotes = "";
99 $insno = 0;
100 foreach (array("primary", "secondary", "tertiary") as $instype) {
101 ++$insno;
102 $sql = "SELECT insurance_companies.name " .
103 "FROM insurance_data, insurance_companies WHERE " .
104 "insurance_data.pid = $patient_id AND " .
105 "insurance_data.type = '$instype' AND " .
106 "insurance_companies.id = insurance_data.provider " .
107 "ORDER BY insurance_data.date DESC LIMIT 1";
108 $result = $db->Execute($sql);
109 if ($result && !$result->EOF && $result->fields['name']) {
110 if ($insnotes) $insnotes .= "\n";
111 $insnotes .= "Ins$insno: " . $result->fields['name'];
114 $invoice_info['notes'] = $insnotes;
116 if (preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/", $dosdate, $matches)) {
117 $dosdate = $matches[2] . '-' . $matches[3] . '-' . $matches[1];
118 } else {
119 $dosdate = date("m-d-Y");
122 $invoice_info['salesman'] = $foreign_provider_id;
123 $invoice_info['customerid'] = $foreign_patient_id;
124 $invoice_info['payer_id'] = $foreign_payer_id;
125 $invoice_info['invoicenumber'] = $patient_id . "." . $encounter;
126 $invoice_info['dosdate'] = $dosdate;
127 $invoice_info['items'] = array();
128 $invoice_info['total'] = '0.00';
130 return '';
133 function invoice_add_line_item(& $invoice_info, $code_type, $code,
134 $code_text, $amount, $units=1)
136 $units = max(1, intval(trim($units)));
137 $amount = sprintf("%01.2f", $amount);
138 $price = $amount / $units;
139 $tmp = sprintf("%01.2f", $price);
140 if (abs($price - $tmp) < 0.000001) $price = $tmp;
141 $tii = array();
142 $tii['maincode'] = $code;
143 $tii['itemtext'] = "$code_type:$code";
144 if ($code_text) $tii['itemtext'] .= " $code_text";
145 // $tii['qty'] = 1;
146 // $tii['price'] = sprintf("%01.2f", $amount);
147 $tii['qty'] = $units;
148 $tii['price'] = $price;
149 $tii['glaccountid'] = $GLOBALS['oer_config']['ws_accounting']['income_acct'];
150 // $invoice_info['total'] = sprintf("%01.2f", $invoice_info['total'] + $tii['price']);
151 $invoice_info['total'] = sprintf("%01.2f", $invoice_info['total'] + $amount);
152 $invoice_info['items'][] = $tii;
153 return '';
156 function invoice_post(& $invoice_info)
158 $function['ezybiz.add_invoice'] = array(new xmlrpcval($invoice_info, "struct"));
160 list($name, $var) = each($function);
161 $f = new xmlrpcmsg($name, $var);
163 $c = new xmlrpc_client($GLOBALS['oer_config']['ws_accounting']['url'],
164 $GLOBALS['oer_config']['ws_accounting']['server'],
165 $GLOBALS['oer_config']['ws_accounting']['port']);
167 $c->setCredentials($GLOBALS['oer_config']['ws_accounting']['username'],
168 $GLOBALS['oer_config']['ws_accounting']['password']);
170 $r = $c->send($f);
171 if (!$r) return "XMLRPC send failed";
173 // We are not doing anything with the return value yet... should we?
174 $tv = $r->value();
175 if (is_object($tv)) {
176 $value = $tv->getval();
178 else {
179 $value = null;
182 if ($r->faultCode()) {
183 return "Fault: Code: " . $r->faultCode() . " Reason '" . $r->faultString() . "'";
186 return '';
189 /////////////////// End of invoice posting functions /////////////////
191 // Generate a receipt from the last-billed invoice for this patient.
193 function generate_receipt($patient_id) {
194 global $sl_err, $sl_cash_acc, $css_header;
196 // Get details for what we guess is the primary facility.
197 $frow = sqlQuery("SELECT * FROM facility " .
198 "ORDER BY billing_location DESC, accepts_assignment DESC, id LIMIT 1");
200 $patdata = getPatientData($patient_id, 'fname,mname,lname,pubpid,street,city,state,postal_code');
202 SLConnect();
204 // Get the most recent invoice data into $arrow.
206 $arres = SLQuery("SELECT * FROM ar WHERE " .
207 "invnumber LIKE '$patient_id.%' " .
208 "ORDER BY id DESC LIMIT 1");
209 if ($sl_err) die($sl_err);
210 if (!SLRowCount($arres)) die(xl("This patient has no activity."));
211 $arrow = SLGetRow($arres, 0);
213 $trans_id = $arrow['id'];
215 // Determine the date of service. An 8-digit encounter number is
216 // presumed to be a date of service imported during conversion or
217 // associated with prescriptions only. Otherwise look it up in the
218 // form_encounter table.
220 $svcdate = "";
221 list($trash, $encounter) = explode(".", $arrow['invnumber']);
222 if (strlen($encounter) >= 8) {
223 $svcdate = substr($encounter, 0, 4) . "-" . substr($encounter, 4, 2) .
224 "-" . substr($encounter, 6, 2);
226 else if ($encounter) {
227 $tmp = sqlQuery("SELECT date FROM form_encounter WHERE " .
228 "encounter = $encounter");
229 $svcdate = substr($tmp['date'], 0, 10);
232 <html>
233 <head>
234 <?php html_header_show(); ?>
235 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
236 <title><?php xl('Receipt for Payment','e'); ?></title>
237 </head>
238 <body class="body_top">
239 <center>
240 <p><b><?php echo $frow['name'] ?>
241 <br><?php echo $frow['street'] ?>
242 <br><?php echo $frow['city'] . ', ' . $frow['state'] . ' ' . $frow['postal_code'] ?>
243 <br><?php echo $frow['phone'] ?>
244 <br>&nbsp;
245 <br><?php echo date('F j, Y') ?>
246 <br>&nbsp;
247 </b></p>
248 </center>
250 <?php echo $patdata['fname'] . ' ' . $patdata['mname'] . ' ' . $patdata['lname'] ?>
251 <br><?php echo $patdata['street'] ?>
252 <br><?php echo $patdata['city'] . ', ' . $patdata['state'] . ' ' . $patdata['postal_code'] ?>
253 <br>&nbsp;
254 </p>
255 <center>
256 <table>
257 <tr>
258 <td><b><?php xl('Date','e'); ?></b></td>
259 <td><b><?php xl('Description','e'); ?></b></td>
260 <td align='right'><b><?php xl('Price','e'); ?></b></td>
261 <td align='right'><b><?php xl('Qty' ,'e'); ?></b></td>
262 <td align='right'><b><?php xl('Total','e'); ?></b></td>
263 </tr>
264 <?php
265 $charges = 0.00;
266 // Request all line items with money belonging to the invoice.
267 $inres = SLQuery("SELECT * FROM invoice WHERE " .
268 "trans_id = $trans_id AND sellprice != 0 ORDER BY id");
269 if ($sl_err) die($sl_err);
271 for ($irow = 0; $irow < SLRowCount($inres); ++$irow) {
272 $row = SLGetRow($inres, $irow);
273 $price = sprintf('%01.2f', $row['sellprice']);
274 $tmp = sprintf('%01.4f', $row['sellprice']);
275 if ($tmp != $price) $price = $tmp;
276 $amount = sprintf('%01.2f', $row['sellprice'] * $row['qty']);
277 $charges += $amount;
278 $desc = preg_replace('/^.{1,6}:/', '', $row['description']);
279 echo " <tr>\n";
280 echo " <td>$svcdate</td>\n";
281 echo " <td>$desc</td>\n";
282 echo " <td align='right'>$price</td>\n";
283 echo " <td align='right'>" . $row['qty'] . "</td>\n";
284 echo " <td align='right'>$amount</td>\n";
285 echo " </tr>\n";
289 <tr>
290 <td colspan='5'>&nbsp;</td>
291 </tr>
292 <tr>
293 <td>&nbsp;</td>
294 <td><b><?php xl('Total Charges','e'); ?></b></td>
295 <td align='right'>&nbsp;</td>
296 <td align='right'>&nbsp;</td>
297 <td align='right'><?php echo sprintf('%01.2f', $charges) ?></td>
298 </tr>
299 <tr>
300 <td colspan='5'>&nbsp;</td>
301 </tr>
303 <?php
304 $chart_id_cash = SLQueryValue("select id from chart where accno = '$sl_cash_acc'");
305 if ($sl_err) die($sl_err);
306 if (! $chart_id_cash) die("There is no COA entry for cash account '$sl_cash_acc'");
308 // Request all cash entries belonging to the invoice.
309 $atres = SLQuery("SELECT * FROM acc_trans WHERE " .
310 "trans_id = $trans_id AND chart_id = $chart_id_cash ORDER BY transdate");
311 if ($sl_err) die($sl_err);
313 for ($irow = 0; $irow < SLRowCount($atres); ++$irow) {
314 $row = SLGetRow($atres, $irow);
315 $amount = sprintf('%01.2f', $row['amount']); // negative
316 $charges += $amount;
317 $rowsource = $row['source'];
318 if (strtolower($rowsource) == 'co-pay') $rowsource = '';
319 echo " <tr>\n";
320 echo " <td>" . $row['transdate'] . "</td>\n";
321 echo " <td>" . xl('Payment') . " $rowsource</td>\n";
322 echo " <td colspan='2'>&nbsp;</td>\n";
323 echo " <td align='right'>$amount</td>\n";
324 echo " </tr>\n";
327 <tr>
328 <td colspan='5'>&nbsp;</td>
329 </tr>
330 <tr>
331 <td>&nbsp;</td>
332 <td><b><?php xl('Balance Due','e'); ?></b></td>
333 <td colspan='2'>&nbsp;</td>
334 <td align='right'><?php echo sprintf('%01.2f', $charges) ?></td>
335 </tr>
336 </table>
337 </center>
338 <p>&nbsp;<a href='' onclick='window.print(); return false;'><?php xl('Print','e'); ?></a></p>
339 </body>
340 </html>
341 <?php
342 SLClose();
343 } // end function
345 // Function to output a line item for the input form.
347 $lino = 0;
348 function write_form_line($code_type, $code, $id, $date, $description,
349 $amount, $units, $taxrates) {
350 global $lino;
351 $amount = sprintf("%01.2f", $amount);
352 if (empty($units)) $units = 1;
353 $price = $amount / $units; // should be even cents, but ok here if not
354 if ($code_type == 'COPAY' && !$description) $description = xl('Payment');
355 echo " <tr>\n";
356 echo " <td>$date";
357 echo "<input type='hidden' name='line[$lino][code_type]' value='$code_type'>";
358 echo "<input type='hidden' name='line[$lino][code]' value='$code'>";
359 echo "<input type='hidden' name='line[$lino][id]' value='$id'>";
360 echo "<input type='hidden' name='line[$lino][description]' value='$description'>";
361 echo "<input type='hidden' name='line[$lino][taxrates]' value='$taxrates'>";
362 echo "<input type='hidden' name='line[$lino][price]' value='$price'>";
363 echo "<input type='hidden' name='line[$lino][units]' value='$units'>";
364 echo "</td>\n";
365 echo " <td>$description</td>";
366 echo " <td align='right'>$units</td>";
367 echo " <td align='right'><input type='text' name='line[$lino][amount]' " .
368 "value='$amount' size='6' maxlength='8'";
369 // Modifying prices requires the acct/disc permission.
370 // if ($code_type == 'TAX' || ($code_type != 'COPAY' && !acl_check('acct','disc')))
371 echo " style='text-align:right;background-color:transparent' readonly";
372 // else echo " style='text-align:right' onkeyup='computeTotals()'";
373 echo "></td>\n";
374 echo " </tr>\n";
375 ++$lino;
378 // Create the taxes array. Key is tax id, value is
379 // (description, rate, accumulated total).
380 $taxes = array();
381 $pres = sqlStatement("SELECT option_id, title, option_value " .
382 "FROM list_options WHERE list_id = 'taxrate' ORDER BY seq");
383 while ($prow = sqlFetchArray($pres)) {
384 $taxes[$prow['option_id']] = array($prow['title'], $prow['option_value'], 0);
387 // Mark the tax rates that are referenced in this invoice.
388 function markTaxes($taxrates) {
389 global $taxes;
390 $arates = explode(':', $taxrates);
391 if (empty($arates)) return;
392 foreach ($arates as $value) {
393 if (!empty($taxes[$value])) $taxes[$value][2] = '1';
397 $payment_methods = array(
398 'Cash',
399 'Check',
400 'MC',
401 'VISA',
402 'AMEX',
403 'DISC',
404 'Other');
406 $alertmsg = ''; // anything here pops up in an alert box
408 // If the Save button was clicked...
410 if ($_POST['form_save']) {
412 // On a save, do the following:
413 // Flag drug_sales and billing items as billed.
414 // Post the corresponding invoice with its payment(s) to sql-ledger
415 // and be careful to use a unique invoice number.
416 // Call the generate-receipt function.
417 // Exit.
419 $form_pid = $_POST['form_pid'];
420 $form_encounter = $_POST['form_encounter'];
422 // Get the posting date from the form as yyyy-mm-dd.
423 $dosdate = date("Y-m-d");
424 if (preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/", $_POST['form_date'], $matches)) {
425 $dosdate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
428 // If there is no associated encounter (i.e. this invoice has only
429 // prescriptions) then assign an encounter number of the service
430 // date, with an optional suffix to ensure that it's unique.
432 if (! $form_encounter) {
433 SLConnect();
434 $form_encounter = substr($dosdate,0,4) . substr($dosdate,5,2) . substr($dosdate,8,2);
435 $tmp = '';
436 while (SLQueryValue("select id from ar where " .
437 "invnumber = '$form_pid.$form_encounter$tmp'")) {
438 $tmp = $tmp ? $tmp + 1 : 1;
440 $form_encounter .= $tmp;
441 SLClose();
444 // Initialize an array of invoice information for posting.
446 $invoice_info = array();
447 $msg = invoice_initialize($invoice_info, $form_pid,
448 $_POST['form_provider'], $_POST['form_payer'], $form_encounter, $dosdate);
449 if ($msg) die($msg);
451 $form_amount = $_POST['form_amount'];
452 $lines = $_POST['line'];
454 for ($lino = 0; $lines[$lino]['code_type']; ++$lino) {
455 $line = $lines[$lino];
457 $code_type = $line['code_type'];
458 $id = $line['id'];
459 $amount = sprintf('%01.2f', trim($line['amount']));
461 $msg = invoice_add_line_item($invoice_info, $code_type,
462 $line['code'], $line['description'], $amount, $line['units']);
463 if ($msg) die($msg);
465 if ($code_type == 'PROD') {
466 $query = "update drug_sales SET fee = '$amount', " .
467 "encounter = '$form_encounter', billed = 1 WHERE " .
468 "sale_id = '$id'";
469 sqlQuery($query);
471 else {
472 // Because there is no insurance here, there is no need for a claims
473 // table entry and so we do not call updateClaim(). Note we should not
474 // eliminate billed and bill_date from the billing table!
475 $query = "UPDATE billing SET fee = '$amount', billed = 1, " .
476 "bill_date = NOW() WHERE id = '$id'";
477 sqlQuery($query);
481 if ($_POST['form_amount']) {
482 $paydesc = $_POST['form_source'] ? $_POST['form_source'] : '';
483 $msg = invoice_add_line_item($invoice_info, 'COPAY',
484 $_POST['form_method'],
485 $paydesc,
486 0 - $_POST['form_amount']);
487 if ($msg) die($msg);
490 $msg = invoice_post($invoice_info);
491 if ($msg) die($msg);
493 generate_receipt($_POST['form_pid']);
494 exit();
497 // Get the unbilled billing table items and prescription sales for
498 // this patient.
500 $query = "SELECT id, date, code_type, code, modifier, code_text, " .
501 "provider_id, payer_id, units, fee, encounter " .
502 "FROM billing " .
503 "WHERE pid = '$pid' AND activity = 1 AND billed = 0 " .
504 "ORDER BY encounter DESC, id ASC";
505 $bres = sqlStatement($query);
507 $query = "SELECT s.sale_id, s.sale_date, s.prescription_id, s.fee, " .
508 "s.quantity, s.encounter, s.drug_id, d.name, r.provider_id " .
509 "FROM drug_sales AS s " .
510 "LEFT JOIN drugs AS d ON d.drug_id = s.drug_id " .
511 "LEFT OUTER JOIN prescriptions AS r ON r.id = s.prescription_id " .
512 "WHERE s.pid = '$pid' AND s.billed = 0 " .
513 "ORDER BY s.encounter DESC, s.sale_id ASC";
514 $dres = sqlStatement($query);
516 // If there are none, just redisplay the last receipt and exit.
518 if (mysql_num_rows($bres) == 0 && mysql_num_rows($dres) == 0) {
519 generate_receipt($pid);
520 exit();
523 // Now write a data entry form:
524 // List unbilled billing items (cpt, hcpcs, copays) for the patient.
525 // List unbilled prescription sales for the patient.
526 // Present an editable dollar amount for each line item, a total
527 // which is also the default value of the input payment amount,
528 // and OK and Cancel buttons.
530 <html>
531 <head>
532 <link rel='stylesheet' href='<?php echo $css_header ?>' type='text/css'>
533 <title><?php xl('Patient Checkout','e'); ?></title>
534 <style>
535 </style>
536 <style type="text/css">@import url(../../library/dynarch_calendar.css);</style>
537 <script type="text/javascript" src="../../library/textformat.js"></script>
538 <script type="text/javascript" src="../../library/dynarch_calendar.js"></script>
539 <script type="text/javascript" src="../../library/dynarch_calendar_en.js"></script>
540 <script type="text/javascript" src="../../library/dynarch_calendar_setup.js"></script>
541 <script language="JavaScript">
542 var mypcc = '<?php echo $GLOBALS['phone_country_code'] ?>';
544 function clearTax() {
545 var f = document.forms[0];
546 for (var lino = 0; true; ++lino) {
547 var pfx = 'line[' + lino + ']';
548 if (! f[pfx + '[code_type]']) break;
549 if (f[pfx + '[code_type]'].value != 'TAX') continue;
550 f[pfx + '[amount]'].value = '0.00';
551 f[pfx + '[price]'].value = '0.00';
555 function addTax(rateid, amount) {
556 if (rateid.length == 0) return 0;
557 var f = document.forms[0];
558 for (var lino = 0; true; ++lino) {
559 var pfx = 'line[' + lino + ']';
560 if (! f[pfx + '[code_type]']) break;
561 if (f[pfx + '[code_type]'].value != 'TAX') continue;
562 if (f[pfx + '[code]'].value != rateid) continue;
563 var tax = amount * parseFloat(f[pfx + '[taxrates]'].value);
564 tax = parseFloat(tax.toFixed(2));
565 var cumtax = parseFloat(f[pfx + '[price]'].value) + tax;
566 f[pfx + '[price]'].value = cumtax.toFixed(2); // requires JS 1.5
567 f[pfx + '[amount]'].value = cumtax.toFixed(2); // requires JS 1.5
568 if (isNaN(tax)) alert('Tax rate not numeric at line ' + lino);
569 return tax;
571 return 0;
574 // This mess applies the discount percentage.
575 function computeTotals() {
576 clearTax();
577 var f = document.forms[0];
578 var total = 0.00;
579 var discount = parseFloat(f.form_discount.value);
580 if (isNaN(discount)) discount = 0;
581 for (var lino = 0; f['line[' + lino + '][code_type]']; ++lino) {
582 var code_type = f['line[' + lino + '][code_type]'].value;
583 var price = parseFloat(f['line[' + lino + '][price]'].value);
584 if (isNaN(price)) alert('Price not numeric at line ' + lino);
585 if (code_type == 'COPAY' || code_type == 'TAX') {
586 total += parseFloat(price.toFixed(2));
587 continue;
589 var units = f['line[' + lino + '][units]'].value;
590 if (discount > 100) discount = 100;
591 if (discount < 0 ) discount = 0;
592 var amount = price * units;
593 if (discount > 0) {
594 amount = ((amount * (100 - discount) / 100) / units).toFixed(2) * units;
596 amount = parseFloat(amount.toFixed(2));
597 f['line[' + lino + '][amount]'].value = amount.toFixed(2);
598 total += amount;
599 var taxrates = f['line[' + lino + '][taxrates]'].value;
600 var taxids = taxrates.split(':');
601 for (var j = 0; j < taxids.length; ++j) {
602 addTax(taxids[j], amount);
605 // f.form_amount.value = total.toFixed(2);
606 f.form_amount.value = total.toFixed(2);
607 return true;
610 </script>
611 </head>
613 <body class="body_top">
615 <form method='post' action='pos_checkout.php'>
616 <input type='hidden' name='form_pid' value='<?php echo $pid ?>' />
618 <center>
621 <table cellspacing='5'>
622 <tr>
623 <td colspan='3' align='center'>
624 <b><?php xl('Patient Checkout for ','e'); ?><?php echo $patdata['fname'] . " " .
625 $patdata['lname'] . " (" . $patdata['pubpid'] . ")" ?></b>
626 </td>
627 </tr>
628 <tr>
629 <td><b><?php xl('Date','e'); ?></b></td>
630 <td><b><?php xl('Description','e'); ?></b></td>
631 <td align='right'><b><?php xl('Qty','e'); ?></b></td>
632 <td align='right'><b><?php xl('Amount','e'); ?></b></td>
633 </tr>
634 <?php
635 $inv_encounter = '';
636 $inv_date = '';
637 $inv_provider = 0;
638 $inv_payer = 0;
640 while ($brow = sqlFetchArray($bres)) {
641 // Skip all but the most recent encounter.
642 if ($inv_encounter && $brow['encounter'] != $inv_encounter) continue;
644 $thisdate = substr($brow['date'], 0, 10);
645 $code_type = $brow['code_type'];
647 $taxrates = '';
648 if ($code_type != 'COPAY' && $code_type != 'TAX') {
649 $query = "SELECT taxrates FROM codes WHERE code_type = '" .
650 $code_types[$code_type]['id'] . "' AND " .
651 "code = '" . $brow['code'] . "' AND ";
652 if ($brow['modifier']) {
653 $query .= "modifier = '" . $brow['modifier'] . "'";
654 } else {
655 $query .= "(modifier IS NULL OR modifier = '')";
657 $query .= " LIMIT 1";
658 $tmp = sqlQuery($query);
659 $taxrates = $tmp['taxrates'];
660 markTaxes($taxrates);
663 write_form_line($code_type, $brow['code'], $brow['id'], $thisdate,
664 ucfirst(strtolower($brow['code_text'])), $brow['fee'], $brow['units'],
665 $taxrates);
666 if (!$inv_encounter) $inv_encounter = $brow['encounter'];
667 if (!$inv_provider ) $inv_provider = $brow['provider_id'];
668 $inv_payer = $brow['payer_id'];
669 if (!$inv_date || $inv_date < $thisdate) $inv_date = $thisdate;
672 while ($drow = sqlFetchArray($dres)) {
673 if ($inv_encounter && $drow['encounter'] && $drow['encounter'] != $inv_encounter) continue;
675 $thisdate = $drow['sale_date'];
676 if (!$inv_encounter) $inv_encounter = $drow['encounter'];
677 if (!$inv_provider ) $inv_provider = $drow['provider_id'] + 0;
678 if (!$inv_date || $inv_date < $thisdate) $inv_date = $thisdate;
679 // $total += $drow['fee'];
681 // Accumulate taxes for this product.
682 $tmp = sqlQuery("SELECT taxrates FROM drug_templates WHERE drug_id = '" .
683 $drow['drug_id'] . "' ORDER BY selector LIMIT 1");
684 // accumTaxes($drow['fee'], $tmp['taxrates']);
685 $taxrates = $tmp['taxrates'];
686 markTaxes($taxrates);
688 write_form_line('PROD', $drow['drug_id'], $drow['sale_id'],
689 $thisdate, $drow['name'], $drow['fee'], $drow['quantity'], $taxrates);
692 // Write a form line for each tax that has money, adding to $total.
693 foreach ($taxes as $key => $value) {
694 if ($value[2]) {
695 write_form_line('TAX', $key, $key, date('Y-m-d'), $value[0], 0, 1, $value[1]);
699 // If there were only products without prescriptions then there is no
700 // provider yet, so get it from the encounter.
701 if ($inv_encounter && !$inv_provider) {
702 $erow = sqlQuery("SELECT users.id FROM forms, users WHERE " .
703 "forms.encounter = '$inv_encounter' AND " .
704 "forms.formdir = 'newpatient' AND " .
705 "users.username = forms.user LIMIT 1");
706 $inv_provider = $erow['id'];
709 </table>
712 <table border='0' cellspacing='8'>
714 <tr>
715 <td>
716 <?php xl('Discount Percentage','e'); ?>:
717 </td>
718 <td>
719 <input type='text' name='form_discount' size='3' value=''
720 style='text-align:right' onkeyup='computeTotals()'>
721 </td>
722 </tr>
724 <tr>
725 <td>
726 <?php xl('Payment Method','e'); ?>:
727 </td>
728 <td>
729 <select name='form_method'>
731 foreach ($payment_methods as $value) {
732 echo " <option value='$value'";
733 echo ">$value</option>\n";
736 </select>
737 </td>
738 </tr>
740 <tr>
741 <td>
742 <?php xl('Check/Reference Number','e'); ?>:
743 </td>
744 <td>
745 <input type='text' name='form_source' size='10' value=''>
746 </td>
747 </tr>
749 <tr>
750 <td>
751 <?php xl('Amount Paid','e'); ?>:
752 </td>
753 <td>
754 <input type='text' name='form_amount' size='10' value='0.00'>
755 </td>
756 </tr>
758 <tr>
759 <td>
760 <?php xl('Posting Date','e'); ?>:
761 </td>
762 <td>
763 <input type='text' size='10' name='form_date' id='form_date'
764 value='<?php echo $inv_date ?>'
765 title='yyyy-mm-dd date of service'
766 onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' />
767 <img src='../pic/show_calendar.gif' align='absbottom' width='24' height='22'
768 id='img_date' border='0' alt='[?]' style='cursor:pointer'
769 title='Click here to choose a date'>
770 </td>
771 </tr>
773 <tr>
774 <td colspan='2' align='center'>
775 &nbsp;<br>
776 <input type='submit' name='form_save' value='<?php xl('Save','e'); ?>' /> &nbsp;
777 <?php if (empty($_GET['framed'])) { ?>
778 <input type='button' value='Cancel' onclick='window.close()' />
779 <?php } ?>
780 <input type='hidden' name='form_provider' value='<?php echo $inv_provider ?>' />
781 <input type='hidden' name='form_payer' value='<?php echo $inv_payer ?>' />
782 <input type='hidden' name='form_encounter' value='<?php echo $inv_encounter ?>' />
783 </td>
784 </tr>
786 </table>
787 </center>
789 </form>
791 <script language='JavaScript'>
792 Calendar.setup({inputField:"form_date", ifFormat:"%Y-%m-%d", button:"img_date"});
793 computeTotals();
794 </script>
796 </body>
797 </html>