Skip to content

Commit

Permalink
fix(reports): improve invoiced vs distributed
Browse files Browse the repository at this point in the history
This commit fixes report configuration page by making the patient a
required property.  Additionally, it removes the creative way the URL
was being stored to bring it in line with all other reports.  Finally,
it rewrites the server portion to use async/await and ensure better
error handling.

Closes #6613.
  • Loading branch information
jniles committed May 27, 2022
1 parent 2740a86 commit 2166f9d
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 164 deletions.
1 change: 0 additions & 1 deletion client/src/js/components/bhFindPatient.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ function FindPatientComponent(Patients, AppCache, Notify, Session, bhConstants,
.catch(Notify.handleError);
}


/**
* @method searchByReference
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ <h3 class="text-capitalize" translate>REPORT.COMPARE_INVOICED_RECEIVED.TITLE</h3
<!--select the Patient -->
<bh-find-patient
suppress-reset="false"
on-search-complete="ReportConfigCtrl.setPatient(patient)">
on-search-complete="ReportConfigCtrl.setPatient(patient)"
required="true">
</bh-find-patient>

<!-- Date interval -->
Expand All @@ -35,7 +36,7 @@ <h3 class="text-capitalize" translate>REPORT.COMPARE_INVOICED_RECEIVED.TITLE</h3
date-to="ReportConfigCtrl.reportDetails.dateTo"
required="true"
limit-min-fiscal>
</bh-date-interval>
</bh-date-interval>

<!--preview-->
<bh-loading-button loading-state="ConfigForm.$loading">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,15 @@ function invoicedeceivedStockController($state, $sce, Notify, AppCache, SavedRep

const vm = this;
const cache = new AppCache('configure_invoiced_received_stock');
const reportUrl = '/reports/finance/invoiced_received_stock/';
let baseReportUrl = '';
const reportUrl = 'reports/finance/invoiced_received_stock';

vm.reportDetails = {};
vm.reportDetails = { };

checkCachedConfiguration();

vm.requestSaveAs = function requestSaveAs() {
const options = {
url : baseReportUrl,
url : reportUrl,
report : reportData,
reportOptions : angular.copy(vm.reportDetails),
};
Expand All @@ -38,7 +37,7 @@ function invoicedeceivedStockController($state, $sce, Notify, AppCache, SavedRep

// set patient
vm.setPatient = function setPatient(patient) {
baseReportUrl = `${reportUrl}${patient.uuid}`;
vm.reportDetails.patientUuid = patient.uuid;
};

vm.preview = function preview(form) {
Expand All @@ -47,7 +46,7 @@ function invoicedeceivedStockController($state, $sce, Notify, AppCache, SavedRep
// update cached configuration
cache.reportDetails = angular.copy(vm.reportDetails);

return SavedReports.requestPreview(baseReportUrl, reportData.id, angular.copy(vm.reportDetails))
return SavedReports.requestPreview(reportUrl, reportData.id, angular.copy(vm.reportDetails))
.then(result => {
vm.previewGenerated = true;
vm.previewResult = $sce.trustAsHtml(result);
Expand Down
2 changes: 1 addition & 1 deletion server/config/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ exports.configure = function configure(app) {
app.get('/reports/finance/client_support', clientSupport.report);
app.get('/reports/finance/realized_profit', realizedProfit.report);
app.get('/reports/finance/recovery_capacity', recoveryCapacity.report);
app.get('/reports/finance/invoiced_received_stock/:uuid', financeReports.invoicedReceivedStock.report);
app.get('/reports/finance/invoiced_received_stock', financeReports.invoicedReceivedStock.report);

app.get('/reports/finance/system_usage_stat', systemUsage.document);

Expand Down
290 changes: 140 additions & 150 deletions server/controllers/finance/reports/invoiced_received_stock/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const ReportManager = require('../../../../lib/ReportManager');
const Patients = require('../../../medical/patients');

const TEMPLATE = './server/controllers/finance/reports/invoiced_received_stock/report.handlebars';

// expose to the API
exports.report = report;

Expand All @@ -21,161 +22,150 @@ const DEFAULT_PARAMS = {
* This report makes it possible to attach the items billed to a patient on
* the articulated items consumed or distributed to the Patient.
*/
function report(req, res, next) {
const params = req.query;
const patientUuid = req.params.uuid;

const data = {};
let reporting;

params.dateFrom = new Date(params.dateFrom);
params.dateTo = new Date(params.dateTo);

data.period = {
dateFrom : params.dateFrom,
dateTo : params.dateTo,
};

const sqlInvoice = `
SELECT iv.uuid, map.text, iv.date
FROM invoice AS iv
JOIN debtor AS d ON d.uuid = iv.debtor_uuid
JOIN patient AS p ON p.debtor_uuid = d.uuid
JOIN document_map AS map ON map.uuid = iv.uuid
WHERE p.uuid = ? AND (DATE(iv.date) >= DATE(?) AND DATE(iv.date) <= DATE(?))
ORDER BY iv.date DESC
`;

const sqlInvoicedDistributed = `
SELECT aggr.reference, BUID(aggr.inventory_uuid) AS inventory_uuid, aggr.inventory_text,
SUM(aggr.quantity) AS quantity_invoiced, aggr.price_invoiced,
BUID(aggr.invoice_uuid) AS invoice_uuid, aggr.invoice_date,
SUM(aggr.quantity_distributed) AS quantity_distributed, SUM(aggr.cost_distributed) AS cost_distributed
FROM (
SELECT map.text AS reference, inv.uuid AS inventory_uuid, inv.text AS inventory_text, item.quantity,
item.inventory_price AS price_invoiced,iv.uuid AS invoice_uuid, iv.date AS invoice_date, 0 AS quantity_distributed,
0 AS cost_distributed
FROM invoice_item AS item
JOIN inventory AS inv ON inv.uuid = item.inventory_uuid
JOIN invoice AS iv ON iv.uuid = item.invoice_uuid
JOIN document_map AS map ON map.uuid = iv.uuid
JOIN patient AS p ON p.debtor_uuid = iv.debtor_uuid
WHERE p.uuid = ? AND (DATE(iv.date) >= DATE(?) AND DATE(iv.date) <= DATE(?))
AND inv.consumable = 1
UNION
SELECT map.text AS reference, inv.uuid AS inventory_uuid, inv.text AS inventory_text,
0 AS quantity, 0 AS price_invoiced, sm.invoice_uuid, sm.date,
SUM(sm.quantity) AS quantity_distributed, sm.unit_cost AS cost_distributed
FROM stock_movement AS sm
JOIN patient AS p ON p.uuid = sm.entity_uuid
JOIN lot AS l ON l.uuid = sm.lot_uuid
JOIN inventory AS inv ON inv.uuid = l.inventory_uuid
JOIN invoice AS iv ON iv.uuid = sm.invoice_uuid
JOIN document_map AS map ON map.uuid = iv.uuid
WHERE sm.invoice_uuid IS NOT NULL AND
p.uuid = ? AND (DATE(sm.date) >= DATE(?) AND DATE(sm.date) <= DATE(?))
AND sm.is_exit = 1
GROUP BY inv.uuid, iv.uuid ) AS aggr
GROUP BY aggr.inventory_uuid, aggr.invoice_uuid
ORDER BY aggr.inventory_text ASC
`;

const sqlNoInvoiceAttributionAggregat = `
SELECT DISTINCT(mov.document_uuid) AS document_uuid, map.text AS document, mov.date
FROM patient AS p
JOIN stock_movement AS mov ON mov.entity_uuid = p.uuid
JOIN document_map AS map ON map.uuid = mov.document_uuid
WHERE p.uuid = ? AND (DATE(mov.date) >= DATE(?) AND DATE(mov.date) <= DATE(?)) AND mov.invoice_uuid IS NULL
ORDER BY mov.date DESC;
`;

const sqlNoInvoiceAttribution = `
SELECT BUID(p.uuid) AS patientUuid, mov.document_uuid, mov.quantity, mov.unit_cost, map.text AS document,
iv.text AS inventory_text, (mov.quantity * mov.unit_cost) AS total_cost, mov.date
FROM patient AS p
JOIN stock_movement AS mov ON mov.entity_uuid = p.uuid
JOIN lot AS l ON l.uuid = mov.lot_uuid
JOIN inventory AS iv ON iv.uuid = l.inventory_uuid
JOIN document_map AS map ON map.uuid = mov.document_uuid
WHERE p.uuid = ? AND (DATE(mov.date) >= DATE(?) AND DATE(mov.date) <= DATE(?))
AND mov.is_exit = 1 AND mov.invoice_uuid IS NULL
ORDER BY iv.text ASC;
`;

_.defaults(params, DEFAULT_PARAMS);

async function report(req, res, next) {
try {
reporting = new ReportManager(TEMPLATE, req.session, params);
} catch (e) {
next(e);
return;
}

const dbPromises = [
Patients.lookupPatient(patientUuid),
db.exec(sqlInvoice, [db.bid(patientUuid), params.dateFrom, params.dateTo]),
db.exec(sqlInvoicedDistributed, [db.bid(patientUuid), params.dateFrom, params.dateTo,
db.bid(patientUuid), params.dateFrom, params.dateTo]),
db.exec(sqlNoInvoiceAttributionAggregat, [db.bid(patientUuid), params.dateFrom, params.dateTo]),
db.exec(sqlNoInvoiceAttribution, [db.bid(patientUuid), params.dateFrom, params.dateTo]),
];

Promise.all(dbPromises)
.then(([patient, invoices, inventoriesInvoicedDistibuted,
noInvoiceAttributionAggregat, noInvoiceAttribution]) => {

_.extend(data, { patient });

invoices.forEach(invoice => {
invoice.inventories = [];
let totalInvoice = 0;
let totalDistribution = 0;

inventoriesInvoicedDistibuted.forEach(inventory => {
if (invoice.text === inventory.reference) {
inventory.quantity_invoiced = inventory.quantity_invoiced || '';
inventory.quantity_distributed = inventory.quantity_distributed || '';
inventory.total_item_invoiced = inventory.quantity_invoiced * inventory.price_invoiced;
inventory.total_item_distributed = inventory.quantity_distributed * inventory.cost_distributed;

inventory.quantity_difference = inventory.quantity_invoiced - inventory.quantity_distributed;
inventory.cost_difference = inventory.total_item_invoiced - inventory.total_item_distributed;

totalInvoice += inventory.total_item_invoiced;
totalDistribution += inventory.total_item_distributed;

invoice.inventories.push(inventory);
}
invoice.total_invoice = totalInvoice;
invoice.total_distribution = totalDistribution;
invoice.difference = totalInvoice - totalDistribution;
});

invoice.emptyInvoice = (invoice.inventories.length === 0);
const { patientUuid } = req.query;
const dateFrom = new Date(req.query.dateFrom);
const dateTo = new Date(req.query.dateTo);

const data = { period : { dateFrom, dateTo } };

const sqlInvoice = `
SELECT iv.uuid, map.text, iv.date
FROM invoice AS iv
JOIN debtor AS d ON d.uuid = iv.debtor_uuid
JOIN patient AS p ON p.debtor_uuid = d.uuid
JOIN document_map AS map ON map.uuid = iv.uuid
WHERE p.uuid = ? AND (DATE(iv.date) >= DATE(?) AND DATE(iv.date) <= DATE(?))
ORDER BY iv.date DESC
`;

const sqlInvoicedDistributed = `
SELECT aggr.reference, BUID(aggr.inventory_uuid) AS inventory_uuid, aggr.inventory_text,
SUM(aggr.quantity) AS quantity_invoiced, aggr.price_invoiced,
BUID(aggr.invoice_uuid) AS invoice_uuid, aggr.invoice_date,
SUM(aggr.quantity_distributed) AS quantity_distributed, SUM(aggr.cost_distributed) AS cost_distributed
FROM (
SELECT map.text AS reference, inv.uuid AS inventory_uuid, inv.text AS inventory_text, item.quantity,
item.inventory_price AS price_invoiced,
iv.uuid AS invoice_uuid, iv.date AS invoice_date,
0 AS quantity_distributed,
0 AS cost_distributed
FROM invoice_item AS item
JOIN inventory AS inv ON inv.uuid = item.inventory_uuid
JOIN invoice AS iv ON iv.uuid = item.invoice_uuid
JOIN document_map AS map ON map.uuid = iv.uuid
JOIN patient AS p ON p.debtor_uuid = iv.debtor_uuid
WHERE p.uuid = ? AND (DATE(iv.date) >= DATE(?) AND DATE(iv.date) <= DATE(?))
AND inv.consumable = 1
UNION ALL
SELECT map.text AS reference, inv.uuid AS inventory_uuid, inv.text AS inventory_text,
0 AS quantity, 0 AS price_invoiced, sm.invoice_uuid, sm.date,
SUM(sm.quantity) AS quantity_distributed, sm.unit_cost AS cost_distributed
FROM stock_movement AS sm
JOIN patient AS p ON p.uuid = sm.entity_uuid
JOIN lot AS l ON l.uuid = sm.lot_uuid
JOIN inventory AS inv ON inv.uuid = l.inventory_uuid
JOIN invoice AS iv ON iv.uuid = sm.invoice_uuid
JOIN document_map AS map ON map.uuid = iv.uuid
WHERE sm.invoice_uuid IS NOT NULL AND
p.uuid = ? AND (DATE(sm.date) >= DATE(?) AND DATE(sm.date) <= DATE(?))
AND sm.is_exit = 1
GROUP BY inv.uuid, iv.uuid
) AS aggr
GROUP BY aggr.inventory_uuid, aggr.invoice_uuid
ORDER BY aggr.inventory_text ASC
`;

const sqlNoInvoiceAttributionAggregat = `
SELECT DISTINCT(mov.document_uuid) AS document_uuid, map.text AS document, mov.date
FROM patient AS p
JOIN stock_movement AS mov ON mov.entity_uuid = p.uuid
JOIN document_map AS map ON map.uuid = mov.document_uuid
WHERE p.uuid = ? AND (DATE(mov.date) >= DATE(?) AND DATE(mov.date) <= DATE(?)) AND mov.invoice_uuid IS NULL
ORDER BY mov.date DESC;
`;

const sqlNoInvoiceAttribution = `
SELECT
BUID(p.uuid) AS patientUuid, mov.document_uuid, mov.quantity, mov.unit_cost, map.text AS document,
iv.text AS inventory_text, (mov.quantity * mov.unit_cost) AS total_cost, mov.date
FROM patient AS p
JOIN stock_movement AS mov ON mov.entity_uuid = p.uuid
JOIN lot AS l ON l.uuid = mov.lot_uuid
JOIN inventory AS iv ON iv.uuid = l.inventory_uuid
JOIN document_map AS map ON map.uuid = mov.document_uuid
WHERE p.uuid = ? AND (DATE(mov.date) >= DATE(?) AND DATE(mov.date) <= DATE(?))
AND mov.is_exit = 1 AND mov.invoice_uuid IS NULL
ORDER BY iv.text ASC;
`;

_.defaults(req.query, DEFAULT_PARAMS);

const reporting = new ReportManager(TEMPLATE, req.session, req.query);
const patientBinaryUuid = db.bid(patientUuid);

const [
patient, invoices, inventoriesInvoicedDistibuted, noInvoiceAttributionAggregat, noInvoiceAttribution,
] = await Promise.all([
Patients.lookupPatient(patientUuid),
db.exec(sqlInvoice, [patientBinaryUuid, dateFrom, dateTo]),
db.exec(sqlInvoicedDistributed, [patientBinaryUuid, dateFrom, dateTo, patientBinaryUuid, dateFrom, dateTo]),
db.exec(sqlNoInvoiceAttributionAggregat, [patientBinaryUuid, dateFrom, dateTo]),
db.exec(sqlNoInvoiceAttribution, [patientBinaryUuid, dateFrom, dateTo]),
]);

_.extend(data, { patient });

invoices.forEach(invoice => {
invoice.inventories = [];
let totalInvoice = 0;
let totalDistribution = 0;

inventoriesInvoicedDistibuted.forEach(inventory => {
if (invoice.text === inventory.reference) {
inventory.quantity_invoiced = inventory.quantity_invoiced || '';
inventory.quantity_distributed = inventory.quantity_distributed || '';
inventory.total_item_invoiced = inventory.quantity_invoiced * inventory.price_invoiced;
inventory.total_item_distributed = inventory.quantity_distributed * inventory.cost_distributed;

inventory.quantity_difference = inventory.quantity_invoiced - inventory.quantity_distributed;
inventory.cost_difference = inventory.total_item_invoiced - inventory.total_item_distributed;

totalInvoice += inventory.total_item_invoiced;
totalDistribution += inventory.total_item_distributed;

invoice.inventories.push(inventory);
}

invoice.total_invoice = totalInvoice;
invoice.total_distribution = totalDistribution;
invoice.difference = totalInvoice - totalDistribution;
});

noInvoiceAttributionAggregat.forEach(movement => {
movement.inventories = [];
movement.total_movement = 0;
noInvoiceAttribution.forEach(inventory => {
if (movement.document === inventory.document) {
movement.inventories.push(inventory);
movement.total_movement += inventory.total_cost;
}
});
invoice.emptyInvoice = (invoice.inventories.length === 0);
});

noInvoiceAttributionAggregat.forEach(movement => {
movement.inventories = [];
movement.total_movement = 0;
noInvoiceAttribution.forEach(inventory => {
if (movement.document === inventory.document) {
movement.inventories.push(inventory);
movement.total_movement += inventory.total_cost;
}
});
});

data.invoices = invoices.filter(item => {
return !item.emptyInvoice;
});
data.invoices = invoices.filter(item => !item.emptyInvoice);

data.noInvoiceAttributionAggregat = noInvoiceAttributionAggregat;
data.checkNoInvoiceAttribution = (noInvoiceAttribution.length > 0);

data.noInvoiceAttributionAggregat = noInvoiceAttributionAggregat;
data.checkNoInvoiceAttribution = (noInvoiceAttribution.length > 0);
const result = await reporting.render(data);

return reporting.render(data);
})
.then(result => {
res.set(result.headers).send(result.report);
})
.catch(next);
res.set(result.headers).send(result.report);
} catch (err) {
next(err);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,3 @@
</div>
</div>
</body>

3 changes: 0 additions & 3 deletions server/models/bhima.sql
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,6 @@ INSERT IGNORE INTO `report` (`report_key`, `title_key`) VALUES
('stock_value', 'TREE.STOCK_VALUE'),
('ohada_profit_loss', 'TREE.OHADA_RESULT_ACCOUNT'),
('income_expense_by_year', 'REPORT.PROFIT_AND_LOSS_BY_YEAR'),
-- ('cost_center', 'REPORT.COST_CENTER.TITLE'),
-- ('break_even', 'TREE.BREAK_EVEN_REPORT'),
-- ('break_even_cost_center', 'TREE.BREAK_EVEN_COST_CENTER_REPORT'),
('indicators_report', 'TREE.INDICATORS_REPORT'),
('visit_report', 'PATIENT_RECORDS.REPORT.VISITS'),
('stock_entry', 'REPORT.STOCK.ENTRY_REPORT'),
Expand Down

0 comments on commit 2166f9d

Please sign in to comment.