From 7317996c3449bb71bc3c9dc77e365d02d9eae9eb Mon Sep 17 00:00:00 2001
From: Rod Roark
Date: Thu, 4 Aug 2016 10:40:06 -0700
Subject: [PATCH] Bring in Fee Sheet improvements from recent IPPF work.
This refactors much of the Fee Sheet into a new pair of classes: FeeSheet to contain
the "business logic" and FeeSheetHtml which extends it and adds functions to facilitate
generation of HTML. Other improvements include:
o Line item price levels. A new column at the line item level that appears if you
have more than one price level to choose from.
o Button to Add More Items, which is a step towards supporting multiple checkouts
which will be in a following commit.
o Button to re-open the encounter.
o Improved logging.
o Some fixes related to translation.
o New feature with checkboxes instead of drop-lists for adding new items.
o Corresponding updates to drugs.inc.php and billing.inc that will be used later.
o Fixed failure of the review feature due to knockout library being moved.
---
interface/drugs/drugs.inc.php | 125 +-
.../fee_sheet/code_choice/css/code_choices.css | 64 +
.../code_choice/initialize_code_choice.php | 27 +
.../forms/fee_sheet/code_choice/js/view_model.js | 123 +
.../code_choice/templates/code_choices.php | 50 +
interface/forms/fee_sheet/new.php | 2691 ++++++++++----------
.../forms/fee_sheet/review/initialize_review.js | 8 +-
.../forms/fee_sheet/review/initialize_review.php | 5 +-
.../forms/fee_sheet/review/js/fee_sheet_core.js | 20 +-
library/FeeSheet.class.php | 1013 ++++++++
library/FeeSheetHtml.class.php | 365 +++
library/appointment_status.inc.php | 38 +
library/billing.inc | 189 +-
sql/4_2_2-to-4_3_1_upgrade.sql | 79 +-
sql/database.sql | 33 +-
version.php | 2 +-
16 files changed, 3374 insertions(+), 1458 deletions(-)
create mode 100644 interface/forms/fee_sheet/code_choice/css/code_choices.css
create mode 100644 interface/forms/fee_sheet/code_choice/initialize_code_choice.php
create mode 100644 interface/forms/fee_sheet/code_choice/js/view_model.js
create mode 100644 interface/forms/fee_sheet/code_choice/templates/code_choices.php
rewrite interface/forms/fee_sheet/new.php (65%)
create mode 100644 library/FeeSheet.class.php
create mode 100644 library/FeeSheetHtml.class.php
create mode 100644 library/appointment_status.inc.php
diff --git a/interface/drugs/drugs.inc.php b/interface/drugs/drugs.inc.php
index 225f08207..9dc33dbf1 100644
--- a/interface/drugs/drugs.inc.php
+++ b/interface/drugs/drugs.inc.php
@@ -1,5 +1,5 @@
+// Copyright (C) 2006-2015 Rod Roark
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -12,6 +12,11 @@
// These lists are based on the constants found in the
// openemr/library/classes/Prescription.class.php file.
+// Decision was made in June 2013 that a sale line item in the Fee Sheet may
+// come only from the specified warehouse. Set this to false if the decision
+// is reversed.
+$GLOBALS['SELL_FROM_ONE_WAREHOUSE'] = true;
+
$substitute_array = array('', xl('Allowed'), xl('Not Allowed'));
function send_drug_email($subject, $body) {
@@ -35,7 +40,8 @@ function send_drug_email($subject, $body) {
}
function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
- $prescription_id=0, $sale_date='', $user='', $default_warehouse='') {
+ $prescription_id=0, $sale_date='', $user='', $default_warehouse='',
+ $testonly=false, &$expiredlots=null, $pricelevel='', $selector='') {
if (empty($patient_id)) $patient_id = $GLOBALS['pid'];
if (empty($sale_date)) $sale_date = date('Y-m-d');
@@ -50,10 +56,22 @@ function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
}
// Get relevant options for this product.
- $rowdrug = sqlQuery("SELECT allow_combining, reorder_point, name " .
+ $rowdrug = sqlQuery("SELECT allow_combining, reorder_point, name, dispensable " .
"FROM drugs WHERE drug_id = ?", array($drug_id));
$allow_combining = $rowdrug['allow_combining'];
-
+ $dispensable = $rowdrug['dispensable'];
+
+ if (!$dispensable) {
+ // Non-dispensable is a much simpler case and does not touch inventory.
+ if ($testonly) return true;
+ $sale_id = sqlInsert("INSERT INTO drug_sales ( " .
+ "drug_id, inventory_id, prescription_id, pid, encounter, user, " .
+ "sale_date, quantity, fee ) VALUES ( " .
+ "?, 0, ?, ?, ?, ?, ?, ?, ?)",
+ array($drug_id, $prescription_id, $patient_id, $encounter_id, $user, $sale_date, $quantity, $fee));
+ return $sale_id;
+ }
+
// Combining is never allowed for prescriptions and will not work with
// dispense_drug.php.
if ($prescription_id) $allow_combining = 0;
@@ -63,6 +81,7 @@ function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
$qty_left = $quantity;
$bad_lot_list = '';
$total_on_hand = 0;
+ $gotexpired = false;
// If the user has a default warehouse, sort those lots first.
$orderby = ($default_warehouse === '') ?
@@ -70,21 +89,28 @@ function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
$orderby .= "lo.seq, di.expiration, di.lot_number, di.inventory_id";
// Retrieve lots in order of expiration date within warehouse preference.
- $res = sqlStatement("SELECT di.*, lo.option_id, lo.seq " .
+ $query = "SELECT di.*, lo.option_id, lo.seq " .
"FROM drug_inventory AS di " .
"LEFT JOIN list_options AS lo ON lo.list_id = 'warehouse' AND " .
"lo.option_id = di.warehouse_id " .
"WHERE " .
- "di.drug_id = ? AND di.destroy_date IS NULL " .
- "ORDER BY $orderby", array($drug_id));
+ "di.drug_id = ? AND di.destroy_date IS NULL ";
+ $sqlarr = array($drug_id);
+ if ($GLOBALS['SELL_FROM_ONE_WAREHOUSE'] && $default_warehouse) {
+ $query .= "AND di.warehouse_id = ? ";
+ $sqlarr[] = $default_warehouse;
+ }
+ $query .= "ORDER BY $orderby";
+ $res = sqlStatement($query, $sqlarr);
// First pass. Pick out lots to be used in filling this order, figure out
// if there is enough quantity on hand and check for lots to be destroyed.
while ($row = sqlFetchArray($res)) {
- // Warehouses with seq > 99 are not available.
- $seq = empty($row['seq']) ? 0 : $row['seq'] + 0;
- if ($seq > 99) continue;
-
+ if ($row['warehouse_id'] != $default_warehouse) {
+ // Warehouses with seq > 99 are not available.
+ $seq = empty($row['seq']) ? 0 : $row['seq'] + 0;
+ if ($seq > 99) continue;
+ }
$on_hand = $row['on_hand'];
$expired = (!empty($row['expiration']) && $row['expiration'] <= $sale_date);
if ($expired || $on_hand < $quantity) {
@@ -93,7 +119,10 @@ function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
if ($bad_lot_list) $bad_lot_list .= ', ';
$bad_lot_list .= $tmp;
}
- if ($expired) continue;
+ if ($expired) {
+ $gotexpired = true;
+ continue;
+ }
/*****************************************************************
// Note the first row in case total quantity is insufficient and we are
@@ -109,6 +138,14 @@ function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
}
}
+ if ($expiredlots !== null) $expiredlots = $gotexpired;
+
+ if ($testonly) {
+ // Just testing inventory, so return true if OK, false if insufficient.
+ // $qty_left, if positive, is the amount requested that could not be allocated.
+ return $qty_left <= 0;
+ }
+
if ($bad_lot_list) {
send_drug_email("Possible lot destruction needed",
"The following lot(s) are expired or were too small to fill the " .
@@ -165,19 +202,75 @@ function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
"on_hand = on_hand - ? " .
"WHERE inventory_id = ?", array($thisqty,$inventory_id));
$sale_id = sqlInsert("INSERT INTO drug_sales ( " .
- "drug_id, inventory_id, prescription_id, pid, encounter, user, sale_date, quantity, fee ) " .
- "VALUES (?,?,?,?,?,?,?,?,?)", array($drug_id,$inventory_id,$prescription_id,$patient_id,$encounter_id,$user,$sale_date,$thisqty,$thisfee));
+ "drug_id, inventory_id, prescription_id, pid, encounter, user, sale_date, quantity, fee, pricelevel, selector ) " .
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ array($drug_id, $inventory_id, $prescription_id, $patient_id, $encounter_id, $user,
+ $sale_date, $thisqty, $thisfee, $pricelevel, $selector));
+
+ // If this sale exhausted the lot then auto-destroy it if that is wanted.
+ if ($row['on_hand'] == $thisqty && !empty($GLOBALS['gbl_auto_destroy_lots'])) {
+ sqlStatement("UPDATE drug_inventory SET " .
+ "destroy_date = ?, destroy_method = ?, destroy_witness = ?, destroy_notes = ? " .
+ "WHERE drug_id = ? AND inventory_id = ?",
+ array($sale_date, xl('Automatic from sale'), $user, "sale_id = $sale_id",
+ $drug_id, $inventory_id));
+ }
}
+ /*******************************************************************
// If appropriate, generate email to notify that re-order is due.
if (($total_on_hand - $quantity) <= $rowdrug['reorder_point']) {
send_drug_email("Product re-order required",
"Product '" . $rowdrug['name'] . "' has reached its reorder point.\n");
}
-
+ // TBD: If the above is un-commented, fix it to handle the case of
+ // $GLOBALS['gbl_min_max_months'] being true.
+ *******************************************************************/
+
// If combining is allowed then $sale_id will be just the last inserted ID,
// and it serves only to indicate that everything worked. Otherwise there
// can be only one inserted row and this is its ID.
return $sale_id;
}
-?>
+
+// Determine if facility and warehouse restrictions are applicable for this user.
+function isUserRestricted($userid=0) {
+ if (!$userid) $userid = $_SESSION['authId'];
+ $countrow = sqlQuery("SELECT count(*) AS count FROM users_facility WHERE " .
+ "tablename = 'users' AND table_id = ?", array($userid));
+ return !empty($countrow['count']);
+}
+
+// Check if the user has access to the given facility.
+// Do not call this if user is not restricted!
+function isFacilityAllowed($facid, $userid=0) {
+ if (!$userid) $userid = $_SESSION['authId'];
+ $countrow = sqlQuery("SELECT count(*) AS count FROM users_facility WHERE " .
+ "tablename = 'users' AND table_id = ? AND facility_id = ?",
+ array($userid, $facid));
+ if (empty($countrow['count'])) {
+ $countrow = sqlQuery("SELECT count(*) AS count FROM users WHERE " .
+ "id = ? AND facility_id = ?",
+ array($userid, $facid));
+ return !empty($countrow['count']);
+ }
+ return true;
+}
+
+// Check if the user has access to the given warehouse within the given facility.
+// Do not call this if user is not restricted!
+function isWarehouseAllowed($facid, $whid, $userid=0) {
+ if (!$userid) $userid = $_SESSION['authId'];
+ $countrow = sqlQuery("SELECT count(*) AS count FROM users_facility WHERE " .
+ "tablename = 'users' AND table_id = ? AND facility_id = ? AND " .
+ "(warehouse_id = ? OR warehouse_id = '')",
+ array($userid, $facid, $whid));
+ if (empty($countrow['count'])) {
+ $countrow = sqlQuery("SELECT count(*) AS count FROM users WHERE " .
+ "id = ? AND default_warehouse = ?",
+ array($userid, $whid));
+ return !empty($countrow['count']);
+ }
+ return true;
+}
+?>
\ No newline at end of file
diff --git a/interface/forms/fee_sheet/code_choice/css/code_choices.css b/interface/forms/fee_sheet/code_choice/css/code_choices.css
new file mode 100644
index 000000000..6c4616a99
--- /dev/null
+++ b/interface/forms/fee_sheet/code_choice/css/code_choices.css
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2014 Kevin Yeh and OEMR
+ *
+ * LICENSE: This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see ;.
+ *
+ * @package OpenEMR
+ * @author Kevin Yeh
+ * @link http://www.open-emr.org
+ */
+
+div.code-choices
+{
+ font-size: 10pt;
+ position:relative;
+ z-index: 0;
+}
+div.category-display
+{
+ float:left;
+ width: 33%;
+ cursor: pointer;
+}
+
+div.category-display > button
+{
+ width: 25em;
+ font-weight: bold;
+ text-align: left;
+}
+
+div.category-display > button:hover
+{
+ color: blue;
+}
+.active-category
+{
+ position: absolute;
+ z-index: 10;
+ background-color: white;
+ width: 99%;
+ border: 1px black solid;
+ padding: 4pt;
+}
+
+div.code-choice
+{
+ float:left;
+ width: 33%;
+ cursor: pointer;
+ text-align: left;
+}
+
+div.code-choice:hover{
+ background-color: yellow;
+}
\ No newline at end of file
diff --git a/interface/forms/fee_sheet/code_choice/initialize_code_choice.php b/interface/forms/fee_sheet/code_choice/initialize_code_choice.php
new file mode 100644
index 000000000..d52dbe5d0
--- /dev/null
+++ b/interface/forms/fee_sheet/code_choice/initialize_code_choice.php
@@ -0,0 +1,27 @@
+ and OEMR
+ *
+ * LICENSE: This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see ;.
+ *
+ * @package OpenEMR
+ * @author Kevin Yeh
+ * @link http://www.open-emr.org
+ */
+
+require_once("templates/code_choices.php");
+?>
+
+
+
+
+
diff --git a/interface/forms/fee_sheet/code_choice/js/view_model.js b/interface/forms/fee_sheet/code_choice/js/view_model.js
new file mode 100644
index 000000000..b52d4586d
--- /dev/null
+++ b/interface/forms/fee_sheet/code_choice/js/view_model.js
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) 2014 Kevin Yeh and OEMR
+ *
+ * LICENSE: This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see ;.
+ *
+ * @package OpenEMR
+ * @author Kevin Yeh
+ * @link http://www.open-emr.org
+ */
+
+function toggle_code(data,event)
+{
+ data.selected(!data.selected());
+}
+
+function codes_ok(data,event)
+{
+ codes_choices_vm.show_choices(false);
+ var f = document.forms[0];
+ var choices=codes_choices_vm.active_category().codes();
+ for (var i = 0; i < choices.length; ++i) {
+ if (choices[i].selected()) {
+ if (f.newcodes.value) f.newcodes.value += '~';
+ f.newcodes.value += choices[i].value();
+ choices[i].selected(false);
+ }
+ }
+ if (f.newcodes.value) {
+ // top.restoreSession();
+ // f.submit();
+ // This supports the option to immediately save:
+ codeselect(null);
+ }
+ return false;
+}
+
+function codes_cancel(data,event)
+{
+ codes_choices_vm.show_choices(false);
+ return false;
+}
+
+//Events
+function set_active_category(data,event)
+{
+ codes_choices_vm.active_category(data);
+ codes_choices_vm.show_choices(true);
+}
+
+//End Events
+var codes_choices_vm={
+ categories : ko.observableArray(),
+ active_category:ko.observable(false),
+ show_choices: ko.observable(false)
+};
+
+function code_category(title)
+{
+ var self=this;
+ this.title=ko.observable(title);
+ this.codes=ko.observableArray();
+ return this;
+}
+
+function code_choice(description,value)
+{
+ var self=this;
+ this.description=ko.observable(description);
+ this.value=ko.observable(value);
+ this.selected=ko.observable(false);
+ return this;
+}
+
+function populate_vm_categories(idx,elem)
+{
+ var jqElem=$(elem);
+ jqElem.hide();
+ jqElem.parent().parent().hide(); // select is child of a td and a tr.
+ var title=jqElem.find("option[value='']").text();
+
+ var category=new code_category(title);
+ codes_choices_vm.categories().push(category);
+
+ var choices=jqElem.find("option:not([value=''])");
+ choices.each(function(idx,elem)
+ {
+ var jqChoice=$(elem);
+ var description=jqChoice.text();
+ var value=jqChoice.attr("value");
+ var choice=new code_choice(description,value);
+ category.codes().push(choice);
+ }
+ );
+}
+
+function analyze_codes()
+{
+ var code_table=$("table[width='95%']");
+ var categories=code_table.find("td[width='50%'] > select");
+ categories.each(populate_vm_categories);
+ add_code_template(code_table);
+}
+
+function add_code_template(elem)
+{
+ var template=$("");
+ template.attr("data-bind","template: {name: 'code-choice-options'}");
+ template.addClass("code-choices");
+ elem.before(template);
+ ko.applyBindings(codes_choices_vm,template.get(0));
+ codes_choices_vm.active_category(codes_choices_vm.categories()[1]);
+}
+
+analyze_codes();
diff --git a/interface/forms/fee_sheet/code_choice/templates/code_choices.php b/interface/forms/fee_sheet/code_choice/templates/code_choices.php
new file mode 100644
index 000000000..a41ccdb92
--- /dev/null
+++ b/interface/forms/fee_sheet/code_choice/templates/code_choices.php
@@ -0,0 +1,50 @@
+ and OEMR
+ *
+ * LICENSE: This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see ;.
+ *
+ * @package OpenEMR
+ * @author Kevin Yeh
+ * @link http://www.open-emr.org
+ */
+?>
+
+
+
diff --git a/interface/forms/fee_sheet/new.php b/interface/forms/fee_sheet/new.php
dissimilarity index 65%
index a7dbf5975..0ed9306d5 100644
--- a/interface/forms/fee_sheet/new.php
+++ b/interface/forms/fee_sheet/new.php
@@ -1,1407 +1,1284 @@
-
-*
-* LICENSE: This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 3
-* of the License, or (at your option) any later version.
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see ;.
-*
-* @package OpenEMR
-* @author Rod Roark
-* @author Terry Hill
-* @link http://www.open-emr.org
-*/
-
-$fake_register_globals=false;
-$sanitize_all_escapes=true;
-
-require_once("../../globals.php");
-require_once("$srcdir/acl.inc");
-require_once("$srcdir/api.inc");
-require_once("codes.php");
-require_once("../../../custom/code_types.inc.php");
-require_once("../../drugs/drugs.inc.php");
-require_once("$srcdir/formatting.inc.php");
-require_once("$srcdir/options.inc.php");
-require_once("$srcdir/formdata.inc.php");
-require_once("$srcdir/log.inc");
-
-// For logging checksums set this to true.
-define('CHECKSUM_LOGGING', true);
-
-// Some table cells will not be displayed unless insurance billing is used.
-$usbillstyle = $GLOBALS['ippf_specific'] ? " style='display:none'" : "";
-
-// This may be an error message or warning that pops up when the form is loaded.
-$alertmsg = '';
-
-function alphaCodeType($id) {
- global $code_types;
- foreach ($code_types as $key => $value) {
- if ($value['id'] == $id) return $key;
- }
- return '';
-}
-
-// Helper function for creating drop-lists.
-function endFSCategory() {
- global $i, $last_category, $FEE_SHEET_COLUMNS;
- if (! $last_category) return;
- echo " \n";
- echo " \n";
- if ($i >= $FEE_SHEET_COLUMNS) {
- echo " \n";
- $i = 0;
- }
-}
-
-// Generate JavaScript to build the array of diagnoses.
-function genDiagJS($code_type, $code) {
- global $code_types;
- if ($code_types[$code_type]['diag']) {
- echo "diags.push('" . attr($code_type) . "|" . attr($code) . "');\n";
- }
-}
-
-// For IPPF only. Returns 0 = none, 1 = nonsurgical, 2 = surgical.
-//
-function contraceptionClass($code_type, $code) {
- global $code_types;
- if (!$GLOBALS['ippf_specific']) return 0;
- $contra = 0;
- // Get the related service codes.
- $codesrow = sqlQuery("SELECT related_code FROM codes WHERE " .
- "code_type = ? " .
- " AND code = ? LIMIT 1", array($code_types[$code_type]['id'],$code) );
- if (!empty($codesrow['related_code']) && $code_type == 'MA') {
- $relcodes = explode(';', $codesrow['related_code']);
- foreach ($relcodes as $relstring) {
- if ($relstring === '') continue;
- list($reltype, $relcode) = explode(':', $relstring);
- if ($reltype !== 'IPPF') continue;
- if (preg_match('/^11....110/' , $relcode)) $contra |= 1;
- else if (preg_match('/^11....999/' , $relcode)) $contra |= 1;
- else if (preg_match('/^112152010/' , $relcode)) $contra |= 1;
- else if (preg_match('/^11317[1-2]111/', $relcode)) $contra |= 1;
- else if (preg_match('/^12118[1-2].13/', $relcode)) $contra |= 2;
- else if (preg_match('/^12118[1-2]999/', $relcode)) $contra |= 2;
- }
- }
- return $contra;
-}
-# gets the provider from the encounter file , or from the logged on user or from the patient file
-function findProvider() {
- global $encounter, $pid;
- $find_provider = sqlQuery("SELECT provider_id FROM form_encounter " .
- "WHERE pid = ? AND encounter = ? " .
- "ORDER BY id DESC LIMIT 1", array($pid,$encounter) );
- $providerid = $find_provider['provider_id'];
- if($providerid == 0) {
- $get_authorized = $_SESSION['userauthorized'];
- if($get_authorized ==1) {
- $providerid = $_SESSION[authUserID];
- }
- }
- if($providerid == 0) {
- $find_provider = sqlQuery("SELECT providerID FROM patient_data " .
- "WHERE pid = ? ", array($pid) );
- $providerid = $find_provider['providerID'];
- }
- return $providerid;
-}
-
-// This writes a billing line item to the output page.
-//
-function echoLine($lino, $codetype, $code, $modifier, $ndc_info='',
- $auth = TRUE, $del = FALSE, $units = NULL, $fee = NULL, $id = NULL,
- $billed = FALSE, $code_text = NULL, $justify = NULL, $provider_id = 0, $notecodes='')
-{
- global $code_types, $ndc_applies, $ndc_uom_choices, $justinit, $pid;
- global $contraception, $usbillstyle, $hasCharges;
-
- // If using line item billing and user wishes to default to a selected provider, then do so.
- if($GLOBALS['default_fee_sheet_line_item_provider'] == 1 && $GLOBALS['support_fee_sheet_line_item_provider'] ==1 ) {
- if ($provider_id == 0) {
- $provider_id = 0 + findProvider();
- }
- }
-
- if ($codetype == 'COPAY') {
- if (!$code_text) $code_text = 'Cash';
- if ($fee > 0) $fee = 0 - $fee;
- }
- if (! $code_text) {
- $sqlArray = array();
- $query = "select id, units, code_text from codes where code_type = ? " .
- " and " .
- "code = ? and ";
- array_push($sqlArray,$code_types[$codetype]['id'],$code);
- if ($modifier) {
- $query .= "modifier = ?";
- array_push($sqlArray,$modifier);
- } else {
- $query .= "(modifier is null or modifier = '')";
- }
- $result = sqlQuery($query, $sqlArray);
- $code_text = $result['code_text'];
- if (empty($units)) $units = max(1, intval($result['units']));
- if (!isset($fee)) {
- // Fees come from the prices table now.
- $query = "SELECT prices.pr_price " .
- "FROM patient_data, prices WHERE " .
- "patient_data.pid = ? AND " .
- "prices.pr_id = ? AND " .
- "prices.pr_selector = '' AND " .
- "prices.pr_level = patient_data.pricelevel " .
- "LIMIT 1";
- echo "\n\n"; // debugging
- $prrow = sqlQuery($query, array($pid,$result['id']) );
- $fee = empty($prrow) ? 0 : $prrow['pr_price'];
- }
- }
- $fee = sprintf('%01.2f', $fee);
- if (empty($units)) $units = 1;
- $units = max(1, intval($units));
- // We put unit price on the screen, not the total line item fee.
- $price = $fee / $units;
- $strike1 = ($id && $del) ? "" : "";
- $strike2 = ($id && $del) ? "" : "";
- echo "
\n";
- echo "
$strike1" .
- ($codetype == 'COPAY' ? xl($codetype) : $codetype) . $strike2;
- //if the line to ouput is copay, show the date here passed as $ndc_info,
- //since this variable is not applicable in the case of copay.
- if($codetype == 'COPAY'){
- echo "(".htmlspecialchars($ndc_info).")";
- $ndc_info = '';
- }
- if ($id) {
- echo "";
- }
- echo "";
- echo "";
- echo "";
- echo "
\n";
- if ($codetype != 'COPAY') {
- echo "
$strike1" . text($code) . "$strike2
\n";
- } else {
- echo "
\n";
- }
- if ($billed) {
- if (modifiers_are_used(true)) {
- echo "
\n";
- }
- if ($billed) {
- if (fees_are_used()) {
- echo "
" . text(oeFormatMoney($price)) . "
\n";
- echo "
" . text($units) . "
\n";
- }
- if (justifiers_are_used()) {
- echo "
\n"; // justify
- }
- echo "
\n"; // provider
- echo "
\n"; // note codes
- echo "
\n"; // auth
- echo "
\n";
- } else {
- if (fees_are_used()) {
- echo "
" .
- "
\n";
- echo "
";
- echo "";
- echo "
\n";
- }
- if (justifiers_are_used()) {
- echo "
\n"; // justify
- }
- echo "
\n"; // provider
- echo "
\n"; // note codes
- echo "
\n"; // auth
- echo "
\n";
- }
-
- echo "
$strike1" . text($code_text) . "$strike2
\n";
- echo "
\n";
-
- if ($fee != 0) $hasCharges = true;
-}
-
-// Build a drop-down list of providers. This includes users who
-// have the word "provider" anywhere in their "additional info"
-// field, so that we can define providers (for billing purposes)
-// who do not appear in the calendar.
-//
-function genProviderSelect($selname, $toptext, $default=0, $disabled=false) {
- $query = "SELECT id, lname, fname FROM users WHERE " .
- "( authorized = 1 OR info LIKE '%provider%' ) AND username != '' " .
- "AND active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
- "ORDER BY lname, fname";
- $res = sqlStatement($query);
- echo " \n";
-}
-
-// Compute a current checksum of Fee Sheet data from the database.
-//
-function visitChecksum($pid, $encounter, $saved=false) {
- $rowb = sqlQuery("SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
- "id, code, modifier, units, fee, authorized, provider_id, ndc_info, justify, billed" .
- "))) AS checksum FROM billing WHERE " .
- "pid = ? AND encounter = ? AND activity = 1",
- array($pid, $encounter));
- $rowp = sqlQuery("SELECT BIT_XOR(CRC32(CONCAT_WS(',', " .
- "sale_id, inventory_id, prescription_id, quantity, fee, sale_date, billed" .
- "))) AS checksum FROM drug_sales WHERE " .
- "pid = ? AND encounter = ?",
- array($pid, $encounter));
- $ret = intval($rowb['checksum']) ^ intval($rowp['checksum']);
- if (CHECKSUM_LOGGING) {
- $comment = "Checksum = '$ret'";
- $comment .= ", AJAX = " . (empty($_POST['running_as_ajax']) ? "false" : "true");
- $comment .= ", Save = " . (empty($_POST['bn_save']) ? "false" : "true");
- $comment .= ", Saved = " . ($saved ? "true" : "false");
- newEvent("checksum", $_SESSION['authUser'], $_SESSION['authProvider'], 1, $comment, $pid);
- }
- return $ret;
-}
-
-// This is just for IPPF, to indicate if the visit includes contraceptive services.
-$contraception = 0;
-
-// Possible units of measure for NDC drug quantities.
-//
-$ndc_uom_choices = array(
- 'ML' => 'ML',
- 'GR' => 'Grams',
- 'ME' => 'Milligrams',
- 'F2' => 'I.U.',
- 'UN' => 'Units'
-);
-
-// $FEE_SHEET_COLUMNS should be defined in codes.php.
-if (empty($FEE_SHEET_COLUMNS)) $FEE_SHEET_COLUMNS = 2;
-
-$returnurl = $GLOBALS['concurrent_layout'] ? 'encounter_top.php' : 'patient_encounter.php';
-
-// Update price level in patient demographics.
-if (!empty($_POST['pricelevel'])) {
- sqlStatement("UPDATE patient_data SET pricelevel = ? WHERE pid = ?", array($_POST['pricelevel'],$pid) );
-}
-
-// Get some info about this visit.
-$visit_row = sqlQuery("SELECT fe.date, opc.pc_catname " .
- "FROM form_encounter AS fe " .
- "LEFT JOIN openemr_postcalendar_categories AS opc ON opc.pc_catid = fe.pc_catid " .
- "WHERE fe.pid = ? AND fe.encounter = ? LIMIT 1", array($pid,$encounter) );
-$visit_date = substr($visit_row['date'], 0, 10);
-
-$current_checksum = visitChecksum($pid, $encounter);
-// It's important to look for a checksum mismatch even if we're just refreshing
-// the display, otherwise the error goes undetected on a refresh-then-save.
-if (isset($_POST['form_checksum'])) {
- if ($_POST['form_checksum'] != $current_checksum) {
- $alertmsg = xl('Someone else has just changed this visit. Please cancel this page and try again.');
- if (CHECKSUM_LOGGING) {
- $comment = "CHECKSUM ERROR, expecting '{$_POST['form_checksum']}'";
- newEvent("checksum", $_SESSION['authUser'], $_SESSION['authProvider'], 1, $comment, $pid);
- }
- }
-}
-
-// If Save or Save-and-Close was clicked, save the new and modified billing
-// lines; then if no error, redirect to $returnurl.
-//
-if (!$alertmsg && ($_POST['bn_save'] || $_POST['bn_save_close'])) {
- $main_provid = 0 + $_POST['ProviderID'];
- $main_supid = 0 + $_POST['SupervisorID'];
- if ($main_supid == $main_provid) $main_supid = 0;
- $default_warehouse = $_POST['default_warehouse'];
-
- $bill = $_POST['bill'];
- $copay_update = FALSE;
- $update_session_id = '';
- $ct0 = '';//takes the code type of the first fee type code type entry from the fee sheet, against which the copay is posted
- $cod0 = '';//takes the code of the first fee type code type entry from the fee sheet, against which the copay is posted
- $mod0 = '';//takes the modifier of the first fee type code type entry from the fee sheet, against which the copay is posted
- for ($lino = 1; $bill["$lino"]['code_type']; ++$lino) {
- $iter = $bill["$lino"];
- $code_type = $iter['code_type'];
- $code = $iter['code'];
- $del = $iter['del'];
-
- // Skip disabled (billed) line items.
- if ($iter['billed']) continue;
-
- $id = $iter['id'];
- $modifier = trim($iter['mod']);
- if( !($cod0) && ($code_types[$code_type]['fee'] == 1) ){
- $mod0 = $modifier;
- $cod0 = $code;
- $ct0 = $code_type;
- }
- $units = max(1, intval(trim($iter['units'])));
- $fee = sprintf('%01.2f',(0 + trim($iter['price'])) * $units);
-
- if($code_type == 'COPAY'){
- if($id == ''){
- //adding new copay from fee sheet into ar_session and ar_activity tables
- if($fee < 0){
- $fee = $fee * -1;
- }
- $session_id = idSqlStatement("INSERT INTO ar_session(payer_id,user_id,pay_total,payment_type,description,".
- "patient_id,payment_method,adjustment_code,post_to_date) VALUES('0',?,?,'patient','COPAY',?,'','patient_payment',now())",
- array($_SESSION['authId'],$fee,$pid));
-
- sqlBeginTrans();
- $sequence_no = sqlQuery( "SELECT IFNULL(MAX(sequence_no),0) + 1 AS increment FROM ar_activity WHERE pid = ? AND encounter = ?", array($pid, $encounter));
- SqlStatement("INSERT INTO ar_activity (pid,encounter,sequence_no,code_type,code,modifier,payer_type,post_time,post_user,session_id,".
- "pay_amount,account_code) VALUES (?,?,?,?,?,?,0,now(),?,?,?,'PCP')",
- array($pid,$encounter,$sequence_no['increment'],$ct0,$cod0,$mod0,$_SESSION['authId'],$session_id,$fee));
- sqlCommitTrans();
- }else{
- //editing copay saved to ar_session and ar_activity
- if($fee < 0){
- $fee = $fee * -1;
- }
- $session_id = $id;
- $res_amount = sqlQuery("SELECT pay_amount FROM ar_activity WHERE pid=? AND encounter=? AND session_id=?",
- array($pid,$encounter,$session_id));
- if($fee != $res_amount['pay_amount']){
- sqlStatement("UPDATE ar_session SET user_id=?,pay_total=?,modified_time=now(),post_to_date=now() WHERE session_id=?",
- array($_SESSION['authId'],$fee,$session_id));
- sqlStatement("UPDATE ar_activity SET code_type=?, code=?, modifier=?, post_user=?, post_time=now(),".
- "pay_amount=?, modified_time=now() WHERE pid=? AND encounter=? AND account_code='PCP' AND session_id=?",
- array($ct0,$cod0,$mod0,$_SESSION['authId'],$fee,$pid,$encounter,$session_id));
- }
- }
- if(!$cod0){
- $copay_update = TRUE;
- $update_session_id = $session_id;
- }
- continue;
- }
- $justify = trim($iter['justify']);
- # Code to create justification for all codes based on first justification
- if ($GLOBALS['replicate_justification']=='1' ) {
- if ($justify !='') {
- $autojustify = $justify;
- }
- }
- if ( ($GLOBALS['replicate_justification']=='1') && ($justify == '') && check_is_code_type_justify($code_type) ) {
- $justify = $autojustify;
- }
-
- $notecodes = trim($iter['notecodes']);
- if ($justify) $justify = str_replace(',', ':', $justify) . ':';
- // $auth = $iter['auth'] ? "1" : "0";
- $auth = "1";
- $provid = 0 + $iter['provid'];
-
- $ndc_info = '';
- if ($iter['ndcnum']) {
- $ndc_info = 'N4' . trim($iter['ndcnum']) . ' ' . $iter['ndcuom'] .
- trim($iter['ndcqty']);
- }
-
- // If the item is already in the database...
- if ($id) {
- if ($del) {
- deleteBilling($id);
- }
- else {
- // authorizeBilling($id, $auth);
- sqlQuery("UPDATE billing SET code = ?, " .
- "units = ?, fee = ?, modifier = ?, " .
- "authorized = ?, provider_id = ?, " .
- "ndc_info = ?, justify = ?, notecodes = ? " .
- "WHERE " .
- "id = ? AND billed = 0 AND activity = 1", array($code,$units,$fee,$modifier,$auth,$provid,$ndc_info,$justify,$notecodes,$id) );
- }
- }
-
- // Otherwise it's a new item...
- else if (! $del) {
- $code_text = lookup_code_descriptions($code_type.":".$code);
- addBilling($encounter, $code_type, $code, $code_text, $pid, $auth,
- $provid, $modifier, $units, $fee, $ndc_info, $justify, 0, $notecodes);
- }
- } // end for
-
- //if modifier is not inserted during loop update the record using the first
- //non-empty modifier and code
- if($copay_update == TRUE && $update_session_id != '' && $mod0 != ''){
- sqlStatement("UPDATE ar_activity SET code_type=?, code=?, modifier=?".
- " WHERE pid=? AND encounter=? AND account_code='PCP' AND session_id=?",
- array($ct0,$cod0,$mod0,$pid,$encounter,$update_session_id));
- }
-
- // Doing similarly to the above but for products.
- $prod = $_POST['prod'];
- for ($lino = 1; $prod["$lino"]['drug_id']; ++$lino) {
- $iter = $prod["$lino"];
-
- if (!empty($iter['billed'])) continue;
-
- $drug_id = $iter['drug_id'];
- $sale_id = $iter['sale_id']; // present only if already saved
- $units = max(1, intval(trim($iter['units'])));
- $fee = sprintf('%01.2f',(0 + trim($iter['price'])) * $units);
- $del = $iter['del'];
-
- // If the item is already in the database...
- if ($sale_id) {
- if ($del) {
- // Zero out this sale and reverse its inventory update. We bring in
- // drug_sales twice so that the original quantity can be referenced
- // unambiguously.
- sqlStatement("UPDATE drug_sales AS dsr, drug_sales AS ds, " .
- "drug_inventory AS di " .
- "SET di.on_hand = di.on_hand + dsr.quantity, " .
- "ds.quantity = 0, ds.fee = 0 WHERE " .
- "dsr.sale_id = ? AND ds.sale_id = dsr.sale_id AND " .
- "di.inventory_id = ds.inventory_id", array($sale_id) );
- // And delete the sale for good measure.
- sqlStatement("DELETE FROM drug_sales WHERE sale_id = ?", array($sale_id) );
- }
- else {
- // Modify the sale and adjust inventory accordingly.
- $query = "UPDATE drug_sales AS dsr, drug_sales AS ds, " .
- "drug_inventory AS di " .
- "SET di.on_hand = di.on_hand + dsr.quantity - " . add_escape_custom($units) . ", " .
- "ds.quantity = ?, ds.fee = ?, " .
- "ds.sale_date = ? WHERE " .
- "dsr.sale_id = ? AND ds.sale_id = dsr.sale_id AND " .
- "di.inventory_id = ds.inventory_id";
- sqlStatement($query, array($units,$fee,$visit_date,$sale_id) );
- }
- }
-
- // Otherwise it's a new item...
- else if (! $del) {
- $sale_id = sellDrug($drug_id, $units, $fee, $pid, $encounter, 0,
- $visit_date, '', $default_warehouse);
- if (!$sale_id) die(xlt("Insufficient inventory for product ID") . " \"" . text($drug_id) . "\".");
- }
- } // end for
-
- // Set the main/default service provider in the new-encounter form.
- /*******************************************************************
- sqlStatement("UPDATE forms, users SET forms.user = users.username WHERE " .
- "forms.pid = '$pid' AND forms.encounter = '$encounter' AND " .
- "forms.formdir = 'newpatient' AND users.id = '$provid'");
- *******************************************************************/
- sqlStatement("UPDATE form_encounter SET provider_id = ?, " .
- "supervisor_id = ? WHERE " .
- "pid = ? AND encounter = ?", array($main_provid,$main_supid,$pid,$encounter) );
-
- // Save-and-Close is currently IPPF-specific but might be more generally
- // useful. It provides the ability to mark an encounter as billed
- // directly from the Fee Sheet, if there are no charges.
- if ($_POST['bn_save_close']) {
- $tmp1 = sqlQuery("SELECT SUM(ABS(fee)) AS sum FROM drug_sales WHERE " .
- "pid = ? AND encounter = ?", array($pid,$encounter) );
- $tmp2 = sqlQuery("SELECT SUM(ABS(fee)) AS sum FROM billing WHERE " .
- "pid = ? AND encounter = ? AND billed = 0 AND " .
- "activity = 1", array($pid,$encounter) );
- if ($tmp1['sum'] + $tmp2['sum'] == 0) {
- sqlStatement("update drug_sales SET billed = 1 WHERE " .
- "pid = ? AND encounter = ? AND billed = 0", array($pid,$encounter));
- sqlStatement("UPDATE billing SET billed = 1, bill_date = NOW() WHERE " .
- "pid = ? AND encounter = ? AND billed = 0 AND " .
- "activity = 1", array($pid,$encounter));
- }
- else {
- // Would be good to display an error message here... they clicked
- // Save and Close but the close could not be done. However the
- // framework does not provide an easy way to do that.
- }
- }
-
- // More IPPF stuff.
- if (!empty($_POST['contrastart'])) {
- $contrastart = $_POST['contrastart'];
- sqlStatement("UPDATE patient_data SET contrastart = ?" .
- " WHERE pid = ?", array($contrastart,$pid) );
- }
-
- // Note: Taxes are computed at checkout time (in pos_checkout.php which
- // also posts to SL). Currently taxes with insurance claims make no sense,
- // so for now we'll ignore tax computation in the insurance billing logic.
-
- if ($_POST['running_as_ajax']) {
- // In the case of running as an AJAX handler, we need to return this same
- // form with an updated checksum to properly support the invoking logic.
- // See review/js/fee_sheet_core.js for that logic.
- $current_checksum = visitChecksum($pid, $encounter, true);
- // Also remove form data for the newly entered lines so they are not
- // duplicated from the database.
- unset($_POST['bill']);
- unset($_POST['prod']);
- }
- else {
- formHeader("Redirecting....");
- formJump();
- formFooter();
- exit;
- }
-}
-
-$billresult = getBillingByEncounter($pid, $encounter, "*");
-?>
-
-
-
-
-
-
-
-
-
-
\n";
-}
-else { // the encounter is not yet billed
-?>
-
-
-
-
- 0");
-if ($trow['count'] && $contraception && !$isBilled) {
- $date1 = substr($visit_row['date'], 0, 10);
- // If admission or surgical, then force contrastart.
- if ($contraception > 1 ||
- strpos(strtolower($visit_row['pc_catname']), 'admission') !== false)
- {
- echo " \n";
- }
- else {
- // echo "\n"; // debugging
- $trow = sqlQuery("SELECT contrastart " .
- "FROM patient_data WHERE " .
- "pid = ? LIMIT 1", array($pid) );
- if (empty($trow['contrastart']) || substr($trow['contrastart'], 0, 4) == '0000') {
- $date0 = date('Y-m-d', strtotime($date1) - (60 * 60 * 24));
- echo " \n";
- echo " \n";
- echo " \n";
- echo " \n";
- echo " \n";
- echo " \n";
- }
- }
-}
-
-// If there is a choice of warehouses, allow override of user default.
-if ($prod_lino > 0) { // if any products are in this form
- $trow = sqlQuery("SELECT count(*) AS count FROM list_options WHERE list_id = 'warehouse'");
- if ($trow['count'] > 1) {
- $trow = sqlQuery("SELECT default_warehouse FROM users WHERE username = ?", array($_SESSION['authUser']) );
- echo " " . xlt('Warehouse') . ":\n";
- echo generate_select_list('default_warehouse', 'warehouse',
- $trow['default_warehouse'], '');
- echo " \n";
- }
-}
-
-// Allow the patient price level to be fixed here.
-$plres = sqlStatement("SELECT option_id, title FROM list_options " .
- "WHERE list_id = 'pricelevel' ORDER BY seq");
-if (true) {
- $trow = sqlQuery("SELECT pricelevel FROM patient_data WHERE " .
- "pid = ? LIMIT 1", array($pid) );
- $pricelevel = $trow['pricelevel'];
- echo " " . xlt('Price Level') . ":\n";
- echo " \n";
- while ($plrow = sqlFetchArray($plres)) {
- $key = $plrow['option_id'];
- $val = $plrow['title'];
- echo " \n";
- }
- echo " \n";
-}
-?>
-
-
-
-
-' />
-
-
-' />
-
-
-'>
-
-
-
-
-
-
-'
- onclick="top.restoreSession();location=''" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+*
+* LICENSE: This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 3
+* of the License, or (at your option) any later version.
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see ;.
+*
+* @package OpenEMR
+* @author Rod Roark
+* @author Terry Hill
+* @link http://www.open-emr.org
+*/
+
+$fake_register_globals = false;
+$sanitize_all_escapes = true;
+
+require_once("../../globals.php");
+require_once("$srcdir/FeeSheetHtml.class.php");
+require_once("codes.php");
+
+// Some table cells will not be displayed unless insurance billing is used.
+$usbillstyle = $GLOBALS['ippf_specific'] ? " style='display:none'" : "";
+$justifystyle = justifiers_are_used() ? "" : " style='display:none'";
+
+$liprovstyle = (isset($GLOBALS['support_fee_sheet_line_item_provider']) &&
+ $GLOBALS['support_fee_sheet_line_item_provider'] != 1) ? " style='display:none'" : "";
+
+// This flag comes from the LBFmsivd form and perhaps later others.
+$rapid_data_entry = empty($_GET['rde']) ? 0 : 1;
+
+// This comes from the Add More Items button, or is preserved from its previous value.
+$add_more_items = (empty($_GET['addmore']) && empty($_POST['bn_addmore'])) ? 0 : 1;
+
+$alertmsg = '';
+
+// Determine if more than one price level is in use.
+$tmp = sqlQuery("SELECT COUNT(*) AS count FROM list_options where list_id = 'pricelevel'");
+$price_levels_are_used = $tmp['count'] > 1;
+
+// Format a money amount with decimals but no other decoration.
+// Second argument is used when extra precision is required.
+function formatMoneyNumber($value, $extradecimals=0) {
+ return sprintf('%01.' . ($GLOBALS['currency_decimals'] + $extradecimals) . 'f', $value);
+}
+
+// Helper function for creating drop-lists.
+function endFSCategory() {
+ global $i, $last_category, $FEE_SHEET_COLUMNS;
+ if (! $last_category) return;
+ echo " \n";
+ echo " \n";
+ if ($i >= $FEE_SHEET_COLUMNS) {
+ echo " \n";
+ $i = 0;
+ }
+}
+
+// Generate JavaScript to build the array of diagnoses.
+function genDiagJS($code_type, $code) {
+ global $code_types;
+ if ($code_types[$code_type]['diag']) {
+ echo "diags.push('" . attr($code_type) . "|" . attr($code) . "');\n";
+ }
+}
+
+// Write all service lines to the web form.
+//
+function echoServiceLines() {
+ global $code_types, $justinit, $usbillstyle, $liprovstyle, $justifystyle, $fs, $price_levels_are_used;
+
+ foreach ($fs->serviceitems as $lino => $li) {
+ $id = $li['hidden']['id'];
+ $codetype = $li['hidden']['code_type'];
+ $code = $li['hidden']['code'];
+ $modifier = $li['hidden']['mod'];
+ $billed = $li['hidden']['billed'];
+ $ndc_info = isset($li['ndc_info']) ? $li['ndc_info'] : '';
+ $pricelevel = $li['pricelevel'];
+ $justify = $li['justify'];
+
+ $strike1 = $li['del'] ? "" : "";
+ $strike2 = $li['del'] ? "" : "";
+
+ echo "
\n";
+
+ echo "
$strike1" .
+ ($codetype == 'COPAY' ? xl($codetype) : $codetype) . $strike2;
+ // if the line to ouput is copay, show the date here passed as $ndc_info,
+ // since this variable is not applicable in the case of copay.
+ if ($codetype == 'COPAY') {
+ echo "(" . text($ndc_info) . ")";
+ $ndc_info = '';
+ }
+ if ($id) {
+ echo "";
+ }
+ echo "";
+ echo "";
+ echo "";
+ if (isset($li['hidden']['method'])) {
+ echo "";
+ echo "";
+ echo "";
+ }
+ echo "
\n";
+
+ if ($codetype != 'COPAY') {
+ echo "
$strike1" . text($code) . "$strike2
\n";
+ } else {
+ echo "
\n";
+ }
+
+ echo "
$strike1" . text($li['code_text']) . "$strike2
\n";
+
+ if ($billed) {
+
+ if (modifiers_are_used(true)) {
+ echo "
$strike1" . text($modifier) . "$strike2" .
+ "
\n";
+ }
+
+ if (fees_are_used()) {
+ if ($price_levels_are_used) {
+ // Show price level for this line.
+ echo "