From d91bb89af066a62e10366f9846b8a382620df60a Mon Sep 17 00:00:00 2001 From: kndone Date: Wed, 29 Nov 2023 17:00:51 +0800 Subject: [PATCH] docs: schedules and app boilerplate --- index.js | 13 ++------- src/app.js | 9 ++++++ .../{conversions => decimal}/parseDecimal.js | 2 +- src/modules/decimal/round2.js | 18 ++++++++++++ src/routes/deposit-ledgers.js | 2 +- src/schedules/agenda.js | 16 +++++++++- src/schedules/jobs/deposit-interests.js | 29 +++++++++---------- src/schedules/jobs/index.js | 8 +++++ src/schedules/jobs/loan-due-dates.js | 11 +++++++ src/schedules/jobs/loan-interests.js | 27 ++++++++--------- 10 files changed, 91 insertions(+), 44 deletions(-) rename src/modules/{conversions => decimal}/parseDecimal.js (95%) create mode 100644 src/modules/decimal/round2.js diff --git a/index.js b/index.js index 5794a9f..b7b3d70 100644 --- a/index.js +++ b/index.js @@ -3,29 +3,25 @@ /** * Module dependencies. */ - import app from './src/app.js' import http from 'http' import debugLogger from 'debug' const debug = debugLogger('unboundmnl-area2-server:server') /** - * Get port from environment and store in Express. + * Port for Express application. Obtained from environment variable PORT, with a default value of 3000. */ - const port = normalizePort(process.env.PORT || '3000') app.set('port', port) /** - * Create HTTP server. + * HTTP server where the application runs on. */ - const server = http.createServer(app) -/** +/* * Listen on provided port, on all network interfaces. */ - server.listen(port) server.on('error', onError) server.on('listening', onListening) @@ -33,7 +29,6 @@ server.on('listening', onListening) /** * Normalize a port into a number, string, or false. */ - function normalizePort(val) { var port = parseInt(val, 10) @@ -53,7 +48,6 @@ function normalizePort(val) { /** * Event listener for HTTP server "error" event. */ - function onError(error) { if (error.syscall !== 'listen') { throw error @@ -79,7 +73,6 @@ function onError(error) { /** * Event listener for HTTP server "listening" event. */ - function onListening() { var addr = server.address() var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port diff --git a/src/app.js b/src/app.js index 3f77593..1c8a90e 100644 --- a/src/app.js +++ b/src/app.js @@ -1,3 +1,8 @@ +/** + * Module for setting up the Express application + * @module app + */ + // Packages import createError from 'http-errors' import express from 'express' @@ -26,6 +31,10 @@ import loansRouter from './routes/loans.js' import depositsRouter from './routes/deposits.js' import settingsRouter from './routes/settings.js' +/** + * Express app + * @object {express.Express} + */ const app = express() // Configure CORS diff --git a/src/modules/conversions/parseDecimal.js b/src/modules/decimal/parseDecimal.js similarity index 95% rename from src/modules/conversions/parseDecimal.js rename to src/modules/decimal/parseDecimal.js index 294b137..c60a059 100644 --- a/src/modules/conversions/parseDecimal.js +++ b/src/modules/decimal/parseDecimal.js @@ -1,5 +1,5 @@ /** - * @module modules/conversions/parseDecimal + * @module modules/decimal/parseDecimal * @export parseDecimal */ diff --git a/src/modules/decimal/round2.js b/src/modules/decimal/round2.js new file mode 100644 index 0000000..52e63e2 --- /dev/null +++ b/src/modules/decimal/round2.js @@ -0,0 +1,18 @@ +/** + * @module modules/decimal/round2 + * @export round2 + * @requires decimal.js + */ + +/** + * Rounds off a decimal.js decimal to 2 places. + * Used for financial calculations. + * + * @param {decimal.Decimal} decimal - The decimal instance to round off. + * @return The input decimal rounded off to 2 decimal places + */ +const round2 = function (decimal) { + return decimal.mul('100').round().mul('0.01') +} + +export default round2 diff --git a/src/routes/deposit-ledgers.js b/src/routes/deposit-ledgers.js index 86cfd11..0e698a3 100644 --- a/src/routes/deposit-ledgers.js +++ b/src/routes/deposit-ledgers.js @@ -18,7 +18,7 @@ const router = Router() // Models import Deposit from '../models/deposit.js' -import parseDecimal from '../modules/conversions/parseDecimal.js' +import parseDecimal from '../modules/decimal/parseDecimal.js' // Routes diff --git a/src/schedules/agenda.js b/src/schedules/agenda.js index 448bac6..7ec3035 100644 --- a/src/schedules/agenda.js +++ b/src/schedules/agenda.js @@ -1,10 +1,18 @@ +/** + * Configure Agenda instance for managing jobs. + * @module schedules/agenda + */ + // Packages import { Agenda } from '@hokify/agenda' // Default MongoDB URI import { DEFAULT_MONGODB_URI } from '../db/default_uri.js' -// Configure Agenda +/** + * Configured Agenda instance. + * @object {agenda.Agenda} + */ const agenda = new Agenda({ ensureIndex: true, processEvery: '10 minutes', @@ -19,6 +27,9 @@ import jobs from './jobs/index.js' // Define jobs for (const jobInfo of Object.values(jobs)) agenda.define(jobInfo.name, jobInfo.handler) +/** + * Graceful stop function for Agenda jobs. Called when receiving signals SIGTERM or SIGINT + */ const graceful = async () => { await agenda.stop() process.exit(0) @@ -27,6 +38,9 @@ const graceful = async () => { process.on('SIGTERM', graceful) process.on('SIGINT', graceful) +/** + * Start Agenda jobs. Called when loading module. + */ async function start() { await agenda.start() for (const jobInfo of Object.values(jobs)) diff --git a/src/schedules/jobs/deposit-interests.js b/src/schedules/jobs/deposit-interests.js index 5e15906..2944e18 100644 --- a/src/schedules/jobs/deposit-interests.js +++ b/src/schedules/jobs/deposit-interests.js @@ -1,3 +1,8 @@ +/** + * Module implementing an Agenda job for regular calculation of deposit interests. + * @module schedules/jobs/deposit-interests + */ + import Deposit from '../../models/deposit.js' import DepositSettings from '../../models/depositSettings.js' import Decimal from 'decimal.js' @@ -5,8 +10,15 @@ import Decimal from 'decimal.js' import moment from 'moment' moment().format() +import parseDecimal from '../../modules/decimal/parseDecimal.js' +import round2 from '../../modules/decimal/round2.js' + const name = 'process-deposit-interests' +/** + * Handler that updates every deposit's interests on callback. + * Updates every deposit that is active and currently due for interest. + */ const handler = async (job, done) => { console.log('Updating deposit interests...') @@ -76,7 +88,7 @@ const handler = async (job, done) => { } } - const ret = await Deposit.updateOne({ depositID: deposit.depositID }, query, { + await Deposit.updateOne({ depositID: deposit.depositID }, query, { runValidators: true }) } @@ -86,21 +98,6 @@ const handler = async (job, done) => { done() } -// https://stackoverflow.com/questions/53369688/extract-decimal-from-decimal128-with-mongoose-mongodb -const parseDecimal = (v, i, prev) => { - if (v !== null && typeof v === 'object') { - if (v.constructor.name === 'Decimal128') prev[i] = parseFloat(v.toString()) - else - Object.entries(v).forEach(([key, value]) => - parseDecimal(value, key, prev ? prev[i] : v) - ) - } -} - -const round2 = function (decimal) { - return decimal.mul('100').round().mul('0.01') -} - const every = '0 1 * * *' // Every 1:00 AM (to avoid desync problems with date checks) // const every = '5 seconds' export default { name, handler, every } diff --git a/src/schedules/jobs/index.js b/src/schedules/jobs/index.js index c6b9323..c16f5d3 100644 --- a/src/schedules/jobs/index.js +++ b/src/schedules/jobs/index.js @@ -1,3 +1,11 @@ +/** + * Index for Agenda jobs + * @module schedules/jobs/index + * @exports loanInterests + * @exports loanDueDates + * @exports depositInterests + */ + import loanInterests from './loan-interests.js' import loanDueDates from './loan-due-dates.js' import depositInterests from './deposit-interests.js' diff --git a/src/schedules/jobs/loan-due-dates.js b/src/schedules/jobs/loan-due-dates.js index beb783f..b7c4f02 100644 --- a/src/schedules/jobs/loan-due-dates.js +++ b/src/schedules/jobs/loan-due-dates.js @@ -1,8 +1,19 @@ +/** + * Module implementing Agenda jobs for managing loan payment due dates. + * @module schedules/jobs/loan-due-dates + */ + // Schema import Loan from '../../models/loan.js' const name = 'extend-loan-due-dates' +/** + * Handler that updates all loans' due dates on callback. + * If a loan is paid for the current loan period, and the current date is beyond + * the due date, updates the due date based on the loan's payment frequency and + * re-flags it as unpaid for this loan period. + */ const handler = async (job, done) => { const loans = await Loan.find({ dueDate: { $lt: new Date() } }).lean() diff --git a/src/schedules/jobs/loan-interests.js b/src/schedules/jobs/loan-interests.js index bf6baf8..65fd373 100644 --- a/src/schedules/jobs/loan-interests.js +++ b/src/schedules/jobs/loan-interests.js @@ -1,3 +1,8 @@ +/** + * Module implementing an Agenda job for regular calculation of loan interests. + * @module schedules/jobs/loan-interests + */ + import Loan from '../../models/loan.js' import LoanSettings from '../../models/loanSettings.js' import Decimal from 'decimal.js' @@ -5,8 +10,15 @@ import Decimal from 'decimal.js' import moment from 'moment' moment().format() +import parseDecimal from '../../modules/decimal/parseDecimal.js' +import round2 from '../../modules/decimal/round2.js' + const name = 'process-loan-interests' +/** + * Handler that updates every loan's interests on callback. + * Updates every loan that is active and currently due for interest. + */ const handler = async (job, done) => { console.log('Updating loan interests...') @@ -86,21 +98,6 @@ const handler = async (job, done) => { done() } -// https://stackoverflow.com/questions/53369688/extract-decimal-from-decimal128-with-mongoose-mongodb -const parseDecimal = (v, i, prev) => { - if (v !== null && typeof v === 'object') { - if (v.constructor.name === 'Decimal128') prev[i] = parseFloat(v.toString()) - else - Object.entries(v).forEach(([key, value]) => - parseDecimal(value, key, prev ? prev[i] : v) - ) - } -} - -const round2 = function (decimal) { - return decimal.mul('100').round().mul('0.01') -} - const every = '0 1 * * *' // Every 1:00 AM (to avoid desync problems with date checks) // const every = '5 seconds' export default { name, handler, every }