Skip to content

Commit

Permalink
Merge #3724
Browse files Browse the repository at this point in the history
3724: (Report) Stock entry report r=jniles a=mbayopanda

This PR adds the stock entry report.

![image](https://user-images.githubusercontent.com/5445251/57624961-dc17e180-758a-11e9-87a8-d751ef0d866a.png)

Co-authored-by: mbayopanda <mbayopanda@gmail.com>
  • Loading branch information
bors[bot] and mbayopanda committed Jun 28, 2019
2 parents d2bc25a + 5f0dc18 commit b244207
Show file tree
Hide file tree
Showing 20 changed files with 742 additions and 13 deletions.
8 changes: 7 additions & 1 deletion client/src/i18n/en/report.json
Expand Up @@ -177,7 +177,13 @@
"INCLUDE_SERVICE_EXIT": "Include stock exit to service",
"INCLUDE_DEPOT_EXIT": "Include stock exit to other depots",
"INCLUDE_LOSS_EXIT": "Include stock loss",
"SHOW_DETAILS": "Show Details"
"SHOW_DETAILS": "Show Details",
"ENTRY_REPORT": "Stock Entry Report",
"ENTRY_REPORT_DESCRIPTION": "This report displays the different stock entries that took place in depots",
"INCLUDE_PURCHASE_ENTRY": "Include entries from purchases",
"INCLUDE_INTEGRATION_ENTRY": "Include entries from integrations",
"INCLUDE_DONATION_ENTRY": "Include entries from donation",
"INCLUDE_TRANSFER_ENTRY": "Include entries from transfers"
},
"UTIL": {
"CANCEL_PREVIEW": "Cancel Preview",
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/en/tree.json
Expand Up @@ -116,6 +116,7 @@
"STOCK_REPORT" : "[Stock] Inventories",
"STOCK_INVENTORY_REPORT" : "[Stock] Inventory Report",
"STOCK_EXIT_REPORT" : "[Stock] Exit Report",
"STOCK_ENTRY_REPORT":"[Stock] Entries Report",
"STOCK_LOTS" : "Stock Lots",
"STOCK_VALUE" : "[Stock] Stock value Report",
"STOCK_MOVEMENTS" : "Stock Movements",
Expand Down
8 changes: 7 additions & 1 deletion client/src/i18n/fr/report.json
Expand Up @@ -177,7 +177,13 @@
"INCLUDE_SERVICE_EXIT" : "Inclure les distributions vers les services",
"INCLUDE_DEPOT_EXIT" : "Inclure les distributions vers d'autres dépôts",
"INCLUDE_LOSS_EXIT" : "Inclure les pertes de stocks",
"SHOW_DETAILS" : "Afficher les details"
"SHOW_DETAILS" : "Afficher les details",
"ENTRY_REPORT": "Rapports des entrées de stocks",
"ENTRY_REPORT_DESCRIPTION": "Ce rapport affiche les différentes entrées de stock qui ont eu lieu dans les dépots",
"INCLUDE_PURCHASE_ENTRY": "Inclure les entrées en provenance des achats",
"INCLUDE_INTEGRATION_ENTRY": "Inclure les entrées en provenance des intégrations",
"INCLUDE_DONATION_ENTRY": "Inclure les entrées en provenance des donations",
"INCLUDE_TRANSFER_ENTRY": "Inclure les entrées en provenance des transferts"
},
"UTIL":{
"CANCEL_PREVIEW" : "Fermer l'Aperçu",
Expand Down
2 changes: 1 addition & 1 deletion client/src/i18n/fr/stock.json
Expand Up @@ -109,7 +109,7 @@
"TRANSFER_AVAILABLE" : "Disponible",
"RECEIPT" : {
"ADJUSTMENT" : "Ajustement",
"ENTRY_DEPOT" : "Entrée de Stock",
"ENTRY_DEPOT" : "Entrée en provenance d'autres dépots",
"ENTRY_DONATION" : "Entree de Stock - Donation",
"ENTRY_PURCHASE" : "Entree de Stock - Achat",
"ENTRY_INTEGRATION" : "Entree de Stock - Intégration",
Expand Down
3 changes: 2 additions & 1 deletion client/src/i18n/fr/tree.json
Expand Up @@ -115,7 +115,8 @@
"STOCK_INVENTORY":"Articles en stock",
"STOCK_REPORT": "[Stock] Articles en stock",
"STOCK_INVENTORY_REPORT":"[Stock] Fiche de stock",
"STOCK_EXIT_REPORT":"[Stock] Sortie des stocks",
"STOCK_EXIT_REPORT":"[Stock] Sorties des stocks",
"STOCK_ENTRY_REPORT":"[Stock] Entrées des stocks",
"STOCK_LOTS":"Lots en stock",
"STOCK_VALUE" : "[Stock] Valeur de stock",
"STOCK_MOVEMENTS":"Movements de stock",
Expand Down
@@ -0,0 +1,87 @@
angular.module('bhima.controllers')
.controller('stock_entryController', StockEntryConfigController);

StockEntryConfigController.$inject = [
'$sce', 'NotifyService', 'BaseReportService', 'AppCache', 'reportData', '$state',
'LanguageService',
];

function StockEntryConfigController($sce, Notify, SavedReports, AppCache, reportData, $state, Languages) {
const vm = this;
const cache = new AppCache('configure_stock_entry_report');
const reportUrl = 'reports/stock/entry';

// default values
vm.reportDetails = {
includePurchaseEntry : 1,
};
vm.previewGenerated = false;
vm.onEntryTypeChange = onEntryTypeChange;

// check cached configuration
checkCachedConfiguration();

// check checked entry type
onEntryTypeChange();

vm.onSelectDepot = depot => {
vm.reportDetails.depotUuid = depot.uuid;
};

vm.clear = key => {
delete vm[key];
};

vm.clearPreview = () => {
vm.previewGenerated = false;
vm.previewResult = null;
};

vm.preview = form => {
if (form.$invalid) {
return 0;
}

if (!vm.hasOneChecked) {
return 0;
}

// update cached configuration
cache.reportDetails = angular.copy(vm.reportDetails);
angular.extend(vm.reportDetails, { lang : Languages.key });

return SavedReports.requestPreview(reportUrl, reportData.id, angular.copy(vm.reportDetails))
.then((result) => {
vm.previewGenerated = true;
vm.previewResult = $sce.trustAsHtml(result);
})
.catch(Notify.handleError);
};

vm.requestSaveAs = function requestSaveAs() {
const options = {
url : reportUrl,
report : reportData,
reportOptions : angular.copy(vm.reportDetails),
};

return SavedReports.saveAsModal(options)
.then(() => {
$state.go('reportsBase.reportsArchive', { key : options.report.report_key });
})
.catch(Notify.handleError);
};

function checkCachedConfiguration() {
vm.reportDetails = angular.copy(cache.reportDetails || {});
}

function onEntryTypeChange() {
// be sure at least one checkbox is checked
const sum = vm.reportDetails.includePurchaseEntry
+ vm.reportDetails.includeIntegrationEntry
+ vm.reportDetails.includeDonationEntry
+ vm.reportDetails.includeTransferEntry;
vm.hasOneChecked = sum > 0;
}
}
92 changes: 92 additions & 0 deletions client/src/modules/reports/generate/stock_entry/stock_entry.html
@@ -0,0 +1,92 @@
<bh-report-preview
ng-if="ReportConfigCtrl.previewGenerated"
source-document="ReportConfigCtrl.previewResult"
on-clear-callback="ReportConfigCtrl.clearPreview()"
on-save-callback="ReportConfigCtrl.requestSaveAs()">
</bh-report-preview>

<div ng-show="!ReportConfigCtrl.previewGenerated">
<div class="row">
<div class="col-md-12">
<h3 translate>REPORT.STOCK.ENTRY_REPORT</h3>
<p class="text-info" translate>REPORT.STOCK.ENTRY_REPORT_DESCRIPTION</p>
</div>
</div>

<div class="row" style="margin-top : 10px">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<span translate>REPORT.UTIL.OPTIONS</span>
</div>

<div class="panel-body">

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

<!-- select depot -->
<bh-depot-select
depot-uuid="ReportConfigCtrl.reportDetails.depotUuid"
on-select-callback="ReportConfigCtrl.onSelectDepot(depot)"
required="true">
</bh-depot-select>

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

<!-- stock entry type -->
<div ng-class="{'has-error': ConfigForm.$submitted && !ReportConfigCtrl.hasOneChecked}">
<div class="checkbox">
<label>
<input type="checkbox" ng-true-value="1" ng-false-value="0" ng-change="ReportConfigCtrl.onEntryTypeChange()" ng-model="ReportConfigCtrl.reportDetails.includePurchaseEntry">
<span translate>REPORT.STOCK.INCLUDE_PURCHASE_ENTRY</span>
</label>
</div>

<div class="checkbox">
<label>
<input type="checkbox" ng-true-value="1" ng-false-value="0" ng-change="ReportConfigCtrl.onEntryTypeChange()" ng-model="ReportConfigCtrl.reportDetails.includeIntegrationEntry">
<span translate>REPORT.STOCK.INCLUDE_INTEGRATION_ENTRY</span>
</label>
</div>

<div class="checkbox">
<label>
<input type="checkbox" ng-true-value="1" ng-false-value="0" ng-change="ReportConfigCtrl.onEntryTypeChange()" ng-model="ReportConfigCtrl.reportDetails.includeDonationEntry">
<span translate>REPORT.STOCK.INCLUDE_DONATION_ENTRY</span>
</label>
</div>

<div class="checkbox">
<label>
<input type="checkbox" ng-true-value="1" ng-false-value="0" ng-change="ReportConfigCtrl.onEntryTypeChange()" ng-model="ReportConfigCtrl.reportDetails.includeTransferEntry">
<span translate>REPORT.STOCK.INCLUDE_TRANSFER_ENTRY</span>
</label>
</div>
<em ng-if="ConfigForm.$submitted && !ReportConfigCtrl.hasOneChecked" class="help-block" translate>STOCK.AT_LEAST_ONE_CHECKED</em>
</div>

<hr>

<div class="checkbox">
<label>
<input type="checkbox" ng-true-value="1" ng-false-value="0" ng-model="ReportConfigCtrl.reportDetails.showDetails">
<span translate>REPORT.STOCK.SHOW_DETAILS</span>
</label>
</div>

<!-- preview -->
<bh-loading-button loading-state="ConfigForm.$loading">
<span translate>REPORT.UTIL.PREVIEW</span>
</bh-loading-button>
</form>
</div>
</div>
</div>
</div>
</div>
1 change: 1 addition & 0 deletions client/src/modules/reports/reports.routes.js
Expand Up @@ -27,6 +27,7 @@ angular.module('bhima.routes')
'operating',
'patientStanding',
'stock_exit',
'stock_entry',
'stock_value',
'unpaid-invoice-payments',
'breakEven',
Expand Down
1 change: 1 addition & 0 deletions server/config/routes.js
Expand Up @@ -757,6 +757,7 @@ exports.configure = function configure(app) {

// stock reports API
app.get('/reports/stock/exit', stockReports.stockExitReport);
app.get('/reports/stock/entry', stockReports.stockEntryReport);
app.get('/reports/stock/lots', stockReports.stockLotsReport);
app.get('/reports/stock/movements', stockReports.stockMovementsReport);
app.get('/reports/stock/inventories', stockReports.stockInventoriesReport);
Expand Down
2 changes: 2 additions & 0 deletions server/controllers/stock/reports/common.js
Expand Up @@ -16,6 +16,7 @@ const STOCK_ADJUSTMENT_TEMPLATE = `${BASE_PATH}/stock_adjustment.receipt.handleb

// reports
const STOCK_EXIT_REPORT_TEMPLATE = `${BASE_PATH}/stock_exit.report.handlebars`;
const STOCK_ENTRY_REPORT_TEMPLATE = `${BASE_PATH}/stock_entry.report.handlebars`;
const STOCK_LOTS_REPORT_TEMPLATE = `${BASE_PATH}/stock_lots.report.handlebars`;
const STOCK_MOVEMENTS_REPORT_TEMPLATE = `${BASE_PATH}/stock_movements.report.handlebars`;
const STOCK_INVENTORIES_REPORT_TEMPLATE = `${BASE_PATH}/stock_inventories.report.handlebars`;
Expand Down Expand Up @@ -198,6 +199,7 @@ exports.STOCK_ENTRY_DONATION_TEMPLATE = STOCK_ENTRY_DONATION_TEMPLATE;
exports.STOCK_ADJUSTMENT_TEMPLATE = STOCK_ADJUSTMENT_TEMPLATE;

exports.STOCK_EXIT_REPORT_TEMPLATE = STOCK_EXIT_REPORT_TEMPLATE;
exports.STOCK_ENTRY_REPORT_TEMPLATE = STOCK_ENTRY_REPORT_TEMPLATE;
exports.STOCK_LOTS_REPORT_TEMPLATE = STOCK_LOTS_REPORT_TEMPLATE;
exports.STOCK_MOVEMENTS_REPORT_TEMPLATE = STOCK_MOVEMENTS_REPORT_TEMPLATE;
exports.STOCK_INVENTORY_REPORT_TEMPLATE = STOCK_INVENTORY_REPORT_TEMPLATE;
Expand Down
2 changes: 2 additions & 0 deletions server/controllers/stock/reports/index.js
Expand Up @@ -8,6 +8,7 @@
*/

const stockExitReport = require('./stock/exit_report');
const stockEntryReport = require('./stock/entry_report');
const stockLotsReport = require('./stock/lots_report');
const stockMovementsReport = require('./stock/movements_report');
const stockInventoriesReport = require('./stock/inventories_report');
Expand All @@ -26,6 +27,7 @@ const stockAssignReceipt = require('./stock/assign_receipt');

// expose to the api
exports.stockExitReport = stockExitReport;
exports.stockEntryReport = stockEntryReport;
exports.stockLotsReport = stockLotsReport;
exports.stockMovementsReport = stockMovementsReport;
exports.stockInventoriesReport = stockInventoriesReport;
Expand Down
38 changes: 38 additions & 0 deletions server/controllers/stock/reports/stock/entry/entryFromDonation.js
@@ -0,0 +1,38 @@
const db = require('../../../../../lib/db');

const IS_EXIT = 0;
const ENTRY_FROM_DONATION_ID = 6;

/**
* @function fetch
* @description fetch stock entry from donation
*/
function fetch(depotUuid, dateFrom, dateTo, showDetails) {
const sql = `
SELECT
i.code, i.text, iu.text AS unit_text, BUID(m.document_uuid) AS document_uuid,
SUM(m.quantity) as quantity, m.date, m.description,
u.display_name AS user_display_name,
dm.text AS document_reference, d.text AS depot_name
FROM stock_movement m
JOIN lot l ON l.uuid = m.lot_uuid
JOIN inventory i ON i.uuid = l.inventory_uuid
JOIN inventory_unit iu ON iu.id = i.unit_id
JOIN depot d ON d.uuid = m.depot_uuid
JOIN user u ON u.id = m.user_id
LEFT JOIN document_map dm ON dm.uuid = m.document_uuid
WHERE m.is_exit = ${IS_EXIT} AND m.flux_id = ${ENTRY_FROM_DONATION_ID} AND d.uuid = ?
AND (DATE(m.date) BETWEEN DATE(?) AND DATE(?))
GROUP BY i.uuid`;

const groupBy = ', m.uuid';
const orderBy = ' ORDER BY i.text, m.date ASC';
const query = showDetails ? sql.concat(groupBy, orderBy) : sql.concat(orderBy);

const _depotUuid = db.bid(depotUuid);
const _dateFrom = new Date(dateFrom);
const _dateTo = new Date(dateTo);
return db.exec(query, [_depotUuid, _dateFrom, _dateTo]);
}

module.exports.fetch = fetch;
@@ -0,0 +1,38 @@
const db = require('../../../../../lib/db');

const IS_EXIT = 0;
const ENTRY_FROM_INTEGRATION_ID = 13;

/**
* @function fetch
* @description fetch stock entry from integration
*/
function fetch(depotUuid, dateFrom, dateTo, showDetails) {
const sql = `
SELECT
i.code, i.text, iu.text AS unit_text, BUID(m.document_uuid) AS document_uuid,
SUM(m.quantity) as quantity, m.date, m.description,
u.display_name AS user_display_name,
dm.text AS document_reference, d.text AS depot_name
FROM stock_movement m
JOIN lot l ON l.uuid = m.lot_uuid
JOIN inventory i ON i.uuid = l.inventory_uuid
JOIN inventory_unit iu ON iu.id = i.unit_id
JOIN depot d ON d.uuid = m.depot_uuid
JOIN user u ON u.id = m.user_id
LEFT JOIN document_map dm ON dm.uuid = m.document_uuid
WHERE m.is_exit = ${IS_EXIT} AND m.flux_id = ${ENTRY_FROM_INTEGRATION_ID} AND d.uuid = ?
AND (DATE(m.date) BETWEEN DATE(?) AND DATE(?))
GROUP BY i.uuid`;

const groupBy = ', m.uuid';
const orderBy = ' ORDER BY i.text, m.date ASC';
const query = showDetails ? sql.concat(groupBy, orderBy) : sql.concat(orderBy);

const _depotUuid = db.bid(depotUuid);
const _dateFrom = new Date(dateFrom);
const _dateTo = new Date(dateTo);
return db.exec(query, [_depotUuid, _dateFrom, _dateTo]);
}

module.exports.fetch = fetch;

0 comments on commit b244207

Please sign in to comment.