2 // Copyright (C) 2006-2010 Rod Roark <rod@sunsetsystems.com>
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 // Modified 7-2009 by BM in order to migrate using the form,
10 // unit, route, and interval lists with the
11 // functions in openemr/library/options.inc.php .
12 // These lists are based on the constants found in the
13 // openemr/library/classes/Prescription.class.php file.
15 $substitute_array = array('', xl('Allowed'), xl('Not Allowed'));
17 function send_drug_email($subject, $body) {
18 require_once ($GLOBALS['srcdir'] . "/classes/class.phpmailer.php");
19 $recipient = $GLOBALS['practice_return_email_path'];
20 if (empty($recipient)) return;
21 $mail = new PHPMailer();
22 $mail->SetLanguage("en", $GLOBALS['fileroot'] . "/library/" );
23 $mail->From
= $recipient;
24 $mail->FromName
= 'In-House Pharmacy';
26 $mail->Host
= "localhost";
27 $mail->Mailer
= "mail";
29 $mail->Subject
= $subject;
30 $mail->AddAddress($recipient);
32 error_log("There has been a mail error sending to " . $recipient .
33 " " . $mail->ErrorInfo
);
37 function sellDrug($drug_id, $quantity, $fee, $patient_id=0, $encounter_id=0,
38 $prescription_id=0, $sale_date='', $user='', $default_warehouse='') {
40 if (empty($patient_id)) $patient_id = $GLOBALS['pid'];
41 if (empty($sale_date)) $sale_date = date('Y-m-d');
42 if (empty($user)) $user = $_SESSION['authUser'];
44 // error_log("quantity = '$quantity'"); // debugging
46 if (empty($default_warehouse)) {
47 // Get the default warehouse, if any, for the user.
48 $rowuser = sqlQuery("SELECT default_warehouse FROM users WHERE username = ?", array($user));
49 $default_warehouse = $rowuser['default_warehouse'];
52 // Get relevant options for this product.
53 $rowdrug = sqlQuery("SELECT allow_combining, reorder_point, name " .
54 "FROM drugs WHERE drug_id = ?", array($drug_id));
55 $allow_combining = $rowdrug['allow_combining'];
57 // Combining is never allowed for prescriptions and will not work with
59 if ($prescription_id) $allow_combining = 0;
63 $qty_left = $quantity;
67 // If the user has a default warehouse, sort those lots first.
68 $orderby = ($default_warehouse === '') ?
69 "" : "di.warehouse_id != '$default_warehouse', ";
70 $orderby .= "lo.seq, di.expiration, di.lot_number, di.inventory_id";
72 // Retrieve lots in order of expiration date within warehouse preference.
73 $res = sqlStatement("SELECT di.*, lo.option_id, lo.seq " .
74 "FROM drug_inventory AS di " .
75 "LEFT JOIN list_options AS lo ON lo.list_id = 'warehouse' AND " .
76 "lo.option_id = di.warehouse_id " .
78 "di.drug_id = ? AND di.destroy_date IS NULL " .
79 "ORDER BY $orderby", array($drug_id));
81 // First pass. Pick out lots to be used in filling this order, figure out
82 // if there is enough quantity on hand and check for lots to be destroyed.
83 while ($row = sqlFetchArray($res)) {
84 // Warehouses with seq > 99 are not available.
85 $seq = empty($row['seq']) ?
0 : $row['seq'] +
0;
86 if ($seq > 99) continue;
88 $on_hand = $row['on_hand'];
89 $expired = (!empty($row['expiration']) && $row['expiration'] <= $sale_date);
90 if ($expired ||
$on_hand < $quantity) {
91 $tmp = $row['lot_number'];
92 if (! $tmp) $tmp = '[missing lot number]';
93 if ($bad_lot_list) $bad_lot_list .= ', ';
94 $bad_lot_list .= $tmp;
96 if ($expired) continue;
98 /*****************************************************************
99 // Note the first row in case total quantity is insufficient and we are
100 // allowed to go negative.
101 if (!$firstrow) $firstrow = $row;
102 *****************************************************************/
104 $total_on_hand +
= $on_hand;
106 if ($on_hand > 0 && $qty_left > 0 && ($allow_combining ||
$on_hand >= $qty_left)) {
108 $qty_left -= $on_hand;
113 send_drug_email("Possible lot destruction needed",
114 "The following lot(s) are expired or were too small to fill the " .
115 "order for patient $patient_id: $bad_lot_list\n");
118 /*******************************************************************
119 if (empty($firstrow)) return 0; // no suitable lots exist
120 // This can happen when combining is not allowed. We will use the
121 // first row and take it negative.
124 $qty_left -= $firstrow['on_hand'];
126 *******************************************************************/
128 // The above was an experiment in permitting a negative lot quantity.
129 // We decided that was a bad idea, so now we just error out if there
130 // is not enough on hand.
131 if ($qty_left > 0) return 0;
134 $qty_final = $quantity; // remaining unallocated quantity
135 $fee_final = $fee; // remaining unallocated fee
137 // Second pass. Update the database.
138 foreach ($rows as $row) {
139 $inventory_id = $row['inventory_id'];
141 /*****************************************************************
142 $thisqty = $row['on_hand'];
144 $thisqty += $qty_left;
147 else if ($thisqty > $qty_final) {
148 $thisqty = $qty_final;
150 *****************************************************************/
151 $thisqty = min($qty_final, $row['on_hand']);
153 $qty_final -= $thisqty;
155 // Compute the proportional fee for this line item. For the last line
156 // item take the remaining unallocated fee to avoid round-off error.
158 $thisfee = sprintf('%0.2f', $fee * $thisqty / $quantity);
160 $thisfee = sprintf('%0.2f', $fee_final);
161 $fee_final -= $thisfee;
163 // Update inventory and create the sale line item.
164 sqlStatement("UPDATE drug_inventory SET " .
165 "on_hand = on_hand - ? " .
166 "WHERE inventory_id = ?", array($thisqty,$inventory_id));
167 $sale_id = sqlInsert("INSERT INTO drug_sales ( " .
168 "drug_id, inventory_id, prescription_id, pid, encounter, user, sale_date, quantity, fee ) " .
169 "VALUES (?,?,?,?,?,?,?,?,?)", array($drug_id,$inventory_id,$prescription_id,$patient_id,$encounter_id,$user,$sale_date,$thisqty,$thisfee));
172 // If appropriate, generate email to notify that re-order is due.
173 if (($total_on_hand - $quantity) <= $rowdrug['reorder_point']) {
174 send_drug_email("Product re-order required",
175 "Product '" . $rowdrug['name'] . "' has reached its reorder point.\n");
178 // If combining is allowed then $sale_id will be just the last inserted ID,
179 // and it serves only to indicate that everything worked. Otherwise there
180 // can be only one inserted row and this is its ID.