From 23ea31d78b2c57dc53851533f42de7954935798e Mon Sep 17 00:00:00 2001 From: Rizki Date: Wed, 11 Mar 2026 15:25:37 +0700 Subject: [PATCH] feat: add route dashboard --- adapter/dashboardadapter.js | 347 ++++++++++++++++++++++++++++++++++++ controllers/dashboard.js | 62 +++++++ routes/dashboard.js | 13 ++ 3 files changed, 422 insertions(+) create mode 100644 adapter/dashboardadapter.js create mode 100644 controllers/dashboard.js create mode 100644 routes/dashboard.js diff --git a/adapter/dashboardadapter.js b/adapter/dashboardadapter.js new file mode 100644 index 0000000..8771ba5 --- /dev/null +++ b/adapter/dashboardadapter.js @@ -0,0 +1,347 @@ +const db = require("../config/dbproc.js"); +const Adapter = require("./dbadapter.js"); +const libre = require("libreoffice-convert"); +libre.convertAsync = require("util").promisify(libre.convert); + +class DashboardAdapter extends Adapter { + constructor() { + super(); + } + + async queryDashboardSummary(req, callback) { + var apires = this.getApiResultDefined(); + + try { + let year = req.query.year || new Date().getFullYear(); + let startDate = year + "-01-01"; + let endDate = parseInt(year) + 1 + "-01-01"; + + let qry = ` + SELECT + ( + SELECT COALESCE(SUM(amount),0) + FROM tbl_requestbudget + WHERE isdeleted = 0 AND years = ? + ) AS total_requested_budget, + + ( + SELECT COALESCE(SUM(amount),0) + FROM tbl_budgetcapexinfo + WHERE isdeleted = 0 AND years = ? + ) AS total_remaining_budget, + + ( + SELECT COALESCE(SUM(amount),0) + FROM tbl_justification + WHERE isdeleted = 0 + AND idt >= ? + AND idt < ? + ) AS total_used_budget + `; + + db.query(qry, [year, year, startDate, endDate], (err, budgetResult) => { + if (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + return callback("err", apires); + } + + let budget = budgetResult[0]; + + budget.total_budget = + parseFloat(budget.total_remaining_budget) + parseFloat(budget.total_requested_budget); + + /* JUSTIFICATION */ + + let qryJustification = ` + SELECT + SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS total_approved, + SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS total_submitted, + SUM(CASE WHEN status = -1 THEN 1 ELSE 0 END) AS total_draft, + SUM(CASE WHEN status = 2 AND iscreatepr = 1 THEN 1 ELSE 0 END) AS total_created_pr + FROM tbl_justification + WHERE isdeleted = 0 + AND idt >= ? + AND idt < ? + `; + + db.query(qryJustification, [startDate, endDate], (err, justificationResult) => { + if (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + return callback("err", apires); + } + + /* PURCHASE REQUEST */ + + let qryPR = ` + SELECT + SUM(CASE WHEN status in (2,4,5,6,7) THEN 1 ELSE 0 END) AS total_approved, + SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS total_submitted + FROM tbl_pr + WHERE isdeleted = 0 + AND idt >= ? + AND idt < ? + `; + + db.query(qryPR, [startDate, endDate], (err, prResult) => { + if (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + return callback("err", apires); + } + + /* PURCHASE ORDER */ + + let qryPO = ` + SELECT + SUM(CASE WHEN status in (3,4,5,6,7) THEN 1 ELSE 0 END) AS total_approved, + SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS total_created, + SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS total_bast + FROM tbl_po + WHERE isdeleted = 0 + AND idt >= ? + AND idt < ? + `; + + db.query(qryPO, [startDate, endDate], (err, poResult) => { + if (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + return callback("err", apires); + } + + /* BAST */ + + let qryBast = ` + SELECT + SUM(CASE WHEN (status = 1 and filehandoversign is NOT NULL) THEN 1 ELSE 0 END) AS total_approved_handover, + SUM(CASE WHEN (status = 1 and filehandoversign is NULL) THEN 1 ELSE 0 END) AS total_handovered, + SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS total_submitted + FROM tbl_bast + WHERE isdeleted = 0 + AND idt >= ? + AND idt < ? + `; + + db.query(qryBast, [startDate, endDate], (err, bastResult) => { + if (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + return callback("err", apires); + } + + apires.success = true; + + apires.data = { + year: year, + budget: budget, + justification: justificationResult[0], + purchase_request: prResult[0], + purchase_order: poResult[0], + bast: bastResult[0], + }; + + callback(null, apires); + }); + }); + }); + }); + }); + } catch (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + callback("error", apires); + } + } + + async queryBudgetLineChart(req, callback) { + var apires = this.getApiResultDefined(); + + try { + let year = req.query.year || new Date().getFullYear(); + + let qry = ` + SELECT + SUM(amount) as used_budget, + MONTH(idt) as month + FROM tbl_justification + WHERE isdeleted=0 + AND YEAR(idt)=? + GROUP BY MONTH(idt) + `; + + db.query(qry, [year], function (err, result) { + if (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + return callback("err", apires); + } + + let months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + let used = new Array(12).fill(0); + + result.forEach((r) => { + used[r.month - 1] = r.used_budget; + }); + + apires.success = true; + apires.data = { + year: year, + months: months, + series: [ + { + name: "Used Budget", + data: used, + }, + ], + }; + + callback(null, apires); + }); + } catch (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + callback("error", apires); + } + } + + async queryProcurementStackedChart(req, callback) { + var apires = this.getApiResultDefined(); + + try { + let year = req.query.year || new Date().getFullYear(); + let start = year + "-01-01"; + let end = parseInt(year) + 1 + "-01-01"; + + let months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + + let justification = new Array(12).fill(0); + let pr = new Array(12).fill(0); + let po = new Array(12).fill(0); + let bast = new Array(12).fill(0); + + let qry = ` + SELECT MONTH(idt) as month, COUNT(*) total + FROM tbl_justification + WHERE isdeleted=0 + AND idt>=? AND idt { + justification[r.month - 1] = r.total; + }); + + apires.success = true; + apires.data = { + year: year, + months: months, + series: [ + {name: "Justification", data: justification}, + {name: "PR", data: pr}, + {name: "PO", data: po}, + {name: "BAST", data: bast}, + ], + }; + + callback(null, apires); + }); + } catch (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + callback("error", apires); + } + } + + async queryProcurementStackedChart(req, callback) { + var apires = this.getApiResultDefined(); + + try { + let year = req.query.year || new Date().getFullYear(); + let start = year + "-01-01"; + let end = parseInt(year) + 1 + "-01-01"; + + let months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + + let justification = new Array(12).fill(0); + let pr = new Array(12).fill(0); + let po = new Array(12).fill(0); + let bast = new Array(12).fill(0); + + let qry = ` + SELECT MONTH(idt) as month, COUNT(*) total + FROM tbl_justification + WHERE isdeleted=0 + AND idt>=? AND idt { + justification[r.month - 1] = r.total; + }); + + apires.success = true; + apires.data = { + year: year, + months: months, + series: [ + {name: "Justification", data: justification}, + {name: "PR", data: pr}, + {name: "PO", data: po}, + {name: "BAST", data: bast}, + ], + }; + + callback(null, apires); + }); + } catch (err) { + apires.meta.code = 500; + apires.meta.message = err.toString(); + callback("error", apires); + } + } +} + +module.exports = DashboardAdapter; diff --git a/controllers/dashboard.js b/controllers/dashboard.js new file mode 100644 index 0000000..7c4fae4 --- /dev/null +++ b/controllers/dashboard.js @@ -0,0 +1,62 @@ +const DashboardAdapter = require("../adapter/dashboardAdapter.js"); +const dashboardAdapter = new DashboardAdapter(); +const Controllers = require("../controllers/controller.js"); +const controllers = new Controllers(); +var apireshandler = controllers.getApiResultDefined(); +// var docxConverter = require('docx-pdf'); + +exports.getDashboardSummary = (req, res) => { + try { + dashboardAdapter.queryDashboardSummary(req, function (err, data) { + let statusCode = data != null ? data.meta.code : 200; + if (err) statusCode = 500; + dashboardAdapter.sendResponse(statusCode, data, res); + }); + } catch (err) { + apireshandler.meta.code = 502; + apireshandler.meta.message = "[31] : Dashboard controller, " + err.toString(); + dashboardAdapter.sendResponse(502, apireshandler, res); + } +}; + +exports.getBudgetLineChart = (req, res) => { + try { + dashboardAdapter.queryBudgetLineChart(req, function (err, data) { + let statusCode = data != null ? data.meta.code : 200; + if (err) statusCode = 500; + dashboardAdapter.sendResponse(statusCode, data, res); + }); + } catch (err) { + apireshandler.meta.code = 502; + apireshandler.meta.message = "Dashboard controller error : " + err.toString(); + dashboardAdapter.sendResponse(502, apireshandler, res); + } +}; + +exports.getProcurementStackedChart = (req, res) => { + try { + dashboardAdapter.queryProcurementStackedChart(req, function (err, data) { + let statusCode = data != null ? data.meta.code : 200; + if (err) statusCode = 500; + dashboardAdapter.sendResponse(statusCode, data, res); + }); + } catch (err) { + apireshandler.meta.code = 502; + apireshandler.meta.message = "Dashboard controller error : " + err.toString(); + dashboardAdapter.sendResponse(502, apireshandler, res); + } +}; + +exports.getMonthlyBudgetUtilization = (req, res) => { + try { + dashboardAdapter.queryMonthlyBudgetUtilization(req, function (err, data) { + let statusCode = data != null ? data.meta.code : 200; + if (err) statusCode = 500; + dashboardAdapter.sendResponse(statusCode, data, res); + }); + } catch (err) { + apireshandler.meta.code = 502; + apireshandler.meta.message = "Dashboard controller error : " + err.toString(); + dashboardAdapter.sendResponse(502, apireshandler, res); + } +}; diff --git a/routes/dashboard.js b/routes/dashboard.js new file mode 100644 index 0000000..366d957 --- /dev/null +++ b/routes/dashboard.js @@ -0,0 +1,13 @@ +const express = require('express'); +// const { body } = require('express-validator'); +const dashboardController = require('../controllers/dashboard.js'); +const jwtauth = require('../middlewares/auth.js'); +const router=express.Router(); + +//=== POST & get METHOD +router.get('/summary',[jwtauth], dashboardController.getDashboardSummary); +router.get('/budget-line',dashboardController.getBudgetLineChart); +router.get('/procurement-chart',dashboardController.getProcurementStackedChart); +router.get('/budget-utilization',dashboardController.getMonthlyBudgetUtilization); + +module.exports = router;