-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New report for avg cost of meds per patient
- Loading branch information
Showing
14 changed files
with
395 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
client/src/modules/reports/generate/avg_med_costs_per_patient/avg_med_costs_per_patient.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<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.AVG_MED_COST_PER_PATIENT.TITLE</h3> | ||
<p class="text-info" translate>REPORT.AVG_MED_COST_PER_PATIENT.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="false"> | ||
<bh-clear on-clear="ReportConfigCtrl.clearDepot()"></bh-clear> | ||
</bh-depot-select> | ||
|
||
<!-- service --> | ||
<bh-service-select | ||
service-uuid="ReportConfigCtrl.reportDetails.serviceUuid" | ||
on-select-callback="ReportConfigCtrl.onSelectService(service)"> | ||
<bh-clear on-clear="ReportConfigCtrl.clearService()"></bh-clear> | ||
</bh-service-select> | ||
|
||
<!-- date interval --> | ||
<bh-date-interval | ||
date-from="ReportConfigCtrl.reportDetails.dateFrom" | ||
date-to="ReportConfigCtrl.reportDetails.dateTo" | ||
limit-min-fiscal | ||
required="true"> | ||
</bh-date-interval> | ||
|
||
<bh-currency-select | ||
currency-id="ReportConfigCtrl.reportDetails.currencyId" | ||
on-change="ReportConfigCtrl.onSelectCurrency(currency)" | ||
required="true"> | ||
</bh-currency-select> | ||
|
||
<!-- preview --> | ||
<bh-loading-button loading-state="ConfigForm.$loading"> | ||
<span translate>REPORT.UTIL.PREVIEW</span> | ||
</bh-loading-button> | ||
</form> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> |
96 changes: 96 additions & 0 deletions
96
client/src/modules/reports/generate/avg_med_costs_per_patient/avg_med_costs_per_patient.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
angular.module('bhima.controllers') | ||
.controller('avg_med_costs_per_patientController', AvgMedCostPerPatientCtrl); | ||
|
||
AvgMedCostPerPatientCtrl.$inject = [ | ||
'$sce', 'NotifyService', 'BaseReportService', 'AppCache', 'reportData', '$state', | ||
'LanguageService', 'SessionService', | ||
]; | ||
|
||
function AvgMedCostPerPatientCtrl($sce, Notify, SavedReports, AppCache, reportData, $state, Languages, Session) { | ||
const vm = this; | ||
const cache = new AppCache('avg_med_costs_per_patient'); | ||
const reportUrl = 'reports/stock/avg_med_costs_per_patient'; | ||
|
||
// default values for the report parameters | ||
vm.reportDetails = { | ||
}; | ||
|
||
vm.previewGenerated = false; | ||
|
||
// check cached configuration | ||
checkCachedConfiguration(); | ||
|
||
vm.onSelectDepot = depot => { | ||
vm.reportDetails.depotUuid = depot.uuid; | ||
vm.reportDetails.depotName = depot.text; | ||
}; | ||
|
||
vm.clearDepot = () => { | ||
delete vm.reportDetails.depotUuid; | ||
delete vm.reportDetails.depotName; | ||
}; | ||
|
||
vm.onSelectService = service => { | ||
vm.reportDetails.serviceUuid = service.uuid; | ||
vm.reportDetails.serviceName = service.name; | ||
}; | ||
|
||
vm.clearService = () => { | ||
delete vm.reportDetails.serviceUuid; | ||
delete vm.reportDetails.serviceName; | ||
}; | ||
|
||
vm.onSelectCurrency = currency => { | ||
vm.reportDetails.currencyId = currency.id; | ||
}; | ||
|
||
vm.clear = key => { | ||
delete vm.reportDetails[key]; | ||
}; | ||
|
||
vm.clearPreview = () => { | ||
vm.previewGenerated = false; | ||
vm.previewResult = null; | ||
}; | ||
|
||
vm.preview = form => { | ||
if (form.$invalid) { | ||
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 || {}); | ||
|
||
// Set the defaults | ||
if (!angular.isDefined(vm.reportDetails.currencyId)) { | ||
vm.reportDetails.currencyId = Session.enterprise.currency_id; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
server/controllers/stock/reports/stock/avg_med_costs_per_patient_report.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
const { | ||
_, ReportManager, | ||
STOCK_AVG_MED_COSTS_PER_PATIENT_TEMPLATE, | ||
db, | ||
} = require('../common'); | ||
|
||
const Exchange = require('../../../finance/exchange'); | ||
|
||
/** | ||
* @method stockAvgMedCostsPerPatientReport | ||
* | ||
* @description | ||
* Construct the report for average medication costs per patient | ||
* | ||
* GET /reports/stock/avg_med_costs_per_patient' | ||
*/ | ||
async function stockAvgMedCostsPerPatientReport(req, res, next) { | ||
let report; | ||
const options = req.query; | ||
const { | ||
dateFrom, dateTo, | ||
depotUuid, depotName, | ||
serviceUuid, serviceName, | ||
} = options; | ||
|
||
const reportOptions = _.extend({}, options, { | ||
filename : 'TREE.AVERAGE_MED_COST_REPORT', | ||
title : 'REPORT.AVG_MED_COST_PER_PATIENT.TITLE', | ||
}); | ||
|
||
const data = {}; | ||
|
||
const enterpriseId = req.session.enterprise.id; | ||
const exchangeRate = await Exchange.getExchangeRate(enterpriseId, options.currencyId, new Date()); | ||
const rate = exchangeRate.rate || 1; | ||
|
||
try { | ||
report = new ReportManager(STOCK_AVG_MED_COSTS_PER_PATIENT_TEMPLATE, req.session, reportOptions); | ||
} catch (e) { | ||
return next(e); | ||
} | ||
const depotSql = depotUuid ? `AND sm.depot_uuid = ?` : ''; | ||
const serviceSql = serviceUuid ? `AND inv.service_uuid = ?` : ''; | ||
|
||
const sql = ` | ||
SELECT | ||
smtot.depot_uuid, dep.text AS depot_name, | ||
smtot.service_uuid, srv.name AS service_name, | ||
smtot.srvTotal, smtot.srvPatCount, | ||
(smtot.srvTotal / smtot.srvPatCount) AS srvAvgCost, | ||
smtot.totalMedCosts, smtot.totalNumPatients, | ||
(smtot.totalMedCosts / smtot.totalNumPatients) AS avgMedCosts | ||
FROM ( | ||
SELECT | ||
sm.entity_uuid AS patient_uuid, | ||
sm.depot_uuid, | ||
inv.service_uuid, | ||
sm.unit_cost, | ||
sm.quantity, | ||
SUM(sm.quantity * sm.unit_cost) OVER (PARTITION BY sm.depot_uuid, inv.service_uuid) AS srvTotal, | ||
-- Computes: COUNT(DISTINCT sm.entity_uuid) OVER (PARTITION BY sm.depot_uuid, inv.service_uuid) | ||
(DENSE_RANK() OVER (PARTITION BY sm.depot_uuid, | ||
inv.service_uuid ORDER BY sm.entity_uuid ASC) + | ||
DENSE_RANK() OVER (PARTITION BY sm.depot_uuid, | ||
inv.service_uuid ORDER BY sm.entity_uuid DESC) - 1) AS srvPatCount, | ||
SUM(sm.quantity * sm.unit_cost) OVER () AS totalMedCosts, | ||
-- Computes: COUNT(DISTINCT sm.entity_uuid) OVER (PARTITION BY sm.entity_uuid) | ||
(DENSE_RANK() OVER (ORDER BY sm.entity_uuid ASC) + | ||
DENSE_RANK() OVER (ORDER BY sm.entity_uuid DESC) - 1) AS totalNumPatients | ||
FROM stock_movement AS sm | ||
JOIN patient AS pat ON pat.uuid = sm.entity_uuid | ||
LEFT JOIN invoice AS inv ON inv.uuid = sm.invoice_uuid | ||
WHERE | ||
sm.flux_id = 9 AND sm.is_exit = 1 | ||
AND DATE(sm.date) BETWEEN DATE(?) AND DATE(?) | ||
${depotSql} | ||
${serviceSql} | ||
) AS smtot | ||
JOIN depot AS dep ON dep.uuid = smtot.depot_uuid | ||
LEFT JOIN service AS srv ON srv.uuid = smtot.service_uuid | ||
GROUP BY smtot.depot_uuid, smtot.service_uuid | ||
ORDER BY dep.text, srv.name | ||
`; | ||
|
||
const params = [dateFrom, dateTo]; | ||
if (depotUuid) { | ||
params.push(db.bid(depotUuid)); | ||
} | ||
if (serviceUuid) { | ||
params.push(db.bid(serviceUuid)); | ||
} | ||
|
||
return db.exec(sql, params) | ||
.then((results) => { | ||
data.currencyId = Number(options.currencyId); | ||
data.dateFrom = dateFrom; | ||
data.dateTo = dateTo; | ||
data.depotName = depotName; | ||
data.serviceName = serviceName; | ||
data.depotOrService = depotUuid || serviceUuid; | ||
data.depotAndService = depotUuid && serviceUuid; | ||
|
||
results.forEach(row => { | ||
if (row.service_name === null) { | ||
row.service_name = 'INVENTORY.NONE'; | ||
} | ||
row.srvTotal *= rate; | ||
row.srvAvgCost *= rate; | ||
}); | ||
|
||
if (results.length > 0) { | ||
data.totalMedCosts = results[0].totalMedCosts * rate; | ||
data.totalNumPatients = results[0].totalNumPatients; | ||
data.avgMedCosts = results[0].avgMedCosts * rate; | ||
} | ||
|
||
data.rows = results; | ||
return report.render(data); | ||
}) | ||
.then((result) => { | ||
res.set(result.headers).send(result.report); | ||
}) | ||
.catch(next) | ||
.done(); | ||
} | ||
|
||
module.exports = stockAvgMedCostsPerPatientReport; |
Oops, something went wrong.