4 * Product Name (blank where repeated)
5 * Warehouse Name (blank where repeated) or Total for Product
6 * Starting Inventory (detail lines: date)
7 * Ending Inventory (detail lines: invoice ID)
14 * @link http://www.open-emr.org
15 * @author Rod Roark <rod@sunsetsystems.com>
16 * @author Brady Miller <brady.g.miller@gmail.com>
17 * @copyright Copyright (c) 2010-2016 Rod Roark <rod@sunsetsystems.com>
18 * @copyright Copyright (c) 2017 Brady Miller <brady.g.miller@gmail.com>
19 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
23 require_once("../globals.php");
24 require_once("$srcdir/patient.inc");
25 require_once("$srcdir/acl.inc");
27 // Specify if product or warehouse is the first column.
28 $product_first = (!empty($_POST['form_by']) && $_POST['form_by'] == 'w') ?
0 : 1;
30 $last_warehouse_id = '~';
33 function esc4Export($str)
35 return str_replace('"', '\\"', $str);
38 // Get ending inventory for the report's end date.
39 // Optionally restricts by product ID and/or warehouse ID.
40 function getEndInventory($product_id = 0, $warehouse_id = '~')
42 global $form_from_date, $form_to_date, $form_product;
45 if ($warehouse_id !== '~') {
46 $whidcond = $warehouse_id === '' ?
47 "AND ( di.warehouse_id IS NULL OR di.warehouse_id = '' )" :
48 "AND di.warehouse_id = '$warehouse_id'";
53 $product_id = $form_product;
57 $prodcond = "AND di.drug_id = '$product_id'";
60 // Get sum of current inventory quantities + destructions done after the
61 // report end date (which is effectively a type of transaction).
62 $eirow = sqlQuery("SELECT sum(di.on_hand) AS on_hand " .
63 "FROM drug_inventory AS di WHERE " .
64 "( di.destroy_date IS NULL OR di.destroy_date > '$form_to_date' ) " .
65 "$prodcond $whidcond");
67 // Get sum of sales/adjustments/purchases after the report end date.
68 $sarow = sqlQuery("SELECT sum(ds.quantity) AS quantity " .
69 "FROM drug_sales AS ds, drug_inventory AS di WHERE " .
70 "ds.sale_date > '$form_to_date' AND " .
71 "di.inventory_id = ds.inventory_id " .
72 "$prodcond $whidcond");
74 // Get sum of transfers out after the report end date.
75 $xfrow = sqlQuery("SELECT sum(ds.quantity) AS quantity " .
76 "FROM drug_sales AS ds, drug_inventory AS di WHERE " .
77 "ds.sale_date > '$form_to_date' AND " .
78 "di.inventory_id = ds.xfer_inventory_id " .
79 "$prodcond $whidcond");
81 return $eirow['on_hand'] +
$sarow['quantity'] - $xfrow['quantity'];
84 function thisLineItem(
96 global $warehouse, $product, $secqtys, $priqtys, $grandqtys;
97 global $whleft, $prodleft; // left 2 columns, blank where repeated
98 global $last_warehouse_id, $last_product_id, $product_first;
101 $invnumber = empty($irnumber) ?
($patient_id ?
"$patient_id.$encounter_id" : "") : $irnumber;
103 // Product name for this detail line item.
104 if (empty($rowprod)) {
105 $rowprod = 'Unnamed Product';
108 // Warehouse name for this line item.
113 // If new warehouse or product...
114 if ($warehouse_id != $last_warehouse_id ||
$product_id != $last_product_id) {
115 // If there was anything to total...
116 if (($product_first && $last_warehouse_id != '~') ||
(!$product_first && $last_product_id)) {
117 $secei = getEndInventory($last_product_id, $last_warehouse_id);
119 // Print second-column totals.
120 if ($form_action == 'export') {
122 if (! $_POST['form_details']) {
123 if ($product_first) {
124 echo '"' . esc4Export($product) . '"';
125 echo ',"' . esc4Export($warehouse) . '"';
127 echo '"' . esc4Export($warehouse) . '"';
128 echo ',"' . esc4Export($product) . '"';
131 echo ',"' . ($secei - $secqtys[0] - $secqtys[1] - $secqtys[2] - $secqtys[3] - $secqtys[4]) . '"'; // start inventory
132 echo ',"' . $secqtys[0] . '"'; // sales
133 echo ',"' . $secqtys[1] . '"'; // distributions
134 echo ',"' . $secqtys[2] . '"'; // purchases
135 echo ',"' . $secqtys[3] . '"'; // transfers
136 echo ',"' . $secqtys[4] . '"'; // adjustments
137 echo ',"' . $secei . '"'; // end inventory
143 <tr bgcolor
="#ddddff">
144 <?php
if ($product_first) { ?
>
146 <?php
echo htmlspecialchars($prodleft);
149 <td
class="detail" colspan
='3'>
151 if ($_POST['form_details']) {
152 echo htmlspecialchars(xl('Total for')) . ' ';
154 echo htmlspecialchars($warehouse); ?
>
158 <?php
echo htmlspecialchars($whleft);
161 <td
class="detail" colspan
='3'>
163 if ($_POST['form_details']) {
164 echo htmlspecialchars(xl('Total for')) . ' ';
166 echo htmlspecialchars($product); ?
>
169 <td
class="dehead" align
="right">
170 <?php
echo $secei - $secqtys[0] - $secqtys[1] - $secqtys[2] - $secqtys[3] - $secqtys[4]; ?
>
172 <td
class="dehead" align
="right">
173 <?php
echo $secqtys[0]; ?
>
175 <td
class="dehead" align
="right">
176 <?php
echo $secqtys[1]; ?
>
178 <td
class="dehead" align
="right">
179 <?php
echo $secqtys[2]; ?
>
181 <td
class="dehead" align
="right">
182 <?php
echo $secqtys[3]; ?
>
184 <td
class="dehead" align
="right">
185 <?php
echo $secqtys[4]; ?
>
187 <td
class="dehead" align
="right">
188 <?php
echo $secei; ?
>
192 } // End not csv export
195 $secqtys = array(0, 0, 0, 0, 0);
196 if ($product_first) {
197 $whleft = $warehouse = $rowwh;
198 $last_warehouse_id = $warehouse_id;
200 $prodleft = $product = $rowprod;
201 $last_product_id = $product_id;
205 // If first column is changing, time for its totals.
206 if (($product_first && $product_id != $last_product_id) ||
207 (!$product_first && $warehouse_id != $last_warehouse_id)) {
208 if (($product_first && $last_product_id) ||
209 (!$product_first && $last_warehouse_id != '~')) {
210 $priei = $product_first ?
getEndInventory($last_product_id) :
211 getEndInventory(0, $last_warehouse_id);
212 // Print first column total.
213 if ($form_action != 'export') {
216 <tr bgcolor
="#ffdddd">
220 <td
class="detail" colspan
="3">
221 <?php
echo htmlspecialchars(xl('Total for')) . ' ';
222 echo htmlspecialchars($product_first ?
$product : $warehouse); ?
>
224 <td
class="dehead" align
="right">
225 <?php
echo $priei - $priqtys[0] - $priqtys[1] - $priqtys[2] - $priqtys[3] - $priqtys[4]; ?
>
227 <td
class="dehead" align
="right">
228 <?php
echo $priqtys[0]; ?
>
230 <td
class="dehead" align
="right">
231 <?php
echo $priqtys[1]; ?
>
233 <td
class="dehead" align
="right">
234 <?php
echo $priqtys[2]; ?
>
236 <td
class="dehead" align
="right">
237 <?php
echo $priqtys[3]; ?
>
239 <td
class="dehead" align
="right">
240 <?php
echo $priqtys[4]; ?
>
242 <td
class="dehead" align
="right">
243 <?php
echo $priei; ?
>
247 } // End not csv export
250 $priqtys = array(0, 0, 0, 0, 0);
251 if ($product_first) {
252 $prodleft = $product = $rowprod;
253 $last_product_id = $product_id;
255 $whleft = $warehouse = $rowwh;
256 $last_warehouse_id = $warehouse_id;
261 if ($_POST['form_details'] && $product_id && ($qtys[0] +
$qtys[1] +
$qtys[2] +
$qtys[3] +
$qtys[4])) {
262 if ($form_action == 'export') {
263 if ($product_first) {
264 echo '"' . esc4Export($product) . '"';
265 echo ',"' . esc4Export($warehouse) . '"';
267 echo '"' . esc4Export($warehouse) . '"';
268 echo ',"' . esc4Export($product) . '"';
271 echo ',"' . oeFormatShortDate($transdate) . '"';
272 echo ',"' . esc4Export($invnumber) . '"';
273 echo ',"' . $qtys[0] . '"'; // sales
274 echo ',"' . $qtys[1] . '"'; // distributions
275 echo ',"' . $qtys[2] . '"'; // purchases
276 echo ',"' . $qtys[3] . '"'; // transfers
277 echo ',"' . $qtys[4] . '"'; // adjustments
282 <?php
if ($product_first) { ?
>
284 <?php
echo htmlspecialchars($prodleft);
288 <?php
echo htmlspecialchars($whleft);
293 <?php
echo htmlspecialchars($whleft);
297 <?php
echo htmlspecialchars($prodleft);
302 <?php
echo oeFormatShortDate($transdate); ?
>
305 <?php
echo htmlspecialchars($invnumber); ?
>
310 <td
class="dehead" align
="right">
311 <?php
echo $qtys[0]; ?
>
313 <td
class="dehead" align
="right">
314 <?php
echo $qtys[1]; ?
>
316 <td
class="dehead" align
="right">
317 <?php
echo $qtys[2]; ?
>
319 <td
class="dehead" align
="right">
320 <?php
echo $qtys[3]; ?
>
322 <td
class="dehead" align
="right">
323 <?php
echo $qtys[4]; ?
>
330 } // End not csv export
332 for ($i = 0; $i < 5; ++
$i) {
333 $secqtys[$i] +
= $qtys[$i];
334 $priqtys[$i] +
= $qtys[$i];
335 $grandqtys[$i] +
= $qtys[$i];
339 if (! acl_check('acct', 'rep')) {
340 die(htmlspecialchars(xl("Unauthorized access.")));
343 // this is "" or "submit" or "export".
344 $form_action = $_POST['form_action'];
346 $form_from_date = fixDate($_POST['form_from_date'], date('Y-m-d'));
347 $form_to_date = fixDate($_POST['form_to_date'], date('Y-m-d'));
348 $form_product = $_POST['form_product'];
350 if ($form_action == 'export') {
351 header("Pragma: public");
352 header("Expires: 0");
353 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
354 header("Content-Type: application/force-download");
355 header("Content-Disposition: attachment; filename=inventory_activity.csv");
356 header("Content-Description: File Transfer");
358 if ($product_first) {
359 echo '"' . esc4export(xl('Product')) . '",';
360 echo '"' . esc4export(xl('Warehouse')) . '",';
362 echo '"' . esc4export(xl('Warehouse')) . '",';
363 echo '"' . esc4export(xl('Product')) . '",';
366 if ($_POST['form_details']) {
367 echo '"' . esc4export(xl('Date')) . '",';
368 echo '"' . esc4export(xl('Invoice')) . '",';
369 echo '"' . esc4export(xl('Sales')) . '",';
370 echo '"' . esc4export(xl('Distributions')) . '",';
371 echo '"' . esc4export(xl('Purchases')) . '",';
372 echo '"' . esc4export(xl('Transfers')) . '",';
373 echo '"' . esc4export(xl('Adjustments')) . '"' . "\n";
375 echo '"' . esc4export(xl('Start')) . '",';
376 echo '"' . esc4export(xl('Sales')) . '",';
377 echo '"' . esc4export(xl('Distributions')) . '",';
378 echo '"' . esc4export(xl('Purchases')) . '",';
379 echo '"' . esc4export(xl('Transfers')) . '",';
380 echo '"' . esc4export(xl('Adjustments')) . '",';
381 echo '"' . esc4export(xl('End')) . '"' . "\n";
388 <?php
html_header_show();?
>
389 <title
><?php
echo htmlspecialchars(xl('Inventory Activity')) ?
></title
>
391 <link rel
='stylesheet' href
='<?php echo $css_header ?>' type
='text/css'>
392 <link rel
="stylesheet" href
="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-datetimepicker-2-5-4/build/jquery.datetimepicker.min.css">
394 <style type
="text/css">
395 /* specifically include & exclude from printing */
397 #report_parameters {visibility: hidden; display: none;}
398 #report_parameters_daterange {visibility: visible; display: inline;}
399 #report_results {margin-top: 30px;}
401 /* specifically exclude some from the screen */
403 #report_parameters_daterange {visibility: hidden; display: none;}
405 body
{ font
-family
:sans
-serif
; font
-size
:10pt
; font
-weight
:normal
}
406 .dehead
{ color
:#000000; font-family:sans-serif; font-size:10pt; font-weight:bold }
407 .detail
{ color
:#000000; font-family:sans-serif; font-size:10pt; font-weight:normal }
409 table
.mymaintable
, table
.mymaintable td
, table
.mymaintable th
{
410 border
: 1px solid
#aaaaaa;
411 border
-collapse
: collapse
;
413 table
.mymaintable td
, table
.mymaintable th
{
414 padding
: 1pt
4pt
1pt
4pt
;
419 <script type
="text/javascript" src
="../../library/textformat.js?v=<?php echo $v_js_includes; ?>"></script
>
420 <script type
="text/javascript" src
="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-min-1-9-1/index.js"></script
>
421 <script type
="text/javascript" src
="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery-datetimepicker-2-5-4/build/jquery.datetimepicker.full.min.js"></script
>
422 <script type
="text/javascript" src
="../../library/js/report_helper.js?v=<?php echo $v_js_includes; ?>"></script
>
424 <script language
='JavaScript'>
426 $
(document
).ready(function() {
427 oeFixedHeaderSetup(document
.getElementById('mymaintable'));
428 var win
= top
.printLogSetup ? top
: opener
.top
;
429 win
.printLogSetup(document
.getElementById('printbutton'));
431 $
('.datepicker').datetimepicker({
432 <?php
$datetimepicker_timepicker = false; ?
>
433 <?php
$datetimepicker_showseconds = false; ?
>
434 <?php
$datetimepicker_formatInput = false; ?
>
435 <?php
require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?
>
436 <?php
// can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
440 function mysubmit(action
) {
441 var f
= document
.forms
[0];
442 f
.form_action
.value
= action
;
443 top
.restoreSession();
451 <body leftmargin
='0' topmargin
='0' marginwidth
='0' marginheight
='0' class='body_top'>
455 <h2
><?php
echo htmlspecialchars(xl('Inventory Activity'))?
></h2
>
457 <form method
='post' action
='inventory_activity.php?product=<?php echo htmlspecialchars($product_first, ENT_QUOTES); ?>'>
459 <div id
="report_parameters">
460 <!-- form_action is set to
"submit" or "export" at form submit time
-->
461 <input type
='hidden' name
='form_action' value
='' />
467 <td
class='label_custom'>
468 <?php
echo htmlspecialchars(xl('By')); ?
>:
471 <select name
='form_by'>
472 <option value
='p'><?php
echo htmlspecialchars(xl('Product')); ?
></option
>
473 <option value
='w'<?php
echo (!$product_first) ?
' selected' : ''; ?
>><?php
echo htmlspecialchars(xl('Warehouse')); ?
></option
>
476 <td
class='label_custom'>
477 <?php
echo htmlspecialchars(xl('From')); ?
>:
480 <input type
='text' class='datepicker' name
='form_from_date' id
="form_from_date" size
='10'
481 value
='<?php echo htmlspecialchars($form_from_date, ENT_QUOTES) ?>'
482 title
='<?php echo htmlspecialchars(xl('yyyy
-mm
-dd
'), ENT_QUOTES) ?>'>
484 <td
class='label_custom'>
485 <?php
echo htmlspecialchars(xl('To')); ?
>:
488 <input type
='text' class='datepicker' name
='form_to_date' id
="form_to_date" size
='10'
489 value
='<?php echo htmlspecialchars($form_to_date, ENT_QUOTES) ?>'
490 title
='<?php echo htmlspecialchars(xl('yyyy
-mm
-dd
'), ENT_QUOTES) ?>'>
494 <td
class='label_custom'>
495 <?php
echo htmlspecialchars(xl('For'), ENT_NOQUOTES
); ?
>:
499 // Build a drop-down list of products.
501 $query = "SELECT drug_id, name FROM drugs ORDER BY name, drug_id";
502 $pres = sqlStatement($query);
503 echo " <select name='form_product'>\n";
504 echo " <option value=''>-- " . htmlspecialchars(xl('All Products')) . " --\n";
505 while ($prow = sqlFetchArray($pres)) {
506 $drug_id = $prow['drug_id'];
507 echo " <option value='$drug_id'";
508 if ($drug_id == $form_product) {
512 echo ">" . htmlspecialchars($prow['name']) . "\n";
518 <td
class='label_custom'>
519 <?php
echo htmlspecialchars(xl('Details')); ?
>:
521 <td colspan
='3' nowrap
>
522 <input type
='checkbox' name
='form_details' value
='1'<?php
echo ($_POST['form_details']) ?
" checked" : "";?
> />
527 <td align
='left' valign
='middle'>
528 <table style
='border-left:1px solid; width:100%; height:100%'>
531 <a href
='#' class='css_button' onclick
='mysubmit("submit")' style
='margin-left:1em'>
532 <span
><?php
echo htmlspecialchars(xl('Submit')); ?
></span
>
534 <?php
if ($form_action) { ?
>
535 <a href
='#' class='css_button' id
='printbutton' style
='margin-left:1em'>
536 <span
><?php
echo htmlspecialchars(xl('Print')); ?
></span
>
538 <a href
='#' class='css_button' onclick
='mysubmit("export")' style
='margin-left:1em'>
539 <span
><?php
echo htmlspecialchars(xl('CSV Export')); ?
></span
>
550 <?php
if ($form_action) { // if submit (already not export here) ?>
552 <div id
="report_results">
553 <table width
='98%' id
='mymaintable' class='mymaintable'>
555 <tr bgcolor
="#dddddd">
557 <?php
echo htmlspecialchars($product_first ?
xl('Product') : xl('Warehouse')); ?
>
559 <?php
if ($_POST['form_details']) { ?
>
561 <?php
echo htmlspecialchars($product_first ?
xl('Warehouse') : xl('Product')); ?
>
564 <?php
echo htmlspecialchars(xl('Date')); ?
>
567 <?php
echo htmlspecialchars(xl('Invoice')); ?
>
570 <td
class="dehead" colspan
="3">
571 <?php
echo htmlspecialchars($product_first ?
xl('Warehouse') : xl('Product')); ?
>
574 <td
class="dehead" align
="right" width
="8%">
575 <?php
echo htmlspecialchars(xl('Start')); ?
>
577 <td
class="dehead" align
="right" width
="8%">
578 <?php
echo htmlspecialchars(xl('Sales')); ?
>
580 <td
class="dehead" align
="right" width
="8%">
581 <?php
echo htmlspecialchars(xl('Distributions')); ?
>
583 <td
class="dehead" align
="right" width
="8%">
584 <?php
echo htmlspecialchars(xl('Purchases')); ?
>
586 <td
class="dehead" align
="right" width
="8%">
587 <?php
echo htmlspecialchars(xl('Transfers')); ?
>
589 <td
class="dehead" align
="right" width
="8%">
590 <?php
echo htmlspecialchars(xl('Adjustments')); ?
>
592 <td
class="dehead" align
="right" width
="8%">
593 <?php
echo htmlspecialchars(xl('End')); ?
>
602 if ($form_action) { // if submit or export
603 $from_date = $form_from_date;
604 $to_date = $form_to_date;
610 $grandqtys = array(0, 0, 0, 0, 0);
611 $priqtys = array(0, 0, 0, 0, 0);
612 $secqtys = array(0, 0, 0, 0, 0);
613 $last_inventory_id = 0;
615 $query = "SELECT s.sale_id, s.sale_date, s.quantity, s.fee, s.pid, s.encounter, " .
616 "s.xfer_inventory_id, s.distributor_id, d.name, lo.title, " .
617 "di.drug_id, di.warehouse_id, di.inventory_id, di.destroy_date, di.on_hand, " .
618 "fe.invoice_refno " .
619 "FROM drug_inventory AS di " .
620 "JOIN drugs AS d ON d.drug_id = di.drug_id " .
621 "LEFT JOIN drug_sales AS s ON " .
622 "s.sale_date >= '$from_date' AND s.sale_date <= '$to_date' AND " .
623 "s.drug_id = di.drug_id AND " .
624 "( s.inventory_id = di.inventory_id OR s.xfer_inventory_id = di.inventory_id ) " .
625 "LEFT JOIN list_options AS lo ON lo.list_id = 'warehouse' AND " .
626 "lo.option_id = di.warehouse_id AND lo.activity = 1 " .
627 "LEFT JOIN form_encounter AS fe ON fe.pid = s.pid AND fe.encounter = s.encounter " .
628 "WHERE ( di.destroy_date IS NULL OR di.destroy_date >= '$form_from_date' )";
630 // If a product was specified.
632 $query .= " AND di.drug_id = '$form_product'";
635 if ($product_first) {
636 $query .= " ORDER BY d.name, d.drug_id, lo.title, di.warehouse_id, " .
637 "di.inventory_id, s.sale_date, s.sale_id";
639 $query .= " ORDER BY lo.title, di.warehouse_id, d.name, d.drug_id, " .
640 "di.inventory_id, s.sale_date, s.sale_id";
643 $res = sqlStatement($query);
644 while ($row = sqlFetchArray($res)) {
645 // If new lot and it was destroyed during the reporting period,
646 // generate a pseudo-adjustment for that.
647 if ($row['inventory_id'] != $last_inventory_id) {
648 $last_inventory_id = $row['inventory_id'];
649 if (!empty($row['destroy_date']) && $row['on_hand'] != 0
650 && $row['destroy_date'] <= $form_to_date) {
653 $row['warehouse_id'],
658 $row['destroy_date'],
659 array(0, 0, 0, 0, 0 - $row['on_hand']),
665 $qtys = array(0, 0, 0, 0, 0);
666 if ($row['sale_id']) {
667 if ($row['xfer_inventory_id']) {
668 // A transfer sale item will appear twice, once with each lot.
669 if ($row['inventory_id'] == $row['xfer_inventory_id']) {
670 $qtys[3] = $row['quantity'];
672 $qtys[3] = 0 - $row['quantity'];
674 } else if ($row['pid']) {
675 $qtys[0] = 0 - $row['quantity'];
676 } else if ($row['distributor_id']) {
677 $qtys[1] = 0 - $row['quantity'];
678 } else if ($row['fee'] != 0) {
679 $qtys[2] = 0 - $row['quantity'];
680 } else { // no pid, distributor, source lot or fee: must be an adjustment
681 $qtys[4] = 0 - $row['quantity'];
687 $row['warehouse_id'],
689 $row['encounter'] +
0,
694 $row['invoice_refno']
698 // Generate totals for last product and warehouse.
699 thisLineItem(0, '~', 0, 0, '', '', '0000-00-00', array(0, 0, 0, 0, 0));
701 // Grand totals line.
702 if ($form_action != 'export') { // if submit
703 $grei = getEndInventory();
705 <tr bgcolor
="#dddddd">
706 <td
class="detail" colspan
="4">
707 <?php
echo htmlspecialchars(xl('Grand Total')); ?
>
709 <td
class="dehead" align
="right">
710 <?php
echo $grei - $grandqtys[0] - $grandqtys[1] - $grandqtys[2] - $grandqtys[3] - $grandqtys[4]; ?
>
712 <td
class="dehead" align
="right">
713 <?php
echo $grandqtys[0]; ?
>
715 <td
class="dehead" align
="right">
716 <?php
echo $grandqtys[1]; ?
>
718 <td
class="dehead" align
="right">
719 <?php
echo $grandqtys[2]; ?
>
721 <td
class="dehead" align
="right">
722 <?php
echo $grandqtys[3]; ?
>
724 <td
class="dehead" align
="right">
725 <?php
echo $grandqtys[4]; ?
>
727 <td
class="dehead" align
="right">
733 } // end if submit or export
735 if ($form_action != 'export') {
742 } // end if ($form_action)