From 82906b0133577bd4d5166e4942dad1db340ac315 Mon Sep 17 00:00:00 2001 From: Dan Gowans Date: Thu, 27 Jun 2024 15:09:31 -0400 Subject: [PATCH] include comments --- app.js | 24 ++++++ bin/www.js | 1 + bin/wwwProcess.js | 11 +++ cypress/e2e/02-update/maps.cy.js | 2 + cypress/support/index.js | 2 + data/config.defaultValues.js | 2 + data/databasePaths.js | 1 + database/addLotOccupancyFee.js | 3 + database/cleanupDatabase.js | 73 +++++++++++++++++++ database/copyLotOccupancy.js | 6 ++ database/getLotOccupancyComments.js | 4 +- database/getNextWorkOrderNumber.js | 8 +- database/getOccupancyTypePrints.js | 5 +- database/getReportData.js | 3 + database/getWorkOrderMilestones.js | 5 ++ gulpfile.js | 18 ++++- handlers/api-get/milestoneICS.js | 21 ++++++ handlers/dashboard-get/dashboard.js | 4 +- .../doGetDynamicsGPDocument.js | 1 + helpers/functions.cache.js | 18 +++++ helpers/functions.dynamicsGP.js | 1 + helpers/functions.lots.js | 2 +- helpers/functions.print.js | 4 + helpers/initializer.database.cemetery.js | 29 ++++++++ helpers/initializer.database.js | 20 +++++ routes/admin.js | 22 ++++++ routes/lotOccupancies.js | 8 ++ routes/lots.js | 6 ++ routes/workOrders.js | 9 +++ temp/legacy.importFromCSV.js | 38 ++++++++++ temp/legacy.importFromCsv.ids.js | 23 ++++++ temp/so.exportMaps.js | 2 + test/0_initializeDatabase.js | 1 + test/1_serverCypress.js | 2 + test/functions.js | 4 + tsconfig.json | 1 - windowsService-install.js | 4 + windowsService-uninstall.js | 4 + 38 files changed, 383 insertions(+), 9 deletions(-) diff --git a/app.js b/app.js index a4184174..43ba3d3f 100644 --- a/app.js +++ b/app.js @@ -27,13 +27,20 @@ import routerReports from './routes/reports.js'; import routerWorkOrders from './routes/workOrders.js'; import { version } from './version.js'; const debug = Debug(`lot-occupancy-system:app:${process.pid}`); +/* + * INITIALIZE THE DATABASE + */ initializeDatabase(); +/* + * INITIALIZE APP + */ const _dirname = '.'; export const app = express(); app.disable('X-Powered-By'); if (!configFunctions.getConfigProperty('reverseProxy.disableEtag')) { app.set('etag', false); } +// View engine setup app.set('views', path.join(_dirname, 'views')); app.set('view engine', 'ejs'); if (!configFunctions.getConfigProperty('reverseProxy.disableCompression')) { @@ -51,10 +58,16 @@ app.use(cookieParser()); app.use(csurf({ cookie: true })); +/* + * Rate Limiter + */ app.use(rateLimit({ windowMs: 10_000, max: useTestDatabases ? 1_000_000 : 200 })); +/* + * STATIC ROUTES + */ const urlPrefix = configFunctions.getConfigProperty('reverseProxy.urlPrefix'); if (urlPrefix !== '') { debug(`urlPrefix = ${urlPrefix}`); @@ -66,8 +79,12 @@ app.use(`${urlPrefix}/lib/cityssm-bulma-webapp-js`, express.static(path.join('no app.use(`${urlPrefix}/lib/fa`, express.static(path.join('node_modules', '@fortawesome', 'fontawesome-free'))); app.use(`${urlPrefix}/lib/leaflet`, express.static(path.join('node_modules', 'leaflet', 'dist'))); app.use(`${urlPrefix}/lib/randomcolor/randomColor.js`, express.static(path.join('node_modules', 'randomcolor', 'randomColor.js'))); +/* + * SESSION MANAGEMENT + */ const sessionCookieName = configFunctions.getConfigProperty('session.cookieName'); const FileStoreSession = FileStore(session); +// Initialize session app.use(session({ store: new FileStoreSession({ path: './data/sessions', @@ -84,6 +101,7 @@ app.use(session({ sameSite: 'strict' } })); +// Clear cookie if no corresponding session app.use((request, response, next) => { if (Object.hasOwn(request.cookies, sessionCookieName) && !Object.hasOwn(request.session, 'user')) { @@ -91,6 +109,7 @@ app.use((request, response, next) => { } next(); }); +// Redirect logged in users const sessionChecker = (request, response, next) => { if (Object.hasOwn(request.session, 'user') && Object.hasOwn(request.cookies, sessionCookieName)) { @@ -100,6 +119,10 @@ const sessionChecker = (request, response, next) => { const redirectUrl = getSafeRedirectURL(request.originalUrl); response.redirect(`${urlPrefix}/login?redirect=${encodeURIComponent(redirectUrl)}`); }; +/* + * ROUTES + */ +// Make the user and config objects available to the templates app.use((request, response, next) => { response.locals.buildNumber = version; response.locals.user = request.session.user; @@ -140,6 +163,7 @@ app.get(`${urlPrefix}/logout`, (request, response) => { response.redirect(`${urlPrefix}/login`); } }); +// Catch 404 and forward to error handler app.use((request, _response, next) => { debug(request.url); next(createError(404, `File not found: ${request.url}`)); diff --git a/bin/www.js b/bin/www.js index 450b4bc8..e6bb7457 100644 --- a/bin/www.js +++ b/bin/www.js @@ -68,6 +68,7 @@ if (process.env.STARTUP_TEST === 'true') { debug(`Killing processes in ${killSeconds} seconds...`); setTimeout(() => { debug('Killing processes'); + // eslint-disable-next-line n/no-process-exit, unicorn/no-process-exit process.exit(0); }, 10_000); } diff --git a/bin/wwwProcess.js b/bin/wwwProcess.js index 92668ecf..fbb41fb2 100644 --- a/bin/wwwProcess.js +++ b/bin/wwwProcess.js @@ -1,3 +1,5 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable n/no-process-exit, unicorn/no-process-exit */ import http from 'node:http'; import Debug from 'debug'; import exitHook from 'exit-hook'; @@ -8,15 +10,21 @@ function onError(error) { if (error.syscall !== 'listen') { throw error; } + // handle specific listen errors with friendly messages switch (error.code) { + // eslint-disable-next-line no-fallthrough case 'EACCES': { debug('Requires elevated privileges'); process.exit(1); + // break; } + // eslint-disable-next-line no-fallthrough case 'EADDRINUSE': { debug('Port is already in use.'); process.exit(1); + // break; } + // eslint-disable-next-line no-fallthrough default: { throw error; } @@ -29,6 +37,9 @@ function onListening(server) { debug(`HTTP Listening on ${bind}`); } } +/* + * Initialize HTTP + */ process.title = `${getConfigProperty('application.applicationName')} (Worker)`; const httpPort = getConfigProperty('application.httpPort'); const httpServer = http.createServer(app); diff --git a/cypress/e2e/02-update/maps.cy.js b/cypress/e2e/02-update/maps.cy.js index c8dcb143..ce90d3c8 100644 --- a/cypress/e2e/02-update/maps.cy.js +++ b/cypress/e2e/02-update/maps.cy.js @@ -18,6 +18,7 @@ describe('Update - Maps', () => { cy.injectAxe(); cy.checkA11y(); cy.log('Populate the fields'); + // eslint-disable-next-line promise/catch-or-return, promise/always-return cy.fixture('map.json').then((mapJSON) => { cy.get("input[name='mapName']") .clear() @@ -53,6 +54,7 @@ describe('Update - Maps', () => { cy.location('pathname') .should('not.contain', '/new') .should('contain', '/edit'); + // eslint-disable-next-line promise/catch-or-return, promise/always-return cy.fixture('map.json').then((mapJSON) => { cy.get("input[name='mapName']").should('have.value', mapJSON.mapName); cy.get("textarea[name='mapDescription']").should('have.value', mapJSON.mapDescription); diff --git a/cypress/support/index.js b/cypress/support/index.js index 02af7901..dbd4e2c9 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -1,3 +1,4 @@ +/* eslint-disable node/no-unpublished-import */ import 'cypress-axe'; export const logout = () => { cy.visit('/logout'); @@ -11,6 +12,7 @@ export const login = (userName) => { cy.get("form [name='password']").type(userName); cy.get('form').submit(); cy.location('pathname').should('not.contain', '/login'); + // Logged in pages have a navbar cy.get('.navbar').should('have.length', 1); }; export const ajaxDelayMillis = 800; diff --git a/data/config.defaultValues.js b/data/config.defaultValues.js index e5d88588..ad1feac6 100644 --- a/data/config.defaultValues.js +++ b/data/config.defaultValues.js @@ -36,6 +36,7 @@ export const configDefaultValues = { 'settings.lot.lotNamePattern': undefined, 'settings.lot.lotNameHelpText': '', 'settings.lot.lotNameSortNameFunction': (lotName) => lotName, + // eslint-disable-next-line no-secrets/no-secrets 'settings.lotOccupancy.occupancyEndDateIsRequired': true, 'settings.lotOccupancy.occupantCityDefault': '', 'settings.lotOccupancy.occupantProvinceDefault': '', @@ -50,6 +51,7 @@ export const configDefaultValues = { 'settings.printPdf.contentDisposition': 'attachment', 'settings.dynamicsGP.integrationIsEnabled': false, 'settings.dynamicsGP.mssqlConfig': undefined, + // eslint-disable-next-line no-secrets/no-secrets 'settings.dynamicsGP.lookupOrder': ['invoice'], 'settings.dynamicsGP.accountCodes': [], 'settings.dynamicsGP.itemNumbers': [], diff --git a/data/databasePaths.js b/data/databasePaths.js index c37d1262..c3ef2a1c 100644 --- a/data/databasePaths.js +++ b/data/databasePaths.js @@ -1,6 +1,7 @@ import Debug from 'debug'; import { getConfigProperty } from '../helpers/functions.config.js'; const debug = Debug('lot-occupancy-system:databasePaths'); +// Determine if test databases should be used export const useTestDatabases = getConfigProperty('application.useTestDatabases') || process.env.TEST_DATABASES === 'true'; if (useTestDatabases) { diff --git a/database/addLotOccupancyFee.js b/database/addLotOccupancyFee.js index 0c5d3a66..343b3747 100644 --- a/database/addLotOccupancyFee.js +++ b/database/addLotOccupancyFee.js @@ -5,6 +5,7 @@ import { acquireConnection } from './pool.js'; export default async function addLotOccupancyFee(lotOccupancyFeeForm, user) { const database = await acquireConnection(); const rightNowMillis = Date.now(); + // Calculate fee and tax (if not set) let feeAmount; let taxAmount; if ((lotOccupancyFeeForm.feeAmount ?? '') === '') { @@ -23,6 +24,7 @@ export default async function addLotOccupancyFee(lotOccupancyFeeForm, user) { ? Number.parseFloat(lotOccupancyFeeForm.taxAmount) : 0; } + // Check if record already exists const record = database .prepare(`select feeAmount, taxAmount, recordDelete_timeMillis from LotOccupancyFees @@ -69,6 +71,7 @@ export default async function addLotOccupancyFee(lotOccupancyFeeForm, user) { return true; } } + // Create new record const result = database .prepare(`insert into LotOccupancyFees ( lotOccupancyId, feeId, diff --git a/database/cleanupDatabase.js b/database/cleanupDatabase.js index e101ed07..1e80a4cf 100644 --- a/database/cleanupDatabase.js +++ b/database/cleanupDatabase.js @@ -9,6 +9,9 @@ export default async function cleanupDatabase(user) { 1000; let inactivatedRecordCount = 0; let purgedRecordCount = 0; + /* + * Work Order Comments + */ inactivatedRecordCount += database .prepare(`update WorkOrderComments set recordDelete_userName = ?, @@ -20,6 +23,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from WorkOrderComments where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Work Order Lot Occupancies + */ inactivatedRecordCount += database .prepare(`update WorkOrderLotOccupancies set recordDelete_userName = ?, @@ -31,6 +37,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from WorkOrderLotOccupancies where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Work Order Lots + */ inactivatedRecordCount += database .prepare(`update WorkOrderLots set recordDelete_userName = ?, @@ -42,6 +51,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from WorkOrderLots where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Work Order Milestones + */ inactivatedRecordCount += database .prepare(`update WorkOrderMilestones set recordDelete_userName = ?, @@ -53,6 +65,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from WorkOrderMilestones where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Work Orders + */ purgedRecordCount += database .prepare(`delete from WorkOrders where recordDelete_timeMillis <= ? @@ -61,17 +76,26 @@ export default async function cleanupDatabase(user) { and workOrderId not in (select workOrderId from WorkOrderLots) and workOrderId not in (select workOrderId from WorkOrderMilestones)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Work Order Milestone Types + */ purgedRecordCount += database .prepare(`delete from WorkOrderMilestoneTypes where recordDelete_timeMillis <= ? and workOrderMilestoneTypeId not in ( select workOrderMilestoneTypeId from WorkOrderMilestones)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Work Order Types + */ purgedRecordCount += database .prepare(`delete from WorkOrderTypes where recordDelete_timeMillis <= ? and workOrderTypeId not in (select workOrderTypeId from WorkOrders)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Occupancy Comments + */ inactivatedRecordCount += database .prepare(`update LotOccupancyComments set recordDelete_userName = ?, @@ -83,6 +107,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from LotOccupancyComments where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Occupancy Fields + */ inactivatedRecordCount += database .prepare(`update LotOccupancyFields set recordDelete_userName = ?, @@ -93,6 +120,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from LotOccupancyFields where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Occupancy Occupants + */ inactivatedRecordCount += database .prepare(`update LotOccupancyOccupants set recordDelete_userName = ?, @@ -103,12 +133,19 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from LotOccupancyOccupants where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Occupancy Fees/Transactions + * - Maintain financials, do not delete related. + */ purgedRecordCount += database .prepare('delete from LotOccupancyFees where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; purgedRecordCount += database .prepare('delete from LotOccupancyTransactions where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Occupancies + */ purgedRecordCount += database .prepare(`delete from LotOccupancies where recordDelete_timeMillis <= ? @@ -119,6 +156,9 @@ export default async function cleanupDatabase(user) { and lotOccupancyId not in (select lotOccupancyId from LotOccupancyTransactions) and lotOccupancyId not in (select lotOccupancyId from WorkOrderLotOccupancies)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Fees + */ inactivatedRecordCount += database .prepare(`update Fees set recordDelete_userName = ?, @@ -131,11 +171,17 @@ export default async function cleanupDatabase(user) { where recordDelete_timeMillis <= ? and feeId not in (select feeId from LotOccupancyFees)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Fee Categories + */ purgedRecordCount += database .prepare(`delete from FeeCategories where recordDelete_timeMillis <= ? and feeCategoryId not in (select feeCategoryId from Fees)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Occupancy Type Fields + */ inactivatedRecordCount += database .prepare(`update OccupancyTypeFields set recordDelete_userName = ?, @@ -148,6 +194,9 @@ export default async function cleanupDatabase(user) { where recordDelete_timeMillis <= ? and occupancyTypeFieldId not in (select occupancyTypeFieldId from LotOccupancyFields)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Occupancy Type Prints + */ inactivatedRecordCount += database .prepare(`update OccupancyTypePrints set recordDelete_userName = ?, @@ -158,6 +207,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from OccupancyTypePrints where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Occupancy Types + */ purgedRecordCount += database .prepare(`delete from OccupancyTypes where recordDelete_timeMillis <= ? @@ -166,11 +218,17 @@ export default async function cleanupDatabase(user) { and occupancyTypeId not in (select occupancyTypeId from LotOccupancies) and occupancyTypeId not in (select occupancyTypeId from Fees)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Occupant Types + */ purgedRecordCount += database .prepare(`delete from LotOccupantTypes where recordDelete_timeMillis <= ? and lotOccupantTypeId not in (select lotOccupantTypeId from LotOccupancyOccupants)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Comments + */ inactivatedRecordCount += database .prepare(`update LotComments set recordDelete_userName = ?, @@ -181,6 +239,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from LotComments where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Fields + */ inactivatedRecordCount += database .prepare(`update LotFields set recordDelete_userName = ?, @@ -191,6 +252,9 @@ export default async function cleanupDatabase(user) { purgedRecordCount += database .prepare('delete from LotFields where recordDelete_timeMillis <= ?') .run(recordDeleteTimeMillisMin).changes; + /* + * Lots + */ inactivatedRecordCount += database .prepare(`update Lots set recordDelete_userName = ?, @@ -206,11 +270,17 @@ export default async function cleanupDatabase(user) { and lotId not in (select lotId from LotOccupancies) and lotId not in (select lotId from WorkOrderLots)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Statuses + */ purgedRecordCount += database .prepare(`delete from LotStatuses where recordDelete_timeMillis <= ? and lotStatusId not in (select lotStatusId from Lots)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Type Fields + */ inactivatedRecordCount += database .prepare(`update LotTypeFields set recordDelete_userName = ?, @@ -223,6 +293,9 @@ export default async function cleanupDatabase(user) { where recordDelete_timeMillis <= ? and lotTypeFieldId not in (select lotTypeFieldId from LotFields)`) .run(recordDeleteTimeMillisMin).changes; + /* + * Lot Types + */ purgedRecordCount += database .prepare(`delete from LotTypes where recordDelete_timeMillis <= ? diff --git a/database/copyLotOccupancy.js b/database/copyLotOccupancy.js index 2ac61275..b4eccc19 100644 --- a/database/copyLotOccupancy.js +++ b/database/copyLotOccupancy.js @@ -12,6 +12,9 @@ export default async function copyLotOccupancy(oldLotOccupancyId, user) { occupancyStartDateString: dateToString(new Date()), occupancyEndDateString: '' }, user, database); + /* + * Copy Fields + */ const rightNowMillis = Date.now(); for (const occupancyField of oldLotOccupancy.lotOccupancyFields ?? []) { database @@ -22,6 +25,9 @@ export default async function copyLotOccupancy(oldLotOccupancyId, user) { values (?, ?, ?, ?, ?, ?, ?)`) .run(newLotOccupancyId, occupancyField.occupancyTypeFieldId, occupancyField.lotOccupancyFieldValue, user.userName, rightNowMillis, user.userName, rightNowMillis); } + /* + * Copy Occupants + */ for (const occupant of oldLotOccupancy.lotOccupancyOccupants ?? []) { await addLotOccupancyOccupant({ lotOccupancyId: newLotOccupancyId, diff --git a/database/getLotOccupancyComments.js b/database/getLotOccupancyComments.js index b4800efe..5e228b6d 100644 --- a/database/getLotOccupancyComments.js +++ b/database/getLotOccupancyComments.js @@ -6,7 +6,9 @@ export default async function getLotOccupancyComments(lotOccupancyId, connectedD database.function('userFn_timeIntegerToString', timeIntegerToString); database.function('userFn_timeIntegerToPeriodString', timeIntegerToPeriodString); const lotComments = database - .prepare(`select lotOccupancyCommentId, + .prepare( + // eslint-disable-next-line no-secrets/no-secrets + `select lotOccupancyCommentId, lotOccupancyCommentDate, userFn_dateIntegerToString(lotOccupancyCommentDate) as lotOccupancyCommentDateString, lotOccupancyCommentTime, userFn_timeIntegerToString(lotOccupancyCommentTime) as lotOccupancyCommentTimeString, diff --git a/database/getNextWorkOrderNumber.js b/database/getNextWorkOrderNumber.js index 189e10fc..c680450d 100644 --- a/database/getNextWorkOrderNumber.js +++ b/database/getNextWorkOrderNumber.js @@ -5,11 +5,15 @@ export default async function getNextWorkOrderNumber(connectedDatabase) { const paddingLength = getConfigProperty('settings.workOrders.workOrderNumberLength'); const currentYearString = new Date().getFullYear().toString(); const regex = new RegExp(`^${currentYearString}-\\d+$`); - database.function('userFn_matchesWorkOrderNumberSyntax', (workOrderNumber) => { + database.function( + // eslint-disable-next-line no-secrets/no-secrets + 'userFn_matchesWorkOrderNumberSyntax', (workOrderNumber) => { return regex.test(workOrderNumber) ? 1 : 0; }); const workOrderNumberRecord = database - .prepare(`select workOrderNumber from WorkOrders + .prepare( + // eslint-disable-next-line no-secrets/no-secrets + `select workOrderNumber from WorkOrders where userFn_matchesWorkOrderNumberSyntax(workOrderNumber) = 1 order by cast(substr(workOrderNumber, instr(workOrderNumber, '-') + 1) as integer) desc`) .get(); diff --git a/database/getOccupancyTypePrints.js b/database/getOccupancyTypePrints.js index 43ebd1a9..2d1602ba 100644 --- a/database/getOccupancyTypePrints.js +++ b/database/getOccupancyTypePrints.js @@ -1,6 +1,7 @@ import { getConfigProperty } from '../helpers/functions.config.js'; import { acquireConnection } from './pool.js'; const availablePrints = getConfigProperty('settings.lotOccupancy.prints'); +// eslint-disable-next-line @typescript-eslint/naming-convention const userFunction_configContainsPrintEJS = (printEJS) => { if (printEJS === '*' || availablePrints.includes(printEJS)) { return 1; @@ -9,7 +10,9 @@ const userFunction_configContainsPrintEJS = (printEJS) => { }; export default async function getOccupancyTypePrints(occupancyTypeId, connectedDatabase) { const database = connectedDatabase ?? (await acquireConnection()); - database.function('userFn_configContainsPrintEJS', userFunction_configContainsPrintEJS); + database.function( + // eslint-disable-next-line no-secrets/no-secrets + 'userFn_configContainsPrintEJS', userFunction_configContainsPrintEJS); const results = database .prepare(`select printEJS, orderNumber from OccupancyTypePrints diff --git a/database/getReportData.js b/database/getReportData.js index 0e1d71bd..ddf0f3ce 100644 --- a/database/getReportData.js +++ b/database/getReportData.js @@ -1,3 +1,5 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable no-case-declarations */ import { dateIntegerToString, dateStringToInteger, dateToInteger, timeIntegerToString } from '@cityssm/utils-datetime'; import camelCase from 'camelcase'; import { getConfigProperty } from '../helpers/functions.config.js'; @@ -38,6 +40,7 @@ const occupantCommentAlias = `${occupantCamelCase}Comment`; export default async function getReportData(reportName, reportParameters = {}) { let sql; const sqlParameters = []; + // eslint-disable-next-line sonarjs/max-switch-cases switch (reportName) { case 'maps-all': { sql = 'select * from Maps'; diff --git a/database/getWorkOrderMilestones.js b/database/getWorkOrderMilestones.js index 32fc3249..382513b2 100644 --- a/database/getWorkOrderMilestones.js +++ b/database/getWorkOrderMilestones.js @@ -3,6 +3,7 @@ import { getConfigProperty } from '../helpers/functions.config.js'; import getLotOccupancies from './getLotOccupancies.js'; import getLots from './getLots.js'; import { acquireConnection } from './pool.js'; +// eslint-disable-next-line security/detect-unsafe-regex const commaSeparatedNumbersRegex = /^\d+(?:,\d+)*$/; function buildWhereClause(filters) { let sqlWhereClause = ' where m.recordDelete_timeMillis is null and w.recordDelete_timeMillis is null'; @@ -66,7 +67,9 @@ export default async function getWorkOrderMilestones(filters, options, connected database.function('userFn_dateIntegerToString', dateIntegerToString); database.function('userFn_timeIntegerToString', timeIntegerToString); database.function('userFn_timeIntegerToPeriodString', timeIntegerToPeriodString); + // Filters const { sqlWhereClause, sqlParameters } = buildWhereClause(filters); + // Order By let orderByClause = ''; switch (options.orderBy) { case 'completion': { @@ -84,6 +87,8 @@ export default async function getWorkOrderMilestones(filters, options, connected break; } } + // Query + // eslint-disable-next-line no-secrets/no-secrets const sql = `select m.workOrderMilestoneId, m.workOrderMilestoneTypeId, t.workOrderMilestoneType, m.workOrderMilestoneDate, diff --git a/gulpfile.js b/gulpfile.js index 927178f7..97986683 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,5 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, n/no-unpublished-import */ import gulp from 'gulp'; import changed from 'gulp-changed'; import include from 'gulp-include'; @@ -5,14 +7,22 @@ import minify from 'gulp-minify'; import gulpSass from 'gulp-sass'; import dartSass from 'sass'; const sass = gulpSass(dartSass); +/* + * Compile SASS + */ const publicSCSSDestination = 'public/stylesheets'; function publicSCSSFunction() { return gulp .src('public-scss/*.scss') - .pipe(sass({ outputStyle: 'compressed', includePaths: ['node_modules'] }).on('error', sass.logError)) + .pipe(sass({ outputStyle: 'compressed', includePaths: ['node_modules'] }).on('error', + // eslint-disable-next-line @typescript-eslint/unbound-method + sass.logError)) .pipe(gulp.dest(publicSCSSDestination)); } gulp.task('public-scss', publicSCSSFunction); +/* + * Minify public/javascripts + */ const publicJavascriptsDestination = 'public/javascripts'; function publicJavascriptsMinFunction() { return gulp @@ -45,6 +55,9 @@ gulp.task('public-javascript-adminTables', publicJavascriptsAdminTablesFunction) gulp.task('public-javascript-lotOccupancyEdit', publicJavascriptsLotOccupancyEditFunction); gulp.task('public-javascript-workOrderEdit', publicJavascriptsWorkOrderEditFunction); gulp.task('public-javascript-min', publicJavascriptsMinFunction); +/* + * Watch + */ function watchFunction() { gulp.watch('public-scss/*.scss', publicSCSSFunction); gulp.watch('public-typescript/adminTables/*.js', publicJavascriptsAdminTablesFunction); @@ -53,6 +66,9 @@ function watchFunction() { gulp.watch('public-typescript/*.js', publicJavascriptsMinFunction); } gulp.task('watch', watchFunction); +/* + * Initialize default + */ gulp.task('default', () => { publicJavascriptsAdminTablesFunction(); publicJavascriptsLotOccupancyEditFunction(); diff --git a/handlers/api-get/milestoneICS.js b/handlers/api-get/milestoneICS.js index 6126ec30..4ee9ec9b 100644 --- a/handlers/api-get/milestoneICS.js +++ b/handlers/api-get/milestoneICS.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */ import ical, { ICalEventStatus } from 'ical-generator'; import getWorkOrderMilestones from '../../database/getWorkOrderMilestones.js'; import { getConfigProperty } from '../../helpers/functions.config.js'; @@ -38,6 +39,7 @@ function buildEventSummary(milestone) { } return summary; } +// eslint-disable-next-line @typescript-eslint/naming-convention function buildEventDescriptionHTML_occupancies(request, milestone) { let descriptionHTML = ''; if (milestone.workOrderLotOccupancies.length > 0) { @@ -82,6 +84,7 @@ function buildEventDescriptionHTML_occupancies(request, milestone) { } return descriptionHTML; } +// eslint-disable-next-line @typescript-eslint/naming-convention function buildEventDescriptionHTML_lots(request, milestone) { let descriptionHTML = ''; if (milestone.workOrderLots.length > 0) { @@ -118,6 +121,7 @@ function buildEventDescriptionHTML_lots(request, milestone) { } return descriptionHTML; } +// eslint-disable-next-line @typescript-eslint/naming-convention function buildEventDescriptionHTML_prints(request, milestone) { let descriptionHTML = ''; const prints = getConfigProperty('settings.workOrders.prints'); @@ -169,6 +173,9 @@ function buildEventLocation(milestone) { } export default async function handler(request, response) { const urlRoot = getUrlRoot(request); + /* + * Get work order milestones + */ const workOrderMilestoneFilters = { workOrderTypeIds: request.query.workOrderTypeIds, workOrderMilestoneTypeIds: request.query.workOrderMilestoneTypeIds @@ -184,6 +191,9 @@ export default async function handler(request, response) { includeWorkOrders: true, orderBy: 'date' }); + /* + * Create calendar object + */ const calendar = ical({ name: 'Work Order Milestone Calendar', url: `${urlRoot}/workOrders` @@ -196,13 +206,19 @@ export default async function handler(request, response) { company: calendarCompany, product: calendarProduct }); + /* + * Loop through milestones + */ for (const milestone of workOrderMilestones) { const milestoneTimePieces = `${milestone.workOrderMilestoneDateString} ${milestone.workOrderMilestoneTimeString}`.split(timeStringSplitRegex); const milestoneDate = new Date(Number.parseInt(milestoneTimePieces[0], 10), Number.parseInt(milestoneTimePieces[1], 10) - 1, Number.parseInt(milestoneTimePieces[2], 10), Number.parseInt(milestoneTimePieces[3], 10), Number.parseInt(milestoneTimePieces[4], 10)); const milestoneEndDate = new Date(milestoneDate.getTime()); milestoneEndDate.setHours(milestoneEndDate.getHours() + 1); + // Build summary (title in Outlook) const summary = buildEventSummary(milestone); + // Build URL const workOrderUrl = getWorkOrderUrl(request, milestone); + // Create event const eventData = { start: milestoneDate, created: new Date(milestone.recordCreate_timeMillis), @@ -216,22 +232,27 @@ export default async function handler(request, response) { eventData.end = milestoneEndDate; } const calendarEvent = calendar.createEvent(eventData); + // Build description const descriptionHTML = buildEventDescriptionHTML(request, milestone); calendarEvent.description({ plain: workOrderUrl, html: descriptionHTML }); + // Set status if (milestone.workOrderMilestoneCompletionDate) { calendarEvent.status(ICalEventStatus.CONFIRMED); } + // Add categories const categories = buildEventCategoryList(milestone); for (const category of categories) { calendarEvent.createCategory({ name: category }); } + // Set location const location = buildEventLocation(milestone); calendarEvent.location(location); + // Set organizer / attendees if (milestone.workOrderLotOccupancies.length > 0) { let organizerSet = false; for (const lotOccupancy of milestone.workOrderLotOccupancies ?? []) { diff --git a/handlers/dashboard-get/dashboard.js b/handlers/dashboard-get/dashboard.js index e793fa8d..23cf6237 100644 --- a/handlers/dashboard-get/dashboard.js +++ b/handlers/dashboard-get/dashboard.js @@ -14,13 +14,13 @@ export default async function handler(_request, response) { const workOrderResults = await getWorkOrders({ workOrderOpenDateString: currentDateString }, { - limit: 1, + limit: 1, // only using the count offset: 0 }); const lotOccupancyResults = await getLotOccupancies({ occupancyStartDateString: currentDateString }, { - limit: 1, + limit: 1, // only using the count offset: 0, includeFees: false, includeOccupants: false, diff --git a/handlers/lotOccupancies-post/doGetDynamicsGPDocument.js b/handlers/lotOccupancies-post/doGetDynamicsGPDocument.js index 1b1637d4..b34b29e9 100644 --- a/handlers/lotOccupancies-post/doGetDynamicsGPDocument.js +++ b/handlers/lotOccupancies-post/doGetDynamicsGPDocument.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/filename-case */ import { getDynamicsGPDocument } from '../../helpers/functions.dynamicsGP.js'; export default async function handler(request, response) { const externalReceiptNumber = request.body.externalReceiptNumber; diff --git a/helpers/functions.cache.js b/helpers/functions.cache.js index 521b53ee..defd7b46 100644 --- a/helpers/functions.cache.js +++ b/helpers/functions.cache.js @@ -9,6 +9,9 @@ import getWorkOrderMilestoneTypesFromDatabase from '../database/getWorkOrderMile import getWorkOrderTypesFromDatabase from '../database/getWorkOrderTypes.js'; import { getConfigProperty } from './functions.config.js'; const debug = Debug(`lot-occupancy-system:functions.cache:${process.pid}`); +/* + * Lot Occupant Types + */ let lotOccupantTypes; export async function getLotOccupantTypes() { if (lotOccupantTypes === undefined) { @@ -33,6 +36,9 @@ export async function getLotOccupantTypeByLotOccupantType(lotOccupantType) { function clearLotOccupantTypesCache() { lotOccupantTypes = undefined; } +/* + * Lot Statuses + */ let lotStatuses; export async function getLotStatuses() { if (lotStatuses === undefined) { @@ -56,6 +62,9 @@ export async function getLotStatusByLotStatus(lotStatus) { function clearLotStatusesCache() { lotStatuses = undefined; } +/* + * Lot Types + */ let lotTypes; export async function getLotTypes() { if (lotTypes === undefined) { @@ -79,6 +88,9 @@ export async function getLotTypesByLotType(lotType) { function clearLotTypesCache() { lotTypes = undefined; } +/* + * Occupancy Types + */ let occupancyTypes; let allOccupancyTypeFields; export async function getOccupancyTypes() { @@ -122,6 +134,9 @@ function clearOccupancyTypesCache() { occupancyTypes = undefined; allOccupancyTypeFields = undefined; } +/* + * Work Order Types + */ let workOrderTypes; export async function getWorkOrderTypes() { if (workOrderTypes === undefined) { @@ -138,6 +153,9 @@ export async function getWorkOrderTypeById(workOrderTypeId) { function clearWorkOrderTypesCache() { workOrderTypes = undefined; } +/* + * Work Order Milestone Types + */ let workOrderMilestoneTypes; export async function getWorkOrderMilestoneTypes() { if (workOrderMilestoneTypes === undefined) { diff --git a/helpers/functions.dynamicsGP.js b/helpers/functions.dynamicsGP.js index 1b9fdebb..4a9917e4 100644 --- a/helpers/functions.dynamicsGP.js +++ b/helpers/functions.dynamicsGP.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */ import { DynamicsGP } from '@cityssm/dynamics-gp'; import { getConfigProperty } from './functions.config.js'; let gp; diff --git a/helpers/functions.lots.js b/helpers/functions.lots.js index 0935c08c..e75afd60 100644 --- a/helpers/functions.lots.js +++ b/helpers/functions.lots.js @@ -5,7 +5,7 @@ import getNextLotIdFromDatabase from '../database/getNextLotId.js'; import getPreviousLotIdFromDatabase from '../database/getPreviousLotId.js'; const debug = Debug(`lot-occupancy-system:functions.lots:${process.pid}`); const cacheOptions = { - stdTTL: 2 * 60, + stdTTL: 2 * 60, // two minutes useClones: false }; const previousLotIdCache = new NodeCache(cacheOptions); diff --git a/helpers/functions.print.js b/helpers/functions.print.js index c5fb47fa..fb3e81a4 100644 --- a/helpers/functions.print.js +++ b/helpers/functions.print.js @@ -1,8 +1,11 @@ +// skipcq: JS-C1003 - Added to ReportData import * as dateTimeFunctions from '@cityssm/utils-datetime'; import getLot from '../database/getLot.js'; import getLotOccupancy from '../database/getLotOccupancy.js'; import getWorkOrder from '../database/getWorkOrder.js'; +// skipcq: JS-C1003 - Added to ReportData import * as configFunctions from './functions.config.js'; +// skipcq: JS-C1003 - Added to ReportData import * as lotOccupancyFunctions from './functions.lotOccupancy.js'; const screenPrintConfigs = { lotOccupancy: { @@ -22,6 +25,7 @@ const pdfPrintConfigs = { title: 'Work Order Field Sheet - Comment Log', params: ['workOrderId'] }, + // Occupancy 'ssm.cemetery.burialPermit': { title: 'Burial Permit', params: ['lotOccupancyId'] diff --git a/helpers/initializer.database.cemetery.js b/helpers/initializer.database.cemetery.js index 52df6796..b997c3b7 100644 --- a/helpers/initializer.database.cemetery.js +++ b/helpers/initializer.database.cemetery.js @@ -14,6 +14,9 @@ const user = { } }; export async function initializeCemeteryDatabase() { + /* + * Ensure database does not already exist + */ debug(`Checking for ${databasePath}...`); const databaseInitialized = initializeDatabase(); if (!databaseInitialized) { @@ -22,15 +25,24 @@ export async function initializeCemeteryDatabase() { return false; } debug('New database file created. Proceeding with initialization.'); + /* + * Lot Types + */ await addRecord('LotTypes', 'Casket Grave', 1, user); await addRecord('LotTypes', 'Columbarium', 2, user); await addRecord('LotTypes', 'Mausoleum', 2, user); await addRecord('LotTypes', 'Niche Wall', 2, user); await addRecord('LotTypes', 'Urn Garden', 2, user); await addRecord('LotTypes', 'Crematorium', 2, user); + /* + * Lot Statuses + */ await addRecord('LotStatuses', 'Available', 1, user); await addRecord('LotStatuses', 'Reserved', 2, user); await addRecord('LotStatuses', 'Taken', 3, user); + /* + * Lot Occupant Types + */ await addLotOccupantType({ lotOccupantType: 'Deceased', fontAwesomeIconClass: 'cross', @@ -52,9 +64,13 @@ export async function initializeCemeteryDatabase() { occupantCommentTitle: 'Relationship to Owner/Deceased', orderNumber: 4 }, user); + /* + * Occupancy Types + */ await addRecord('OccupancyTypes', 'Preneed', 1, user); const intermentOccupancyTypeId = await addRecord('OccupancyTypes', 'Interment', 2, user); const cremationOccupancyTypeId = await addRecord('OccupancyTypes', 'Cremation', 3, user); + // Death Date const deathDateField = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Death Date', @@ -69,6 +85,7 @@ export async function initializeCemeteryDatabase() { await addOccupancyTypeField(Object.assign(deathDateField, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Death Age const deathAgeField = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Death Age', @@ -81,6 +98,7 @@ export async function initializeCemeteryDatabase() { }; await addOccupancyTypeField(deathAgeField, user); await addOccupancyTypeField(Object.assign(deathAgeField, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Death Age Period const deathAgePeriod = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Death Age Period', @@ -95,6 +113,7 @@ export async function initializeCemeteryDatabase() { await addOccupancyTypeField(Object.assign(deathAgePeriod, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Death Place const deathPlace = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Death Place', @@ -107,6 +126,7 @@ export async function initializeCemeteryDatabase() { }; await addOccupancyTypeField(deathPlace, user); await addOccupancyTypeField(Object.assign(deathPlace, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Funeral Home const funeralHome = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Funeral Home', @@ -119,6 +139,7 @@ export async function initializeCemeteryDatabase() { }; await addOccupancyTypeField(funeralHome, user); await addOccupancyTypeField(Object.assign(funeralHome, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Funeral Date const funeralDate = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Funeral Date', @@ -131,6 +152,7 @@ export async function initializeCemeteryDatabase() { }; await addOccupancyTypeField(funeralDate, user); await addOccupancyTypeField(Object.assign(funeralDate, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Container Type const containerType = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Container Type', @@ -143,6 +165,7 @@ export async function initializeCemeteryDatabase() { }; await addOccupancyTypeField(containerType, user); await addOccupancyTypeField(Object.assign(containerType, { occupancyTypeId: cremationOccupancyTypeId }), user); + // Committal Type const committalType = { occupancyTypeId: intermentOccupancyTypeId, occupancyTypeField: 'Committal Type', @@ -155,11 +178,17 @@ export async function initializeCemeteryDatabase() { }; await addOccupancyTypeField(committalType, user); await addOccupancyTypeField(Object.assign(committalType, { occupancyTypeId: cremationOccupancyTypeId }), user); + /* + * Fee Categories + */ await addRecord('FeeCategories', 'Interment Rights', 1, user); await addRecord('FeeCategories', 'Cremation Services', 2, user); await addRecord('FeeCategories', 'Burial Charges', 3, user); await addRecord('FeeCategories', 'Disinterment of Human Remains', 4, user); await addRecord('FeeCategories', 'Additional Services', 5, user); + /* + * Work Orders + */ await addRecord('WorkOrderTypes', 'Cemetery Work Order', 1, user); await addRecord('WorkOrderMilestoneTypes', 'Funeral', 1, user); await addRecord('WorkOrderMilestoneTypes', 'Arrival', 2, user); diff --git a/helpers/initializer.database.js b/helpers/initializer.database.js index 760548ae..fd63f75b 100644 --- a/helpers/initializer.database.js +++ b/helpers/initializer.database.js @@ -9,20 +9,33 @@ const recordColumns = `recordCreate_userName varchar(30) not null, recordDelete_userName varchar(30), recordDelete_timeMillis integer`; const createStatements = [ + /* + * Lot Types + */ `create table if not exists LotTypes (lotTypeId integer not null primary key autoincrement, lotType varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, 'create index if not exists idx_lottypes_ordernumber on LotTypes (orderNumber, lotType)', `create table if not exists LotTypeFields (lotTypeFieldId integer not null primary key autoincrement, lotTypeId integer not null, lotTypeField varchar(100) not null, lotTypeFieldValues text, isRequired bit not null default 0, pattern varchar(100), minimumLength smallint not null default 1 check (minimumLength >= 0), maximumLength smallint not null default 100 check (maximumLength >= 0), orderNumber smallint not null default 0, ${recordColumns}, foreign key (lotTypeId) references LotTypes (lotTypeId))`, 'create index if not exists idx_lottypefields_ordernumber on LotTypeFields (lotTypeId, orderNumber, lotTypeField)', + /* + * Lot Statuses + */ `create table if not exists LotStatuses (lotStatusId integer not null primary key autoincrement, lotStatus varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, 'create index if not exists idx_lotstatuses_ordernumber on LotStatuses (orderNumber, lotStatus)', + /* + * Maps and Lots + */ `create table if not exists Maps (mapId integer not null primary key autoincrement, mapName varchar(200) not null, mapDescription text, mapLatitude decimal(10, 8) check (mapLatitude between -90 and 90), mapLongitude decimal(11, 8) check (mapLongitude between -180 and 180), mapSVG varchar(50), mapAddress1 varchar(50), mapAddress2 varchar(50), mapCity varchar(20), mapProvince varchar(2), mapPostalCode varchar(7), mapPhoneNumber varchar(30), ${recordColumns})`, `create table if not exists Lots (lotId integer not null primary key autoincrement, lotTypeId integer not null, lotName varchar(100), mapId integer, mapKey varchar(100), lotLatitude decimal(10, 8) check (lotLatitude between -90 and 90), lotLongitude decimal(11, 8) check (lotLongitude between -180 and 180), lotStatusId integer, ${recordColumns}, foreign key (lotTypeId) references LotTypes (lotTypeId), foreign key (mapId) references Maps (mapId), foreign key (lotStatusId) references LotStatuses (lotStatusId))`, `create table if not exists LotFields (lotId integer not null, lotTypeFieldId integer not null, lotFieldValue text not null, ${recordColumns}, primary key (lotId, lotTypeFieldId), foreign key (lotId) references Lots (lotId), foreign key (lotTypeFieldId) references LotTypeFields (lotTypeFieldId)) without rowid`, `create table if not exists LotComments (lotCommentId integer not null primary key autoincrement, lotId integer not null, lotCommentDate integer not null check (lotCommentDate > 0), lotCommentTime integer not null check (lotCommentTime >= 0), lotComment text not null, ${recordColumns}, foreign key (lotId) references Lots (lotId))`, 'create index if not exists idx_lotcomments_datetime on LotComments (lotId, lotCommentDate, lotCommentTime)', + /* + * Occupancies + */ `create table if not exists OccupancyTypes (occupancyTypeId integer not null primary key autoincrement, occupancyType varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, 'create index if not exists idx_occupancytypes_ordernumber on OccupancyTypes (orderNumber, occupancyType)', `create table if not exists OccupancyTypeFields (occupancyTypeFieldId integer not null primary key autoincrement, occupancyTypeId integer, occupancyTypeField varchar(100) not null, occupancyTypeFieldValues text, isRequired bit not null default 0, pattern varchar(100), minimumLength smallint not null default 1 check (minimumLength >= 0), maximumLength smallint not null default 100 check (maximumLength >= 0), orderNumber smallint not null default 0, ${recordColumns}, foreign key (occupancyTypeId) references OccupancyTypes (occupancyTypeId))`, + // eslint-disable-next-line no-secrets/no-secrets 'create index if not exists idx_occupancytypefields_ordernumber on OccupancyTypeFields (occupancyTypeId, orderNumber, occupancyTypeField)', `create table if not exists OccupancyTypePrints (occupancyTypeId integer not null, printEJS varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns}, primary key (occupancyTypeId, printEJS), foreign key (occupancyTypeId) references OccupancyTypes (occupancyTypeId))`, 'create index if not exists idx_occupancytypeprints_ordernumber on OccupancyTypePrints (occupancyTypeId, orderNumber, printEJS)', @@ -33,12 +46,16 @@ const createStatements = [ occupantCommentTitle varchar(50) not null default '', orderNumber smallint not null default 0, ${recordColumns})`, + // eslint-disable-next-line no-secrets/no-secrets 'create index if not exists idx_lotoccupanttypes_ordernumber on LotOccupantTypes (orderNumber, lotOccupantType)', `create table if not exists LotOccupancies (lotOccupancyId integer not null primary key autoincrement, occupancyTypeId integer not null, lotId integer, occupancyStartDate integer not null check (occupancyStartDate > 0), occupancyEndDate integer check (occupancyEndDate > 0), ${recordColumns}, foreign key (lotId) references Lots (lotId), foreign key (occupancyTypeId) references OccupancyTypes (occupancyTypeId))`, `create table if not exists LotOccupancyOccupants (lotOccupancyId integer not null, lotOccupantIndex integer not null, occupantName varchar(200) not null, occupantAddress1 varchar(50), occupantAddress2 varchar(50), occupantCity varchar(20), occupantProvince varchar(2), occupantPostalCode varchar(7), occupantPhoneNumber varchar(30), occupantEmailAddress varchar(200), lotOccupantTypeId integer not null, occupantComment text not null default '', ${recordColumns}, primary key (lotOccupancyId, lotOccupantIndex), foreign key (lotOccupancyId) references LotOccupancies (lotOccupancyId), foreign key (lotOccupantTypeId) references LotOccupantTypes (lotOccupantTypeId)) without rowid`, `create table if not exists LotOccupancyFields (lotOccupancyId integer not null, occupancyTypeFieldId integer not null, lotOccupancyFieldValue text not null, ${recordColumns}, primary key (lotOccupancyId, occupancyTypeFieldId), foreign key (lotOccupancyId) references LotOccupancies (lotOccupancyId), foreign key (occupancyTypeFieldId) references OccupancyTypeFields (occupancyTypeFieldId)) without rowid`, `create table if not exists LotOccupancyComments (lotOccupancyCommentId integer not null primary key autoincrement, lotOccupancyId integer not null, lotOccupancyCommentDate integer not null check (lotOccupancyCommentDate > 0), lotOccupancyCommentTime integer not null check (lotOccupancyCommentTime >= 0), lotOccupancyComment text not null, ${recordColumns}, foreign key (lotOccupancyId) references LotOccupancies (lotOccupancyId))`, 'create index if not exists idx_lotoccupancycomments_datetime on LotOccupancyComments (lotOccupancyId, lotOccupancyCommentDate, lotOccupancyCommentTime)', + /* + * Fees and Transactions + */ `create table if not exists FeeCategories (feeCategoryId integer not null primary key autoincrement, feeCategory varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, `create table if not exists Fees ( feeId integer not null primary key autoincrement, @@ -64,6 +81,9 @@ const createStatements = [ `create table if not exists LotOccupancyFees (lotOccupancyId integer not null, feeId integer not null, quantity decimal(4, 1) not null default 1, feeAmount decimal(8, 2) not null, taxAmount decmial(8, 2) not null, ${recordColumns}, primary key (lotOccupancyId, feeId), foreign key (lotOccupancyId) references LotOccupancies (lotOccupancyId), foreign key (feeId) references Fees (feeId)) without rowid`, `create table if not exists LotOccupancyTransactions (lotOccupancyId integer not null, transactionIndex integer not null, transactionDate integer not null check (transactionDate > 0), transactionTime integer not null check (transactionTime >= 0), transactionAmount decimal(8, 2) not null, externalReceiptNumber varchar(100), transactionNote text, ${recordColumns}, primary key (lotOccupancyId, transactionIndex), foreign key (lotOccupancyId) references LotOccupancies (lotOccupancyId)) without rowid`, 'create index if not exists idx_lotoccupancytransactions_ordernumber on LotOccupancyTransactions (lotOccupancyId, transactionDate, transactionTime)', + /* + * Work Orders + */ `create table if not exists WorkOrderTypes (workOrderTypeId integer not null primary key autoincrement, workOrderType varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, 'create index if not exists idx_workordertypes_ordernumber on WorkOrderTypes (orderNumber, workOrderType)', `create table if not exists WorkOrders (workOrderId integer not null primary key autoincrement, workOrderTypeId integer not null, workOrderNumber varchar(50) not null, workOrderDescription text, workOrderOpenDate integer check (workOrderOpenDate > 0), workOrderCloseDate integer check (workOrderCloseDate > 0), ${recordColumns}, foreign key (workOrderTypeId) references WorkOrderTypes (workOrderTypeId))`, diff --git a/routes/admin.js b/routes/admin.js index 0e9f8431..4db87de3 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -61,7 +61,11 @@ import handler_doUpdateOccupancyType from '../handlers/admin-post/doUpdateOccupa import handler_doUpdateOccupancyTypeField from '../handlers/admin-post/doUpdateOccupancyTypeField.js'; import handler_doUpdateWorkOrderMilestoneType from '../handlers/admin-post/doUpdateWorkOrderMilestoneType.js'; import handler_doUpdateWorkOrderType from '../handlers/admin-post/doUpdateWorkOrderType.js'; +// Ntfy Startup export const router = Router(); +/* + * Fees + */ router.get('/fees', handler_fees); router.post('/doAddFeeCategory', handler_doAddFeeCategory); router.post('/doUpdateFeeCategory', handler_doUpdateFeeCategory); @@ -73,55 +77,73 @@ router.post('/doUpdateFee', handler_doUpdateFee); router.post('/doMoveFeeUp', handler_doMoveFeeUp); router.post('/doMoveFeeDown', handler_doMoveFeeDown); router.post('/doDeleteFee', handler_doDeleteFee); +/* + * Occupancy Type Management + */ router.get('/occupancyTypes', handler_occupancyTypes); router.post('/doAddOccupancyType', handler_doAddOccupancyType); router.post('/doUpdateOccupancyType', handler_doUpdateOccupancyType); router.post('/doMoveOccupancyTypeUp', handler_doMoveOccupancyTypeUp); router.post('/doMoveOccupancyTypeDown', handler_doMoveOccupancyTypeDown); router.post('/doDeleteOccupancyType', handler_doDeleteOccupancyType); +// Occupancy Type Fields router.post('/doAddOccupancyTypeField', handler_doAddOccupancyTypeField); router.post('/doUpdateOccupancyTypeField', handler_doUpdateOccupancyTypeField); router.post('/doMoveOccupancyTypeFieldUp', handler_doMoveOccupancyTypeFieldUp); router.post('/doMoveOccupancyTypeFieldDown', handler_doMoveOccupancyTypeFieldDown); router.post('/doDeleteOccupancyTypeField', handler_doDeleteOccupancyTypeField); +// Occupancy Type Prints router.post('/doAddOccupancyTypePrint', handler_doAddOccupancyTypePrint); router.post('/doMoveOccupancyTypePrintUp', handler_doMoveOccupancyTypePrintUp); router.post('/doMoveOccupancyTypePrintDown', handler_doMoveOccupancyTypePrintDown); router.post('/doDeleteOccupancyTypePrint', handler_doDeleteOccupancyTypePrint); +/* + * Lot Type Management + */ router.get('/lotTypes', handler_lotTypes); router.post('/doAddLotType', handler_doAddLotType); router.post('/doUpdateLotType', handler_doUpdateLotType); router.post('/doMoveLotTypeUp', handler_doMoveLotTypeUp); router.post('/doMoveLotTypeDown', handler_doMoveLotTypeDown); router.post('/doDeleteLotType', handler_doDeleteLotType); +// Lot Type Fields router.post('/doAddLotTypeField', handler_doAddLotTypeField); router.post('/doUpdateLotTypeField', handler_doUpdateLotTypeField); router.post('/doMoveLotTypeFieldUp', handler_doMoveLotTypeFieldUp); router.post('/doMoveLotTypeFieldDown', handler_doMoveLotTypeFieldDown); router.post('/doDeleteLotTypeField', handler_doDeleteLotTypeField); +/* + * Config Tables + */ router.get('/tables', handler_tables); +// Config Tables - Work Order Types router.post('/doAddWorkOrderType', handler_doAddWorkOrderType); router.post('/doUpdateWorkOrderType', handler_doUpdateWorkOrderType); router.post('/doMoveWorkOrderTypeUp', handler_doMoveWorkOrderTypeUp); router.post('/doMoveWorkOrderTypeDown', handler_doMoveWorkOrderTypeDown); router.post('/doDeleteWorkOrderType', handler_doDeleteWorkOrderType); +// Config Tables - Work Order Milestone Types router.post('/doAddWorkOrderMilestoneType', handler_doAddWorkOrderMilestoneType); router.post('/doUpdateWorkOrderMilestoneType', handler_doUpdateWorkOrderMilestoneType); router.post('/doMoveWorkOrderMilestoneTypeUp', handler_doMoveWorkOrderMilestoneTypeUp); router.post('/doMoveWorkOrderMilestoneTypeDown', handler_doMoveWorkOrderMilestoneTypeDown); router.post('/doDeleteWorkOrderMilestoneType', handler_doDeleteWorkOrderMilestoneType); +// Config Tables - Lot Statuses router.post('/doAddLotStatus', handler_doAddLotStatus); router.post('/doUpdateLotStatus', handler_doUpdateLotStatus); router.post('/doMoveLotStatusUp', handler_doMoveLotStatusUp); router.post('/doMoveLotStatusDown', handler_doMoveLotStatusDown); router.post('/doDeleteLotStatus', handler_doDeleteLotStatus); +// Config Tables - Lot Occupant Types router.post('/doAddLotOccupantType', handler_doAddLotOccupantType); router.post('/doUpdateLotOccupantType', handler_doUpdateLotOccupantType); router.post('/doMoveLotOccupantTypeUp', handler_doMoveLotOccupantTypeUp); router.post('/doMoveLotOccupantTypeDown', handler_doMoveLotOccupantTypeDown); router.post('/doDeleteLotOccupantType', handler_doDeleteLotOccupantType); +// Database Maintenance router.get('/database', handler_database); router.post('/doBackupDatabase', handler_doBackupDatabase); router.post('/doCleanupDatabase', handler_doCleanupDatabase); +// Ntfy Startup router.get('/ntfyStartup', handler_ntfyStartup); export default router; diff --git a/routes/lotOccupancies.js b/routes/lotOccupancies.js index 908d7d71..d3da892f 100644 --- a/routes/lotOccupancies.js +++ b/routes/lotOccupancies.js @@ -27,27 +27,35 @@ import handler_doUpdateLotOccupancyTransaction from '../handlers/lotOccupancies- import { updateGetHandler, updatePostHandler } from '../handlers/permissions.js'; import { getConfigProperty } from '../helpers/functions.config.js'; export const router = Router(); +// Search router.get('/', handler_search); router.post('/doSearchLotOccupancies', handler_doSearchLotOccupancies); +// Create router.get('/new', updateGetHandler, handler_new); router.post('/doGetOccupancyTypeFields', updatePostHandler, handler_doGetOccupancyTypeFields); router.post('/doCreateLotOccupancy', updatePostHandler, handler_doCreateLotOccupancy); +// View router.get('/:lotOccupancyId', handler_view); +// Edit router.get('/:lotOccupancyId/edit', updateGetHandler, handler_edit); router.post('/doUpdateLotOccupancy', updatePostHandler, handler_doUpdateLotOccupancy); router.post('/doCopyLotOccupancy', updatePostHandler, handler_doCopyLotOccupancy); router.post('/doDeleteLotOccupancy', updatePostHandler, handler_doDeleteLotOccupancy); +// Occupants router.post('/doSearchPastOccupants', updatePostHandler, handler_doSearchPastOccupants); router.post('/doAddLotOccupancyOccupant', updatePostHandler, handler_doAddLotOccupancyOccupant); router.post('/doUpdateLotOccupancyOccupant', updatePostHandler, handler_doUpdateLotOccupancyOccupant); router.post('/doDeleteLotOccupancyOccupant', updatePostHandler, handler_doDeleteLotOccupancyOccupant); +// Comments router.post('/doAddLotOccupancyComment', updatePostHandler, handler_doAddLotOccupancyComment); router.post('/doUpdateLotOccupancyComment', updatePostHandler, handler_doUpdateLotOccupancyComment); router.post('/doDeleteLotOccupancyComment', updatePostHandler, handler_doDeleteLotOccupancyComment); +// Fees router.post('/doGetFees', updatePostHandler, handler_doGetFees); router.post('/doAddLotOccupancyFee', updatePostHandler, handler_doAddLotOccupancyFee); router.post('/doUpdateLotOccupancyFeeQuantity', updatePostHandler, handler_doUpdateLotOccupancyFeeQuantity); router.post('/doDeleteLotOccupancyFee', updatePostHandler, handler_doDeleteLotOccupancyFee); +// Transactions if (getConfigProperty('settings.dynamicsGP.integrationIsEnabled')) { router.post('/doGetDynamicsGPDocument', updatePostHandler, handler_doGetDynamicsGPDocument); } diff --git a/routes/lots.js b/routes/lots.js index 5e953be5..3a30834d 100644 --- a/routes/lots.js +++ b/routes/lots.js @@ -15,8 +15,14 @@ import handler_doUpdateLot from '../handlers/lots-post/doUpdateLot.js'; import handler_doUpdateLotComment from '../handlers/lots-post/doUpdateLotComment.js'; import * as permissionHandlers from '../handlers/permissions.js'; export const router = Router(); +/* + * Lot Search + */ router.get('/', handler_search); router.post('/doSearchLots', handler_doSearchLots); +/* + * Lot View / Edit + */ router.get('/new', permissionHandlers.updateGetHandler, handler_new); router.get('/:lotId', handler_view); router.get('/:lotId/next', handler_next); diff --git a/routes/workOrders.js b/routes/workOrders.js index b00953b6..05085513 100644 --- a/routes/workOrders.js +++ b/routes/workOrders.js @@ -27,27 +27,36 @@ import handler_doUpdateWorkOrder from '../handlers/workOrders-post/doUpdateWorkO import handler_doUpdateWorkOrderComment from '../handlers/workOrders-post/doUpdateWorkOrderComment.js'; import handler_doUpdateWorkOrderMilestone from '../handlers/workOrders-post/doUpdateWorkOrderMilestone.js'; export const router = Router(); +// Search router.get('/', handler_search); router.post('/doSearchWorkOrders', handler_doSearchWorkOrders); +// Milestone Calendar router.get('/milestoneCalendar', handler_milestoneCalendar); router.post('/doGetWorkOrderMilestones', handler_doGetWorkOrderMilestones); +// Outlook Integration router.get('/outlook', handler_outlook); +// New router.get('/new', permissionHandlers.updateGetHandler, handler_new); router.post('/doCreateWorkOrder', permissionHandlers.updatePostHandler, handler_doCreateWorkOrder); +// View router.get('/:workOrderId', handler_view); router.post('/doReopenWorkOrder', permissionHandlers.updatePostHandler, handler_doReopenWorkOrder); +// Edit router.get('/:workOrderId/edit', permissionHandlers.updateGetHandler, handler_edit); router.post('/doUpdateWorkOrder', permissionHandlers.updatePostHandler, handler_doUpdateWorkOrder); router.post('/doCloseWorkOrder', permissionHandlers.updatePostHandler, handler_doCloseWorkOrder); router.post('/doDeleteWorkOrder', permissionHandlers.updatePostHandler, handler_doDeleteWorkOrder); +// Lot Occupancy router.post('/doAddWorkOrderLotOccupancy', permissionHandlers.updatePostHandler, handler_doAddWorkOrderLotOccupancy); router.post('/doDeleteWorkOrderLotOccupancy', permissionHandlers.updatePostHandler, handler_doDeleteWorkOrderLotOccupancy); router.post('/doAddWorkOrderLot', permissionHandlers.updatePostHandler, handler_doAddWorkOrderLot); router.post('/doUpdateLotStatus', permissionHandlers.updatePostHandler, handler_doUpdateLotStatus); router.post('/doDeleteWorkOrderLot', permissionHandlers.updatePostHandler, handler_doDeleteWorkOrderLot); +// Comments router.post('/doAddWorkOrderComment', permissionHandlers.updatePostHandler, handler_doAddWorkOrderComment); router.post('/doUpdateWorkOrderComment', permissionHandlers.updatePostHandler, handler_doUpdateWorkOrderComment); router.post('/doDeleteWorkOrderComment', permissionHandlers.updatePostHandler, handler_doDeleteWorkOrderComment); +// Milestones router.post('/doAddWorkOrderMilestone', permissionHandlers.updatePostHandler, handler_doAddWorkOrderMilestone); router.post('/doUpdateWorkOrderMilestone', permissionHandlers.updatePostHandler, handler_doUpdateWorkOrderMilestone); router.post('/doCompleteWorkOrderMilestone', permissionHandlers.updatePostHandler, handler_doCompleteWorkOrderMilestone); diff --git a/temp/legacy.importFromCSV.js b/temp/legacy.importFromCSV.js index e44d41f3..18f64b96 100644 --- a/temp/legacy.importFromCSV.js +++ b/temp/legacy.importFromCSV.js @@ -105,6 +105,12 @@ const cemeteryToMapName = { const mapCache = new Map(); async function getMap(dataRow) { const mapCacheKey = dataRow.cemetery; + /* + if (masterRow.CM_CEMETERY === "HS" && + (masterRow.CM_BLOCK === "F" || masterRow.CM_BLOCK === "G" || masterRow.CM_BLOCK === "H" || masterRow.CM_BLOCK === "J")) { + mapCacheKey += "-" + masterRow.CM_BLOCK; + } + */ if (mapCache.has(mapCacheKey)) { return mapCache.get(mapCacheKey); } @@ -181,14 +187,17 @@ async function importFromMasterCSV() { masterRow.CM_INTERMENT_YR !== '0') { occupancyEndDateString = formatDateString(masterRow.CM_INTERMENT_YR, masterRow.CM_INTERMENT_MON, masterRow.CM_INTERMENT_DAY); } + // if purchase date unavailable if (preneedOccupancyStartDateString === '0000-00-00' && occupancyEndDateString !== '') { preneedOccupancyStartDateString = occupancyEndDateString; } + // if end date unavailable if (preneedOccupancyStartDateString === '0000-00-00' && masterRow.CM_DEATH_YR !== '' && masterRow.CM_DEATH_YR !== '0') { preneedOccupancyStartDateString = formatDateString(masterRow.CM_DEATH_YR, masterRow.CM_DEATH_MON, masterRow.CM_DEATH_DAY); + // if death took place, and there's no preneed end date if (occupancyEndDateString === '0000-00-00' || occupancyEndDateString === '') { occupancyEndDateString = preneedOccupancyStartDateString; @@ -251,6 +260,7 @@ async function importFromMasterCSV() { let deceasedLotOccupancyId; if (masterRow.CM_DECEASED_NAME !== '') { deceasedOccupancyStartDateString = formatDateString(masterRow.CM_INTERMENT_YR, masterRow.CM_INTERMENT_MON, masterRow.CM_INTERMENT_DAY); + // if interment date unavailable if (deceasedOccupancyStartDateString === '0000-00-00' && masterRow.CM_DEATH_YR !== '' && masterRow.CM_DEATH_YR !== '0') { @@ -331,6 +341,20 @@ async function importFromMasterCSV() { occupantPhoneNumber: funeralHomeOccupant.occupantPhoneNumber, occupantEmailAddress: funeralHomeOccupant.occupantEmailAddress }, user); + /* + addOrUpdateLotOccupancyField( + { + lotOccupancyId: deceasedLotOccupancyId, + occupancyTypeFieldId: allOccupancyTypeFields.find( + (occupancyTypeField) => { + return occupancyTypeField.occupancyTypeField === "Funeral Home"; + } + ).occupancyTypeFieldId, + lotOccupancyFieldValue: masterRow.CM_FUNERAL_HOME + }, + user + ); + */ } if (masterRow.CM_FUNERAL_YR !== '') { const lotOccupancyFieldValue = formatDateString(masterRow.CM_FUNERAL_YR, masterRow.CM_FUNERAL_MON, masterRow.CM_FUNERAL_DAY); @@ -811,6 +835,18 @@ async function importFromWorkOrderCSV() { occupantPhoneNumber: funeralHomeOccupant.occupantPhoneNumber, occupantEmailAddress: funeralHomeOccupant.occupantEmailAddress }, user); + /* + addOrUpdateLotOccupancyField( + { + lotOccupancyId: lotOccupancyId, + occupancyTypeFieldId: allOccupancyTypeFields.find((occupancyTypeField) => { + return occupancyTypeField.occupancyTypeField === "Funeral Home"; + }).occupancyTypeFieldId, + lotOccupancyFieldValue: workOrderRow.WO_FUNERAL_HOME + }, + user + ); + */ } if (workOrderRow.WO_FUNERAL_YR !== '') { const lotOccupancyFieldValue = formatDateString(workOrderRow.WO_FUNERAL_YR, workOrderRow.WO_FUNERAL_MON, workOrderRow.WO_FUNERAL_DAY); @@ -850,6 +886,7 @@ async function importFromWorkOrderCSV() { workOrderId: workOrder.workOrderId, lotOccupancyId }, user); + // Milestones let hasIncompleteMilestones = !workOrderRow.WO_CONFIRMATION_IN; let maxMilestoneCompletionDateString = workOrderOpenDateString; if (importIds.acknowledgedWorkOrderMilestoneTypeId) { @@ -971,6 +1008,7 @@ async function importFromWorkOrderCSV() { console.log(`Started ${new Date().toLocaleString()}`); console.time('importFromCsv'); purgeTables(); +// purgeConfigTables(); await importFromMasterCSV(); await importFromPrepaidCSV(); await importFromWorkOrderCSV(); diff --git a/temp/legacy.importFromCsv.ids.js b/temp/legacy.importFromCsv.ids.js index fe9f9562..75ca6ec4 100644 --- a/temp/legacy.importFromCsv.ids.js +++ b/temp/legacy.importFromCsv.ids.js @@ -1,6 +1,11 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable unicorn/no-await-expression-member */ import sqlite from 'better-sqlite3'; import { lotOccupancyDB as databasePath } from '../data/databasePaths.js'; import * as cacheFunctions from '../helpers/functions.cache.js'; +/* + * Fee IDs + */ const feeCache = new Map(); export function getFeeIdByFeeDescription(feeDescription) { if (feeCache.keys.length === 0) { @@ -17,6 +22,9 @@ export function getFeeIdByFeeDescription(feeDescription) { } return feeCache.get(feeDescription); } +/* + * Lot Occupant Type IDs + */ export const preneedOwnerLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Preneed Owner')) .lotOccupantTypeId; export const funeralDirectorLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Funeral Director')).lotOccupantTypeId; @@ -24,9 +32,15 @@ export const deceasedLotOccupantTypeId = (await cacheFunctions.getLotOccupantTyp .lotOccupantTypeId; export const purchaserLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Purchaser')) .lotOccupantTypeId; +/* + * Lot Status IDs + */ export const availableLotStatusId = (await cacheFunctions.getLotStatusByLotStatus('Available')).lotStatusId; export const reservedLotStatusId = (await cacheFunctions.getLotStatusByLotStatus('Reserved')).lotStatusId; export const takenLotStatusId = (await cacheFunctions.getLotStatusByLotStatus('Taken')).lotStatusId; +/* + * Lot Type IDs + */ const casketLotTypeId = (await cacheFunctions.getLotTypesByLotType('Casket Grave')).lotTypeId; const columbariumLotTypeId = (await cacheFunctions.getLotTypesByLotType('Columbarium')).lotTypeId; const crematoriumLotTypeId = (await cacheFunctions.getLotTypesByLotType('Crematorium')).lotTypeId; @@ -55,12 +69,21 @@ export function getLotTypeId(dataRow) { } return casketLotTypeId; } +/* + * Occupancy Type IDs + */ export const preneedOccupancyType = (await cacheFunctions.getOccupancyTypeByOccupancyType('Preneed')); export const deceasedOccupancyType = (await cacheFunctions.getOccupancyTypeByOccupancyType('Interment')); export const cremationOccupancyType = (await cacheFunctions.getOccupancyTypeByOccupancyType('Cremation')); +/* + * Work Order Milestone Type IDs + */ export const acknowledgedWorkOrderMilestoneTypeId = (await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType('Acknowledged'))?.workOrderMilestoneTypeId; export const deathWorkOrderMilestoneTypeId = (await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType('Death'))?.workOrderMilestoneTypeId; export const funeralWorkOrderMilestoneTypeId = (await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType('Funeral'))?.workOrderMilestoneTypeId; export const cremationWorkOrderMilestoneTypeId = (await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType('Cremation'))?.workOrderMilestoneTypeId; export const intermentWorkOrderMilestoneTypeId = (await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType('Interment'))?.workOrderMilestoneTypeId; +/* + * Work Order Type IDs + */ export const workOrderTypeId = 1; diff --git a/temp/so.exportMaps.js b/temp/so.exportMaps.js index dd4f8ce5..9a820833 100644 --- a/temp/so.exportMaps.js +++ b/temp/so.exportMaps.js @@ -20,6 +20,7 @@ async function importMaps() { } } catch { + // ignore } finally { try { @@ -28,6 +29,7 @@ async function importMaps() { } } catch { + // ignore } } } diff --git a/test/0_initializeDatabase.js b/test/0_initializeDatabase.js index 665ae969..2d67836f 100644 --- a/test/0_initializeDatabase.js +++ b/test/0_initializeDatabase.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */ import assert from 'node:assert'; import fs from 'node:fs/promises'; import { lotOccupancyDB as databasePath, useTestDatabases } from '../data/databasePaths.js'; diff --git a/test/1_serverCypress.js b/test/1_serverCypress.js index a948e606..d3b69bb3 100644 --- a/test/1_serverCypress.js +++ b/test/1_serverCypress.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */ import assert from 'node:assert'; import { exec } from 'node:child_process'; import * as http from 'node:http'; @@ -34,6 +35,7 @@ describe('lot-occupancy-system', () => { httpServer.close(); } catch { + // ignore } }); it(`Ensure server starts on port ${portNumber.toString()}`, () => { diff --git a/test/functions.js b/test/functions.js index 930b7376..570d3b11 100644 --- a/test/functions.js +++ b/test/functions.js @@ -1,8 +1,11 @@ import assert from 'node:assert'; import fs from 'node:fs'; import { lotNameSortNameFunction } from '../data/config.cemetery.ssm.js'; +// skipcq: JS-C1003 - Testing functions import * as cacheFunctions from '../helpers/functions.cache.js'; +// skipcq: JS-C1003 - Testing functions import * as sqlFilterFunctions from '../helpers/functions.sqlFilters.js'; +// skipcq: JS-C1003 - Testing functions import * as userFunctions from '../helpers/functions.user.js'; describe('config.cemetery.ssm', () => { it('Sorts burial site names', () => { @@ -13,6 +16,7 @@ describe('config.cemetery.ssm', () => { }); describe('functions.cache', () => { const badId = -3; + // eslint-disable-next-line no-secrets/no-secrets const badName = 'qwertyuiopasdfghjklzxcvbnm'; before(() => { cacheFunctions.clearCaches(); diff --git a/tsconfig.json b/tsconfig.json index 52f947bd..6e158929 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,6 @@ "isolatedModules": false, "declaration": true, "noImplicitAny": false, - "removeComments": true, "allowUnreachableCode": false, "allowSyntheticDefaultImports": true, "resolveJsonModule": true, diff --git a/windowsService-install.js b/windowsService-install.js index 210a2441..90b4702a 100644 --- a/windowsService-install.js +++ b/windowsService-install.js @@ -1,6 +1,10 @@ +/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */ import { Service } from 'node-windows'; import { serviceConfig } from './windowsService.js'; +// Create a new service object const svc = new Service(serviceConfig); +// Listen for the "install" event, which indicates the +// process is available as a service. svc.on('install', () => { svc.start(); }); diff --git a/windowsService-uninstall.js b/windowsService-uninstall.js index 8329a5c5..710c36a5 100644 --- a/windowsService-uninstall.js +++ b/windowsService-uninstall.js @@ -1,8 +1,12 @@ +/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */ import { Service } from 'node-windows'; import { serviceConfig } from './windowsService.js'; +// Create a new service object const svc = new Service(serviceConfig); +// Listen for the "uninstall" event so we know when it's done. svc.on('uninstall', () => { console.log('Uninstall complete.'); console.log('The service exists:', svc.exists); }); +// Uninstall the service. svc.uninstall();