Skip to content

Commit

Permalink
fix(reports): stock expiration report
Browse files Browse the repository at this point in the history
This commit fixes the stock expiration report by doing the following
things:
  1. Removes the date range as these don't make any sense.
  2. Uses the same colorscheme as used in the other reports for
     warning/danger text.
  3. Adds total summaries to the top of the report.
  4. Removes the inventory select.
  5. Simplifies the queries so that less for loops are done.
  6. Fixes the currency bug so things render in the enterprise currency.
  7. Adds the column for the unit type.

Closes #4835.
  • Loading branch information
jniles committed Sep 15, 2020
1 parent aa6bf61 commit 8135d8a
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 158 deletions.
4 changes: 2 additions & 2 deletions client/src/i18n/en/report.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@
"EXCLUDE_INVENTORIES_ZERO_VALUE": "Exclude inventories with zero stock value"
},
"STOCK_EXPIRATION_REPORT" : {
"TITLE": "Stock expiration report",
"DESCRIPTION": ""
"TITLE": "Stock Expiration Report",
"DESCRIPTION": "This report shows the lots that are currently in stock and are also expired or will expire prior to being consummed."
},
"STOCK_CONSUMPTION_GRAPH_REPORT" : {
"TITLE" : "Stock Consumption's graph report",
Expand Down
28 changes: 14 additions & 14 deletions client/src/js/components/bhIndicator/bhIndicator.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ <h4 class="title" translate>{{ $ctrl.label }}</h4>
<sup class="value-symbol" translate>{{ $ctrl.valueSymbol }}</sup>
</div>
<div class="description-section">
<div class="description" translate>
{{ $ctrl.description }}
</div>
<ul ng-if="$ctrl.dependencies && $ctrl.dependencies.length">
<li ng-repeat="deps in $ctrl.dependencies">
<span translate>{{ 'DASHBOARD.INDICATORS_FILES.' + deps.key }}</span>
<span>{{ deps.value | number }}</span>
</li>
</ul>
<div class="norm">
<span translate>DASHBOARD.NORM</span>
<span translate>{{ $ctrl.norm }}</span>
</div>
<div class="description" translate>
{{ $ctrl.description }}
</div>
<ul ng-if="$ctrl.dependencies && $ctrl.dependencies.length">
<li ng-repeat="deps in $ctrl.dependencies">
<span translate>{{ 'DASHBOARD.INDICATORS_FILES.' + deps.key }}</span>
<span>{{ deps.value | number }}</span>
</li>
</ul>
<div class="norm">
<span translate>DASHBOARD.NORM</span>
<span translate>{{ $ctrl.norm }}</span>
</div>
</div>
</div>
</div>
</div>
7 changes: 3 additions & 4 deletions client/src/modules/dashboards/finance/finance.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
/* Medium devices (desktops, 992px and up) */
@media (min-width: 992px) {
.dashboard {
grid-template-columns: repeat(2, 1fr);
grid-template-columns: repeat(2, 1fr);
}
}
</style>
Expand All @@ -37,7 +37,7 @@
<li class="static" translate>TREE.DASHBOARDS.TITLE</li>
<li class="title" translate>TREE.DASHBOARDS.FINANCES</li>
</ol>

<div class="toolbar">
<div class="toolbar-item">
<bh-dashboard-filter
Expand All @@ -49,7 +49,7 @@
</div>
</div>
</div>

<div class="flex-content">
<div class="container">
<h3 class="no-space" translate>DASHBOARD.INDICATORS_FILES.FINANCES_INDICATORS</h3>
Expand Down Expand Up @@ -202,4 +202,3 @@ <h3 class="no-space" translate>DASHBOARD.INDICATORS_FILES.FINANCES_INDICATORS</h
</div>
</div>
</div>

Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ function StockExpirationReportConfigCtrl($sce, Notify, SavedReports, AppCache, r
vm.reportDetails.depot_uuid = depot.uuid;
};

vm.onSelectInventory = inventory => {
vm.reportDetails.inventory_uuid = inventory.uuid;
};

vm.onSelectFiscalYear = year => {
vm.reportDetails.fiscal_id = year.id;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ <h3 translate>REPORT.STOCK_EXPIRATION_REPORT.TITLE</h3>

<form name="ConfigForm" bh-submit="ReportConfigCtrl.preview(ConfigForm)" novalidate autocomplete="off">

<bh-date-interval
date-from="ReportConfigCtrl.reportDetails.dateFrom"
date-to="ReportConfigCtrl.reportDetails.dateTo"
required="true"
limit-min-fiscal>
</bh-date-interval>

<!-- depot options -->
<div class="checkbox">
<label>
Expand All @@ -41,35 +34,15 @@ <h3 translate>REPORT.STOCK_EXPIRATION_REPORT.TITLE</h3>

<!-- select depot -->
<div ng-if="!!ReportConfigCtrl.chooseOneDepot">

<!-- select depot -->
<bh-depot-select
depot-uuid="ReportConfigCtrl.reportDetails.depot_uuid"
on-select-callback="ReportConfigCtrl.onSelectDepot(depot)">
<bh-clear on-clear="ReportConfigCtrl.clear('depot_uuid')"></bh-clear>
</bh-depot-select>
</div>

<!-- inventory options -->
<div class="checkbox">
<label>
<input type="checkbox" ng-model="ReportConfigCtrl.chooseOneInventory">
<span translate>REPORT.STOCK.ONE_INVENTORY</span>
</label>
</bh-depot-select>
</div>

<!-- select inventory -->
<div ng-if="!!ReportConfigCtrl.chooseOneInventory">

<!-- select inventory -->
<bh-inventory-select
inventory-uuid="ReportConfigCtrl.reportDetails.inventory_uuid"
on-select-callback="ReportConfigCtrl.onSelectInventory(inventory)"
only-consumable="true">

<bh-clear on-clear="ReportConfigCtrl.clear('inventory_uuid')"></bh-clear>
</bh-inventory-select>
</div>
<!-- preview -->
<bh-loading-button loading-state="ConfigForm.$loading">
<span translate>REPORT.UTIL.PREVIEW</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<td class="text-right">{{debcred row.total_invoiced ../metadata.enterprise.currency_id}}</td>
<td class="text-right">{{debcred row.avg_cost ../metadata.enterprise.currency_id}}</td>
<td class="text-right">{{debcred row.total_paid ../metadata.enterprise.currency_id}}</td>
<td
<td
style="width: 15em;"
{{#gt row.recovery_capacity 0.71}} class="bg-success text-success text-right" {{/gt}}
{{#between row.recovery_capacity 0.6 0.7}} class="bg-warning text-warning text-right" {{/between}}
Expand All @@ -69,7 +69,7 @@
<th class="text-right">{{debcred totals.total_invoiced metadata.enterprise.currency_id}}</th>
<th class="text-right">{{debcred totals.avg_cost metadata.enterprise.currency_id}}</th>
<th class="text-right">{{debcred totals.total_paid metadata.enterprise.currency_id}}</th>
<th
<th
style="width: 15em;"
{{#gt totals.recovery_capacity 0.71}} class="bg-success text-success text-right" {{/gt}}
{{#between totals.recovery_capacity 0.6 0.7}} class="bg-warning text-warning text-right" {{/between}}
Expand All @@ -84,4 +84,4 @@
</div>

</div>
</body>
</body>
4 changes: 2 additions & 2 deletions server/controllers/stock/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ async function getLotsDepot(depotUuid, params, finalClause) {
emptyLotToken = 'HAVING quantity > 0';
delete params.includeEmptyLot;
} else if (includeEmptyLot === 2) {
emptyLotToken = 'HAVING quantity=0';
emptyLotToken = 'HAVING quantity = 0';
}

const sql = `
Expand Down Expand Up @@ -799,7 +799,7 @@ function processMultipleLots(inventories) {
// if we have more months of stock than the expiration date,
// then we'll need to label these are in risk of expiration
const numDaysOfStockLeft = numMonthsOfStockLeft * 30.5;
const isInRiskOfExpiration = lot.expiration_date < moment(today).add(numDaysOfStockLeft, 'days').toDate();
const isInRiskOfExpiration = lot.expiration_date <= moment(today).add(numDaysOfStockLeft, 'days').toDate();
lot.IS_IN_RISK_EXPIRATION = isInRiskOfExpiration;

lot.S_LOT_LIFETIME = zeroMSD || lot.lifetime < 0 ? 0 : lot.lifetime - lotLifetime;
Expand Down
100 changes: 53 additions & 47 deletions server/controllers/stock/reports/stock/expiration_report.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
const {
_, db, ReportManager, pdfOptions, STOCK_EXPIRATION_REPORT_TEMPLATE,
} = require('../common');

const stockCore = require('../../core');

/**
* @method stockEntryReport
*
* @description
* This method builds the stock entry report as either a JSON, PDF, or HTML
* file to be sent to the client.
*
* GET /reports/stock/consumption_graph
*/
* @method stockExpirationReport
*
* @description
*
*/
async function stockExpirationReport(req, res, next) {
try {

const params = _.clone(req.query);
try {
const params = { includeEmptyLot : 0, ...req.query };

const optionReport = _.extend(params, pdfOptions, {
filename : 'REPORT.STOCK_CONSUMPTION_GRAPH_REPORT.TITLE',
filename : 'REPORT.STOCK_EXPIRATION_REPORT.TITLE',
});

// set up the report with report manager
const report = new ReportManager(STOCK_EXPIRATION_REPORT_TEMPLATE, req.session, optionReport);

const depotSql = 'SELECT text FROM depot WHERE uuid=?';
const options = req.query;
const options = params;

if (req.session.enterprise.settings.enable_strict_depot_permission) {
options.check_user_id = req.session.user.id;
Expand All @@ -33,53 +31,61 @@ async function stockExpirationReport(req, res, next) {
let depot = {};

if (options.depot_uuid) {
const depotSql = 'SELECT text FROM depot WHERE uuid = ?';
depot = await db.one(depotSql, db.bid(options.depot_uuid));
}

const dateFrom = new Date(options.dateFrom);
const dateTo = new Date(options.dateTo);
// clean off the label if it exists so it doesn't mess up the PDF export
delete options.label;

// get the lots for this depot
const lots = await stockCore.getLotsDepot(options.depot_uuid, options);

const resultByDepot = _.groupBy(lots, 'depot_uuid');
const depotUuids = Object.keys(resultByDepot);
const result = {};
depotUuids.forEach(depotUuid => {
const depotLots = resultByDepot[depotUuid].filter(row => {
let found = false;
if (row.status === 'stock_out') {
row.status = `STOCK.STATUS.${row.status.toUpperCase()}`;
row.color = 'red';
found = true;
} else if (row.IS_IN_RISK_EXPIRATION) {
row.status = `STOCK.STATUS.IS_IN_RISK_OF_EXPIRATION`;
row.color = '#f5cb42';
found = true;
// get the lots that are "at risk"
const risky = lots.filter(lot => lot.IS_IN_RISK_EXPIRATION);

// make sure lots are grouped by depot.
const groupedByDepot = _.groupBy(risky, 'depot_uuid');

// grand totals
const totals = {
expired : { value : 0, quantity : 0 },
at_risk : { value : 0, quantity : 0 },
};

const today = new Date();

const values = _.map(groupedByDepot, (rows) => {
let total = 0;

rows.forEach(lot => {
lot.value = (lot.mvt_quantity * lot.unit_cost);
total += lot.value;

if (lot.expiration_date < today) {
lot.statusKey = 'STOCK.EXPIRED';
lot.classKey = 'bg-danger text-danger';
totals.expired.value += lot.value;
totals.expired.quantity += lot.mvt_quantity;
} else {
lot.statusKey = 'STOCK.STATUS.IS_IN_RISK_OF_EXPIRATION';
lot.classKey = 'bg-warning text-warning';
totals.at_risk.value += lot.value;
totals.at_risk.quantity += lot.mvt_quantity;
}
return found;
});

if (depotLots.length > 0) { // there are lots in this depot
let total = 0;
depotLots.forEach(lot => {
lot.value = lot.mvt_quantity * lot.unit_cost;
total += lot.value;
});

result[depotUuid] = {
rows : depotLots,
total,
depot_name : depotLots[0].depot_text,
};
}
return {
total,
rows,
depot_name : rows[0].depot_text,
};
});

const reportResult = await report.render({
dateFrom,
dateTo,
depot,
result,
depot, result : values, totals,
});

res.set(reportResult.headers).send(reportResult.report);
} catch (error) {
next(error);
Expand Down
Loading

0 comments on commit 8135d8a

Please sign in to comment.