-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
3827: feat(report) debtor summary report r=lomamech a=jeremielodi closes #3826 Co-authored-by: jeremielodi <jeremielodi@gmail.com>
- Loading branch information
Showing
10 changed files
with
321 additions
and
3 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
65 changes: 65 additions & 0 deletions
65
client/src/modules/reports/generate/debtorSummary/debtorSummary.config.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,65 @@ | ||
angular.module('bhima.controllers') | ||
.controller('debtorSummaryController', DebtorSummaryController); | ||
|
||
DebtorSummaryController.$inject = [ | ||
'$sce', 'NotifyService', 'BaseReportService', | ||
'AppCache', 'reportData', '$state', | ||
]; | ||
|
||
function DebtorSummaryController($sce, Notify, SavedReports, AppCache, reportData, $state) { | ||
const vm = this; | ||
const cache = new AppCache('debtorSummary'); | ||
const reportUrl = 'reports/finance/debtorSummary'; | ||
|
||
vm.previewGenerated = false; | ||
vm.reportDetails = {}; | ||
|
||
vm.clearPreview = function clearPreview() { | ||
vm.previewGenerated = false; | ||
vm.previewResult = null; | ||
}; | ||
|
||
vm.onSelectDebtor = (debtorGroup) => { | ||
vm.reportDetails.group_uuid = debtorGroup.uuid; | ||
}; | ||
|
||
vm.preview = function preview(form) { | ||
if (form.$invalid) { | ||
Notify.danger('FORM.ERRORS.RECORD_ERROR'); | ||
return 0; | ||
} | ||
|
||
|
||
// update cached configuration | ||
cache.reportDetails = angular.copy(vm.reportDetails); | ||
|
||
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); | ||
}; | ||
|
||
checkCachedConfiguration(); | ||
|
||
function checkCachedConfiguration() { | ||
if (cache.reportDetails) { | ||
vm.reportDetails = angular.copy(cache.reportDetails); | ||
} | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
client/src/modules/reports/generate/debtorSummary/debtorSummary.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,49 @@ | ||
<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 class="text-capitalize" translate>REPORT.DEBTOR_SUMMARY.TITLE</h3> | ||
<p class="text-info" translate>REPORT.DEBTOR_SUMMARY.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> | ||
|
||
<!-- debtor group --> | ||
<bh-debtor-group-select | ||
required="true" | ||
debtor-group-uuid = "ReportConfigCtrl.reportDetails.group_uuid" | ||
on-select-callback = "ReportConfigCtrl.onSelectDebtor(debtorGroup)"> | ||
</bh-debtor-group-select> | ||
|
||
|
||
<!-- Date interval --> | ||
<bh-date-interval | ||
date-from="ReportConfigCtrl.reportDetails.dateFrom" | ||
date-to="ReportConfigCtrl.reportDetails.dateTo" | ||
required="true" | ||
limit-min-fiscal> | ||
</bh-date-interval> | ||
|
||
<bh-loading-button loading-state="ConfigForm.$loading"> | ||
<span translate>REPORT.UTIL.PREVIEW</span> | ||
</bh-loading-button> | ||
</form> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> |
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
67 changes: 67 additions & 0 deletions
67
server/controllers/finance/reports/debtors/summaryReport.handlebars
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,67 @@ | ||
{{> head title="REPORT.CLIENTS.TITLE"}} | ||
|
||
<body> | ||
<main class="container"> | ||
{{> header }} | ||
|
||
<h3 class="text-center text-capitalize"> | ||
<strong>{{translate "REPORT.DEBTOR_SUMMARY.TITLE"}}</strong> | ||
</h3> | ||
|
||
<h4 class="text-center text-capitalize"> | ||
{{ debtorGroup.name }} | ||
</h4> | ||
<h5 class="text-center"> | ||
<strong class="text-capitalize">{{date dateFrom "MMMM YYYY"}}</strong> | ||
- | ||
<strong class="text-capitalize">{{date dateTo "MMMM YYYY"}}</strong> | ||
</h4> | ||
|
||
<section> | ||
<table style="font-size:11px !important" class="table table-condensed table-report table-header-rotated table-bordered"> | ||
<thead> | ||
<tr class="text-capitalize text-center" style="background: #ddd"> | ||
<th>{{translate "FORM.LABELS.NO"}}</th> | ||
<th>{{translate "FORM.LABELS.DATE"}}</th> | ||
<th>{{translate "TABLE.COLUMNS.REFERENCE"}}</th> | ||
<th>{{translate "TABLE.COLUMNS.NAME"}}</th> | ||
<th>{{translate "FORM.LABELS.SERVICE"}}</th> | ||
{{#each ./inventoryGroups as | s |}} | ||
<th class="rotate-45" > | ||
<div><span style="padding-left:2px;">{{ s.name }}</span></div></th> | ||
|
||
{{/each}} | ||
<th class="rotate-45"><div><span style="padding-left:2px;">{{translate "FORM.LABELS.TOTAL"}}</span></div></th> | ||
|
||
</tr> | ||
</thead> | ||
<tbody> | ||
{{#each ./data as |invoice| }} | ||
<tr> | ||
<td>{{ add @index 1}}</td> | ||
<td>{{ date invoice.date "DD/MM/YYYY"}}</td> | ||
<td>{{ invoice.invRef}}</td> | ||
<td>{{ invoice.debtorName}}</td> | ||
<td>{{ invoice.serviceName}}</td> | ||
|
||
{{#each invoice.inventoryGroups as | amount |}} | ||
<th class="text-right">{{amount}}</th> | ||
{{/each}} | ||
<th class="text-right">{{currency invoice.total ../metadata.enterprise.currency_id}}</th> | ||
</tr> | ||
|
||
{{/each}} | ||
|
||
</tbody> | ||
|
||
<tfoot> | ||
<td colspan="5" class="text-right">{{ translate 'FORM.LABELS.TOTAL'}}</td> | ||
{{#each inventoryGroups as | s |}} | ||
<td class="text-right">{{ currency s.total ../metadata.enterprise.currency_id}}</td> | ||
{{/each}} | ||
<td>{{currency gobalSum ../metadata.enterprise.currency_id}}</td> | ||
</tfoot> | ||
</table> | ||
</section> | ||
</main> | ||
</body> |
112 changes: 112 additions & 0 deletions
112
server/controllers/finance/reports/debtors/summaryReport.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,112 @@ | ||
/** | ||
* @overview ./finance/reports/debtors/summaryReport.js | ||
* | ||
*/ | ||
|
||
const _ = require('lodash'); | ||
const ReportManager = require('../../../../lib/ReportManager'); | ||
const db = require('../../../../lib/db'); | ||
const util = require('../../../../lib/util'); | ||
|
||
module.exports.summaryReport = summaryReport; | ||
|
||
// path to the template to render | ||
const TEMPLATE = './server/controllers/finance/reports/debtors/summaryReport.handlebars'; | ||
|
||
const DEFAULT_OPTIONS = { | ||
csvKey : 'debtors', | ||
orientation : 'landscape', | ||
footerRight : '[page] / [toPage]', | ||
footerFontSize : '7', | ||
}; | ||
|
||
/** | ||
* @method summaryReport | ||
* | ||
* @description | ||
* The HTTP interface which actually creates the report. | ||
*/ | ||
async function summaryReport(req, res, next) { | ||
try { | ||
const qs = _.extend(req.query, DEFAULT_OPTIONS); | ||
const { dateFrom, dateTo } = req.query; | ||
const groupUuid = req.query.group_uuid; | ||
const metadata = _.clone(req.session); | ||
|
||
const report = new ReportManager(TEMPLATE, metadata, qs); | ||
|
||
const inventoryGroupMap = {}; | ||
const emptyArray = []; | ||
const inventoryGroupIndexMap = {}; | ||
let gobalSum = 0; | ||
|
||
const invoiceSql = ` | ||
SELECT BUID(i.uuid) AS invoice_uuid, i.date, dm.text AS invRef, ent.text AS debtorRef, | ||
d.text, SUM(it.transaction_price) AS amount, i.cost as total, BUID(i.debtor_uuid) AS debtor_uuid, | ||
invg.name as inventoryGroupName, BUID(invg.uuid) as inventoryGroupUuid, inv.text as inventoryName, i.service_id, | ||
s.name as serviceName | ||
FROM invoice i | ||
JOIN invoice_item it ON it.invoice_uuid = i.uuid | ||
JOIN inventory inv ON inv.uuid = it.inventory_uuid | ||
JOIN inventory_group invg ON invg.uuid = inv.group_uuid | ||
JOIN debtor d ON d.uuid = i.debtor_uuid | ||
JOIN debtor_group dg ON dg.uuid = d.group_uuid | ||
JOIN entity_map ent ON ent.uuid = d.uuid | ||
JOIN document_map dm ON dm.uuid = i.uuid | ||
JOIN service s ON s.id = i.service_id | ||
WHERE dg.uuid = ? AND (i.date BETWEEN ? AND ?) AND i.reversed = 0 | ||
GROUP BY invg.uuid, i.uuid | ||
ORDER BY i.date | ||
`; | ||
|
||
|
||
const inventoryGroupsSql = ` | ||
SELECT DISTINCT x.inventoryGroupUuid as id, x.inventoryGroupName as name | ||
FROM (${invoiceSql}) as x | ||
`; | ||
|
||
const debtorGroup = await db.one('SELECT name FROM debtor_group WHERE uuid=?', db.bid(groupUuid)); | ||
const inventoryGroups = await db.exec(inventoryGroupsSql, [db.bid(groupUuid), dateFrom, dateTo]); | ||
|
||
// initilisation | ||
inventoryGroups.forEach((s, index) => { | ||
inventoryGroupMap[s.id] = s; | ||
inventoryGroupMap[s.id].total = 0; | ||
emptyArray.push(null); | ||
inventoryGroupIndexMap[s.id] = index; | ||
}); | ||
|
||
// let get the list of invoices for this group | ||
const invoices = await db.exec(invoiceSql, [db.bid(groupUuid), dateFrom, dateTo]); | ||
|
||
const invoicesList = _.groupBy(invoices, 'invoice_uuid'); | ||
const data = []; | ||
// let loop each invoice attribute each invoice item to it inventoryGroup | ||
Object.keys(invoicesList).forEach(invKey => { | ||
const invItems = invoicesList[invKey]; | ||
const record = { inventoryGroups : _.clone(emptyArray) }; | ||
invItems.forEach(item => { | ||
record.date = item.date; | ||
record.invRef = item.invRef; | ||
record.debtorRef = item.debtorRef; | ||
record.total = item.total; | ||
record.debtorName = item.text; | ||
record.serviceName = item.serviceName; | ||
record.inventoryGroups[inventoryGroupIndexMap[item.inventoryGroupUuid]] = item.amount; | ||
inventoryGroupMap[item.inventoryGroupUuid].total += item.amount; | ||
}); | ||
data.push(record); | ||
}); | ||
|
||
data.forEach(record => { | ||
gobalSum += record.total; | ||
}); | ||
// then let render the report | ||
const result = await report.render({ | ||
debtorGroup, inventoryGroups, data, dateFrom, dateTo, gobalSum : util.roundDecimal(gobalSum, 2), | ||
}); | ||
res.set(result.headers).send(result.report); | ||
} catch (ex) { | ||
next(ex); | ||
} | ||
} |
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