created fee_sheet_options table and an administrative user interface for customizing...
[openemr.git] / interface / forms / fee_sheet / new.php
blob0e2acdcd6874a65615c51b013cef2c13c7ad377c
1 <?php
2 //////////////////////////////////////////////////////////////////////
3 // ------------------ DO NOT MODIFY VIEW.PHP !!! ---------------------
4 // View.php is an exact duplicate of new.php. If you wish to make
5 // any changes, then change new.php and either (recommended) make
6 // view.php a symbolic link to new.php, or copy new.php to view.php.
7 //
8 // And if you check in a change to either module, be sure to check
9 // in the other (identical) module also.
11 // This nonsense will go away if we ever move to subversion.
12 //////////////////////////////////////////////////////////////////////
14 // Copyright (C) 2005-2008 Rod Roark <rod@sunsetsystems.com>
16 // This program is free software; you can redistribute it and/or
17 // modify it under the terms of the GNU General Public License
18 // as published by the Free Software Foundation; either version 2
19 // of the License, or (at your option) any later version.
21 require_once("../../globals.php");
22 require_once("$srcdir/api.inc");
23 require_once("codes.php");
24 require_once("../../../custom/code_types.inc.php");
25 require_once("../../drugs/drugs.inc.php");
27 // Possible units of measure for NDC drug quantities.
29 $ndc_uom_choices = array(
30 'ML' => 'ML',
31 'GR' => 'Grams',
32 'F2' => 'I.U.',
33 'UN' => 'Units'
36 // $FEE_SHEET_COLUMNS should be defined in codes.php.
37 if (empty($FEE_SHEET_COLUMNS)) $FEE_SHEET_COLUMNS = 2;
39 $returnurl = $GLOBALS['concurrent_layout'] ? 'encounter_top.php' : 'patient_encounter.php';
41 // If Save was clicked, save the new and modified billing lines;
42 // then if no error, redirect to $returnurl.
44 if ($_POST['bn_save']) {
45 $provid = $_POST['ProviderID'];
46 if (! $provid) $provid = $_SESSION["authUserID"];
48 $bill = $_POST['bill'];
49 for ($lino = 1; $bill["$lino"]['code_type']; ++$lino) {
50 $iter = $bill["$lino"];
52 // Skip disabled (billed) line items.
53 if ($iter['billed']) continue;
55 $id = $iter['id'];
56 $code_type = $iter['code_type'];
57 $code = $iter['code'];
58 $modifier = trim($iter['mod']);
59 $units = max(1, intval(trim($iter['units'])));
60 $fee = 0 + trim($iter['fee']);
61 if ($code_type == 'COPAY') {
62 if ($fee > 0) $fee = 0 - $fee;
63 $code = sprintf('%01.2f', 0 - $fee);
65 $justify = trim($iter['justify']);
66 if ($justify) $justify = str_replace(',', ':', $justify) . ':';
67 // $auth = $iter['auth'] ? "1" : "0";
68 $auth = "1";
69 $del = $iter['del'];
71 $ndc_info = '';
72 if ($iter['ndcnum']) {
73 $ndc_info = 'N4' . trim($iter['ndcnum']) . ' ' . $iter['ndcuom'] .
74 trim($iter['ndcqty']);
77 // If the item is already in the database...
78 if ($id) {
79 if ($del) {
80 deleteBilling($id);
82 else {
83 // authorizeBilling($id, $auth);
84 sqlQuery("UPDATE billing SET code = '$code', " .
85 "units = '$units', fee = '$fee', modifier = '$modifier', " .
86 "authorized = $auth, provider_id = '$provid', " .
87 "ndc_info = '$ndc_info', justify = '$justify' WHERE " .
88 "id = '$id' AND billed = 0 AND activity = 1");
92 // Otherwise it's a new item...
93 else if (! $del) {
94 $query = "select code_text from codes where code_type = '" .
95 $code_types[$code_type]['id'] . "' and " .
96 "code = '$code' and ";
97 if ($modifier) {
98 $query .= "modifier = '$modifier'";
99 } else {
100 $query .= "(modifier is null or modifier = '')";
102 $result = sqlQuery($query);
103 $code_text = addslashes($result['code_text']);
104 addBilling($encounter, $code_type, $code, $code_text, $pid, $auth,
105 $provid, $modifier, $units, $fee, $ndc_info, $justify);
107 } // end for
109 // Doing similarly to the above but for products.
110 $prod = $_POST['prod'];
111 for ($lino = 1; $prod["$lino"]['drug_id']; ++$lino) {
112 $iter = $prod["$lino"];
114 if (!empty($iter['billed'])) continue;
116 $drug_id = $iter['drug_id'];
117 $sale_id = $iter['sale_id']; // present only if already saved
118 $units = max(1, intval(trim($iter['units'])));
119 $fee = 0 + trim($iter['fee']);
120 $del = $iter['del'];
122 // If the item is already in the database...
123 if ($sale_id) {
124 if ($del) {
125 // Zero out this sale and reverse its inventory update. We bring in
126 // drug_sales twice so that the original quantity can be referenced
127 // unambiguously.
128 sqlStatement("UPDATE drug_sales AS dsr, drug_sales AS ds, " .
129 "drug_inventory AS di " .
130 "SET di.on_hand = di.on_hand + dsr.quantity, " .
131 "ds.quantity = 0, ds.fee = 0 WHERE " .
132 "dsr.sale_id = '$sale_id' AND ds.sale_id = dsr.sale_id AND " .
133 "di.inventory_id = ds.inventory_id");
134 // And delete the sale for good measure.
135 sqlStatement("DELETE FROM drug_sales WHERE sale_id = '$sale_id'");
137 else {
138 // Modify the sale and adjust inventory accordingly.
139 $query = "UPDATE drug_sales AS dsr, drug_sales AS ds, " .
140 "drug_inventory AS di " .
141 "SET di.on_hand = di.on_hand + dsr.quantity - $units, " .
142 "ds.quantity = '$units', ds.fee = '$fee' WHERE " .
143 "dsr.sale_id = '$sale_id' AND ds.sale_id = dsr.sale_id AND " .
144 "di.inventory_id = ds.inventory_id";
145 sqlStatement($query);
149 // Otherwise it's a new item...
150 else if (! $del) {
151 $sale_id = sellDrug($drug_id, $units, $fee, $pid, $encounter);
152 if (!$sale_id) die("Insufficient inventory for product ID \"$drug_id\".");
154 } // end for
156 // Note: I was going to compute taxes here, but now I think better to
157 // do that at checkout time (in pos_checkout.php which also posts to SL).
158 // Currently taxes with insurance claims make no sense, so for now we'll
159 // ignore tax computation in the insurance billing logic.
161 formHeader("Redirecting....");
162 formJump();
163 formFooter();
164 exit;
167 $billresult = getBillingByEncounter($pid, $encounter, "*");
169 <html>
170 <head>
171 <link rel=stylesheet href="<?echo $css_header;?>" type="text/css">
172 <style>
173 .billcell { font-family: sans-serif; font-size: 10pt }
174 </style>
175 <script language="JavaScript">
177 var diags = new Array();
179 <?php
180 // Generate JavaScript to build the array of diagnoses.
181 function genDiagJS($code_type, $code) {
182 if ($code_type == 'ICD9') {
183 echo "diags.push('$code');\n";
186 if ($billresult) {
187 foreach ($billresult as $iter) {
188 genDiagJS($iter["code_type"], trim($iter["code"]));
191 if ($_POST['bill']) {
192 foreach ($_POST['bill'] as $iter) {
193 if ($iter["del"]) continue; // skip if Delete was checked
194 if ($iter["id"]) continue; // skip if it came from the database
195 genDiagJS($iter["code_type"], $iter["code"]);
198 if ($_POST['newcodes']) {
199 $arrcodes = explode('~', $_POST['newcodes']);
200 foreach ($arrcodes as $codestring) {
201 if ($codestring === '') continue;
202 $arrcode = explode('|', $codestring);
203 list($code, $modifier) = explode(":", $arrcode[1]);
204 genDiagJS($arrcode[0], $code);
209 // This is invoked by <select onchange> for the various dropdowns,
210 // including search results.
211 function codeselect(selobj) {
212 var i = selobj.selectedIndex;
213 if (i > 0) {
214 top.restoreSession();
215 var f = document.forms[0];
216 f.newcodes.value = selobj.options[i].value;
217 f.submit();
221 function copayselect() {
222 top.restoreSession();
223 var f = document.forms[0];
224 f.newcodes.value = 'COPAY||';
225 f.submit();
228 function validate(f) {
229 for (var lino = 1; f['bill['+lino+'][code_type]']; ++lino) {
230 var pfx = 'bill['+lino+']';
231 if (f[pfx+'[ndcnum]'] && f[pfx+'[ndcnum]'].value) {
232 // Check NDC number format.
233 var ndcok = true;
234 var ndc = f[pfx+'[ndcnum]'].value;
235 var a = ndc.split('-');
236 if (a.length != 3) {
237 ndcok = false;
239 else if (a[0].length < 1 || a[1].length < 1 || a[2].length < 1 ||
240 a[0].length > 5 || a[1].length > 4 || a[2].length > 2) {
241 ndcok = false;
243 else {
244 for (var i = 0; i < 3; ++i) {
245 for (var j = 0; j < a[i].length; ++j) {
246 var c = a[i].charAt(j);
247 if (c < '0' || c > '9') ndcok = false;
251 if (!ndcok) {
252 alert('<?php xl('Format incorrect for NDC','e') ?> "' + ndc +
253 '", <?php xl('should be like nnnnn-nnnn-nn','e') ?>');
254 if (f[pfx+'[ndcnum]'].focus) f[pfx+'[ndcnum]'].focus();
255 return false;
257 // Check for valid quantity.
258 var qty = f[pfx+'[ndcqty]'].value - 0;
259 if (isNaN(qty) || qty <= 0) {
260 alert('<?php xl('Quantity for NDC','e') ?> "' + ndc +
261 '" <?php xl('is not valid (decimal fractions are OK).','e') ?>');
262 if (f[pfx+'[ndcqty]'].focus) f[pfx+'[ndcqty]'].focus();
263 return false;
267 top.restoreSession();
268 return true;
271 // When a justify selection is made, apply it to the current list for
272 // this procedure and then rebuild its selection list.
274 function setJustify(seljust) {
275 var theopts = seljust.options;
276 var jdisplay = theopts[0].text;
277 // Compute revised justification string. Note this does nothing if
278 // the first entry is still selected, which is handy at startup.
279 if (seljust.selectedIndex > 0) {
280 var newdiag = seljust.value;
281 if (newdiag.length == 0) {
282 jdisplay = '';
284 else {
285 if (jdisplay.length) jdisplay += ',';
286 jdisplay += newdiag;
289 // Rebuild selection list.
290 var jhaystack = ',' + jdisplay + ',';
291 var j = 0;
292 theopts.length = 0;
293 theopts[j++] = new Option(jdisplay,jdisplay,true,true);
294 for (var i = 0; i < diags.length; ++i) {
295 if (jhaystack.indexOf(',' + diags[i] + ',') < 0) {
296 theopts[j++] = new Option(diags[i],diags[i],false,false);
299 theopts[j++] = new Option('Clear','',false,false);
302 </script>
303 </head>
305 <body <?echo $top_bg_line;?> topmargin="0" rightmargin="0" leftmargin="2"
306 bottommargin="0" marginwidth="2" marginheight="0">
307 <form method="post" action="<?php echo $rootdir; ?>/forms/fee_sheet/new.php"
308 onsubmit="return validate(this)">
309 <span class="title"><? echo ($GLOBALS['phone_country_code'] == '1') ? 'Fee' : 'Coding' ?> <?php xl('Sheet','e');?></span><br>
310 <input type='hidden' name='newcodes' value=''>
312 <center>
313 <table width='95%'>
314 <?php
315 $i = 0;
316 $last_category = '';
318 // Helper function for creating drop-lists.
319 function endFSCategory() {
320 global $i, $last_category, $FEE_SHEET_COLUMNS;
321 if (! $last_category) return;
322 echo " </select>\n";
323 echo " </td>\n";
324 if ($i >= $FEE_SHEET_COLUMNS) {
325 echo " </tr>\n";
326 $i = 0;
330 // Create all the drop-lists of preselected service codes.
331 $res = sqlStatement("SELECT * FROM fee_sheet_options " .
332 "ORDER BY fs_category, fs_option");
333 while ($row = sqlFetchArray($res)) {
334 $fs_category = $row['fs_category'];
335 $fs_option = $row['fs_option'];
336 $fs_codes = $row['fs_codes'];
337 if($fs_category !== $last_category) {
338 endFSCategory();
339 $last_category = $fs_category;
340 ++$i;
341 echo ($i <= 1) ? " <tr>\n" : "";
342 echo " <td width='50%' align='center' nowrap>\n";
343 echo " <select style='width:96%' onchange='codeselect(this)'>\n";
344 echo " <option value=''> " . substr($fs_category, 1) . "\n";
346 echo " <option value='$fs_codes'>" . substr($fs_option, 1) . "\n";
348 endFSCategory();
350 // Create one more drop-list, for Products.
351 if ($GLOBALS['sell_non_drug_products']) {
352 ++$i;
353 echo ($i <= 1) ? " <tr>\n" : "";
354 echo " <td width='50%' align='center' nowrap>\n";
355 echo " <select name='Products' style='width:96%' onchange='codeselect(this)'>\n";
356 echo " <option value=''> " . xl('Products') . "\n";
357 $tres = sqlStatement("SELECT dt.drug_id, dt.selector, d.name " .
358 "FROM drug_templates AS dt, drugs AS d WHERE " .
359 "d.drug_id = dt.drug_id " .
360 "ORDER BY d.name, dt.selector, dt.drug_id");
361 while ($trow = sqlFetchArray($tres)) {
362 echo " <option value='PROD|" . $trow['drug_id'] . '|' . $trow['selector'] . "'>" .
363 $trow['drug_id'] . ':' . $trow['selector'] . ' ' . $trow['name'] . "</option>\n";
365 echo " </select>\n";
366 echo " </td>\n";
367 if ($i >= $FEE_SHEET_COLUMNS) {
368 echo " </tr>\n";
369 $i = 0;
373 $search_type = $default_search_type;
374 if ($_POST['search_type']) $search_type = $_POST['search_type'];
376 $ndc_applies = true; // Assume all payers require NDC info.
378 echo $i ? " <td></td>\n </tr>\n" : "";
379 echo " <tr>\n";
380 echo " <td colspan='$FEE_SHEET_COLUMNS' align='center' nowrap>\n";
382 // If Search was clicked, do it and write the list of results here.
383 // There's no limit on the number of results!
385 $numrows = 0;
386 if ($_POST['bn_search'] && $_POST['search_term']) {
387 $query = "select code, modifier, code_text from codes where " .
388 "(code_text like '%" . $_POST['search_term'] . "%' or " .
389 "code like '%" . $_POST['search_term'] . "%') and " .
390 "code_type = '" . $code_types[$search_type]['id'] . "' " .
391 "order by code";
392 $res = sqlStatement($query);
393 $numrows = mysql_num_rows($res); // FIXME - not portable!
396 echo " <select name='Search Results' style='width:98%' " .
397 "onchange='codeselect(this)'";
398 if (! $numrows) echo ' disabled';
399 echo ">\n";
400 echo " <option value=''> Search Results ($numrows items)\n";
402 if ($numrows) {
403 while ($row = sqlFetchArray($res)) {
404 $code = $row['code'];
405 if ($row['modifier']) $code .= ":" . $row['modifier'];
406 echo " <option value='$search_type|$code|'>$code " .
407 ucfirst(strtolower($row['code_text'])) . "</option>\n";
411 echo " </select>\n";
412 echo " </td>\n";
413 echo " </tr>\n";
416 </table>
418 <p style='margin-top:8px;margin-bottom:8px'>
419 <table>
420 <tr>
421 <td>
422 <input type='button' value='<?php xl('Add Copay','e');?>'
423 onclick="copayselect()" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
424 </td>
425 <td>
426 <?php xl('Search','e'); ?>&nbsp;
428 foreach ($code_types as $key => $value) {
429 echo " <input type='radio' name='search_type' value='$key'";
430 if ($key == $default_search_type) echo " checked";
431 echo " />$key&nbsp;\n";
434 <?php xl('for','e'); ?>&nbsp;
435 </td>
436 <td>
437 <input type='text' name='search_term' value=''> &nbsp;
438 </td>
439 <td>
440 <input type='submit' name='bn_search' value='<?php xl('Search','e');?>'>
441 </td>
442 </tr>
443 </table>
444 </p>
446 <p style='margin-top:16px;margin-bottom:8px'>
447 <table cellspacing='5'>
448 <tr>
449 <td class='billcell'><b><?php xl('Type','e');?></b></td>
450 <td class='billcell'><b><?php xl('Code','e');?></b></td>
451 <? if (modifiers_are_used()) { ?>
452 <td class='billcell'><b><?php xl('Mod','e');?></b></td>
453 <? } ?>
454 <? if (fees_are_used()) { ?>
455 <td class='billcell' align='center'><b><?php xl('Units','e');?></b></td>
456 <td class='billcell' align='right'><b><?php xl('Fee','e');?></b>&nbsp;</td>
457 <td class='billcell' align='center'><b><?php xl('Justify','e');?></b></td>
458 <? } ?>
459 <td class='billcell' align='center'><b><?php xl('Auth','e');?></b></td>
460 <td class='billcell' align='center'><b><?php xl('Delete','e');?></b></td>
461 <td class='billcell'><b><?php xl('Description','e');?></b></td>
462 </tr>
464 <?php
465 $justinit = "var f = document.forms[0];\n";
467 // This writes a billing line item to the output page.
469 function echoLine($lino, $codetype, $code, $modifier, $ndc_info='',
470 $auth = TRUE, $del = FALSE, $units = NULL, $fee = NULL, $id = NULL,
471 $billed = FALSE, $code_text = NULL, $justify = NULL)
473 global $code_types, $ndc_applies, $ndc_uom_choices, $justinit, $pid;
475 if ($codetype == 'COPAY') {
476 if (!$code_text) $code_text = 'Cash';
477 if ($fee > 0) $fee = 0 - $fee;
479 if (! $code_text) {
480 // $query = "select units, fee, code_text from codes where code_type = '" .
481 $query = "select id, units, code_text from codes where code_type = '" .
482 $code_types[$codetype]['id'] . "' and " .
483 "code = '$code' and ";
484 if ($modifier) {
485 $query .= "modifier = '$modifier'";
486 } else {
487 $query .= "(modifier is null or modifier = '')";
489 $result = sqlQuery($query);
490 $code_text = $result['code_text'];
491 if (empty($units)) $units = max(1, intval($result['units']));
492 if (!isset($fee)) {
493 // $fee = $result['fee'];
494 // The above is obsolete now, fees come from the prices table:
495 $query = "SELECT prices.pr_price " .
496 "FROM patient_data, prices WHERE " .
497 "patient_data.pid = '$pid' AND " .
498 "prices.pr_id = '" . $result['id'] . "' AND " .
499 "prices.pr_selector = '' AND " .
500 "prices.pr_level = patient_data.pricelevel " .
501 "LIMIT 1";
502 echo "\n<!-- $query -->\n"; // debugging
503 $prrow = sqlQuery($query);
504 $fee = empty($prrow) ? 0 : $prrow['pr_price'];
507 $fee = sprintf('%01.2f', $fee);
508 $strike1 = ($id && $del) ? "<strike>" : "";
509 $strike2 = ($id && $del) ? "</strike>" : "";
510 echo " <tr>\n";
511 echo " <td class='billcell'>$strike1$codetype$strike2";
512 if ($id) {
513 echo "<input type='hidden' name='bill[$lino][id]' value='$id'>";
515 echo "<input type='hidden' name='bill[$lino][code_type]' value='$codetype'>";
516 echo "<input type='hidden' name='bill[$lino][code]' value='$code'>";
517 echo "<input type='hidden' name='bill[$lino][billed]' value='$billed'>";
518 echo "</td>\n";
519 if ($codetype != 'COPAY') {
520 echo " <td class='billcell'>$strike1$code$strike2</td>\n";
521 } else {
522 echo " <td class='billcell'>&nbsp;</td>\n";
524 if ($billed) {
525 if (modifiers_are_used()) {
526 echo " <td class='billcell'>$strike1$modifier$strike2" .
527 "<input type='hidden' name='bill[$lino][mod]' value='$modifier'></td>\n";
529 if (fees_are_used()) {
530 if ($codetype != 'COPAY') {
531 echo " <td class='billcell' align='center'>$units</td>\n";
532 } else {
533 echo " <td class='billcell'>&nbsp;</td>\n";
535 echo " <td class='billcell' align='right'>$fee</td>\n";
536 echo " <td class='billcell' align='center'>$justify</td>\n";
538 echo " <td class='billcell' align='center'><input type='checkbox'" .
539 ($auth ? " checked" : "") . " disabled /></td>\n";
540 echo " <td class='billcell' align='center'><input type='checkbox'" .
541 " disabled /></td>\n";
542 } else {
543 if (modifiers_are_used()) {
544 if ($codetype != 'COPAY' && ($code_types[$codetype]['mod'] || $modifier)) {
545 echo " <td class='billcell'><input type='text' name='bill[$lino][mod]' " .
546 "value='$modifier' size='" . $code_types[$codetype]['mod'] . "'></td>\n";
547 } else {
548 echo " <td class='billcell'>&nbsp;</td>\n";
551 if (fees_are_used()) {
552 if ($codetype == 'COPAY' || $code_types[$codetype]['fee'] || $fee != 0) {
553 echo " <td class='billcell' align='center'>";
554 if ($codetype != 'COPAY') {
555 echo "<input type='text' name='bill[$lino][units]' " .
556 "value='$units' size='2' style='text-align:right'>";
557 } else {
558 echo "<input type='hidden' name='bill[$lino][units]' value='$units'>";
560 echo "</td>\n";
561 echo " <td class='billcell' align='right'>" .
562 "<input type='text' name='bill[$lino][fee]' " .
563 "value='$fee' size='6' style='text-align:right'></td>\n";
564 if ($code_types[$codetype]['just'] || $justify) {
565 echo " <td class='billcell' align='center'>";
566 echo "<select name='bill[$lino][justify]' onchange='setJustify(this)'>";
567 echo "<option value='$justify'>$justify</option></select>";
568 echo "</td>\n";
569 $justinit .= "setJustify(f['bill[$lino][justify]']);\n";
570 } else {
571 echo " <td class='billcell'>&nbsp;</td>\n";
573 } else {
574 echo " <td class='billcell'>&nbsp;</td>\n";
575 echo " <td class='billcell'>&nbsp;</td>\n";
576 echo " <td class='billcell'>&nbsp;</td>\n";
579 echo " <td class='billcell' align='center'><input type='checkbox' name='bill[$lino][auth]' " .
580 "value='1'" . ($auth ? " checked" : "") . " /></td>\n";
581 echo " <td class='billcell' align='center'><input type='checkbox' name='bill[$lino][del]' " .
582 "value='1'" . ($del ? " checked" : "") . " /></td>\n";
585 echo " <td class='billcell'>$strike1" . ucfirst(strtolower($code_text)) . "$strike2</td>\n";
586 echo " </tr>\n";
588 // If NDC info exists or may be required, add a line for it.
589 if ($codetype == 'HCPCS' && $ndc_applies && !$billed) {
590 $ndcnum = ''; $ndcuom = ''; $ndcqty = '';
591 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndc_info, $tmp)) {
592 $ndcnum = $tmp[1]; $ndcuom = $tmp[2]; $ndcqty = $tmp[3];
594 echo " <tr>\n";
595 echo " <td class='billcell' colspan='2'>&nbsp;</td>\n";
596 echo " <td class='billcell' colspan='6'>&nbsp;NDC:&nbsp;";
597 echo "<input type='text' name='bill[$lino][ndcnum]' value='$ndcnum' " .
598 "size='11' style='background-color:transparent'>";
599 echo " &nbsp;Qty:&nbsp;";
600 echo "<input type='text' name='bill[$lino][ndcqty]' value='$ndcqty' " .
601 "size='3' style='background-color:transparent;text-align:right'>";
602 echo " ";
603 echo "<select name='bill[$lino][ndcuom]' style='background-color:transparent'>";
604 foreach ($ndc_uom_choices as $key => $value) {
605 echo "<option value='$key'";
606 if ($key == $ndcuom) echo " selected";
607 echo ">$value</option>";
609 echo "</select>";
610 echo "</td>\n";
611 echo " </tr>\n";
613 else if ($ndc_info) {
614 echo " <tr>\n";
615 echo " <td class='billcell' colspan='2'>&nbsp;</td>\n";
616 echo " <td class='billcell' colspan='6'>&nbsp;NDC Data: $ndc_info</td>\n";
617 echo " </tr>\n";
621 // This writes a product (drug_sales) line item to the output page.
623 function echoProdLine($lino, $drug_id, $del = FALSE, $units = NULL,
624 $fee = NULL, $sale_id = 0, $billed = FALSE)
626 global $code_types, $ndc_applies, $pid;
628 /*******************************************************************
629 list ($drug_id, $selector) = explode(':', $drugsel);
630 if (! $units) { // if this is a new selection then apply defaults for it
631 $query = "SELECT dt.*, d.name FROM drug_templates, drugs WHERE " .
632 "dt.drug_id = '$drug_id' AND dt.selector = '$selector' AND " .
633 "d.drug_id = dt.drug_id";
634 $result = sqlQuery($query);
635 $code_text = $result['name'] . " ($selector)";
636 if (empty($units)) $units = max(1, intval($result['quantity']));
637 if (!isset($fee)) {
638 // Fees come from the prices table:
639 $query = "SELECT prices.pr_price " .
640 "FROM patient_data, prices WHERE " .
641 "patient_data.pid = '$pid' AND " .
642 "prices.pr_id = '$drug_id' AND " .
643 "prices.pr_selector = '$selector' AND " .
644 "prices.pr_level = patient_data.pricelevel " .
645 "LIMIT 1";
646 // echo "\n<!-- $query -->\n"; // debugging
647 $prrow = sqlQuery($query);
648 $fee = empty($prrow) ? 0 : $prrow['pr_price'];
651 *******************************************************************/
652 $drow = sqlQuery("SELECT name FROM drugs WHERE drug_id = '$drug_id'");
653 $code_text = $drow['name'];
654 /******************************************************************/
656 $fee = sprintf('%01.2f', $fee);
657 $strike1 = ($sale_id && $del) ? "<strike>" : "";
658 $strike2 = ($sale_id && $del) ? "</strike>" : "";
659 echo " <tr>\n";
660 echo " <td class='billcell'>{$strike1}Product$strike2";
661 echo "<input type='hidden' name='prod[$lino][sale_id]' value='$sale_id'>";
662 echo "<input type='hidden' name='prod[$lino][drug_id]' value='$drug_id'>";
663 echo "<input type='hidden' name='prod[$lino][billed]' value='$billed'>";
664 echo "</td>\n";
665 echo " <td class='billcell'>$strike1$drug_id$strike2</td>\n";
666 if (modifiers_are_used()) {
667 echo " <td class='billcell'>&nbsp;</td>\n";
669 if ($billed) {
670 if (fees_are_used()) {
671 echo " <td class='billcell' align='center'>$units</td>\n";
672 echo " <td class='billcell' align='right'>$fee</td>\n";
673 echo " <td class='billcell' align='center'>&nbsp;</td>\n"; // justify
675 echo " <td class='billcell' align='center'>&nbsp;</td>\n"; // auth
676 echo " <td class='billcell' align='center'><input type='checkbox'" . // del
677 " disabled /></td>\n";
678 } else {
679 if (fees_are_used()) {
680 echo " <td class='billcell' align='center'>";
681 echo "<input type='text' name='prod[$lino][units]' " .
682 "value='$units' size='2' style='text-align:right'>";
683 echo "</td>\n";
684 echo " <td class='billcell' align='right'>" .
685 "<input type='text' name='prod[$lino][fee]' " .
686 "value='$fee' size='6' style='text-align:right'></td>\n";
687 echo " <td class='billcell'>&nbsp;</td>\n";
689 echo " <td class='billcell' align='center'>&nbsp;</td>\n"; // auth
690 echo " <td class='billcell' align='center'><input type='checkbox' name='prod[$lino][del]' " .
691 "value='1'" . ($del ? " checked" : "") . " /></td>\n";
694 echo " <td class='billcell'>$strike1" . ucfirst(strtolower($code_text)) . "$strike2</td>\n";
695 echo " </tr>\n";
698 $encounter_provid = -1;
700 // Generate lines for items already in the billing table for this encounter,
701 // and also set the rendering provider if we come across one.
703 $bill_lino = 0;
704 if ($billresult) {
705 foreach ($billresult as $iter) {
706 ++$bill_lino;
707 $bline = $_POST['bill']["$bill_lino"];
708 $del = $bline['del']; // preserve Delete if checked
710 $modifier = trim($iter["modifier"]);
711 $units = $iter["units"];
712 $fee = $iter["fee"];
713 $authorized = $iter["authorized"];
714 $ndc_info = $iter["ndc_info"];
715 $justify = trim($iter['justify']);
716 if ($justify) $justify = substr(str_replace(':', ',', $justify), 0, strlen($justify) - 1);
718 // Also preserve other items from the form, if present.
719 if ($bline['id'] && !$iter["billed"]) {
720 $modifier = trim($bline['mod']);
721 $units = trim($bline['units']);
722 $fee = trim($bline['fee']);
723 $authorized = $bline['auth'];
724 $ndc_info = '';
725 if ($bline['ndcnum']) {
726 $ndc_info = 'N4' . trim($bline['ndcnum']) . ' ' . $bline['ndcuom'] .
727 trim($bline['ndcqty']);
729 $justify = $bline['justify'];
732 // list($code, $modifier) = explode("-", $iter["code"]);
733 echoLine($bill_lino, $iter["code_type"], trim($iter["code"]),
734 $modifier, $ndc_info, $authorized,
735 $del, $units, $fee, $iter["id"], $iter["billed"],
736 $iter["code_text"], $justify);
737 // If no default provider yet then try this one.
738 if ($encounter_provid < 0 && ! $del) $encounter_provid = $iter["provider_id"];
742 // Echo new billing items from this form here, but omit any line
743 // whose Delete checkbox is checked.
745 if ($_POST['bill']) {
746 foreach ($_POST['bill'] as $key => $iter) {
747 if ($iter["id"]) continue; // skip if it came from the database
748 if ($iter["del"]) continue; // skip if Delete was checked
749 $ndc_info = '';
750 if ($iter['ndcnum']) {
751 $ndc_info = 'N4' . trim($iter['ndcnum']) . ' ' . $iter['ndcuom'] .
752 trim($iter['ndcqty']);
754 $fee = 0 + trim($iter['fee']);
755 if ($iter['code_type'] == 'COPAY' && $fee > 0) $fee = 0 - $fee;
756 echoLine(++$bill_lino, $iter["code_type"], $iter["code"], trim($iter["mod"]),
757 $ndc_info, $iter["auth"], $iter["del"], trim($iter["units"]),
758 $fee, NULL, FALSE, NULL, $iter["justify"]);
762 // Generate lines for items already in the drug_sales table for this encounter.
764 $query = "SELECT * FROM drug_sales WHERE " .
765 "pid = '$pid' AND encounter = '$encounter' " .
766 "ORDER BY sale_id";
767 $sres = sqlStatement($query);
768 $prod_lino = 0;
769 while ($srow = sqlFetchArray($sres)) {
770 ++$prod_lino;
771 $pline = $_POST['prod']["$prod_lino"];
772 $del = $pline['del']; // preserve Delete if checked
773 $sale_id = $srow['sale_id'];
774 $drug_id = $srow['drug_id'];
775 $units = $srow['quantity'];
776 $fee = $srow['fee'];
777 $billed = $srow['billed'];
778 // Also preserve other items from the form, if present and unbilled.
779 if ($pline['sale_id'] && !$srow['billed']) {
780 $units = trim($pline['units']);
781 $fee = trim($pline['fee']);
783 echoProdLine($prod_lino, $drug_id, $del, $units, $fee, $sale_id, $billed);
786 // Echo new product items from this form here, but omit any line
787 // whose Delete checkbox is checked.
789 if ($_POST['prod']) {
790 foreach ($_POST['prod'] as $key => $iter) {
791 if ($iter["sale_id"]) continue; // skip if it came from the database
792 if ($iter["del"]) continue; // skip if Delete was checked
793 $fee = 0 + trim($iter['fee']);
794 echoProdLine(++$prod_lino, $iter['drug_id'], FALSE, trim($iter["units"]), $fee);
798 // If new billing code(s) were <select>ed, add their line(s) here.
800 if ($_POST['newcodes']) {
801 $arrcodes = explode('~', $_POST['newcodes']);
802 foreach ($arrcodes as $codestring) {
803 if ($codestring === '') continue;
804 $arrcode = explode('|', $codestring);
805 $newtype = $arrcode[0];
806 $newcode = $arrcode[1];
807 $newsel = $arrcode[2];
808 if ($newtype == 'COPAY') {
809 $tmp = sqlQuery("SELECT copay FROM insurance_data WHERE pid = '$pid' " .
810 "AND type = 'primary' ORDER BY date DESC LIMIT 1");
811 $code = sprintf('%01.2f', 0 + $tmp['copay']);
812 echoLine(++$bill_lino, $newtype, $code, '', '', '1', '0', '1',
813 sprintf('%01.2f', 0 - $code));
815 else if ($newtype == 'PROD') {
816 $result = sqlQuery("SELECT * FROM drug_templates WHERE " .
817 "drug_id = '$newcode' AND selector = '$newsel'");
818 $units = max(1, intval($result['quantity']));
819 $prrow = sqlQuery("SELECT prices.pr_price " .
820 "FROM patient_data, prices WHERE " .
821 "patient_data.pid = '$pid' AND " .
822 "prices.pr_id = '$newcode' AND " .
823 "prices.pr_selector = '$newsel' AND " .
824 "prices.pr_level = patient_data.pricelevel " .
825 "LIMIT 1");
826 $fee = empty($prrow) ? 0 : $prrow['pr_price'];
827 echoProdLine(++$prod_lino, $newcode, FALSE, $units, $fee);
829 else {
830 list($code, $modifier) = explode(":", $newcode);
831 $ndc_info = '';
832 // If HCPCS, find last NDC string used for this code.
833 if ($newtype == 'HCPCS' && $ndc_applies) {
834 $tmp = sqlQuery("SELECT ndc_info FROM billing WHERE " .
835 "code_type = '$newtype' AND code = '$code' AND ndc_info LIKE 'N4%' " .
836 "ORDER BY date DESC LIMIT 1");
837 if (!empty($tmp)) $ndc_info = $tmp['ndc_info'];
839 echoLine(++$bill_lino, $newtype, $code, trim($modifier), $ndc_info);
844 // If no valid provider yet, try setting it to that of the new encounter form.
846 $tmp = sqlQuery("SELECT authorized FROM users WHERE id = '$encounter_provid'");
847 if (empty($tmp['authorized'])) {
848 $encounter_provid = -1;
849 $tmp = sqlQuery("SELECT users.id FROM forms, users WHERE " .
850 "forms.pid = '$pid' AND forms.encounter = '$encounter' AND " .
851 "forms.formdir='newpatient' AND users.username = forms.user AND " .
852 "users.authorized = 1");
853 if ($tmp['id']) $encounter_provid = $tmp['id'];
856 // If still no default provider then make it the logged-in user.
858 if ($encounter_provid < 0) $encounter_provid = $_SESSION["authUserID"];
860 </table>
861 </p>
863 <br>
864 &nbsp;
866 <span class="billcell"><?php xl('PROVIDER:','e');?></span>
868 <?php
869 // Build a drop-down list of providers. This includes users who
870 // have the word "provider" anywhere in their "additional info"
871 // field, so that we can define providers (for billing purposes)
872 // who do not appear in the calendar.
874 $query = "SELECT id, lname, fname FROM users WHERE " .
875 "( authorized = 1 OR info LIKE '%provider%' ) AND username != '' " .
876 "ORDER BY lname, fname";
877 $res = sqlStatement($query);
879 echo " <select name='ProviderID'>\n";
880 echo " <option value=''>-- Please Select --\n";
882 while ($row = sqlFetchArray($res)) {
883 $provid = $row['id'];
884 echo " <option value='$provid'";
885 if ($provid == $encounter_provid) echo " selected";
886 echo ">" . $row['lname'] . ", " . $row['fname'] . "\n";
889 echo " </select>\n";
892 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
894 <input type='submit' name='bn_save' value='<?php xl('Save','e');?>' />
895 &nbsp;
896 <input type='submit' name='bn_refresh' value='<?php xl('Refresh','e');?>'>
897 &nbsp;
898 <input type='button' value='<?php xl('Cancel','e');?>'
899 onclick="top.restoreSession();location='<? echo "$rootdir/patient_file/encounter/$returnurl" ?>'" />
901 <?php if ($code_types['UCSMC']) { ?>
902 <p style='font-family:sans-serif;font-size:8pt;color:#666666;'>
903 &nbsp;<br>
904 <?php xl('UCSMC codes provided by the University of Calgary Sports Medicine Centre','e');?>
905 </p>
906 <? } ?>
908 </center>
910 </form>
912 <?php
913 // TBD: If $alertmsg, display it with a JavaScript alert().
916 <script language='JavaScript'>
917 <?php echo $justinit; ?>
918 </script>
920 </body>
921 </html>