From 0dbbd3f750ebd982eb6e8c0c146e88008b0022f9 Mon Sep 17 00:00:00 2001 From: Dan Gowans Date: Thu, 20 Mar 2025 11:53:56 -0400 Subject: [PATCH] development - add latitude and longitude bounds - add purchaser relationship suggestions - clean up dashboard - switch to native node testing - linting --- data/config.baseOntario.js | 4 + data/config.baseOntario.ts | 6 + data/config.baseSsm.js | 6 +- data/config.baseSsm.ts | 7 +- data/config.defaultValues.d.ts | 6 + data/config.defaultValues.js | 23 +- data/config.defaultValues.ts | 24 +- database/getReportData.js | 382 ++++++++--------- database/getReportData.ts | 429 +++++++++----------- docs/README.md | 7 + handlers/contracts-get/view.js | 2 +- handlers/contracts-get/view.ts | 2 +- handlers/dashboard-get/dashboard.js | 21 +- handlers/dashboard-get/dashboard.ts | 29 +- helpers/burialSites.helpers.js | 8 +- helpers/burialSites.helpers.ts | 8 +- package-lock.json | 14 +- package.json | 6 +- public/images/sunrise-cms.svg | 12 +- public/javascripts/burialSite.edit.js | 12 +- public/javascripts/burialSite.edit.ts | 30 +- public/javascripts/contract.editComments.js | 37 +- public/javascripts/contract.editComments.ts | 60 +-- public/javascripts/fees.admin.js | 4 +- public/javascripts/fees.admin.ts | 1 + public/javascripts/tables.admin.js | 13 +- public/javascripts/tables.admin.ts | 71 ++-- public/javascripts/theme.js | 4 +- public/javascripts/theme.ts | 4 +- test/0_initializeDatabase.js | 5 +- test/0_initializeDatabase.ts | 5 +- test/1_serverCypress.js | 23 +- test/1_serverCypress.ts | 35 +- test/functions.js | 114 +++--- test/functions.ts | 166 ++++---- test/version.js | 5 +- test/version.ts | 5 +- types/configTypes.d.ts | 5 + types/configTypes.ts | 5 + types/recordTypes.d.ts | 14 +- types/recordTypes.ts | 14 +- views/burialSite-edit.ejs | 10 +- views/cemetery-edit.ejs | 426 +++++++++---------- views/contract-edit.ejs | 12 +- views/contract-view.ejs | 20 +- views/dashboard.ejs | 166 ++++---- views/report-search.ejs | 212 +++++----- 47 files changed, 1265 insertions(+), 1209 deletions(-) create mode 100644 docs/README.md diff --git a/data/config.baseOntario.js b/data/config.baseOntario.js index a1e27d50..bb0625f1 100644 --- a/data/config.baseOntario.js +++ b/data/config.baseOntario.js @@ -1,5 +1,9 @@ import { config as baseConfig } from './config.base.js'; export const config = Object.assign({}, baseConfig); config.settings.provinceDefault = 'ON'; +config.settings.latitudeMax = 56.85; +config.settings.latitudeMin = 41.68; +config.settings.longitudeMax = -74; +config.settings.longitudeMin = -95.15; config.settings.fees.taxPercentageDefault = 13; export default config; diff --git a/data/config.baseOntario.ts b/data/config.baseOntario.ts index 077fb234..b475372d 100644 --- a/data/config.baseOntario.ts +++ b/data/config.baseOntario.ts @@ -4,6 +4,12 @@ export const config = Object.assign({}, baseConfig) config.settings.provinceDefault = 'ON' +config.settings.latitudeMax = 56.85 +config.settings.latitudeMin = 41.68 + +config.settings.longitudeMax = -74 +config.settings.longitudeMin = -95.15 + config.settings.fees.taxPercentageDefault = 13 export default config diff --git a/data/config.baseSsm.js b/data/config.baseSsm.js index ea3bc42b..23823626 100644 --- a/data/config.baseSsm.js +++ b/data/config.baseSsm.js @@ -13,7 +13,7 @@ config.settings.burialSites.burialSiteNameSegments = { maxLength: 1 }, 2: { - isRequired: true, + isRequired: false, isAvailable: true, label: 'Range', minLength: 1, @@ -36,6 +36,10 @@ config.settings.burialSites.burialSiteNameSegments = { } }; config.settings.cityDefault = 'Sault Ste. Marie'; +config.settings.latitudeMax = 46.75; +config.settings.latitudeMin = 46.4; +config.settings.longitudeMax = -84.2; +config.settings.longitudeMin = -84.5; config.settings.contracts.prints = [ 'pdf/ssm.cemetery.burialPermit', 'pdf/ssm.cemetery.contract' diff --git a/data/config.baseSsm.ts b/data/config.baseSsm.ts index 7059e2ef..1b730809 100644 --- a/data/config.baseSsm.ts +++ b/data/config.baseSsm.ts @@ -18,7 +18,7 @@ config.settings.burialSites.burialSiteNameSegments = { maxLength: 1 }, 2: { - isRequired: true, + isRequired: false, isAvailable: true, label: 'Range', minLength: 1, @@ -43,6 +43,11 @@ config.settings.burialSites.burialSiteNameSegments = { config.settings.cityDefault = 'Sault Ste. Marie' +config.settings.latitudeMax = 46.75 +config.settings.latitudeMin = 46.4 +config.settings.longitudeMax = -84.2 +config.settings.longitudeMin = -84.5 + config.settings.contracts.prints = [ 'pdf/ssm.cemetery.burialPermit', 'pdf/ssm.cemetery.contract' diff --git a/data/config.defaultValues.d.ts b/data/config.defaultValues.d.ts index 7697af44..47789579 100644 --- a/data/config.defaultValues.d.ts +++ b/data/config.defaultValues.d.ts @@ -26,9 +26,15 @@ export declare const configDefaultValues: { 'aliases.workOrderCloseDate': string; 'settings.cityDefault': string; 'settings.provinceDefault': string; + 'settings.latitudeMin': number; + 'settings.latitudeMax': number; + 'settings.longitudeMin': number; + 'settings.longitudeMax': number; 'settings.burialSites.burialSiteNameSegments': ConfigBurialSiteNameSegments; + 'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': boolean; 'settings.contracts.burialSiteIdIsRequired': boolean; 'settings.contracts.contractEndDateIsRequired': boolean; + 'settings.contracts.purchaserRelationships': string[]; 'settings.contracts.deathAgePeriods': string[]; 'settings.contracts.prints': string[]; 'settings.fees.taxPercentageDefault': number; diff --git a/data/config.defaultValues.js b/data/config.defaultValues.js index 932319f8..61c99212 100644 --- a/data/config.defaultValues.js +++ b/data/config.defaultValues.js @@ -4,7 +4,7 @@ export const configDefaultValues = { 'application.applicationName': 'Sunrise CMS', 'application.backgroundURL': '/images/cemetery-background.jpg', 'application.logoURL': '/images/sunrise-cms.svg', - 'application.httpPort': 7000, + 'application.httpPort': 9000, 'application.userDomain': '', 'application.useTestDatabases': false, 'application.maximumProcesses': 4, @@ -25,8 +25,13 @@ export const configDefaultValues = { 'aliases.workOrderCloseDate': 'Completion Date', 'settings.cityDefault': '', 'settings.provinceDefault': '', + 'settings.latitudeMin': -90, + 'settings.latitudeMax': 90, + 'settings.longitudeMin': -180, + 'settings.longitudeMax': 180, 'settings.burialSites.burialSiteNameSegments': { separator: '-', + includeCemeteryKey: false, segments: { 1: { isRequired: true, @@ -37,9 +42,23 @@ export const configDefaultValues = { } } }, + 'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': false, 'settings.contracts.burialSiteIdIsRequired': true, 'settings.contracts.contractEndDateIsRequired': false, - 'settings.contracts.deathAgePeriods': ['Years', 'Months', 'Days', 'Stillborn'], + 'settings.contracts.purchaserRelationships': [ + 'Spouse', + 'Child', + 'Parent', + 'Sibling', + 'Friend', + 'Self' + ], + 'settings.contracts.deathAgePeriods': [ + 'Years', + 'Months', + 'Days', + 'Stillborn' + ], 'settings.contracts.prints': ['screen/contract'], 'settings.fees.taxPercentageDefault': 0, 'settings.workOrders.workOrderNumberLength': 6, diff --git a/data/config.defaultValues.ts b/data/config.defaultValues.ts index 6e3759dc..7c1638d8 100644 --- a/data/config.defaultValues.ts +++ b/data/config.defaultValues.ts @@ -14,7 +14,7 @@ export const configDefaultValues = { 'application.applicationName': 'Sunrise CMS', 'application.backgroundURL': '/images/cemetery-background.jpg', 'application.logoURL': '/images/sunrise-cms.svg', - 'application.httpPort': 7000, + 'application.httpPort': 9000, 'application.userDomain': '', 'application.useTestDatabases': false, 'application.maximumProcesses': 4, @@ -42,8 +42,14 @@ export const configDefaultValues = { 'settings.cityDefault': '', 'settings.provinceDefault': '', + 'settings.latitudeMin': -90, + 'settings.latitudeMax': 90, + 'settings.longitudeMin': -180, + 'settings.longitudeMax': 180, + 'settings.burialSites.burialSiteNameSegments': { separator: '-', + includeCemeteryKey: false, segments: { 1: { isRequired: true, @@ -55,10 +61,24 @@ export const configDefaultValues = { } } as unknown as ConfigBurialSiteNameSegments, + 'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': false, 'settings.contracts.burialSiteIdIsRequired': true, 'settings.contracts.contractEndDateIsRequired': false, - 'settings.contracts.deathAgePeriods': ['Years', 'Months', 'Days', 'Stillborn'], + 'settings.contracts.purchaserRelationships': [ + 'Spouse', + 'Child', + 'Parent', + 'Sibling', + 'Friend', + 'Self' + ], + 'settings.contracts.deathAgePeriods': [ + 'Years', + 'Months', + 'Days', + 'Stillborn' + ], 'settings.contracts.prints': ['screen/contract'], 'settings.fees.taxPercentageDefault': 0, diff --git a/database/getReportData.js b/database/getReportData.js index de34aca3..5dc4cc55 100644 --- a/database/getReportData.js +++ b/database/getReportData.js @@ -1,224 +1,182 @@ import { dateIntegerToString, dateStringToInteger, dateToInteger, timeIntegerToString } from '@cityssm/utils-datetime'; import { acquireConnection } from './pool.js'; -// eslint-disable-next-line complexity +const simpleReports = { + 'burialSiteComments-all': 'select * from BurialSiteComments', + 'burialSiteFields-all': 'select * from BurialSiteFields', + 'burialSites-all': 'select * from BurialSites', + 'burialSiteStatuses-all': 'select * from BurialSiteStatuses', + 'burialSiteTypeFields-all': 'select * from BurialSiteTypeFields', + 'burialSiteTypes-all': 'select * from BurialSiteTypes', + 'cemeteries-all': 'select * from Cemeteries', + 'cemeteries-formatted': `select cemeteryName, + cemeteryDescription, + cemeteryAddress1, cemeteryAddress2, + cemeteryCity, cemeteryProvince, + cemeteryPostalCode, + cemeteryPhoneNumber + from Cemeteries + where recordDelete_timeMillis is null + order by cemeteryName`, + 'contractComments-all': 'select * from ContractComments', + 'contractFees-all': 'select * from ContractFees', + 'contractFields-all': 'select * from ContractFields', + 'contractInterments-all': 'select * from ContractInterments', + 'contracts-all': 'select * from Contracts', + 'contractTransactions-all': 'select * from ContractTransactions', + 'contractTypeFields-all': 'select * from ContractTypeFields', + 'contractTypes-all': 'select * from ContractTypes', + 'feeCategories-all': 'select * from FeeCategories', + 'fees-all': 'select * from Fees', + 'funeralHomes-all': 'select * from FuneralHomes', + 'funeralHomes-formatted': `select funeralHomeName, + funeralHomeAddress1, funeralHomeAddress2, + funeralHomeCity, funeralHomeProvince, + funeralHomePostalCode, + funeralHomePhoneNumber + from FuneralHomes + where recordDelete_timeMillis is null`, + 'intermentContainerTypes-all': 'select * from IntermentContainerTypes', + 'workOrderBurialSites-all': 'select * from WorkOrderBurialSites', + 'workOrderComments-all': 'select * from WorkOrderComments', + 'workOrderMilestones-all': 'select * from WorkOrderMilestones', + 'workOrderMilestoneTypes-all': 'select * from WorkOrderMilestoneTypes', + 'workOrders-all': 'select * from WorkOrders', + 'workOrderTypes-all': 'select * from WorkOrderTypes' +}; export default async function getReportData(reportName, reportParameters = {}) { let sql = ''; const sqlParameters = []; - switch (reportName) { - case 'cemeteries-all': { - sql = 'select * from Cemeteries'; - break; - } - case 'cemeteries-formatted': { - sql = `select cemeteryName, - cemeteryDescription, - cemeteryAddress1, cemeteryAddress2, - cemeteryCity, cemeteryProvince, - cemeteryPostalCode, - cemeteryPhoneNumber - from Cemeteries - where recordDelete_timeMillis is null - order by cemeteryName`; - break; - } - case 'burialSites-all': { - sql = 'select * from BurialSites'; - break; - } - case 'burialSites-byBurialSiteTypeId': { - sql = `select l.burialSiteId, - m.cemeteryName, - l.burialSiteName, - t.burialSiteType, - s.burialSiteStatus - from BurialSites l - left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId - left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where l.recordDelete_timeMillis is null - and l.burialSiteTypeId = ?`; - sqlParameters.push(reportParameters.burialSiteTypeId); - break; - } - case 'burialSites-byBurialSiteStatusId': { - sql = `select l.burialSiteId, - m.cemeteryName, - l.burialSiteName, - t.burialSiteType, - s.burialSiteStatus - from BurialSites l - left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId - left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where l.recordDelete_timeMillis is null - and l.burialSiteStatusId = ?`; - sqlParameters.push(reportParameters.burialSiteStatusId); - break; - } - case 'burialSites-byCemeteryId': { - sql = `select l.burialSiteId, - m.cemeteryName, - l.burialSiteName, - t.burialSiteType, - s.burialSiteStatus - from BurialSites l - left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId - left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where l.recordDelete_timeMillis is null - and l.cemeteryId = ?`; - sqlParameters.push(reportParameters.cemeteryId); - break; - } - case 'burialSiteComments-all': { - sql = 'select * from BurialSiteComments'; - break; - } - case 'burialSiteFields-all': { - sql = 'select * from BurialSiteFields'; - break; - } - case 'contracts-all': { - sql = 'select * from Contracts'; - break; - } - case 'contracts-current-byCemeteryId': { - sql = `select o.contractId, - l.burialSiteName, - m.cemeteryName, - ot.contractType, - o.contractStartDate, - o.contractEndDate - from Contracts o - left join ContractTypes ot on o.contractTypeId = ot.contractTypeId - left join BurialSites l on o.burialSiteId = l.burialSiteId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where o.recordDelete_timeMillis is null - and (o.contractEndDate is null or o.contractEndDate >= ?) - and l.cemeteryId = ?`; - sqlParameters.push(dateToInteger(new Date()), reportParameters.cemeteryId); - break; - } - case 'contractComments-all': { - sql = 'select * from ContractComments'; - break; - } - case 'contractFees-all': { - sql = 'select * from ContractFees'; - break; - } - case 'contractFields-all': { - sql = 'select * from ContractFields'; - break; - } - case 'contractInterments-all': { - sql = 'select * from ContractInterments'; - break; - } - case 'contractTransactions-all': { - sql = 'select * from ContractTransactions'; - break; - } - case 'contractTransactions-byTransactionDateString': { - sql = `select t.contractId, t.transactionIndex, - t.transactionDate, t.transactionTime, - t.transactionAmount, - t.externalReceiptNumber, t.transactionNote - from ContractTransactions t - where t.recordDelete_timeMillis is null - and t.transactionDate = ?`; - sqlParameters.push(dateStringToInteger(reportParameters.transactionDateString)); - break; - } - case 'workOrders-all': { - sql = 'select * from WorkOrders'; - break; - } - case 'workOrders-open': { - sql = `select w.workOrderId, w.workOrderNumber, - t.workOrderType, w.workOrderDescription, - w.workOrderOpenDate, - m.workOrderMilestoneCount, m.workOrderMilestoneCompletionCount - from WorkOrders w - left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId - left join ( - select m.workOrderId, - count(m.workOrderMilestoneId) as workOrderMilestoneCount, - sum(case when m.workOrderMilestoneCompletionDate is null then 0 else 1 end) as workOrderMilestoneCompletionCount + // eslint-disable-next-line security/detect-object-injection + if (simpleReports[reportName] === undefined) { + switch (reportName) { + case 'burialSites-byBurialSiteTypeId': { + sql = `select l.burialSiteId, + m.cemeteryName, + l.burialSiteName, + t.burialSiteType, + s.burialSiteStatus + from BurialSites l + left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId + left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where l.recordDelete_timeMillis is null + and l.burialSiteTypeId = ?`; + sqlParameters.push(reportParameters.burialSiteTypeId); + break; + } + case 'burialSites-byBurialSiteStatusId': { + sql = `select l.burialSiteId, + m.cemeteryName, + l.burialSiteName, + t.burialSiteType, + s.burialSiteStatus + from BurialSites l + left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId + left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where l.recordDelete_timeMillis is null + and l.burialSiteStatusId = ?`; + sqlParameters.push(reportParameters.burialSiteStatusId); + break; + } + case 'burialSites-byCemeteryId': { + sql = `select l.burialSiteId, + m.cemeteryName, + l.burialSiteName, + t.burialSiteType, + s.burialSiteStatus + from BurialSites l + left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId + left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where l.recordDelete_timeMillis is null + and l.cemeteryId = ?`; + sqlParameters.push(reportParameters.cemeteryId); + break; + } + case 'contracts-current-byCemeteryId': { + sql = `select o.contractId, + l.burialSiteName, + m.cemeteryName, + ot.contractType, + o.contractStartDate, + o.contractEndDate + from Contracts o + left join ContractTypes ot on o.contractTypeId = ot.contractTypeId + left join BurialSites l on o.burialSiteId = l.burialSiteId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where o.recordDelete_timeMillis is null + and (o.contractEndDate is null or o.contractEndDate >= ?) + and l.cemeteryId = ?`; + sqlParameters.push(dateToInteger(new Date()), reportParameters.cemeteryId); + break; + } + case 'contractInterments-byContractId': { + sql = `select i.contractId, i.intermentNumber, + i.deceasedName, i.deceasedAddress1, i.deceasedAddress2, + i.deceasedCity, i.deceasedProvince, i.deceasedPostalCode, + i.birthDate, i.birthPlace, + i.deathDate, i.deathPlace, + i.deathAge, i.deathAgePeriod + from ContractInterments i + left join IntermentContainerTypes t on i.intermentContainerTypeId = t.intermentContainerTypeId + where i.recordDelete_timeMillis is null + and i.contractId = ?`; + sqlParameters.push(reportParameters.contractId); + break; + } + case 'contractTransactions-byTransactionDateString': { + sql = `select t.contractId, t.transactionIndex, + t.transactionDate, t.transactionTime, + t.transactionAmount, + t.externalReceiptNumber, t.transactionNote + from ContractTransactions t + where t.recordDelete_timeMillis is null + and t.transactionDate = ?`; + sqlParameters.push(dateStringToInteger(reportParameters.transactionDateString)); + break; + } + case 'workOrders-open': { + sql = `select w.workOrderId, w.workOrderNumber, + t.workOrderType, w.workOrderDescription, + w.workOrderOpenDate, + m.workOrderMilestoneCount, m.workOrderMilestoneCompletionCount + from WorkOrders w + left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId + left join ( + select m.workOrderId, + count(m.workOrderMilestoneId) as workOrderMilestoneCount, + sum(case when m.workOrderMilestoneCompletionDate is null then 0 else 1 end) as workOrderMilestoneCompletionCount + from WorkOrderMilestones m + where m.recordDelete_timeMillis is null + group by m.workOrderId + ) m on w.workOrderId = m.workOrderId + where w.recordDelete_timeMillis is null + and w.workOrderCloseDate is null`; + break; + } + case 'workOrderMilestones-byWorkOrderId': { + sql = `select t.workOrderMilestoneType, + m.workOrderMilestoneDate, + m.workOrderMilestoneTime, + m.workOrderMilestoneDescription, + m.workOrderMilestoneCompletionDate, + m.workOrderMilestoneCompletionTime from WorkOrderMilestones m + left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId where m.recordDelete_timeMillis is null - group by m.workOrderId - ) m on w.workOrderId = m.workOrderId - where w.recordDelete_timeMillis is null - and w.workOrderCloseDate is null`; - break; - } - case 'workOrderComments-all': { - sql = 'select * from WorkOrderComments'; - break; - } - case 'workOrderBurialSites-all': { - sql = 'select * from WorkOrderBurialSites'; - break; - } - case 'workOrderMilestones-all': { - sql = 'select * from WorkOrderMilestones'; - break; - } - case 'workOrderMilestones-byWorkOrderId': { - sql = `select t.workOrderMilestoneType, - m.workOrderMilestoneDate, - m.workOrderMilestoneTime, - m.workOrderMilestoneDescription, - m.workOrderMilestoneCompletionDate, - m.workOrderMilestoneCompletionTime - from WorkOrderMilestones m - left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId - where m.recordDelete_timeMillis is null - and m.workOrderId = ?`; - sqlParameters.push(reportParameters.workOrderId); - break; - } - case 'fees-all': { - sql = 'select * from Fees'; - break; - } - case 'feeCategories-all': { - sql = 'select * from FeeCategories'; - break; - } - case 'burialSiteTypes-all': { - sql = 'select * from BurialSiteTypes'; - break; - } - case 'burialSiteTypeFields-all': { - sql = 'select * from BurialSiteTypeFields'; - break; - } - case 'burialSiteStatuses-all': { - sql = 'select * from BurialSiteStatuses'; - break; - } - case 'contractTypes-all': { - sql = 'select * from ContractTypes'; - break; - } - case 'contractTypeFields-all': { - sql = 'select * from ContractTypeFields'; - break; - } - case 'workOrderTypes-all': { - sql = 'select * from WorkOrderTypes'; - break; - } - case 'workOrderMilestoneTypes-all': { - sql = 'select * from WorkOrderMilestoneTypes'; - break; - } - default: { - return undefined; + and m.workOrderId = ?`; + sqlParameters.push(reportParameters.workOrderId); + break; + } + default: { + return undefined; + } } } + else { + sql = simpleReports[reportName]; + } const database = await acquireConnection(); database.function('userFn_dateIntegerToString', dateIntegerToString); database.function('userFn_timeIntegerToString', timeIntegerToString); diff --git a/database/getReportData.ts b/database/getReportData.ts index b50237f9..1895f664 100644 --- a/database/getReportData.ts +++ b/database/getReportData.ts @@ -10,7 +10,54 @@ import { acquireConnection } from './pool.js' export type ReportParameters = Record -// eslint-disable-next-line complexity +const simpleReports: Record<`${string}-all` | `${string}-formatted`, string> = { + 'burialSiteComments-all': 'select * from BurialSiteComments', + 'burialSiteFields-all': 'select * from BurialSiteFields', + 'burialSites-all': 'select * from BurialSites', + 'burialSiteStatuses-all': 'select * from BurialSiteStatuses', + 'burialSiteTypeFields-all': 'select * from BurialSiteTypeFields', + 'burialSiteTypes-all': 'select * from BurialSiteTypes', + + 'cemeteries-all': 'select * from Cemeteries', + 'cemeteries-formatted': `select cemeteryName, + cemeteryDescription, + cemeteryAddress1, cemeteryAddress2, + cemeteryCity, cemeteryProvince, + cemeteryPostalCode, + cemeteryPhoneNumber + from Cemeteries + where recordDelete_timeMillis is null + order by cemeteryName`, + + 'contractComments-all': 'select * from ContractComments', + 'contractFees-all': 'select * from ContractFees', + 'contractFields-all': 'select * from ContractFields', + 'contractInterments-all': 'select * from ContractInterments', + 'contracts-all': 'select * from Contracts', + 'contractTransactions-all': 'select * from ContractTransactions', + 'contractTypeFields-all': 'select * from ContractTypeFields', + 'contractTypes-all': 'select * from ContractTypes', + 'feeCategories-all': 'select * from FeeCategories', + 'fees-all': 'select * from Fees', + + 'funeralHomes-all': 'select * from FuneralHomes', + 'funeralHomes-formatted': `select funeralHomeName, + funeralHomeAddress1, funeralHomeAddress2, + funeralHomeCity, funeralHomeProvince, + funeralHomePostalCode, + funeralHomePhoneNumber + from FuneralHomes + where recordDelete_timeMillis is null`, + + 'intermentContainerTypes-all': 'select * from IntermentContainerTypes', + 'workOrderBurialSites-all': 'select * from WorkOrderBurialSites', + 'workOrderComments-all': 'select * from WorkOrderComments', + 'workOrderMilestones-all': 'select * from WorkOrderMilestones', + 'workOrderMilestoneTypes-all': 'select * from WorkOrderMilestoneTypes', + 'workOrders-all': 'select * from WorkOrders', + 'workOrderTypes-all': 'select * from WorkOrderTypes' +} + export default async function getReportData( reportName: string, reportParameters: ReportParameters = {} @@ -18,265 +65,163 @@ export default async function getReportData( let sql = '' const sqlParameters: unknown[] = [] - switch (reportName) { - case 'cemeteries-all': { - sql = 'select * from Cemeteries' - break - } + // eslint-disable-next-line security/detect-object-injection + if (simpleReports[reportName] === undefined) { + switch (reportName) { + case 'burialSites-byBurialSiteTypeId': { + sql = `select l.burialSiteId, + m.cemeteryName, + l.burialSiteName, + t.burialSiteType, + s.burialSiteStatus + from BurialSites l + left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId + left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where l.recordDelete_timeMillis is null + and l.burialSiteTypeId = ?` - case 'cemeteries-formatted': { - sql = `select cemeteryName, - cemeteryDescription, - cemeteryAddress1, cemeteryAddress2, - cemeteryCity, cemeteryProvince, - cemeteryPostalCode, - cemeteryPhoneNumber - from Cemeteries - where recordDelete_timeMillis is null - order by cemeteryName` + sqlParameters.push(reportParameters.burialSiteTypeId) - break - } + break + } - case 'burialSites-all': { - sql = 'select * from BurialSites' - break - } + case 'burialSites-byBurialSiteStatusId': { + sql = `select l.burialSiteId, + m.cemeteryName, + l.burialSiteName, + t.burialSiteType, + s.burialSiteStatus + from BurialSites l + left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId + left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where l.recordDelete_timeMillis is null + and l.burialSiteStatusId = ?` - case 'burialSites-byBurialSiteTypeId': { - sql = `select l.burialSiteId, - m.cemeteryName, - l.burialSiteName, - t.burialSiteType, - s.burialSiteStatus - from BurialSites l - left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId - left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where l.recordDelete_timeMillis is null - and l.burialSiteTypeId = ?` + sqlParameters.push(reportParameters.burialSiteStatusId) - sqlParameters.push(reportParameters.burialSiteTypeId) + break + } - break - } + case 'burialSites-byCemeteryId': { + sql = `select l.burialSiteId, + m.cemeteryName, + l.burialSiteName, + t.burialSiteType, + s.burialSiteStatus + from BurialSites l + left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId + left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where l.recordDelete_timeMillis is null + and l.cemeteryId = ?` - case 'burialSites-byBurialSiteStatusId': { - sql = `select l.burialSiteId, - m.cemeteryName, - l.burialSiteName, - t.burialSiteType, - s.burialSiteStatus - from BurialSites l - left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId - left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where l.recordDelete_timeMillis is null - and l.burialSiteStatusId = ?` + sqlParameters.push(reportParameters.cemeteryId) - sqlParameters.push(reportParameters.burialSiteStatusId) + break + } - break - } + case 'contracts-current-byCemeteryId': { + sql = `select o.contractId, + l.burialSiteName, + m.cemeteryName, + ot.contractType, + o.contractStartDate, + o.contractEndDate + from Contracts o + left join ContractTypes ot on o.contractTypeId = ot.contractTypeId + left join BurialSites l on o.burialSiteId = l.burialSiteId + left join Cemeteries m on l.cemeteryId = m.cemeteryId + where o.recordDelete_timeMillis is null + and (o.contractEndDate is null or o.contractEndDate >= ?) + and l.cemeteryId = ?` - case 'burialSites-byCemeteryId': { - sql = `select l.burialSiteId, - m.cemeteryName, - l.burialSiteName, - t.burialSiteType, - s.burialSiteStatus - from BurialSites l - left join BurialSiteTypes t on l.burialSiteTypeId = t.burialSiteTypeId - left join BurialSiteStatuses s on l.burialSiteStatusId = s.burialSiteStatusId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where l.recordDelete_timeMillis is null - and l.cemeteryId = ?` - - sqlParameters.push(reportParameters.cemeteryId) - - break - } - - case 'burialSiteComments-all': { - sql = 'select * from BurialSiteComments' - break - } - - case 'burialSiteFields-all': { - sql = 'select * from BurialSiteFields' - break - } - - case 'contracts-all': { - sql = 'select * from Contracts' - break - } - - case 'contracts-current-byCemeteryId': { - sql = `select o.contractId, - l.burialSiteName, - m.cemeteryName, - ot.contractType, - o.contractStartDate, - o.contractEndDate - from Contracts o - left join ContractTypes ot on o.contractTypeId = ot.contractTypeId - left join BurialSites l on o.burialSiteId = l.burialSiteId - left join Cemeteries m on l.cemeteryId = m.cemeteryId - where o.recordDelete_timeMillis is null - and (o.contractEndDate is null or o.contractEndDate >= ?) - and l.cemeteryId = ?` - - sqlParameters.push(dateToInteger(new Date()), reportParameters.cemeteryId) - - break - } - - case 'contractComments-all': { - sql = 'select * from ContractComments' - break - } - - case 'contractFees-all': { - sql = 'select * from ContractFees' - break - } - - case 'contractFields-all': { - sql = 'select * from ContractFields' - break - } - - case 'contractInterments-all': { - sql = 'select * from ContractInterments' - break - } - - case 'contractTransactions-all': { - sql = 'select * from ContractTransactions' - break - } - - case 'contractTransactions-byTransactionDateString': { - sql = `select t.contractId, t.transactionIndex, - t.transactionDate, t.transactionTime, - t.transactionAmount, - t.externalReceiptNumber, t.transactionNote - from ContractTransactions t - where t.recordDelete_timeMillis is null - and t.transactionDate = ?` - - sqlParameters.push( - dateStringToInteger( - reportParameters.transactionDateString as DateString + sqlParameters.push( + dateToInteger(new Date()), + reportParameters.cemeteryId ) - ) - break - } - case 'workOrders-all': { - sql = 'select * from WorkOrders' - break - } + break + } - case 'workOrders-open': { - sql = `select w.workOrderId, w.workOrderNumber, - t.workOrderType, w.workOrderDescription, - w.workOrderOpenDate, - m.workOrderMilestoneCount, m.workOrderMilestoneCompletionCount - from WorkOrders w - left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId - left join ( - select m.workOrderId, - count(m.workOrderMilestoneId) as workOrderMilestoneCount, - sum(case when m.workOrderMilestoneCompletionDate is null then 0 else 1 end) as workOrderMilestoneCompletionCount + case 'contractInterments-byContractId': { + sql = `select i.contractId, i.intermentNumber, + i.deceasedName, i.deceasedAddress1, i.deceasedAddress2, + i.deceasedCity, i.deceasedProvince, i.deceasedPostalCode, + i.birthDate, i.birthPlace, + i.deathDate, i.deathPlace, + i.deathAge, i.deathAgePeriod + from ContractInterments i + left join IntermentContainerTypes t on i.intermentContainerTypeId = t.intermentContainerTypeId + where i.recordDelete_timeMillis is null + and i.contractId = ?` + + sqlParameters.push(reportParameters.contractId) + + break + } + + case 'contractTransactions-byTransactionDateString': { + sql = `select t.contractId, t.transactionIndex, + t.transactionDate, t.transactionTime, + t.transactionAmount, + t.externalReceiptNumber, t.transactionNote + from ContractTransactions t + where t.recordDelete_timeMillis is null + and t.transactionDate = ?` + + sqlParameters.push( + dateStringToInteger( + reportParameters.transactionDateString as DateString + ) + ) + break + } + + case 'workOrders-open': { + sql = `select w.workOrderId, w.workOrderNumber, + t.workOrderType, w.workOrderDescription, + w.workOrderOpenDate, + m.workOrderMilestoneCount, m.workOrderMilestoneCompletionCount + from WorkOrders w + left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId + left join ( + select m.workOrderId, + count(m.workOrderMilestoneId) as workOrderMilestoneCount, + sum(case when m.workOrderMilestoneCompletionDate is null then 0 else 1 end) as workOrderMilestoneCompletionCount + from WorkOrderMilestones m + where m.recordDelete_timeMillis is null + group by m.workOrderId + ) m on w.workOrderId = m.workOrderId + where w.recordDelete_timeMillis is null + and w.workOrderCloseDate is null` + + break + } + + case 'workOrderMilestones-byWorkOrderId': { + sql = `select t.workOrderMilestoneType, + m.workOrderMilestoneDate, + m.workOrderMilestoneTime, + m.workOrderMilestoneDescription, + m.workOrderMilestoneCompletionDate, + m.workOrderMilestoneCompletionTime from WorkOrderMilestones m + left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId where m.recordDelete_timeMillis is null - group by m.workOrderId - ) m on w.workOrderId = m.workOrderId - where w.recordDelete_timeMillis is null - and w.workOrderCloseDate is null` - break - } + and m.workOrderId = ?` - case 'workOrderComments-all': { - sql = 'select * from WorkOrderComments' - break - } + sqlParameters.push(reportParameters.workOrderId) + break + } - case 'workOrderBurialSites-all': { - sql = 'select * from WorkOrderBurialSites' - break - } - - case 'workOrderMilestones-all': { - sql = 'select * from WorkOrderMilestones' - break - } - - case 'workOrderMilestones-byWorkOrderId': { - sql = `select t.workOrderMilestoneType, - m.workOrderMilestoneDate, - m.workOrderMilestoneTime, - m.workOrderMilestoneDescription, - m.workOrderMilestoneCompletionDate, - m.workOrderMilestoneCompletionTime - from WorkOrderMilestones m - left join WorkOrderMilestoneTypes t on m.workOrderMilestoneTypeId = t.workOrderMilestoneTypeId - where m.recordDelete_timeMillis is null - and m.workOrderId = ?` - sqlParameters.push(reportParameters.workOrderId) - break - } - - case 'fees-all': { - sql = 'select * from Fees' - break - } - - case 'feeCategories-all': { - sql = 'select * from FeeCategories' - break - } - - case 'burialSiteTypes-all': { - sql = 'select * from BurialSiteTypes' - break - } - - case 'burialSiteTypeFields-all': { - sql = 'select * from BurialSiteTypeFields' - break - } - - case 'burialSiteStatuses-all': { - sql = 'select * from BurialSiteStatuses' - break - } - - case 'contractTypes-all': { - sql = 'select * from ContractTypes' - break - } - - case 'contractTypeFields-all': { - sql = 'select * from ContractTypeFields' - break - } - - case 'workOrderTypes-all': { - sql = 'select * from WorkOrderTypes' - break - } - - case 'workOrderMilestoneTypes-all': { - sql = 'select * from WorkOrderMilestoneTypes' - break - } - - default: { - return undefined + default: { + return undefined + } } + } else { + sql = simpleReports[reportName] } const database = await acquireConnection() diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..90813407 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,7 @@ +[Home](https://cityssm.github.io/sunrise-csm/) + +# Help Documentation + +**Thank you for taking the time to read the documentation.** + +**Coming soon.** diff --git a/handlers/contracts-get/view.js b/handlers/contracts-get/view.js index 0758415c..6cc7a445 100644 --- a/handlers/contracts-get/view.js +++ b/handlers/contracts-get/view.js @@ -9,7 +9,7 @@ export default async function handler(request, response) { } const contractTypePrints = await getContractTypePrintsById(contract.contractTypeId); response.render('contract-view', { - headTitle: 'Contract View', + headTitle: `Contract #${contract.contractId.toString()}`, contract, contractTypePrints }); diff --git a/handlers/contracts-get/view.ts b/handlers/contracts-get/view.ts index af1a703f..f87b0542 100644 --- a/handlers/contracts-get/view.ts +++ b/handlers/contracts-get/view.ts @@ -26,7 +26,7 @@ export default async function handler( ) response.render('contract-view', { - headTitle: 'Contract View', + headTitle: `Contract #${contract.contractId.toString()}`, contract, contractTypePrints }) diff --git a/handlers/dashboard-get/dashboard.js b/handlers/dashboard-get/dashboard.js index 39b6bff6..d404db4b 100644 --- a/handlers/dashboard-get/dashboard.js +++ b/handlers/dashboard-get/dashboard.js @@ -1,7 +1,5 @@ import { dateToString } from '@cityssm/utils-datetime'; -import getContracts from '../../database/getContracts.js'; import getWorkOrderMilestones from '../../database/getWorkOrderMilestones.js'; -import { getWorkOrders } from '../../database/getWorkOrders.js'; export default async function handler(_request, response) { const currentDateString = dateToString(new Date()); const workOrderMilestones = await getWorkOrderMilestones({ @@ -11,25 +9,8 @@ export default async function handler(_request, response) { orderBy: 'completion', includeWorkOrders: true }); - const workOrderResults = await getWorkOrders({ - workOrderOpenDateString: currentDateString - }, { - limit: 1, // only using the count - offset: 0 - }); - const contractResults = await getContracts({ - contractStartDateString: currentDateString - }, { - limit: 1, // only using the count - offset: 0, - includeFees: false, - includeInterments: false, - includeTransactions: false - }); response.render('dashboard', { headTitle: 'Dashboard', - workOrderMilestones, - workOrderCount: workOrderResults.count, - contractCount: contractResults.count + workOrderMilestones }); } diff --git a/handlers/dashboard-get/dashboard.ts b/handlers/dashboard-get/dashboard.ts index c28a2493..0d1d037a 100644 --- a/handlers/dashboard-get/dashboard.ts +++ b/handlers/dashboard-get/dashboard.ts @@ -1,9 +1,7 @@ import { dateToString } from '@cityssm/utils-datetime' import type { Request, Response } from 'express' -import getContracts from '../../database/getContracts.js' import getWorkOrderMilestones from '../../database/getWorkOrderMilestones.js' -import { getWorkOrders } from '../../database/getWorkOrders.js' export default async function handler( _request: Request, @@ -22,33 +20,8 @@ export default async function handler( } ) - const workOrderResults = await getWorkOrders( - { - workOrderOpenDateString: currentDateString - }, - { - limit: 1, // only using the count - offset: 0 - } - ) - - const contractResults = await getContracts( - { - contractStartDateString: currentDateString - }, - { - limit: 1, // only using the count - offset: 0, - includeFees: false, - includeInterments: false, - includeTransactions: false - } - ) - response.render('dashboard', { headTitle: 'Dashboard', - workOrderMilestones, - workOrderCount: workOrderResults.count, - contractCount: contractResults.count + workOrderMilestones }) } diff --git a/helpers/burialSites.helpers.js b/helpers/burialSites.helpers.js index de18aefd..ab7653ef 100644 --- a/helpers/burialSites.helpers.js +++ b/helpers/burialSites.helpers.js @@ -31,7 +31,9 @@ function cacheBurialSiteIds(burialSiteId, nextBurialSiteId, relayMessage = true) process.send(workerMessage); } } - catch { } + catch { + // Ignore + } } export async function getNextBurialSiteId(burialSiteId) { let nextBurialSiteId = nextBurialSiteIdCache.get(burialSiteId); @@ -82,7 +84,9 @@ export function clearNextPreviousBurialSiteIdCache(burialSiteId = -1, relayMessa process.send(workerMessage); } } - catch { } + catch { + // Ignore + } } const segmentConfig = getConfigProperty('settings.burialSites.burialSiteNameSegments'); export function buildBurialSiteName(cemeteryKey, segments) { diff --git a/helpers/burialSites.helpers.ts b/helpers/burialSites.helpers.ts index 3779ac6f..c9b361f3 100644 --- a/helpers/burialSites.helpers.ts +++ b/helpers/burialSites.helpers.ts @@ -52,7 +52,9 @@ function cacheBurialSiteIds( process.send(workerMessage) } - } catch {} + } catch { + // Ignore + } } export async function getNextBurialSiteId( @@ -131,7 +133,9 @@ export function clearNextPreviousBurialSiteIdCache( process.send(workerMessage) } - } catch {} + } catch { + // Ignore + } } const segmentConfig = getConfigProperty( diff --git a/package-lock.json b/package-lock.json index 0aa81db0..9304ad00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,14 +59,12 @@ "@types/express-session": "^1.18.1", "@types/http-errors": "^2.0.4", "@types/leaflet": "^1.9.16", - "@types/mocha": "^10.0.10", "@types/mssql": "^9.1.7", "@types/node-windows": "^0.1.6", "@types/papaparse": "^5.3.15", "@types/randomcolor": "^0.5.9", "@types/session-file-store": "^1.2.5", "axe-core": "^4.10.3", - "bulma": "^1.0.3", "cypress": "^14.2.0", "cypress-axe": "^1.6.0", "eslint-config-cityssm": "^20.0.0", @@ -1831,8 +1829,9 @@ "version": "10.0.10", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@types/ms": { "version": "0.7.31", @@ -3081,13 +3080,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bulma": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.3.tgz", - "integrity": "sha512-9eVXBrXwlU337XUXBjIIq7i88A+tRbJYAjXQjT/21lwam+5tpvKF0R7dCesre9N+HV9c6pzCNEPKrtgvBBes2g==", - "dev": true, - "license": "MIT" - }, "node_modules/bulma-tooltip": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bulma-tooltip/-/bulma-tooltip-3.0.2.tgz", diff --git a/package.json b/package.json index 80b8295c..63edef59 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,9 @@ "cy:open": "cypress open --config-file cypress.config.js", "cy:run": "cypress run --config-file cypress.config.js", "cy:run:firefox": "cypress run --config-file cypress.config.js --browser firefox", - "test": "cross-env NODE_ENV=dev DEBUG=sunrise:* TEST_DATABASES=true mocha --timeout 30000 --exit", + "test": "cross-env NODE_ENV=dev DEBUG=sunrise:* TEST_DATABASES=true node --test", "test:startup": "cross-env NODE_ENV=dev DEBUG=sunrise:* TEST_DATABASES=true STARTUP_TEST=true node ./bin/www.js", - "coverage": "cross-env NODE_ENV=dev DEBUG=sunrise:* TEST_DATABASES=true c8 --reporter=lcov --reporter=text --reporter=text-summary mocha --timeout 30000 --exit", + "coverage": "cross-env NODE_ENV=dev DEBUG=sunrise:* TEST_DATABASES=true c8 --reporter=lcov --reporter=text --reporter=text-summary node --test", "temp:legacyImportFromCsv": "cross-env NODE_ENV=dev DEBUG=sunrise:* TEST_DATABASES=true node ./temp/legacyImportFromCsv/index.js" }, "repository": { @@ -82,14 +82,12 @@ "@types/express-session": "^1.18.1", "@types/http-errors": "^2.0.4", "@types/leaflet": "^1.9.16", - "@types/mocha": "^10.0.10", "@types/mssql": "^9.1.7", "@types/node-windows": "^0.1.6", "@types/papaparse": "^5.3.15", "@types/randomcolor": "^0.5.9", "@types/session-file-store": "^1.2.5", "axe-core": "^4.10.3", - "bulma": "^1.0.3", "cypress": "^14.2.0", "cypress-axe": "^1.6.0", "eslint-config-cityssm": "^20.0.0", diff --git a/public/images/sunrise-cms.svg b/public/images/sunrise-cms.svg index 00bd414f..eda568d3 100644 --- a/public/images/sunrise-cms.svg +++ b/public/images/sunrise-cms.svg @@ -7,6 +7,9 @@ id="svg3" sodipodi:docname="sunrise-cms.svg" inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" + inkscape:export-filename="sunrise-cms.png" + inkscape:export-xdpi="2.6444559" + inkscape:export-ydpi="2.6444559" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -23,15 +26,16 @@ inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" - inkscape:zoom="0.44790474" - inkscape:cx="10007.708" - inkscape:cy="6998.1399" + inkscape:zoom="0.07917912" + inkscape:cx="4868.7078" + inkscape:cy="10880.394" inkscape:window-width="1920" inkscape:window-height="1009" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="svg3" /> + inkscape:current-layer="svg3" + showgrid="false" /> cityssm.openHtmlModal('burialSite-editComment', { onshow(modalElement) { sunrise.populateAliases(modalElement) - ;( - modalElement.querySelector( - '#burialSiteCommentEdit--burialSiteId' - ) as HTMLInputElement - ).value = burialSiteId - ;( - modalElement.querySelector( - '#burialSiteCommentEdit--burialSiteCommentId' - ) as HTMLInputElement - ).value = burialSiteCommentId.toString() + + modalElement + .querySelector('#burialSiteCommentEdit--burialSiteId') + ?.setAttribute('value', burialSiteId) + + modalElement + .querySelector('#burialSiteCommentEdit--burialSiteCommentId') + ?.setAttribute('value', burialSiteCommentId.toString()) ;( modalElement.querySelector( '#burialSiteCommentEdit--comment' - ) as HTMLInputElement + ) as HTMLTextAreaElement ).value = burialSiteComment.comment ?? '' const commentDateStringElement = modalElement.querySelector( @@ -526,11 +524,11 @@ declare const exports: Record cityssm.openHtmlModal('burialSite-addComment', { onshow(modalElement) { sunrise.populateAliases(modalElement) - ;( - modalElement.querySelector( - '#burialSiteCommentAdd--burialSiteId' - ) as HTMLInputElement - ).value = burialSiteId + + modalElement + .querySelector('#burialSiteCommentAdd--burialSiteId') + ?.setAttribute('value', burialSiteId) + modalElement .querySelector('form') ?.addEventListener('submit', doAddComment) diff --git a/public/javascripts/contract.editComments.js b/public/javascripts/contract.editComments.js index 42eaca37..a7fb18ce 100644 --- a/public/javascripts/contract.editComments.js +++ b/public/javascripts/contract.editComments.js @@ -9,15 +9,17 @@ Object.defineProperty(exports, "__esModule", { value: true }); const contractCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset .contractCommentId ?? '', 10); const contractComment = contractComments.find((currentComment) => currentComment.contractCommentId === contractCommentId); - let editFormElement; - let editCloseModalFunction; + let editFormElement = undefined; + let editCloseModalFunction = undefined; function editContractComment(submitEvent) { submitEvent.preventDefault(); cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doUpdateContractComment`, editFormElement, (rawResponseJSON) => { const responseJSON = rawResponseJSON; if (responseJSON.success) { contractComments = responseJSON.contractComments ?? []; - editCloseModalFunction(); + if (editCloseModalFunction !== undefined) { + editCloseModalFunction(); + } renderContractComments(); } else { @@ -32,18 +34,23 @@ Object.defineProperty(exports, "__esModule", { value: true }); cityssm.openHtmlModal('contract-editComment', { onshow(modalElement) { sunrise.populateAliases(modalElement); - modalElement.querySelector('#contractCommentEdit--contractId').value = contractId; - modalElement.querySelector('#contractCommentEdit--contractCommentId').value = contractCommentId.toString(); - modalElement.querySelector('#contractCommentEdit--comment').value = contractComment.comment ?? ''; + modalElement + .querySelector('#contractCommentEdit--contractId') + ?.setAttribute('value', contractId); + modalElement + .querySelector('#contractCommentEdit--contractCommentId') + ?.setAttribute('value', contractCommentId.toString()); + modalElement.querySelector('#contractCommentEdit--comment').value = contractComment.comment; const contractCommentDateStringElement = modalElement.querySelector('#contractCommentEdit--commentDateString'); contractCommentDateStringElement.value = - contractComment.commentDateString ?? ''; + contractComment.commentDateString; const currentDateString = cityssm.dateToString(new Date()); contractCommentDateStringElement.max = + // eslint-disable-next-line unicorn/prefer-math-min-max contractComment.commentDateString <= currentDateString ? currentDateString - : contractComment.commentDateString ?? ''; - modalElement.querySelector('#contractCommentEdit--commentTimeString').value = contractComment.commentTimeString ?? ''; + : contractComment.commentDateString; + modalElement.querySelector('#contractCommentEdit--commentTimeString').value = contractComment.commentTimeString; }, onshown(modalElement, closeModalFunction) { bulmaJS.toggleHtmlClipped(); @@ -109,15 +116,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); for (const contractComment of contractComments) { const tableRowElement = document.createElement('tr'); tableRowElement.dataset.contractCommentId = - contractComment.contractCommentId?.toString(); + contractComment.contractCommentId.toString(); tableRowElement.innerHTML = `${cityssm.escapeHTML(contractComment.recordCreate_userName ?? '')} - ${cityssm.escapeHTML(contractComment.commentDateString ?? '')} + ${cityssm.escapeHTML(contractComment.commentDateString)} ${cityssm.escapeHTML(contractComment.commentTime === 0 ? '' - : contractComment.commentTimePeriodString ?? '')} + : contractComment.commentTimePeriodString)} - ${cityssm.escapeHTML(contractComment.comment ?? '')} + ${cityssm.escapeHTML(contractComment.comment)}
diff --git a/views/cemetery-edit.ejs b/views/cemetery-edit.ejs index a4224070..0626302b 100644 --- a/views/cemetery-edit.ejs +++ b/views/cemetery-edit.ejs @@ -83,247 +83,257 @@ -
- + -
-
-
-
-
- -
- /> -
-
-
- -
- -
-
-
- -
- -
-
+
+
+
+
+
+ +
+ /> +
+
+
+ +
+ /> + <% if (configFunctions.getConfigProperty('settings.burialSites.burialSiteNameSegments.includeCemeteryKey')) { %> +

+ The cemetery key is prepended to the burial site names. +

+ <% } %> +
+
+
+ +
+
-
-
-

Address

-
-
- -
- -
-
-
-
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
-
+
-
-
-
-

Geographic Location

-
+
+
+

Address

+
- +
- +
-
- +
-
-
-
-
-
-

Image

-
-
- -
-
- +
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+

Geographic Location

+
+
+ +
+ +
+
+
+ +
+
+
- +
+
+

Image

+
+
+ +
+
+ +
+
+
+
+
+
+
<% if (!isCreate) { %> - <% const burialSiteSearchUrl = urlPrefix + "/burialSites?cemeteryId=" + cemetery.cemeteryId; %> -
-
-
-
-
-

- Burial Site Summaries - - <%= cemetery.burialSiteCount %> - -

-
-
-
- -
- - - Export All + <% const burialSiteSearchUrl = urlPrefix + "/burialSites?cemeteryId=" + cemetery.cemeteryId; %> +
+ -
- <% if (cemetery.burialSiteCount === 0) { %> -
-

- There are no burial sites - associated with this cemetery. -

-
- <% } else { %> -
-
- - + +
+ <% if (cemetery.burialSiteCount === 0) { %> +
+

+ There are no burial sites + associated with this cemetery. +

+
+ <% } else { %> +
+
+
+ + + + + + + + + <% for (const burialSiteType of burialSiteTypeSummary) { %> - - - + + + - - - <% for (const burialSiteType of burialSiteTypeSummary) { %> - - - - - - <% } %> - -
Type + Burial Site Count + Percentage
Type - Burial Site Count - Percentage + + <%= burialSiteType.burialSiteType %> + + + <%= burialSiteType.burialSiteCount %> + + <%= ((burialSiteType.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>% +
- - <%= burialSiteType.burialSiteType %> - - - <%= burialSiteType.burialSiteCount %> - - <%= ((burialSiteType.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>% -
-
-
- - - - - - - - - - <% for (const burialSiteStatus of burialSiteStatusSummary) { %> - - - - - - <% } %> - -
Status - Burial Site Count - Percentage
- - <%= burialSiteStatus.burialSiteStatus %> - - - <%= burialSiteStatus.burialSiteCount %> - - <%= ((burialSiteStatus.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>% -
-
+ <% } %> + +
- <% } %> -
-
+
+ + + + + + + + + + <% for (const burialSiteStatus of burialSiteStatusSummary) { %> + + + + + + <% } %> + +
Status + Burial Site Count + Percentage
+ + <%= burialSiteStatus.burialSiteStatus %> + + + <%= burialSiteStatus.burialSiteCount %> + + <%= ((burialSiteStatus.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>% +
+
+
+ <% } %> +
+
<% } %> <%- include('_footerA'); -%> diff --git a/views/contract-edit.ejs b/views/contract-edit.ejs index 980ee7fc..decc894f 100644 --- a/views/contract-edit.ejs +++ b/views/contract-edit.ejs @@ -158,7 +158,7 @@ required accesskey="f" <%= (isCreate ? " autofocus" : "") %>> <% if (isCreate) { %> - + <% } %> <% let typeIsFound = false; %> <% for (const contractType of contractTypes) { %> @@ -498,9 +498,17 @@
- +
+ + <% for (const relationship of configFunctions.getConfigProperty('settings.contracts.purchaserRelationships')) { %> +
diff --git a/views/contract-view.ejs b/views/contract-view.ejs index 82cc2276..637e3e8a 100644 --- a/views/contract-view.ejs +++ b/views/contract-view.ejs @@ -254,20 +254,28 @@ Birth:
- <%= contractInterment.birthDateString ?? '(No Birth Date)' %>
- <%= contractInterment.birthPlace ?? '(No Birth Place)' %> + <% if (contractInterment.birthDateString === '') { %> + (No Birth Date) + <% } else { %> + <%= contractInterment.birthDateString %> + <% } %>
+ <%= contractInterment.birthPlace %>
-
+
Death:
- <%= contractInterment.deathDateString ?? '(No Death Date)' %>
- <%= contractInterment.deathPlace ?? '(No Death Place)' %> + <% if (contractInterment.deathDateString === '') { %> + (No Death Date) + <% } else { %> + <%= contractInterment.deathDateString %> + <% } %>
+ <%= contractInterment.deathPlace %>
-
+
Age:
diff --git a/views/dashboard.ejs b/views/dashboard.ejs index 7efa375a..4ffc8ec3 100644 --- a/views/dashboard.ejs +++ b/views/dashboard.ejs @@ -94,30 +94,23 @@
-
-
+
+ + +
<% if (user.userProperties.canUpdate) { %> @@ -137,31 +130,26 @@
-
-
+
+ + +
<% if (user.userProperties.canUpdate) { %> @@ -182,89 +170,98 @@
-
-
-
+
+ - <% if (user.userProperties.canUpdate) { %> + + <% if (user.userProperties.canUpdate) { %> +
New Cemetery - <% } %> -
+
+ <% } %>
-
-
-
+
+ +
+
+ +
+
+ +

Tips and tricks to get the most out of Sunrise CMS.

+
+
+
+ <% if (user.userProperties.isAdmin) { %> -

Administrator Tools

- -
-

Open Work Orders

+

Open Work Orders

All active work orders without completion dates.

@@ -101,7 +101,7 @@ ICS
-

Work Order Milestone Calendar

+

Work Order Milestone Calendar

Upcoming and recently passed work order milestones, compatible with Microsoft Outlook and other calendar tools. @@ -118,40 +118,40 @@

-
- - -
- CSV -
-
-

- Current Contract By Cemetery -

-
-
- -
-
-
- -
-
-
- -
+
+ + +
+ CSV +
+
+

+ Current Contract By Cemetery +

+
+
+ +
+
+
+
+
+
+ +
+
@@ -161,7 +161,7 @@ CSV
-

Transactions by Date

+

Transactions by Date

-

+

Burial Sites By Cemetery

@@ -229,7 +229,7 @@ CSV
-

Burial Sites By Type

+

Burial Sites By Type

-

Burial Sites By Status

+

Burial Sites By Status

-
- -
-
-
- -
-
-
- +
+ +
+
+
+
+
+
+ +
@@ -302,7 +302,7 @@ CSV
-

Full Cemetery List

+

Full Cemetery List

All active cemeteries.

@@ -368,26 +368,37 @@
-
- - -
- CSV -
-
-

Full ContractInterments Table

-
+
+ + +
+ CSV +
+
+

Full ContractInterments Table

+
-
- - -
- CSV -
-
-

Full ContractTransactions Table

-
+
+ + +
+ CSV +
+
+

Full ContractTransactions Table

+
+
+ +
+ + +
+ CSV +
+
+

Full FuneralHomes Table

+
@@ -565,26 +576,37 @@