Fee sheet improvements. Can set default code type. take 3.
[openemr.git] / interface / forms / fee_sheet / new.php
blobf75595b9de80807e00b3cd22fe6f9a5770836586
1 <?php
2 /*
3 *
4 * Fee Sheet Program used to create charges, copays and add diagnosis codes to the encounter
5 *
6 * Copyright (C) 2005-2015 Rod Roark <rod@sunsetsystems.com>
7 *
8 * LICENSE: This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
19 * @package OpenEMR
20 * @author Rod Roark <rod@sunsetsystems.com>
21 * @author Terry Hill <terry@lillysystems.com>
22 * @link http://www.open-emr.org
25 $fake_register_globals=false;
26 $sanitize_all_escapes=true;
28 require_once("../../globals.php");
29 require_once("$srcdir/acl.inc");
30 require_once("$srcdir/api.inc");
31 require_once("codes.php");
32 require_once("../../../custom/code_types.inc.php");
33 require_once("../../drugs/drugs.inc.php");
34 require_once("$srcdir/formatting.inc.php");
35 require_once("$srcdir/options.inc.php");
36 require_once("$srcdir/formdata.inc.php");
37 require_once("$srcdir/log.inc");
39 // For logging checksums set this to true.
40 define('CHECKSUM_LOGGING', true);
42 // Some table cells will not be displayed unless insurance billing is used.
43 $usbillstyle = $GLOBALS['ippf_specific'] ? " style='display:none'" : "";
45 // This may be an error message or warning that pops up when the form is loaded.
46 $alertmsg = '';
48 function alphaCodeType($id) {
49 global $code_types;
50 foreach ($code_types as $key => $value) {
51 if ($value['id'] == $id) return $key;
53 return '';
56 // Helper function for creating drop-lists.
57 function endFSCategory() {
58 global $i, $last_category, $FEE_SHEET_COLUMNS;
59 if (! $last_category) return;
60 echo " </select>\n";
61 echo " </td>\n";
62 if ($i >= $FEE_SHEET_COLUMNS) {
63 echo " </tr>\n";
64 $i = 0;
68 // Generate JavaScript to build the array of diagnoses.
69 function genDiagJS($code_type, $code) {
70 global $code_types;
71 if ($code_types[$code_type]['diag']) {
72 echo "diags.push('" . attr($code_type) . "|" . attr($code) . "');\n";
76 // For IPPF only. Returns 0 = none, 1 = nonsurgical, 2 = surgical.
78 function contraceptionClass($code_type, $code) {
79 global $code_types;
80 if (!$GLOBALS['ippf_specific']) return 0;
81 $contra = 0;
82 // Get the related service codes.
83 $codesrow = sqlQuery("SELECT related_code FROM codes WHERE " .
84 "code_type = ? " .
85 " AND code = ? LIMIT 1", array($code_types[$code_type]['id'],$code) );
86 if (!empty($codesrow['related_code']) && $code_type == 'MA') {
87 $relcodes = explode(';', $codesrow['related_code']);
88 foreach ($relcodes as $relstring) {
89 if ($relstring === '') continue;
90 list($reltype, $relcode) = explode(':', $relstring);
91 if ($reltype !== 'IPPF') continue;
92 if (preg_match('/^11....110/' , $relcode)) $contra |= 1;
93 else if (preg_match('/^11....999/' , $relcode)) $contra |= 1;
94 else if (preg_match('/^112152010/' , $relcode)) $contra |= 1;
95 else if (preg_match('/^11317[1-2]111/', $relcode)) $contra |= 1;
96 else if (preg_match('/^12118[1-2].13/', $relcode)) $contra |= 2;
97 else if (preg_match('/^12118[1-2]999/', $relcode)) $contra |= 2;
100 return $contra;
102 # gets the provider from the encounter file , or from the logged on user or from the patient file
103 function findProvider() {
104 global $encounter, $pid;
105 $find_provider = sqlQuery("SELECT provider_id FROM form_encounter " .
106 "WHERE pid = ? AND encounter = ? " .
107 "ORDER BY id DESC LIMIT 1", array($pid,$encounter) );
108 $providerid = $find_provider['provider_id'];
109 if($providerid == 0) {
110 $get_authorized = $_SESSION['userauthorized'];
111 if($get_authorized ==1) {
112 $providerid = $_SESSION[authUserID];
115 if($providerid == 0) {
116 $find_provider = sqlQuery("SELECT providerID FROM patient_data " .
117 "WHERE pid = ? ", array($pid) );
118 $providerid = $find_provider['providerID'];
120 return $providerid;
123 // This writes a billing line item to the output page.
125 function echoLine($lino, $codetype, $code, $modifier, $ndc_info='',
126 $auth = TRUE, $del = FALSE, $units = NULL, $fee = NULL, $id = NULL,
127 $billed = FALSE, $code_text = NULL, $justify = NULL, $provider_id = 0, $notecodes='')
129 global $code_types, $ndc_applies, $ndc_uom_choices, $justinit, $pid;
130 global $contraception, $usbillstyle, $hasCharges;
132 // If using line item billing and user wishes to default to a selected provider, then do so.
133 if($GLOBALS['default_fee_sheet_line_item_provider'] == 1 && $GLOBALS['support_fee_sheet_line_item_provider'] ==1 ) {
134 if ($provider_id == 0) {
135 $provider_id = 0 + findProvider();
139 if ($codetype == 'COPAY') {
140 if (!$code_text) $code_text = 'Cash';
141 if ($fee > 0) $fee = 0 - $fee;
143 if (! $code_text) {
144 $sqlArray = array();
145 $query = "select id, units, code_text from codes where code_type = ? " .
146 " and " .
147 "code = ? and ";
148 array_push($sqlArray,$code_types[$codetype]['id'],$code);
149 if ($modifier) {
150 $query .= "modifier = ?";
151 array_push($sqlArray,$modifier);
152 } else {
153 $query .= "(modifier is null or modifier = '')";
155 $result = sqlQuery($query, $sqlArray);
156 $code_text = $result['code_text'];
157 if (empty($units)) $units = max(1, intval($result['units']));
158 if (!isset($fee)) {
159 // Fees come from the prices table now.
160 $query = "SELECT prices.pr_price " .
161 "FROM patient_data, prices WHERE " .
162 "patient_data.pid = ? AND " .
163 "prices.pr_id = ? AND " .
164 "prices.pr_selector = '' AND " .
165 "prices.pr_level = patient_data.pricelevel " .
166 "LIMIT 1";
167 echo "\n<!-- $query -->\n"; // debugging
168 $prrow = sqlQuery($query, array($pid,$result['id']) );
169 $fee = empty($prrow) ? 0 : $prrow['pr_price'];
172 $fee = sprintf('%01.2f', $fee);
173 if (empty($units)) $units = 1;
174 $units = max(1, intval($units));
175 // We put unit price on the screen, not the total line item fee.
176 $price = $fee / $units;
177 $strike1 = ($id && $del) ? "<strike>" : "";
178 $strike2 = ($id && $del) ? "</strike>" : "";
179 echo " <tr>\n";
180 echo " <td class='billcell'>$strike1" .
181 ($codetype == 'COPAY' ? xl($codetype) : $codetype) . $strike2;
182 //if the line to ouput is copay, show the date here passed as $ndc_info,
183 //since this variable is not applicable in the case of copay.
184 if($codetype == 'COPAY'){
185 echo "(".htmlspecialchars($ndc_info).")";
186 $ndc_info = '';
188 if ($id) {
189 echo "<input type='hidden' name='bill[".attr($lino)."][id]' value='$id'>";
191 echo "<input type='hidden' name='bill[".attr($lino)."][code_type]' value='".attr($codetype)."'>";
192 echo "<input type='hidden' name='bill[".attr($lino)."][code]' value='".attr($code)."'>";
193 echo "<input type='hidden' name='bill[".attr($lino)."][billed]' value='".attr($billed)."'>";
194 echo "</td>\n";
195 if ($codetype != 'COPAY') {
196 echo " <td class='billcell'>$strike1" . text($code) . "$strike2</td>\n";
197 } else {
198 echo " <td class='billcell'>&nbsp;</td>\n";
200 if ($billed) {
201 if (modifiers_are_used(true)) {
202 echo " <td class='billcell'>$strike1" . text($modifier) . "$strike2" .
203 "<input type='hidden' name='bill[".attr($lino)."][mod]' value='".attr($modifier)."'></td>\n";
205 if (fees_are_used()) {
206 echo " <td class='billcell' align='right'>" . text(oeFormatMoney($price)) . "</td>\n";
207 if ($codetype != 'COPAY') {
208 echo " <td class='billcell' align='center'>" . text($units) . "</td>\n";
209 } else {
210 echo " <td class='billcell'>&nbsp;</td>\n";
213 if (justifiers_are_used()) {
214 echo " <td class='billcell' align='center'$usbillstyle>" . text($justify) . "</td>\n";
217 // Show provider for this line (if using line item billing).
218 if($GLOBALS['support_fee_sheet_line_item_provider'] ==1) {
219 echo " <td class='billcell' align='center'>";
221 else
223 echo " <td class='billcell' align='center' style='display: none'>";
225 genProviderSelect('', '-- '.xl("Default").' --', $provider_id, true);
226 echo "</td>\n";
228 if ($code_types[$codetype]['claim'] && !$code_types[$codetype]['diag']) {
229 echo " <td class='billcell' align='center'$usbillstyle>" .
230 htmlspecialchars($notecodes, ENT_NOQUOTES) . "</td>\n";
232 else {
233 echo " <td class='billcell' align='center'$usbillstyle></td>\n";
235 echo " <td class='billcell' align='center'$usbillstyle><input type='checkbox'" .
236 ($auth ? " checked" : "") . " disabled /></td>\n";
237 echo " <td class='billcell' align='center'><input type='checkbox'" .
238 " disabled /></td>\n";
240 else { // not billed
241 if (modifiers_are_used(true)) {
242 if ($codetype != 'COPAY' && ($code_types[$codetype]['mod'] || $modifier)) {
243 echo " <td class='billcell'><input type='text' name='bill[".attr($lino)."][mod]' " .
244 "value='" . attr($modifier) . "' " .
245 "title='" . xla("Multiple modifiers can be separated by colons or spaces, maximum of 4 (M1:M2:M3:M4)") . "' " .
246 "value='" . attr($modifier) . "' size='" . attr($code_types[$codetype]['mod']) . "'></td>\n";
247 } else {
248 echo " <td class='billcell'>&nbsp;</td>\n";
251 if (fees_are_used()) {
252 if ($codetype == 'COPAY' || $code_types[$codetype]['fee'] || $fee != 0) {
253 echo " <td class='billcell' align='right'>" .
254 "<input type='text' name='bill[".attr($lino)."][price]' " .
255 "value='" . attr($price) . "' size='6'";
256 if (acl_check('acct','disc'))
257 echo " style='text-align:right'";
258 else
259 echo " style='text-align:right;background-color:transparent' readonly";
260 echo "></td>\n";
261 echo " <td class='billcell' align='center'>";
262 if ($codetype != 'COPAY') {
263 echo "<input type='text' name='bill[".attr($lino)."][units]' " .
264 "value='" . attr($units) . "' size='2' style='text-align:right'>";
265 } else {
266 echo "<input type='hidden' name='bill[".attr($lino)."][units]' value='" . attr($units) . "'>";
268 echo "</td>\n";
269 } else {
270 echo " <td class='billcell'>&nbsp;</td>\n";
271 echo " <td class='billcell'>&nbsp;</td>\n";
274 if (justifiers_are_used()) {
275 if ($code_types[$codetype]['just'] || $justify) {
276 echo " <td class='billcell' align='center'$usbillstyle ";
277 echo "title='" . xla("Select one or more diagnosis codes to justify the service") . "' >";
278 echo "<select name='bill[".attr($lino)."][justify]' onchange='setJustify(this)'>";
279 echo "<option value='" . attr($justify) . "'>" . text($justify) . "</option></select>";
280 echo "</td>\n";
281 $justinit .= "setJustify(f['bill[".attr($lino)."][justify]']);\n";
282 } else {
283 echo " <td class='billcell'$usbillstyle>&nbsp;</td>\n";
287 // Show provider for this line (if using line item billing)
288 if($GLOBALS['support_fee_sheet_line_item_provider'] ==1) {
289 echo " <td class='billcell' align='center'>";
291 else
293 echo " <td class='billcell' align='center' style='display: none'>";
295 genProviderSelect("bill[$lino][provid]", '-- '.xl("Default").' --', $provider_id);
296 echo "</td>\n";
298 if ($code_types[$codetype]['claim'] && !$code_types[$codetype]['diag']) {
299 echo " <td class='billcell' align='center'$usbillstyle><input type='text' name='bill[".attr($lino)."][notecodes]' " .
300 "value='" . htmlspecialchars($notecodes, ENT_QUOTES) . "' maxlength='10' size='8' /></td>\n";
302 else {
303 echo " <td class='billcell' align='center'$usbillstyle></td>\n";
305 echo " <td class='billcell' align='center'$usbillstyle><input type='checkbox' name='bill[".attr($lino)."][auth]' " .
306 "value='1'" . ($auth ? " checked" : "") . " /></td>\n";
307 echo " <td class='billcell' align='center'><input type='checkbox' name='bill[".attr($lino)."][del]' " .
308 "value='1'" . ($del ? " checked" : "") . " /></td>\n";
311 echo " <td class='billcell'>$strike1" . text($code_text) . "$strike2</td>\n";
312 echo " </tr>\n";
314 // If NDC info exists or may be required, add a line for it.
315 if ($codetype == 'HCPCS' && $ndc_applies && !$billed) {
316 $ndcnum = ''; $ndcuom = ''; $ndcqty = '';
317 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndc_info, $tmp)) {
318 $ndcnum = $tmp[1]; $ndcuom = $tmp[2]; $ndcqty = $tmp[3];
320 echo " <tr>\n";
321 echo " <td class='billcell' colspan='2'>&nbsp;</td>\n";
322 echo " <td class='billcell' colspan='6'>&nbsp;NDC:&nbsp;";
323 echo "<input type='text' name='bill[".attr($lino)."][ndcnum]' value='" . attr($ndcnum) . "' " .
324 "size='11' style='background-color:transparent'>";
325 echo " &nbsp;Qty:&nbsp;";
326 echo "<input type='text' name='bill[".attr($lino)."][ndcqty]' value='" . attr($ndcqty) . "' " .
327 "size='3' style='background-color:transparent;text-align:right'>";
328 echo " ";
329 echo "<select name='bill[".attr($lino)."][ndcuom]' style='background-color:transparent'>";
330 foreach ($ndc_uom_choices as $key => $value) {
331 echo "<option value='" . attr($key) . "'";
332 if ($key == $ndcuom) echo " selected";
333 echo ">" . text($value) . "</option>";
335 echo "</select>";
336 echo "</td>\n";
337 echo " </tr>\n";
339 else if ($ndc_info) {
340 echo " <tr>\n";
341 echo " <td class='billcell' colspan='2'>&nbsp;</td>\n";
342 echo " <td class='billcell' colspan='6'>&nbsp;" . xlt("NDC Data") . ": " . text($ndc_info) . "</td>\n";
343 echo " </tr>\n";
346 // For IPPF. Track contraceptive services.
347 if (!$del) $contraception |= contraceptionClass($codetype, $code);
349 if ($fee != 0) $hasCharges = true;
352 // This writes a product (drug_sales) line item to the output page.
354 function echoProdLine($lino, $drug_id, $del = FALSE, $units = NULL,
355 $fee = NULL, $sale_id = 0, $billed = FALSE)
357 global $code_types, $ndc_applies, $pid, $usbillstyle, $hasCharges;
359 $drow = sqlQuery("SELECT name FROM drugs WHERE drug_id = ?", array($drug_id) );
360 $code_text = $drow['name'];
362 $fee = sprintf('%01.2f', $fee);
363 if (empty($units)) $units = 1;
364 $units = max(1, intval($units));
365 // We put unit price on the screen, not the total line item fee.
366 $price = $fee / $units;
367 $strike1 = ($sale_id && $del) ? "<strike>" : "";
368 $strike2 = ($sale_id && $del) ? "</strike>" : "";
369 echo " <tr>\n";
370 echo " <td class='billcell'>{$strike1}" . xlt("Product") . "$strike2";
371 echo "<input type='hidden' name='prod[".attr($lino)."][sale_id]' value='" . attr($sale_id) . "'>";
372 echo "<input type='hidden' name='prod[".attr($lino)."][drug_id]' value='" . attr($drug_id) . "'>";
373 echo "<input type='hidden' name='prod[".attr($lino)."][billed]' value='" . attr($billed) . "'>";
374 echo "</td>\n";
375 echo " <td class='billcell'>$strike1" . text($drug_id) . "$strike2</td>\n";
376 if (modifiers_are_used(true)) {
377 echo " <td class='billcell'>&nbsp;</td>\n";
379 if ($billed) {
380 if (fees_are_used()) {
381 echo " <td class='billcell' align='right'>" . text(oeFormatMoney($price)) . "</td>\n";
382 echo " <td class='billcell' align='center'>" . text($units) . "</td>\n";
384 if (justifiers_are_used()) {
385 echo " <td class='billcell' align='center'$usbillstyle>&nbsp;</td>\n"; // justify
387 echo " <td class='billcell' align='center'>&nbsp;</td>\n"; // provider
388 echo " <td class='billcell' align='center'$usbillstyle>&nbsp;</td>\n"; // note codes
389 echo " <td class='billcell' align='center'$usbillstyle>&nbsp;</td>\n"; // auth
390 echo " <td class='billcell' align='center'><input type='checkbox'" . // del
391 " disabled /></td>\n";
392 } else {
393 if (fees_are_used()) {
394 echo " <td class='billcell' align='right'>" .
395 "<input type='text' name='prod[".attr($lino)."][price]' " .
396 "value='" . attr($price) . "' size='6'";
397 if (acl_check('acct','disc'))
398 echo " style='text-align:right'";
399 else
400 echo " style='text-align:right;background-color:transparent' readonly";
401 echo "></td>\n";
402 echo " <td class='billcell' align='center'>";
403 echo "<input type='text' name='prod[".attr($lino)."][units]' " .
404 "value='" . attr($units) . "' size='2' style='text-align:right'>";
405 echo "</td>\n";
407 if (justifiers_are_used()) {
408 echo " <td class='billcell'$usbillstyle>&nbsp;</td>\n"; // justify
410 echo " <td class='billcell' align='center'>&nbsp;</td>\n"; // provider
411 echo " <td class='billcell' align='center'$usbillstyle>&nbsp;</td>\n"; // note codes
412 echo " <td class='billcell' align='center'$usbillstyle>&nbsp;</td>\n"; // auth
413 echo " <td class='billcell' align='center'><input type='checkbox' name='prod[".attr($lino)."][del]' " .
414 "value='1'" . ($del ? " checked" : "") . " /></td>\n";
417 echo " <td class='billcell'>$strike1" . text($code_text) . "$strike2</td>\n";
418 echo " </tr>\n";
420 if ($fee != 0) $hasCharges = true;
423 // Build a drop-down list of providers. This includes users who
424 // have the word "provider" anywhere in their "additional info"
425 // field, so that we can define providers (for billing purposes)
426 // who do not appear in the calendar.
428 function genProviderSelect($selname, $toptext, $default=0, $disabled=false) {
429 $query = "SELECT id, lname, fname FROM users WHERE " .
430 "( authorized = 1 OR info LIKE '%provider%' ) AND username != '' " .
431 "AND active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
432 "ORDER BY lname, fname";
433 $res = sqlStatement($query);
434 echo " <select name='" . attr($selname) . "'";
435 if ($disabled) echo " disabled";
436 echo ">\n";
437 echo " <option value=''>" . text($toptext) . "\n";
438 while ($row = sqlFetchArray($res)) {
439 $provid = $row['id'];
440 echo " <option value='" . attr($provid) . "'";
441 if ($provid == $default) echo " selected";
442 echo ">" . text($row['lname'] . ", " . $row['fname']) . "\n";
444 echo " </select>\n";
447 // Compute a current checksum of Fee Sheet data from the database.
449 function visitChecksum($pid, $encounter, $saved=false) {
450 $rowb = sqlQuery("SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
451 "id, code, modifier, units, fee, authorized, provider_id, ndc_info, justify, billed" .
452 "))) AS checksum FROM billing WHERE " .
453 "pid = ? AND encounter = ? AND activity = 1",
454 array($pid, $encounter));
455 $rowp = sqlQuery("SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
456 "sale_id, inventory_id, prescription_id, quantity, fee, sale_date, billed" .
457 "))) AS checksum FROM drug_sales WHERE " .
458 "pid = ? AND encounter = ?",
459 array($pid, $encounter));
460 $ret = intval($rowb['checksum']) ^ intval($rowp['checksum']);
461 if (CHECKSUM_LOGGING) {
462 $comment = "Checksum = '$ret'";
463 $comment .= ", AJAX = " . (empty($_POST['running_as_ajax']) ? "false" : "true");
464 $comment .= ", Save = " . (empty($_POST['bn_save']) ? "false" : "true");
465 $comment .= ", Saved = " . ($saved ? "true" : "false");
466 newEvent("checksum", $_SESSION['authUser'], $_SESSION['authProvider'], 1, $comment, $pid);
468 return $ret;
471 // This is just for IPPF, to indicate if the visit includes contraceptive services.
472 $contraception = 0;
474 // Possible units of measure for NDC drug quantities.
476 $ndc_uom_choices = array(
477 'ML' => 'ML',
478 'GR' => 'Grams',
479 'ME' => 'Milligrams',
480 'F2' => 'I.U.',
481 'UN' => 'Units'
484 // $FEE_SHEET_COLUMNS should be defined in codes.php.
485 if (empty($FEE_SHEET_COLUMNS)) $FEE_SHEET_COLUMNS = 2;
487 $returnurl = $GLOBALS['concurrent_layout'] ? 'encounter_top.php' : 'patient_encounter.php';
489 // Update price level in patient demographics.
490 if (!empty($_POST['pricelevel'])) {
491 sqlStatement("UPDATE patient_data SET pricelevel = ? WHERE pid = ?", array($_POST['pricelevel'],$pid) );
494 // Get some info about this visit.
495 $visit_row = sqlQuery("SELECT fe.date, opc.pc_catname " .
496 "FROM form_encounter AS fe " .
497 "LEFT JOIN openemr_postcalendar_categories AS opc ON opc.pc_catid = fe.pc_catid " .
498 "WHERE fe.pid = ? AND fe.encounter = ? LIMIT 1", array($pid,$encounter) );
499 $visit_date = substr($visit_row['date'], 0, 10);
501 $current_checksum = visitChecksum($pid, $encounter);
502 // It's important to look for a checksum mismatch even if we're just refreshing
503 // the display, otherwise the error goes undetected on a refresh-then-save.
504 if (isset($_POST['form_checksum'])) {
505 if ($_POST['form_checksum'] != $current_checksum) {
506 $alertmsg = xl('Someone else has just changed this visit. Please cancel this page and try again.');
507 if (CHECKSUM_LOGGING) {
508 $comment = "CHECKSUM ERROR, expecting '{$_POST['form_checksum']}'";
509 newEvent("checksum", $_SESSION['authUser'], $_SESSION['authProvider'], 1, $comment, $pid);
514 // If Save or Save-and-Close was clicked, save the new and modified billing
515 // lines; then if no error, redirect to $returnurl.
517 if (!$alertmsg && ($_POST['bn_save'] || $_POST['bn_save_close'])) {
518 $main_provid = 0 + $_POST['ProviderID'];
519 $main_supid = 0 + $_POST['SupervisorID'];
520 if ($main_supid == $main_provid) $main_supid = 0;
521 $default_warehouse = $_POST['default_warehouse'];
523 $bill = $_POST['bill'];
524 $copay_update = FALSE;
525 $update_session_id = '';
526 $ct0 = '';//takes the code type of the first fee type code type entry from the fee sheet, against which the copay is posted
527 $cod0 = '';//takes the code of the first fee type code type entry from the fee sheet, against which the copay is posted
528 $mod0 = '';//takes the modifier of the first fee type code type entry from the fee sheet, against which the copay is posted
529 for ($lino = 1; $bill["$lino"]['code_type']; ++$lino) {
530 $iter = $bill["$lino"];
531 $code_type = $iter['code_type'];
532 $code = $iter['code'];
533 $del = $iter['del'];
535 // Skip disabled (billed) line items.
536 if ($iter['billed']) continue;
538 $id = $iter['id'];
539 $modifier = trim($iter['mod']);
540 if( !($cod0) && ($code_types[$code_type]['fee'] == 1) ){
541 $mod0 = $modifier;
542 $cod0 = $code;
543 $ct0 = $code_type;
545 $units = max(1, intval(trim($iter['units'])));
546 $fee = sprintf('%01.2f',(0 + trim($iter['price'])) * $units);
548 if($code_type == 'COPAY'){
549 if($id == ''){
550 //adding new copay from fee sheet into ar_session and ar_activity tables
551 if($fee < 0){
552 $fee = $fee * -1;
554 $session_id = idSqlStatement("INSERT INTO ar_session(payer_id,user_id,pay_total,payment_type,description,".
555 "patient_id,payment_method,adjustment_code,post_to_date) VALUES('0',?,?,'patient','COPAY',?,'','patient_payment',now())",
556 array($_SESSION['authId'],$fee,$pid));
557 SqlStatement("INSERT INTO ar_activity (pid,encounter,code_type,code,modifier,payer_type,post_time,post_user,session_id,".
558 "pay_amount,account_code) VALUES (?,?,?,?,?,0,now(),?,?,?,'PCP')",
559 array($pid,$encounter,$ct0,$cod0,$mod0,$_SESSION['authId'],$session_id,$fee));
560 }else{
561 //editing copay saved to ar_session and ar_activity
562 if($fee < 0){
563 $fee = $fee * -1;
565 $session_id = $id;
566 $res_amount = sqlQuery("SELECT pay_amount FROM ar_activity WHERE pid=? AND encounter=? AND session_id=?",
567 array($pid,$encounter,$session_id));
568 if($fee != $res_amount['pay_amount']){
569 sqlStatement("UPDATE ar_session SET user_id=?,pay_total=?,modified_time=now(),post_to_date=now() WHERE session_id=?",
570 array($_SESSION['authId'],$fee,$session_id));
571 sqlStatement("UPDATE ar_activity SET code_type=?, code=?, modifier=?, post_user=?, post_time=now(),".
572 "pay_amount=?, modified_time=now() WHERE pid=? AND encounter=? AND account_code='PCP' AND session_id=?",
573 array($ct0,$cod0,$mod0,$_SESSION['authId'],$fee,$pid,$encounter,$session_id));
576 if(!$cod0){
577 $copay_update = TRUE;
578 $update_session_id = $session_id;
580 continue;
582 $justify = trim($iter['justify']);
583 $notecodes = trim($iter['notecodes']);
584 if ($justify) $justify = str_replace(',', ':', $justify) . ':';
585 // $auth = $iter['auth'] ? "1" : "0";
586 $auth = "1";
587 $provid = 0 + $iter['provid'];
589 $ndc_info = '';
590 if ($iter['ndcnum']) {
591 $ndc_info = 'N4' . trim($iter['ndcnum']) . ' ' . $iter['ndcuom'] .
592 trim($iter['ndcqty']);
595 // If the item is already in the database...
596 if ($id) {
597 if ($del) {
598 deleteBilling($id);
600 else {
601 // authorizeBilling($id, $auth);
602 sqlQuery("UPDATE billing SET code = ?, " .
603 "units = ?, fee = ?, modifier = ?, " .
604 "authorized = ?, provider_id = ?, " .
605 "ndc_info = ?, justify = ?, notecodes = ? " .
606 "WHERE " .
607 "id = ? AND billed = 0 AND activity = 1", array($code,$units,$fee,$modifier,$auth,$provid,$ndc_info,$justify,$notecodes,$id) );
611 // Otherwise it's a new item...
612 else if (! $del) {
613 $code_text = lookup_code_descriptions($code_type.":".$code);
614 addBilling($encounter, $code_type, $code, $code_text, $pid, $auth,
615 $provid, $modifier, $units, $fee, $ndc_info, $justify, 0, $notecodes);
617 } // end for
619 //if modifier is not inserted during loop update the record using the first
620 //non-empty modifier and code
621 if($copay_update == TRUE && $update_session_id != '' && $mod0 != ''){
622 sqlStatement("UPDATE ar_activity SET code_type=?, code=?, modifier=?".
623 " WHERE pid=? AND encounter=? AND account_code='PCP' AND session_id=?",
624 array($ct0,$cod0,$mod0,$pid,$encounter,$update_session_id));
627 // Doing similarly to the above but for products.
628 $prod = $_POST['prod'];
629 for ($lino = 1; $prod["$lino"]['drug_id']; ++$lino) {
630 $iter = $prod["$lino"];
632 if (!empty($iter['billed'])) continue;
634 $drug_id = $iter['drug_id'];
635 $sale_id = $iter['sale_id']; // present only if already saved
636 $units = max(1, intval(trim($iter['units'])));
637 $fee = sprintf('%01.2f',(0 + trim($iter['price'])) * $units);
638 $del = $iter['del'];
640 // If the item is already in the database...
641 if ($sale_id) {
642 if ($del) {
643 // Zero out this sale and reverse its inventory update. We bring in
644 // drug_sales twice so that the original quantity can be referenced
645 // unambiguously.
646 sqlStatement("UPDATE drug_sales AS dsr, drug_sales AS ds, " .
647 "drug_inventory AS di " .
648 "SET di.on_hand = di.on_hand + dsr.quantity, " .
649 "ds.quantity = 0, ds.fee = 0 WHERE " .
650 "dsr.sale_id = ? AND ds.sale_id = dsr.sale_id AND " .
651 "di.inventory_id = ds.inventory_id", array($sale_id) );
652 // And delete the sale for good measure.
653 sqlStatement("DELETE FROM drug_sales WHERE sale_id = ?", array($sale_id) );
655 else {
656 // Modify the sale and adjust inventory accordingly.
657 $query = "UPDATE drug_sales AS dsr, drug_sales AS ds, " .
658 "drug_inventory AS di " .
659 "SET di.on_hand = di.on_hand + dsr.quantity - " . add_escape_custom($units) . ", " .
660 "ds.quantity = ?, ds.fee = ?, " .
661 "ds.sale_date = ? WHERE " .
662 "dsr.sale_id = ? AND ds.sale_id = dsr.sale_id AND " .
663 "di.inventory_id = ds.inventory_id";
664 sqlStatement($query, array($units,$fee,$visit_date,$sale_id) );
668 // Otherwise it's a new item...
669 else if (! $del) {
670 $sale_id = sellDrug($drug_id, $units, $fee, $pid, $encounter, 0,
671 $visit_date, '', $default_warehouse);
672 if (!$sale_id) die(xlt("Insufficient inventory for product ID") . " \"" . text($drug_id) . "\".");
674 } // end for
676 // Set the main/default service provider in the new-encounter form.
677 /*******************************************************************
678 sqlStatement("UPDATE forms, users SET forms.user = users.username WHERE " .
679 "forms.pid = '$pid' AND forms.encounter = '$encounter' AND " .
680 "forms.formdir = 'newpatient' AND users.id = '$provid'");
681 *******************************************************************/
682 sqlStatement("UPDATE form_encounter SET provider_id = ?, " .
683 "supervisor_id = ? WHERE " .
684 "pid = ? AND encounter = ?", array($main_provid,$main_supid,$pid,$encounter) );
686 // Save-and-Close is currently IPPF-specific but might be more generally
687 // useful. It provides the ability to mark an encounter as billed
688 // directly from the Fee Sheet, if there are no charges.
689 if ($_POST['bn_save_close']) {
690 $tmp1 = sqlQuery("SELECT SUM(ABS(fee)) AS sum FROM drug_sales WHERE " .
691 "pid = ? AND encounter = ?", array($pid,$encounter) );
692 $tmp2 = sqlQuery("SELECT SUM(ABS(fee)) AS sum FROM billing WHERE " .
693 "pid = ? AND encounter = ? AND billed = 0 AND " .
694 "activity = 1", array($pid,$encounter) );
695 if ($tmp1['sum'] + $tmp2['sum'] == 0) {
696 sqlStatement("update drug_sales SET billed = 1 WHERE " .
697 "pid = ? AND encounter = ? AND billed = 0", array($pid,$encounter));
698 sqlStatement("UPDATE billing SET billed = 1, bill_date = NOW() WHERE " .
699 "pid = ? AND encounter = ? AND billed = 0 AND " .
700 "activity = 1", array($pid,$encounter));
702 else {
703 // Would be good to display an error message here... they clicked
704 // Save and Close but the close could not be done. However the
705 // framework does not provide an easy way to do that.
709 // More IPPF stuff.
710 if (!empty($_POST['contrastart'])) {
711 $contrastart = $_POST['contrastart'];
712 sqlStatement("UPDATE patient_data SET contrastart = ?" .
713 " WHERE pid = ?", array($contrastart,$pid) );
716 // Note: Taxes are computed at checkout time (in pos_checkout.php which
717 // also posts to SL). Currently taxes with insurance claims make no sense,
718 // so for now we'll ignore tax computation in the insurance billing logic.
720 if ($_POST['running_as_ajax']) {
721 // In the case of running as an AJAX handler, we need to return this same
722 // form with an updated checksum to properly support the invoking logic.
723 // See review/js/fee_sheet_core.js for that logic.
724 $current_checksum = visitChecksum($pid, $encounter, true);
725 // Also remove form data for the newly entered lines so they are not
726 // duplicated from the database.
727 unset($_POST['bill']);
728 unset($_POST['prod']);
730 else {
731 formHeader("Redirecting....");
732 formJump();
733 formFooter();
734 exit;
738 $billresult = getBillingByEncounter($pid, $encounter, "*");
740 <html>
741 <head>
742 <?php html_header_show(); ?>
743 <link rel="stylesheet" href="<?php echo $css_header;?>" type="text/css">
744 <style>
745 .billcell { font-family: sans-serif; font-size: 10pt }
746 </style>
747 <script language="JavaScript">
749 var diags = new Array();
751 <?php
752 if ($billresult) {
753 foreach ($billresult as $iter) {
754 genDiagJS($iter["code_type"], trim($iter["code"]));
757 if ($_POST['bill']) {
758 foreach ($_POST['bill'] as $iter) {
759 if ($iter["del"]) continue; // skip if Delete was checked
760 if ($iter["id"]) continue; // skip if it came from the database
761 genDiagJS($iter["code_type"], $iter["code"]);
764 if ($_POST['newcodes']) {
765 $arrcodes = explode('~', $_POST['newcodes']);
766 foreach ($arrcodes as $codestring) {
767 if ($codestring === '') continue;
768 $arrcode = explode('|', $codestring);
769 list($code, $modifier) = explode(":", $arrcode[1]);
770 genDiagJS($arrcode[0], $code);
775 // This is invoked by <select onchange> for the various dropdowns,
776 // including search results.
777 function codeselect(selobj) {
778 var i = selobj.selectedIndex;
779 if (i > 0) {
780 top.restoreSession();
781 var f = document.forms[0];
782 f.newcodes.value = selobj.options[i].value;
783 f.submit();
787 function copayselect() {
788 top.restoreSession();
789 var f = document.forms[0];
790 f.newcodes.value = 'COPAY||';
791 f.submit();
794 function validate(f) {
795 for (var lino = 1; f['bill['+lino+'][code_type]']; ++lino) {
796 var pfx = 'bill['+lino+']';
797 if (f[pfx+'[ndcnum]'] && f[pfx+'[ndcnum]'].value) {
798 // Check NDC number format.
799 var ndcok = true;
800 var ndc = f[pfx+'[ndcnum]'].value;
801 var a = ndc.split('-');
802 if (a.length != 3) {
803 ndcok = false;
805 else if (a[0].length < 1 || a[1].length < 1 || a[2].length < 1 ||
806 a[0].length > 5 || a[1].length > 4 || a[2].length > 2) {
807 ndcok = false;
809 else {
810 for (var i = 0; i < 3; ++i) {
811 for (var j = 0; j < a[i].length; ++j) {
812 var c = a[i].charAt(j);
813 if (c < '0' || c > '9') ndcok = false;
817 if (!ndcok) {
818 alert('<?php echo addslashes(xl('Format incorrect for NDC')) ?> "' + ndc +
819 '", <?php echo addslashes(xl('should be like nnnnn-nnnn-nn')) ?>');
820 if (f[pfx+'[ndcnum]'].focus) f[pfx+'[ndcnum]'].focus();
821 return false;
823 // Check for valid quantity.
824 var qty = f[pfx+'[ndcqty]'].value - 0;
825 if (isNaN(qty) || qty <= 0) {
826 alert('<?php echo addslashes(xl('Quantity for NDC')) ?> "' + ndc +
827 '" <?php echo addslashes(xl('is not valid (decimal fractions are OK).')) ?>');
828 if (f[pfx+'[ndcqty]'].focus) f[pfx+'[ndcqty]'].focus();
829 return false;
833 top.restoreSession();
834 return true;
837 // When a justify selection is made, apply it to the current list for
838 // this procedure and then rebuild its selection list.
840 function setJustify(seljust) {
841 var theopts = seljust.options;
842 var jdisplay = theopts[0].text;
843 // Compute revised justification string. Note this does nothing if
844 // the first entry is still selected, which is handy at startup.
845 if (seljust.selectedIndex > 0) {
846 var newdiag = seljust.value;
847 if (newdiag.length == 0) {
848 jdisplay = '';
850 else {
851 if (jdisplay.length) jdisplay += ',';
852 jdisplay += newdiag;
855 // Rebuild selection list.
856 var jhaystack = ',' + jdisplay + ',';
857 var j = 0;
858 theopts.length = 0;
859 theopts[j++] = new Option(jdisplay,jdisplay,true,true);
860 for (var i = 0; i < diags.length; ++i) {
861 if (jhaystack.indexOf(',' + diags[i] + ',') < 0) {
862 theopts[j++] = new Option(diags[i],diags[i],false,false);
865 theopts[j++] = new Option('Clear','',false,false);
868 </script>
869 </head>
871 <body class="body_top">
872 <form method="post" action="<?php echo $rootdir; ?>/forms/fee_sheet/new.php"
873 onsubmit="return validate(this)">
874 <span class="title"><?php echo xlt('Fee Sheet'); ?></span><br>
875 <input type='hidden' name='newcodes' value=''>
877 <center>
879 <?php
880 $isBilled = isEncounterBilled($pid, $encounter);
881 if ($isBilled) {
882 echo "<p><font color='green'>" . xlt("This encounter has been billed. If you need to change it, it must be re-opened.") . "</font></p>\n";
884 else { // the encounter is not yet billed
887 <table width='95%'>
888 <?php
889 $i = 0;
890 $last_category = '';
892 // Create drop-lists based on the fee_sheet_options table.
893 $res = sqlStatement("SELECT * FROM fee_sheet_options " .
894 "ORDER BY fs_category, fs_option");
895 while ($row = sqlFetchArray($res)) {
896 $fs_category = $row['fs_category'];
897 $fs_option = $row['fs_option'];
898 $fs_codes = $row['fs_codes'];
899 if($fs_category !== $last_category) {
900 endFSCategory();
901 $last_category = $fs_category;
902 ++$i;
903 echo ($i <= 1) ? " <tr>\n" : "";
904 echo " <td width='50%' align='center' nowrap>\n";
905 echo " <select style='width:96%' onchange='codeselect(this)'>\n";
906 echo " <option value=''> " . text(substr($fs_category, 1)) . "</option>\n";
908 echo " <option value='" . attr($fs_codes) . "'>" . text(substr($fs_option, 1)) . "</option>\n";
910 endFSCategory();
912 // Create drop-lists based on categories defined within the codes.
913 $pres = sqlStatement("SELECT option_id, title FROM list_options " .
914 "WHERE list_id = 'superbill' ORDER BY seq");
915 while ($prow = sqlFetchArray($pres)) {
916 global $code_types;
917 ++$i;
918 echo ($i <= 1) ? " <tr>\n" : "";
919 echo " <td width='50%' align='center' nowrap>\n";
920 echo " <select style='width:96%' onchange='codeselect(this)'>\n";
921 echo " <option value=''> " . text($prow['title']) . "\n";
922 $res = sqlStatement("SELECT code_type, code, code_text,modifier FROM codes " .
923 "WHERE superbill = ? AND active = 1 " .
924 "ORDER BY code_text", array($prow['option_id']) );
925 while ($row = sqlFetchArray($res)) {
926 $ctkey = alphaCodeType($row['code_type']);
927 if ($code_types[$ctkey]['nofs']) continue;
928 echo " <option value='" . attr($ctkey) . "|" .
929 attr($row['code']) . ':'. attr($row['modifier']) . "|'>" . text($row['code_text']) . "</option>\n";
931 echo " </select>\n";
932 echo " </td>\n";
933 if ($i >= $FEE_SHEET_COLUMNS) {
934 echo " </tr>\n";
935 $i = 0;
939 // Create one more drop-list, for Products.
940 if ($GLOBALS['sell_non_drug_products']) {
941 ++$i;
942 echo ($i <= 1) ? " <tr>\n" : "";
943 echo " <td width='50%' align='center' nowrap>\n";
944 echo " <select name='Products' style='width:96%' onchange='codeselect(this)'>\n";
945 echo " <option value=''> " . xlt('Products') . "\n";
946 $tres = sqlStatement("SELECT dt.drug_id, dt.selector, d.name " .
947 "FROM drug_templates AS dt, drugs AS d WHERE " .
948 "d.drug_id = dt.drug_id AND d.active = 1 " .
949 "ORDER BY d.name, dt.selector, dt.drug_id");
950 while ($trow = sqlFetchArray($tres)) {
951 echo " <option value='PROD|" . attr($trow['drug_id']) . '|' . attr($trow['selector']) . "'>" .
952 text($trow['drug_id']) . ':' . text($trow['selector']);
953 if ($trow['name'] !== $trow['selector']) echo ' ' . text($trow['name']);
954 echo "</option>\n";
956 echo " </select>\n";
957 echo " </td>\n";
958 if ($i >= $FEE_SHEET_COLUMNS) {
959 echo " </tr>\n";
960 $i = 0;
964 $search_type = $default_search_type;
965 if ($_POST['search_type']) $search_type = $_POST['search_type'];
967 $ndc_applies = true; // Assume all payers require NDC info.
969 echo $i ? " <td></td>\n </tr>\n" : "";
970 echo " <tr>\n";
971 echo " <td colspan='" . attr($FEE_SHEET_COLUMNS) . "' align='center' nowrap>\n";
973 // If Search was clicked, do it and write the list of results here.
974 // There's no limit on the number of results!
976 $numrows = 0;
977 if ($_POST['bn_search'] && $_POST['search_term']) {
978 $res = main_code_set_search($search_type,$_POST['search_term']);
979 if (!empty($res)) {
980 $numrows = sqlNumRows($res);
984 echo " <select name='Search Results' style='width:98%' " .
985 "onchange='codeselect(this)'";
986 if (! $numrows) echo ' disabled';
987 echo ">\n";
988 echo " <option value=''> " . xlt("Search Results") . " ($numrows " . xlt("items") . ")\n";
990 if ($numrows) {
991 while ($row = sqlFetchArray($res)) {
992 $code = $row['code'];
993 if ($row['modifier']) $code .= ":" . $row['modifier'];
994 echo " <option value='" . attr($search_type) . "|" . attr($code) . "|'>" . text($code) . " " .
995 text($row['code_text']) . "</option>\n";
999 echo " </select>\n";
1000 echo " </td>\n";
1001 echo " </tr>\n";
1004 </table>
1006 <p style='margin-top:8px;margin-bottom:8px'>
1007 <table>
1008 <tr>
1009 <td>
1010 <input type='button' value='<?php echo xla('Add Copay');?>'
1011 onclick="copayselect()" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
1012 </td>
1013 <td>
1014 <?php echo xlt('Search'); ?>&nbsp;
1015 </td>
1016 <td>
1017 <?php
1018 $nofs_code_types = array();
1019 foreach ($code_types as $key => $value) {
1020 if (!empty($value['nofs'])) continue;
1021 $nofs_code_types[$key] = $value;
1023 $size_select = (count($nofs_code_types) < 5) ? count($nofs_code_types) : 5;
1025 <select name='search_type' size='<?php echo attr($size_select) ?>'>
1026 <?php
1027 foreach ($nofs_code_types as $key => $value) {
1028 echo " <option value='" . attr($key) . "'";
1029 if ($key == $search_type) echo " selected";
1030 echo " />" . xlt($value['label']) . "</option>";
1033 </select>
1034 </td>
1035 <td>
1036 <?php echo xlt('for'); ?>&nbsp;
1037 </td>
1038 <td>
1039 <input type='text' name='search_term' value=''> &nbsp;
1040 </td>
1041 <td>
1042 <input type='submit' name='bn_search' value='<?php echo xla('Search');?>'>
1043 </td>
1044 </tr>
1045 </table>
1046 </p>
1047 <p style='margin-top:16px;margin-bottom:8px'>
1049 <?php } // end encounter not billed ?>
1051 <table cellspacing='5'>
1052 <tr>
1053 <td class='billcell'><b><?php echo xlt('Type');?></b></td>
1054 <td class='billcell'><b><?php echo xlt('Code');?></b></td>
1055 <?php if (modifiers_are_used(true)) { ?>
1056 <td class='billcell'><b><?php echo xlt('Modifiers');?></b></td>
1057 <?php } ?>
1058 <?php if (fees_are_used()) { ?>
1059 <td class='billcell' align='right'><b><?php echo xlt('Price');?></b>&nbsp;</td>
1060 <td class='billcell' align='center'><b><?php echo xlt('Units');?></b></td>
1061 <?php } ?>
1062 <?php if (justifiers_are_used()) { ?>
1063 <td class='billcell' align='center'<?php echo $usbillstyle; ?>><b><?php echo xlt('Justify');?></b></td>
1064 <?php } ?>
1066 <?php // Show provider (only if using line item billing) ?>
1067 <?php if($GLOBALS['support_fee_sheet_line_item_provider'] ==1) { ?>
1068 <td class='billcell' align='center'>
1069 <?php } else { ?>
1070 <td class='billcell' align='center' style='display: none'>
1071 <?php } ?>
1072 <b><?php echo xlt('Provider');?></b></td>
1074 <td class='billcell' align='center'<?php echo $usbillstyle; ?>><b><?php echo xlt('Note Codes');?></b></td>
1075 <td class='billcell' align='center'<?php echo $usbillstyle; ?>><b><?php echo xlt('Auth');?></b></td>
1076 <td class='billcell' align='center'><b><?php echo xlt('Delete');?></b></td>
1077 <td class='billcell'><b><?php echo xlt('Description');?></b></td>
1078 </tr>
1080 <?php
1081 $justinit = "var f = document.forms[0];\n";
1083 // $encounter_provid = -1;
1085 $hasCharges = false;
1087 // Generate lines for items already in the billing table for this encounter,
1088 // and also set the rendering provider if we come across one.
1090 $bill_lino = 0;
1091 if ($billresult) {
1092 foreach ($billresult as $iter) {
1093 ++$bill_lino;
1094 $bline = $_POST['bill']["$bill_lino"];
1095 $del = $bline['del']; // preserve Delete if checked
1097 $modifier = trim($iter["modifier"]);
1098 $units = $iter["units"];
1099 $fee = $iter["fee"];
1100 $authorized = $iter["authorized"];
1101 $ndc_info = $iter["ndc_info"];
1102 $justify = trim($iter['justify']);
1103 $notecodes = trim($iter['notecodes']);
1104 if ($justify) $justify = substr(str_replace(':', ',', $justify), 0, strlen($justify) - 1);
1105 $provider_id = $iter['provider_id'];
1107 // Also preserve other items from the form, if present.
1108 if ($bline['id'] && !$iter["billed"]) {
1109 $modifier = trim($bline['mod']);
1110 $units = max(1, intval(trim($bline['units'])));
1111 $fee = sprintf('%01.2f',(0 + trim($bline['price'])) * $units);
1112 $authorized = $bline['auth'];
1113 $ndc_info = '';
1114 if ($bline['ndcnum']) {
1115 $ndc_info = 'N4' . trim($bline['ndcnum']) . ' ' . $bline['ndcuom'] .
1116 trim($bline['ndcqty']);
1118 $justify = $bline['justify'];
1119 $notecodes = trim($bline['notecodes']);
1120 $provider_id = 0 + $bline['provid'];
1123 if($iter['code_type'] == 'COPAY'){//moved copay display to below
1124 --$bill_lino;
1125 continue;
1128 // list($code, $modifier) = explode("-", $iter["code"]);
1129 echoLine($bill_lino, $iter["code_type"], trim($iter["code"]),
1130 $modifier, $ndc_info, $authorized,
1131 $del, $units, $fee, $iter["id"], $iter["billed"],
1132 $iter["code_text"], $justify, $provider_id, $notecodes);
1136 $resMoneyGot = sqlStatement("SELECT pay_amount as PatientPay,session_id as id,date(post_time) as date ".
1137 "FROM ar_activity where pid =? and encounter =? and payer_type=0 and account_code='PCP'",
1138 array($pid,$encounter));//new fees screen copay gives account_code='PCP'
1139 while($rowMoneyGot = sqlFetchArray($resMoneyGot)){
1140 $PatientPay=$rowMoneyGot['PatientPay']*-1;
1141 $id=$rowMoneyGot['id'];
1142 echoLine(++$bill_lino,'COPAY','','',$rowMoneyGot['date'],'1','','',$PatientPay,$id);
1145 // Echo new billing items from this form here, but omit any line
1146 // whose Delete checkbox is checked.
1148 if ($_POST['bill']) {
1149 foreach ($_POST['bill'] as $key => $iter) {
1150 if ($iter["id"]) continue; // skip if it came from the database
1151 if ($iter["del"]) continue; // skip if Delete was checked
1152 $ndc_info = '';
1153 if ($iter['ndcnum']) {
1154 $ndc_info = 'N4' . trim($iter['ndcnum']) . ' ' . $iter['ndcuom'] .
1155 trim($iter['ndcqty']);
1157 // $fee = 0 + trim($iter['fee']);
1158 $units = max(1, intval(trim($iter['units'])));
1159 $fee = sprintf('%01.2f',(0 + trim($iter['price'])) * $units);
1160 //the date is passed as $ndc_info, since this variable is not applicable in the case of copay.
1161 $ndc_info = '';
1162 if ($iter['code_type'] == 'COPAY'){
1163 $ndc_info = date("Y-m-d");
1164 if($fee > 0)
1165 $fee = 0 - $fee;
1167 echoLine(++$bill_lino, $iter["code_type"], $iter["code"], trim($iter["mod"]),
1168 $ndc_info, $iter["auth"], $iter["del"], $units,
1169 $fee, NULL, FALSE, NULL, $iter["justify"], 0 + $iter['provid'],
1170 $iter['notecodes']);
1174 // Generate lines for items already in the drug_sales table for this encounter.
1176 $query = "SELECT * FROM drug_sales WHERE " .
1177 "pid = ? AND encounter = ? " .
1178 "ORDER BY sale_id";
1179 $sres = sqlStatement($query, array($pid,$encounter) );
1180 $prod_lino = 0;
1181 while ($srow = sqlFetchArray($sres)) {
1182 ++$prod_lino;
1183 $pline = $_POST['prod']["$prod_lino"];
1184 $del = $pline['del']; // preserve Delete if checked
1185 $sale_id = $srow['sale_id'];
1186 $drug_id = $srow['drug_id'];
1187 $units = $srow['quantity'];
1188 $fee = $srow['fee'];
1189 $billed = $srow['billed'];
1190 // Also preserve other items from the form, if present and unbilled.
1191 if ($pline['sale_id'] && !$srow['billed']) {
1192 // $units = trim($pline['units']);
1193 // $fee = trim($pline['fee']);
1194 $units = max(1, intval(trim($pline['units'])));
1195 $fee = sprintf('%01.2f',(0 + trim($pline['price'])) * $units);
1197 echoProdLine($prod_lino, $drug_id, $del, $units, $fee, $sale_id, $billed);
1200 // Echo new product items from this form here, but omit any line
1201 // whose Delete checkbox is checked.
1203 if ($_POST['prod']) {
1204 foreach ($_POST['prod'] as $key => $iter) {
1205 if ($iter["sale_id"]) continue; // skip if it came from the database
1206 if ($iter["del"]) continue; // skip if Delete was checked
1207 // $fee = 0 + trim($iter['fee']);
1208 $units = max(1, intval(trim($iter['units'])));
1209 $fee = sprintf('%01.2f',(0 + trim($iter['price'])) * $units);
1210 echoProdLine(++$prod_lino, $iter['drug_id'], FALSE, $units, $fee);
1214 // If new billing code(s) were <select>ed, add their line(s) here.
1216 if ($_POST['newcodes']) {
1217 $arrcodes = explode('~', $_POST['newcodes']);
1218 foreach ($arrcodes as $codestring) {
1219 if ($codestring === '') continue;
1220 $arrcode = explode('|', $codestring);
1221 $newtype = $arrcode[0];
1222 $newcode = $arrcode[1];
1223 $newsel = $arrcode[2];
1224 if ($newtype == 'COPAY') {
1225 $tmp = sqlQuery("SELECT copay FROM insurance_data WHERE pid = ? " .
1226 "AND type = 'primary' ORDER BY date DESC LIMIT 1", array($pid) );
1227 $code = sprintf('%01.2f', 0 + $tmp['copay']);
1228 echoLine(++$bill_lino, $newtype, $code, '', date("Y-m-d"), '1', '0', '1',
1229 sprintf('%01.2f', 0 - $code));
1231 else if ($newtype == 'PROD') {
1232 $result = sqlQuery("SELECT * FROM drug_templates WHERE " .
1233 "drug_id = ? AND selector = ?", array($newcode,$newsel) );
1234 $units = max(1, intval($result['quantity']));
1235 $prrow = sqlQuery("SELECT prices.pr_price " .
1236 "FROM patient_data, prices WHERE " .
1237 "patient_data.pid = ? AND " .
1238 "prices.pr_id = ? AND " .
1239 "prices.pr_selector = ? AND " .
1240 "prices.pr_level = patient_data.pricelevel " .
1241 "LIMIT 1", array($pid,$newcode,$newsel) );
1242 $fee = empty($prrow) ? 0 : $prrow['pr_price'];
1243 echoProdLine(++$prod_lino, $newcode, FALSE, $units, $fee);
1245 else {
1246 list($code, $modifier) = explode(":", $newcode);
1247 $ndc_info = '';
1248 // If HCPCS, find last NDC string used for this code.
1249 if ($newtype == 'HCPCS' && $ndc_applies) {
1250 $tmp = sqlQuery("SELECT ndc_info FROM billing WHERE " .
1251 "code_type = ? AND code = ? AND ndc_info LIKE 'N4%' " .
1252 "ORDER BY date DESC LIMIT 1", array($newtype,$code) );
1253 if (!empty($tmp)) $ndc_info = $tmp['ndc_info'];
1255 echoLine(++$bill_lino, $newtype, $code, trim($modifier), $ndc_info);
1260 $tmp = sqlQuery("SELECT provider_id, supervisor_id FROM form_encounter " .
1261 "WHERE pid = ? AND encounter = ? " .
1262 "ORDER BY id DESC LIMIT 1", array($pid,$encounter) );
1263 $encounter_provid = 0 + findProvider();
1264 $encounter_supid = 0 + $tmp['supervisor_id'];
1266 </table>
1267 </p>
1269 <br />
1270 &nbsp;
1272 <?php
1273 // Choose rendering and supervising providers.
1274 echo "<span class='billcell'><b>\n";
1275 echo xlt('Providers') . ": &nbsp;";
1277 echo "&nbsp;&nbsp;" . xlt('Rendering') . "\n";
1278 genProviderSelect('ProviderID', '-- '.xl("Please Select").' --', $encounter_provid, $isBilled);
1280 if (!$GLOBALS['ippf_specific']) {
1281 echo "&nbsp;&nbsp;" . xlt('Supervising') . "\n";
1282 genProviderSelect('SupervisorID', '-- '.xl("N/A").' --', $encounter_supid, $isBilled);
1285 echo "</b></span>\n";
1289 &nbsp;
1291 <?php
1292 // If applicable, ask for the contraceptive services start date.
1293 $trow = sqlQuery("SELECT count(*) AS count FROM layout_options WHERE " .
1294 "form_id = 'DEM' AND field_id = 'contrastart' AND uor > 0");
1295 if ($trow['count'] && $contraception && !$isBilled) {
1296 $date1 = substr($visit_row['date'], 0, 10);
1297 // If admission or surgical, then force contrastart.
1298 if ($contraception > 1 ||
1299 strpos(strtolower($visit_row['pc_catname']), 'admission') !== false)
1301 echo " <input type='hidden' name='contrastart' value='" . attr($date1) . "' />\n";
1303 else {
1304 // echo "<!-- contraception = $contraception -->\n"; // debugging
1305 $trow = sqlQuery("SELECT contrastart " .
1306 "FROM patient_data WHERE " .
1307 "pid = ? LIMIT 1", array($pid) );
1308 if (empty($trow['contrastart']) || substr($trow['contrastart'], 0, 4) == '0000') {
1309 $date0 = date('Y-m-d', strtotime($date1) - (60 * 60 * 24));
1310 echo " <select name='contrastart'>\n";
1311 echo " <option value='" . attr($date1) . "'>" . xlt('This visit begins new contraceptive use') . "</option>\n";
1312 echo " <option value='" . attr($date0) . "'>" . xlt('Contraceptive services previously started') . "</option>\n";
1313 echo " <option value=''>" . xlt('None of the above') . "</option>\n";
1314 echo " </select>\n";
1315 echo "&nbsp; &nbsp; &nbsp;\n";
1320 // If there is a choice of warehouses, allow override of user default.
1321 if ($prod_lino > 0) { // if any products are in this form
1322 $trow = sqlQuery("SELECT count(*) AS count FROM list_options WHERE list_id = 'warehouse'");
1323 if ($trow['count'] > 1) {
1324 $trow = sqlQuery("SELECT default_warehouse FROM users WHERE username = ?", array($_SESSION['authUser']) );
1325 echo " <span class='billcell'><b>" . xlt('Warehouse') . ":</b></span>\n";
1326 echo generate_select_list('default_warehouse', 'warehouse',
1327 $trow['default_warehouse'], '');
1328 echo "&nbsp; &nbsp; &nbsp;\n";
1332 // Allow the patient price level to be fixed here.
1333 $plres = sqlStatement("SELECT option_id, title FROM list_options " .
1334 "WHERE list_id = 'pricelevel' ORDER BY seq");
1335 if (true) {
1336 $trow = sqlQuery("SELECT pricelevel FROM patient_data WHERE " .
1337 "pid = ? LIMIT 1", array($pid) );
1338 $pricelevel = $trow['pricelevel'];
1339 echo " <span class='billcell'><b>" . xlt('Price Level') . ":</b></span>\n";
1340 echo " <select name='pricelevel'";
1341 if ($isBilled) echo " disabled";
1342 echo ">\n";
1343 while ($plrow = sqlFetchArray($plres)) {
1344 $key = $plrow['option_id'];
1345 $val = $plrow['title'];
1346 echo " <option value='" . attr($key) . "'";
1347 if ($key == $pricelevel) echo ' selected';
1348 echo ">" . text($val) . "</option>\n";
1350 echo " </select>\n";
1354 &nbsp; &nbsp; &nbsp;
1356 <?php if (!$isBilled) { ?>
1357 <input type='submit' name='bn_save' value='<?php echo xla('Save');?>' />
1358 &nbsp;
1359 <?php if (!$hasCharges) { ?>
1360 <input type='submit' name='bn_save_close' value='<?php echo xla('Mark as Billed');?>' />
1361 &nbsp;
1362 <?php } ?>
1363 <input type='submit' name='bn_refresh' value='<?php echo xla('Refresh');?>'>
1364 &nbsp;
1365 <?php } ?>
1367 <input type='hidden' name='form_checksum' value='<?php echo $current_checksum; ?>' />
1368 <input type='hidden' name='form_alertmsg' value='<?php echo attr($alertmsg); ?>' />
1370 <input type='button' value='<?php echo xla('Cancel');?>'
1371 onclick="top.restoreSession();location='<?php echo "$rootdir/patient_file/encounter/$returnurl" ?>'" />
1373 <?php if ($code_types['UCSMC']) { ?>
1374 <p style='font-family:sans-serif;font-size:8pt;color:#666666;'>
1375 &nbsp;<br>
1376 <?php echo xlt('UCSMC codes provided by the University of Calgary Sports Medicine Centre');?>
1377 </p>
1378 <?php } ?>
1380 </center>
1382 </form>
1383 <script language='JavaScript'>
1384 <?php
1385 echo $justinit;
1386 if ($alertmsg) {
1387 echo "alert('" . addslashes($alertmsg) . "');\n";
1390 </script>
1391 </body>
1392 </html>
1393 <?php require_once("review/initialize_review.php"); ?>