development
- add latitude and longitude bounds - add purchaser relationship suggestions - clean up dashboard - switch to native node testing - lintingpull/3/head
parent
28fe138fb5
commit
0dbbd3f750
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
import { dateIntegerToString, dateStringToInteger, dateToInteger, timeIntegerToString } from '@cityssm/utils-datetime';
|
||||
import { acquireConnection } from './pool.js';
|
||||
// eslint-disable-next-line complexity
|
||||
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,
|
||||
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,
|
||||
|
|
@ -18,13 +16,39 @@ export default async function getReportData(reportName, reportParameters = {}) {
|
|||
cemeteryPhoneNumber
|
||||
from Cemeteries
|
||||
where recordDelete_timeMillis is null
|
||||
order by cemeteryName`;
|
||||
break;
|
||||
}
|
||||
case 'burialSites-all': {
|
||||
sql = 'select * from BurialSites';
|
||||
break;
|
||||
}
|
||||
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 = [];
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
if (simpleReports[reportName] === undefined) {
|
||||
switch (reportName) {
|
||||
case 'burialSites-byBurialSiteTypeId': {
|
||||
sql = `select l.burialSiteId,
|
||||
m.cemeteryName,
|
||||
|
|
@ -70,18 +94,6 @@ export default async function getReportData(reportName, reportParameters = {}) {
|
|||
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,
|
||||
|
|
@ -99,24 +111,18 @@ export default async function getReportData(reportName, reportParameters = {}) {
|
|||
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';
|
||||
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': {
|
||||
|
|
@ -130,10 +136,6 @@ export default async function getReportData(reportName, reportParameters = {}) {
|
|||
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,
|
||||
|
|
@ -153,18 +155,6 @@ export default async function getReportData(reportName, reportParameters = {}) {
|
|||
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,
|
||||
|
|
@ -179,46 +169,14 @@ export default async function getReportData(reportName, reportParameters = {}) {
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
sql = simpleReports[reportName];
|
||||
}
|
||||
const database = await acquireConnection();
|
||||
database.function('userFn_dateIntegerToString', dateIntegerToString);
|
||||
database.function('userFn_timeIntegerToString', timeIntegerToString);
|
||||
|
|
|
|||
|
|
@ -10,22 +10,16 @@ import { acquireConnection } from './pool.js'
|
|||
|
||||
export type ReportParameters = Record<string, string | number>
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
export default async function getReportData(
|
||||
reportName: string,
|
||||
reportParameters: ReportParameters = {}
|
||||
): Promise<unknown[] | undefined> {
|
||||
let sql = ''
|
||||
const sqlParameters: unknown[] = []
|
||||
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',
|
||||
|
||||
switch (reportName) {
|
||||
case 'cemeteries-all': {
|
||||
sql = 'select * from Cemeteries'
|
||||
break
|
||||
}
|
||||
|
||||
case 'cemeteries-formatted': {
|
||||
sql = `select cemeteryName,
|
||||
'cemeteries-all': 'select * from Cemeteries',
|
||||
'cemeteries-formatted': `select cemeteryName,
|
||||
cemeteryDescription,
|
||||
cemeteryAddress1, cemeteryAddress2,
|
||||
cemeteryCity, cemeteryProvince,
|
||||
|
|
@ -33,16 +27,47 @@ export default async function getReportData(
|
|||
cemeteryPhoneNumber
|
||||
from Cemeteries
|
||||
where recordDelete_timeMillis is null
|
||||
order by cemeteryName`
|
||||
order by cemeteryName`,
|
||||
|
||||
break
|
||||
}
|
||||
'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',
|
||||
|
||||
case 'burialSites-all': {
|
||||
sql = 'select * from BurialSites'
|
||||
break
|
||||
}
|
||||
'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 = {}
|
||||
): Promise<unknown[] | undefined> {
|
||||
let sql = ''
|
||||
const sqlParameters: unknown[] = []
|
||||
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
if (simpleReports[reportName] === undefined) {
|
||||
switch (reportName) {
|
||||
case 'burialSites-byBurialSiteTypeId': {
|
||||
sql = `select l.burialSiteId,
|
||||
m.cemeteryName,
|
||||
|
|
@ -97,21 +122,6 @@ export default async function getReportData(
|
|||
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,
|
||||
|
|
@ -127,33 +137,28 @@ export default async function getReportData(
|
|||
and (o.contractEndDate is null or o.contractEndDate >= ?)
|
||||
and l.cemeteryId = ?`
|
||||
|
||||
sqlParameters.push(dateToInteger(new Date()), reportParameters.cemeteryId)
|
||||
sqlParameters.push(
|
||||
dateToInteger(new Date()),
|
||||
reportParameters.cemeteryId
|
||||
)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'contractComments-all': {
|
||||
sql = 'select * from ContractComments'
|
||||
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 = ?`
|
||||
|
||||
case 'contractFees-all': {
|
||||
sql = 'select * from ContractFees'
|
||||
break
|
||||
}
|
||||
sqlParameters.push(reportParameters.contractId)
|
||||
|
||||
case 'contractFields-all': {
|
||||
sql = 'select * from ContractFields'
|
||||
break
|
||||
}
|
||||
|
||||
case 'contractInterments-all': {
|
||||
sql = 'select * from ContractInterments'
|
||||
break
|
||||
}
|
||||
|
||||
case 'contractTransactions-all': {
|
||||
sql = 'select * from ContractTransactions'
|
||||
break
|
||||
}
|
||||
|
||||
|
|
@ -174,11 +179,6 @@ export default async function getReportData(
|
|||
break
|
||||
}
|
||||
|
||||
case 'workOrders-all': {
|
||||
sql = 'select * from WorkOrders'
|
||||
break
|
||||
}
|
||||
|
||||
case 'workOrders-open': {
|
||||
sql = `select w.workOrderId, w.workOrderNumber,
|
||||
t.workOrderType, w.workOrderDescription,
|
||||
|
|
@ -196,21 +196,7 @@ export default async function getReportData(
|
|||
) 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
|
||||
}
|
||||
|
||||
|
|
@ -225,59 +211,18 @@ export default async function getReportData(
|
|||
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
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sql = simpleReports[reportName]
|
||||
}
|
||||
|
||||
const database = await acquireConnection()
|
||||
|
||||
|
|
|
|||
|
|
@ -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.**
|
||||
|
|
@ -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
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export default async function handler(
|
|||
)
|
||||
|
||||
response.render('contract-view', {
|
||||
headTitle: 'Contract View',
|
||||
headTitle: `Contract #${contract.contractId.toString()}`,
|
||||
contract,
|
||||
contractTypePrints
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
<path
|
||||
fill="#16272f"
|
||||
d="M95 3826c-44-23-66-45-81-81l-14-32v-216l11-39c6-22 22-57 35-78l24-38 41-29 40-30 68-17 67-18 2-520 2-521 12-50c27-122 67-220 131-315l29-45 82-80 82-80 89-47 90-46 90-29 90-28h350l90 28 90 29 74 39c164 88 273 202 360 377l41 81 20 86 20 86v1036l168 6 167 5 43 16 44 16 38 30 39 31 30 61 31 61v237l-15.922 78.571-30.507 50.95L1530 3842H125Z"
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.7 KiB |
|
|
@ -213,8 +213,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
cityssm.openHtmlModal('burialSite-editComment', {
|
||||
onshow(modalElement) {
|
||||
sunrise.populateAliases(modalElement);
|
||||
modalElement.querySelector('#burialSiteCommentEdit--burialSiteId').value = burialSiteId;
|
||||
modalElement.querySelector('#burialSiteCommentEdit--burialSiteCommentId').value = burialSiteCommentId.toString();
|
||||
modalElement
|
||||
.querySelector('#burialSiteCommentEdit--burialSiteId')
|
||||
?.setAttribute('value', burialSiteId);
|
||||
modalElement
|
||||
.querySelector('#burialSiteCommentEdit--burialSiteCommentId')
|
||||
?.setAttribute('value', burialSiteCommentId.toString());
|
||||
modalElement.querySelector('#burialSiteCommentEdit--comment').value = burialSiteComment.comment ?? '';
|
||||
const commentDateStringElement = modalElement.querySelector('#burialSiteCommentEdit--commentDateString');
|
||||
commentDateStringElement.value =
|
||||
|
|
@ -339,7 +343,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
cityssm.openHtmlModal('burialSite-addComment', {
|
||||
onshow(modalElement) {
|
||||
sunrise.populateAliases(modalElement);
|
||||
modalElement.querySelector('#burialSiteCommentAdd--burialSiteId').value = burialSiteId;
|
||||
modalElement
|
||||
.querySelector('#burialSiteCommentAdd--burialSiteId')
|
||||
?.setAttribute('value', burialSiteId);
|
||||
modalElement
|
||||
.querySelector('form')
|
||||
?.addEventListener('submit', doAddComment);
|
||||
|
|
|
|||
|
|
@ -333,20 +333,18 @@ declare const exports: Record<string, unknown>
|
|||
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<string, unknown>
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -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 ?? [];
|
||||
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 = `<td>${cityssm.escapeHTML(contractComment.recordCreate_userName ?? '')}</td>
|
||||
<td>
|
||||
${cityssm.escapeHTML(contractComment.commentDateString ?? '')}
|
||||
${cityssm.escapeHTML(contractComment.commentDateString)}
|
||||
${cityssm.escapeHTML(contractComment.commentTime === 0
|
||||
? ''
|
||||
: contractComment.commentTimePeriodString ?? '')}
|
||||
: contractComment.commentTimePeriodString)}
|
||||
</td>
|
||||
<td>${cityssm.escapeHTML(contractComment.comment ?? '')}</td>
|
||||
<td>${cityssm.escapeHTML(contractComment.comment)}</td>
|
||||
<td class="is-hidden-print">
|
||||
<div class="buttons are-small is-justify-content-end">
|
||||
<button class="button is-primary button--edit" type="button">
|
||||
|
|
@ -151,7 +158,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
const responseJSON = rawResponseJSON;
|
||||
if (responseJSON.success) {
|
||||
contractComments = responseJSON.contractComments;
|
||||
if (addCloseModalFunction !== undefined) {
|
||||
addCloseModalFunction();
|
||||
}
|
||||
renderContractComments();
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ declare const exports: Record<string, unknown>
|
|||
(currentComment) => currentComment.contractCommentId === contractCommentId
|
||||
) as ContractComment
|
||||
|
||||
let editFormElement: HTMLFormElement
|
||||
let editCloseModalFunction: () => void
|
||||
let editFormElement: HTMLFormElement | undefined = undefined
|
||||
let editCloseModalFunction: (() => void) | undefined = undefined
|
||||
|
||||
function editContractComment(submitEvent: SubmitEvent): void {
|
||||
submitEvent.preventDefault()
|
||||
|
|
@ -47,7 +47,11 @@ declare const exports: Record<string, unknown>
|
|||
|
||||
if (responseJSON.success) {
|
||||
contractComments = responseJSON.contractComments ?? []
|
||||
|
||||
if (editCloseModalFunction !== undefined) {
|
||||
editCloseModalFunction()
|
||||
}
|
||||
|
||||
renderContractComments()
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
|
|
@ -63,44 +67,42 @@ declare const exports: Record<string, unknown>
|
|||
cityssm.openHtmlModal('contract-editComment', {
|
||||
onshow(modalElement) {
|
||||
sunrise.populateAliases(modalElement)
|
||||
;(
|
||||
modalElement.querySelector(
|
||||
'#contractCommentEdit--contractId'
|
||||
) as HTMLInputElement
|
||||
).value = contractId
|
||||
;(
|
||||
modalElement.querySelector(
|
||||
'#contractCommentEdit--contractCommentId'
|
||||
) as HTMLInputElement
|
||||
).value = contractCommentId.toString()
|
||||
|
||||
modalElement
|
||||
.querySelector('#contractCommentEdit--contractId')
|
||||
?.setAttribute('value', contractId)
|
||||
|
||||
modalElement
|
||||
.querySelector('#contractCommentEdit--contractCommentId')
|
||||
?.setAttribute('value', contractCommentId.toString())
|
||||
;(
|
||||
modalElement.querySelector(
|
||||
'#contractCommentEdit--comment'
|
||||
) as HTMLInputElement
|
||||
).value = contractComment.comment ?? ''
|
||||
) as HTMLTextAreaElement
|
||||
).value = contractComment.comment
|
||||
|
||||
const contractCommentDateStringElement = modalElement.querySelector(
|
||||
'#contractCommentEdit--commentDateString'
|
||||
) as HTMLInputElement
|
||||
|
||||
contractCommentDateStringElement.value =
|
||||
contractComment.commentDateString ?? ''
|
||||
contractComment.commentDateString
|
||||
|
||||
const currentDateString = cityssm.dateToString(new Date())
|
||||
|
||||
contractCommentDateStringElement.max =
|
||||
contractComment.commentDateString! <= currentDateString
|
||||
// eslint-disable-next-line unicorn/prefer-math-min-max
|
||||
contractComment.commentDateString <= currentDateString
|
||||
? currentDateString
|
||||
: contractComment.commentDateString ?? ''
|
||||
: contractComment.commentDateString
|
||||
;(
|
||||
modalElement.querySelector(
|
||||
'#contractCommentEdit--commentTimeString'
|
||||
) as HTMLInputElement
|
||||
).value = contractComment.commentTimeString ?? ''
|
||||
).value = contractComment.commentTimeString
|
||||
},
|
||||
onshown(modalElement, closeModalFunction) {
|
||||
bulmaJS.toggleHtmlClipped()
|
||||
|
||||
;(
|
||||
modalElement.querySelector(
|
||||
'#contractCommentEdit--comment'
|
||||
|
|
@ -190,18 +192,18 @@ declare const exports: Record<string, unknown>
|
|||
for (const contractComment of contractComments) {
|
||||
const tableRowElement = document.createElement('tr')
|
||||
tableRowElement.dataset.contractCommentId =
|
||||
contractComment.contractCommentId?.toString()
|
||||
contractComment.contractCommentId.toString()
|
||||
|
||||
tableRowElement.innerHTML = `<td>${cityssm.escapeHTML(contractComment.recordCreate_userName ?? '')}</td>
|
||||
<td>
|
||||
${cityssm.escapeHTML(contractComment.commentDateString ?? '')}
|
||||
${cityssm.escapeHTML(contractComment.commentDateString)}
|
||||
${cityssm.escapeHTML(
|
||||
contractComment.commentTime === 0
|
||||
? ''
|
||||
: contractComment.commentTimePeriodString ?? ''
|
||||
: contractComment.commentTimePeriodString
|
||||
)}
|
||||
</td>
|
||||
<td>${cityssm.escapeHTML(contractComment.comment ?? '')}</td>
|
||||
<td>${cityssm.escapeHTML(contractComment.comment)}</td>
|
||||
<td class="is-hidden-print">
|
||||
<div class="buttons are-small is-justify-content-end">
|
||||
<button class="button is-primary button--edit" type="button">
|
||||
|
|
@ -232,8 +234,8 @@ declare const exports: Record<string, unknown>
|
|||
document
|
||||
.querySelector('#button--addComment')
|
||||
?.addEventListener('click', () => {
|
||||
let addFormElement: HTMLFormElement
|
||||
let addCloseModalFunction: () => void
|
||||
let addFormElement: HTMLFormElement | undefined
|
||||
let addCloseModalFunction: (() => void) | undefined
|
||||
|
||||
function addComment(submitEvent: SubmitEvent): void {
|
||||
submitEvent.preventDefault()
|
||||
|
|
@ -250,7 +252,11 @@ declare const exports: Record<string, unknown>
|
|||
|
||||
if (responseJSON.success) {
|
||||
contractComments = responseJSON.contractComments
|
||||
|
||||
if (addCloseModalFunction !== undefined) {
|
||||
addCloseModalFunction()
|
||||
}
|
||||
|
||||
renderContractComments()
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
|
|
|
|||
|
|
@ -497,7 +497,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
function doDelete() {
|
||||
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doDeleteFee`, {
|
||||
feeId
|
||||
}, (rawResponseJSON) => {
|
||||
},
|
||||
// eslint-disable-next-line sonarjs/no-nested-functions
|
||||
(rawResponseJSON) => {
|
||||
const responseJSON = rawResponseJSON;
|
||||
if (responseJSON.success) {
|
||||
feeCategories = responseJSON.feeCategories;
|
||||
|
|
|
|||
|
|
@ -791,6 +791,7 @@ declare const exports: Record<string, unknown>
|
|||
{
|
||||
feeId
|
||||
},
|
||||
// eslint-disable-next-line sonarjs/no-nested-functions
|
||||
(rawResponseJSON) => {
|
||||
const responseJSON = rawResponseJSON as ResponseJSON
|
||||
|
||||
|
|
|
|||
|
|
@ -310,16 +310,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
tableRowElement
|
||||
.querySelector('form')
|
||||
?.addEventListener('submit', updateWorkOrderMilestoneType);
|
||||
tableRowElement.querySelector('.button--moveWorkOrderMilestoneTypeUp').addEventListener('click', moveWorkOrderMilestoneType);
|
||||
tableRowElement.querySelector('.button--moveWorkOrderMilestoneTypeDown').addEventListener('click', moveWorkOrderMilestoneType);
|
||||
tableRowElement
|
||||
.querySelector('.button--moveWorkOrderMilestoneTypeUp')
|
||||
?.addEventListener('click', moveWorkOrderMilestoneType);
|
||||
tableRowElement
|
||||
.querySelector('.button--moveWorkOrderMilestoneTypeDown')
|
||||
?.addEventListener('click', moveWorkOrderMilestoneType);
|
||||
tableRowElement
|
||||
.querySelector('.button--deleteWorkOrderMilestoneType')
|
||||
?.addEventListener('click', deleteWorkOrderMilestoneType);
|
||||
containerElement.append(tableRowElement);
|
||||
}
|
||||
}
|
||||
;
|
||||
document.querySelector('#form--addWorkOrderMilestoneType').addEventListener('submit', (submitEvent) => {
|
||||
document
|
||||
.querySelector('#form--addWorkOrderMilestoneType')
|
||||
?.addEventListener('submit', (submitEvent) => {
|
||||
submitEvent.preventDefault();
|
||||
const formElement = submitEvent.currentTarget;
|
||||
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doAddWorkOrderMilestoneType`, formElement, (rawResponseJSON) => {
|
||||
|
|
|
|||
|
|
@ -457,16 +457,14 @@ declare const bulmaJS: BulmaJS
|
|||
tableRowElement
|
||||
.querySelector('form')
|
||||
?.addEventListener('submit', updateWorkOrderMilestoneType)
|
||||
;(
|
||||
tableRowElement.querySelector(
|
||||
'.button--moveWorkOrderMilestoneTypeUp'
|
||||
) as HTMLButtonElement
|
||||
).addEventListener('click', moveWorkOrderMilestoneType)
|
||||
;(
|
||||
tableRowElement.querySelector(
|
||||
'.button--moveWorkOrderMilestoneTypeDown'
|
||||
) as HTMLButtonElement
|
||||
).addEventListener('click', moveWorkOrderMilestoneType)
|
||||
|
||||
tableRowElement
|
||||
.querySelector('.button--moveWorkOrderMilestoneTypeUp')
|
||||
?.addEventListener('click', moveWorkOrderMilestoneType)
|
||||
|
||||
tableRowElement
|
||||
.querySelector('.button--moveWorkOrderMilestoneTypeDown')
|
||||
?.addEventListener('click', moveWorkOrderMilestoneType)
|
||||
|
||||
tableRowElement
|
||||
.querySelector('.button--deleteWorkOrderMilestoneType')
|
||||
|
|
@ -475,11 +473,10 @@ declare const bulmaJS: BulmaJS
|
|||
containerElement.append(tableRowElement)
|
||||
}
|
||||
}
|
||||
;(
|
||||
document.querySelector(
|
||||
'#form--addWorkOrderMilestoneType'
|
||||
) as HTMLFormElement
|
||||
).addEventListener('submit', (submitEvent: SubmitEvent) => {
|
||||
|
||||
document
|
||||
.querySelector('#form--addWorkOrderMilestoneType')
|
||||
?.addEventListener('submit', (submitEvent: SubmitEvent) => {
|
||||
submitEvent.preventDefault()
|
||||
|
||||
const formElement = submitEvent.currentTarget as HTMLFormElement
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
function doLogout() {
|
||||
const urlPrefix = document.querySelector('main')?.getAttribute('data-url-prefix') ?? '';
|
||||
globalThis.localStorage.clear();
|
||||
globalThis.location.href = urlPrefix + '/logout';
|
||||
globalThis.location.href = `${urlPrefix}/logout`;
|
||||
}
|
||||
document
|
||||
.querySelector('#cityssm-theme--logout-button')
|
||||
|
|
@ -27,7 +27,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
.querySelector('main')
|
||||
?.getAttribute('data-session-keep-alive-millis');
|
||||
function doKeepAlive() {
|
||||
cityssm.postJSON(urlPrefix + '/keepAlive', {
|
||||
cityssm.postJSON(`${urlPrefix}/keepAlive`, {
|
||||
t: Date.now()
|
||||
}, () => {
|
||||
// Do nothing
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ declare const bulmaJS: BulmaJS
|
|||
document.querySelector('main')?.getAttribute('data-url-prefix') ?? ''
|
||||
|
||||
globalThis.localStorage.clear()
|
||||
globalThis.location.href = urlPrefix + '/logout'
|
||||
globalThis.location.href = `${urlPrefix}/logout`
|
||||
}
|
||||
|
||||
document
|
||||
|
|
@ -46,7 +46,7 @@ declare const bulmaJS: BulmaJS
|
|||
|
||||
function doKeepAlive(): void {
|
||||
cityssm.postJSON(
|
||||
urlPrefix + '/keepAlive',
|
||||
`${urlPrefix}/keepAlive`,
|
||||
{
|
||||
t: Date.now()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */
|
||||
import assert from 'node:assert';
|
||||
import fs from 'node:fs/promises';
|
||||
import { describe, it } from 'node:test';
|
||||
import { initializeDatabase } from '../database/initializeDatabase.js';
|
||||
import { sunriseDB as databasePath, useTestDatabases } from '../helpers/database.helpers.js';
|
||||
describe('Initialize Database', () => {
|
||||
it('initializes the database', async () => {
|
||||
await describe('Initialize Database', async () => {
|
||||
await it('initializes the database', async () => {
|
||||
if (!useTestDatabases) {
|
||||
assert.fail('Test database must be used!');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import assert from 'node:assert'
|
||||
import fs from 'node:fs/promises'
|
||||
import { describe, it } from 'node:test'
|
||||
|
||||
import { initializeDatabase } from '../database/initializeDatabase.js'
|
||||
import {
|
||||
|
|
@ -9,8 +10,8 @@ import {
|
|||
useTestDatabases
|
||||
} from '../helpers/database.helpers.js'
|
||||
|
||||
describe('Initialize Database', () => {
|
||||
it('initializes the database', async () => {
|
||||
await describe('Initialize Database', async () => {
|
||||
await it('initializes the database', async () => {
|
||||
if (!useTestDatabases) {
|
||||
assert.fail('Test database must be used!')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */
|
||||
/* eslint-disable no-console, unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */
|
||||
import assert from 'node:assert';
|
||||
import { exec } from 'node:child_process';
|
||||
import http from 'node:http';
|
||||
import { minutesToMillis } from '@cityssm/to-millis';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { hoursToMillis } from '@cityssm/to-millis';
|
||||
import { app } from '../app.js';
|
||||
import { portNumber } from './_globals.js';
|
||||
function runCypress(browser, done) {
|
||||
|
|
@ -23,7 +24,7 @@ function runCypress(browser, done) {
|
|||
done();
|
||||
});
|
||||
}
|
||||
describe('sunrise-cms', () => {
|
||||
await describe('sunrise-cms', async () => {
|
||||
const httpServer = http.createServer(app);
|
||||
let serverStarted = false;
|
||||
before(() => {
|
||||
|
|
@ -40,15 +41,19 @@ describe('sunrise-cms', () => {
|
|||
// ignore
|
||||
}
|
||||
});
|
||||
it(`Ensure server starts on port ${portNumber.toString()}`, () => {
|
||||
await it(`Ensure server starts on port ${portNumber.toString()}`, () => {
|
||||
assert.ok(serverStarted);
|
||||
});
|
||||
describe('Cypress tests', () => {
|
||||
it('Should run Cypress tests in Chrome', (done) => {
|
||||
await describe('Cypress tests', async () => {
|
||||
await it('Should run Cypress tests in Chrome', {
|
||||
timeout: hoursToMillis(1)
|
||||
}, (context, done) => {
|
||||
runCypress('chrome', done);
|
||||
}).timeout(minutesToMillis(30));
|
||||
it('Should run Cypress tests in Firefox', (done) => {
|
||||
});
|
||||
await it('Should run Cypress tests in Firefox', {
|
||||
timeout: hoursToMillis(1)
|
||||
}, (context, done) => {
|
||||
runCypress('firefox', done);
|
||||
}).timeout(minutesToMillis(30));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
/* eslint-disable unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */
|
||||
/* eslint-disable no-console, unicorn/filename-case, @eslint-community/eslint-comments/disable-enable-pair */
|
||||
|
||||
import assert from 'node:assert'
|
||||
import { exec } from 'node:child_process'
|
||||
import http from 'node:http'
|
||||
import { after, before, describe, it } from 'node:test'
|
||||
|
||||
import { minutesToMillis } from '@cityssm/to-millis'
|
||||
import { hoursToMillis } from '@cityssm/to-millis'
|
||||
|
||||
import { app } from '../app.js'
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ function runCypress(browser: 'chrome' | 'firefox', done: () => void): void {
|
|||
})
|
||||
}
|
||||
|
||||
describe('sunrise-cms', () => {
|
||||
await describe('sunrise-cms', async () => {
|
||||
const httpServer = http.createServer(app)
|
||||
|
||||
let serverStarted = false
|
||||
|
|
@ -55,17 +56,29 @@ describe('sunrise-cms', () => {
|
|||
}
|
||||
})
|
||||
|
||||
it(`Ensure server starts on port ${portNumber.toString()}`, () => {
|
||||
await it(`Ensure server starts on port ${portNumber.toString()}`, () => {
|
||||
assert.ok(serverStarted)
|
||||
})
|
||||
|
||||
describe('Cypress tests', () => {
|
||||
it('Should run Cypress tests in Chrome', (done) => {
|
||||
await describe('Cypress tests', async () => {
|
||||
await it(
|
||||
'Should run Cypress tests in Chrome',
|
||||
{
|
||||
timeout: hoursToMillis(1)
|
||||
},
|
||||
(context, done) => {
|
||||
runCypress('chrome', done)
|
||||
}).timeout(minutesToMillis(30))
|
||||
}
|
||||
)
|
||||
|
||||
it('Should run Cypress tests in Firefox', (done) => {
|
||||
await it(
|
||||
'Should run Cypress tests in Firefox',
|
||||
{
|
||||
timeout: hoursToMillis(1)
|
||||
},
|
||||
(context, done) => {
|
||||
runCypress('firefox', done)
|
||||
}).timeout(minutesToMillis(30))
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
import assert from 'node:assert';
|
||||
import fs from 'node:fs';
|
||||
// skipcq: JS-C1003 - Testing functions
|
||||
import { before, describe, it } from 'node:test';
|
||||
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('functions.cache', () => {
|
||||
await describe('functions.cache', async () => {
|
||||
const badId = -3;
|
||||
// eslint-disable-next-line no-secrets/no-secrets
|
||||
const badName = 'qwertyuiopasdfghjklzxcvbnm';
|
||||
before(() => {
|
||||
cacheFunctions.clearCaches();
|
||||
});
|
||||
describe('Burial Site Statuses', () => {
|
||||
it('returns Burial Site Statuses', async () => {
|
||||
await describe('Burial Site Statuses', async () => {
|
||||
await it('returns Burial Site Statuses', async () => {
|
||||
cacheFunctions.clearCacheByTableName('BurialSiteStatuses');
|
||||
const burialSiteStatuses = await cacheFunctions.getBurialSiteStatuses();
|
||||
assert.ok(burialSiteStatuses.length > 0);
|
||||
|
|
@ -25,17 +23,17 @@ describe('functions.cache', () => {
|
|||
assert.strictEqual(burialSiteStatus.burialSiteStatus, byName?.burialSiteStatus);
|
||||
}
|
||||
});
|
||||
it('returns undefined with a bad burialSiteStatusId', async () => {
|
||||
await it('returns undefined with a bad burialSiteStatusId', async () => {
|
||||
const byBadId = await cacheFunctions.getBurialSiteStatusById(badId);
|
||||
assert.ok(byBadId === undefined);
|
||||
});
|
||||
it('returns undefined with a bad lotStatus', async () => {
|
||||
await it('returns undefined with a bad lotStatus', async () => {
|
||||
const byBadName = await cacheFunctions.getBurialSiteStatusByBurialSiteStatus(badName);
|
||||
assert.ok(byBadName === undefined);
|
||||
});
|
||||
});
|
||||
describe('Lot Types', () => {
|
||||
it('returns Lot Types', async () => {
|
||||
await describe('Burial Site Types', async () => {
|
||||
await it('returns Burial Site Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('BurialSiteTypes');
|
||||
const burialSiteTypes = await cacheFunctions.getBurialSiteTypes();
|
||||
assert.ok(burialSiteTypes.length > 0);
|
||||
|
|
@ -46,17 +44,17 @@ describe('functions.cache', () => {
|
|||
assert.strictEqual(burialSiteType.burialSiteType, byName?.burialSiteType);
|
||||
}
|
||||
});
|
||||
it('returns undefined with a bad burialSiteTypeId', async () => {
|
||||
await it('returns undefined with a bad burialSiteTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getBurialSiteTypeById(badId);
|
||||
assert.ok(byBadId === undefined);
|
||||
});
|
||||
it('returns undefined with a bad lotType', async () => {
|
||||
await it('returns undefined with a bad lotType', async () => {
|
||||
const byBadName = await cacheFunctions.getBurialSiteTypesByBurialSiteType(badName);
|
||||
assert.ok(byBadName === undefined);
|
||||
});
|
||||
});
|
||||
describe('Occupancy Types', () => {
|
||||
it('returns Contract Types', async () => {
|
||||
await describe('Contract Types', async () => {
|
||||
await it('returns Contract Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('ContractTypes');
|
||||
const contractTypes = await cacheFunctions.getContractTypes();
|
||||
assert.ok(contractTypes.length > 0);
|
||||
|
|
@ -67,17 +65,17 @@ describe('functions.cache', () => {
|
|||
assert.strictEqual(contractType.contractType, byName?.contractType);
|
||||
}
|
||||
});
|
||||
it('returns undefined with a bad contractTypeId', async () => {
|
||||
await it('returns undefined with a bad contractTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getContractTypeById(badId);
|
||||
assert.ok(byBadId === undefined);
|
||||
});
|
||||
it('returns undefined with a bad contractType', async () => {
|
||||
await it('returns undefined with a bad contractType', async () => {
|
||||
const byBadName = await cacheFunctions.getContractTypeByContractType(badName);
|
||||
assert.ok(byBadName === undefined);
|
||||
});
|
||||
});
|
||||
describe('Work Order Types', () => {
|
||||
it('returns Work Order Types', async () => {
|
||||
await describe('Work Order Types', async () => {
|
||||
await it('returns Work Order Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('WorkOrderTypes');
|
||||
const workOrderTypes = await cacheFunctions.getWorkOrderTypes();
|
||||
assert.ok(workOrderTypes.length > 0);
|
||||
|
|
@ -86,13 +84,13 @@ describe('functions.cache', () => {
|
|||
assert.strictEqual(workOrderType.workOrderTypeId, byId?.workOrderTypeId);
|
||||
}
|
||||
});
|
||||
it('returns undefined with a bad workOrderTypeId', async () => {
|
||||
await it('returns undefined with a bad workOrderTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getWorkOrderTypeById(badId);
|
||||
assert.ok(byBadId === undefined);
|
||||
});
|
||||
});
|
||||
describe('Work Order Milestone Types', () => {
|
||||
it('returns Work Order Milestone Types', async () => {
|
||||
await describe('Work Order Milestone Types', async () => {
|
||||
await it('returns Work Order Milestone Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('WorkOrderMilestoneTypes');
|
||||
const workOrderMilestoneTypes = await cacheFunctions.getWorkOrderMilestoneTypes();
|
||||
assert.ok(workOrderMilestoneTypes.length > 0);
|
||||
|
|
@ -103,49 +101,49 @@ describe('functions.cache', () => {
|
|||
assert.strictEqual(workOrderMilestoneType.workOrderMilestoneType, byName?.workOrderMilestoneType);
|
||||
}
|
||||
});
|
||||
it('returns undefined with a bad workOrderMilestoneTypeId', async () => {
|
||||
await it('returns undefined with a bad workOrderMilestoneTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getWorkOrderMilestoneTypeById(badId);
|
||||
assert.ok(byBadId === undefined);
|
||||
});
|
||||
it('returns undefined with a bad workOrderMilestoneType', async () => {
|
||||
await it('returns undefined with a bad workOrderMilestoneType', async () => {
|
||||
const byBadName = await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType(badName);
|
||||
assert.ok(byBadName === undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('functions.sqlFilters', () => {
|
||||
describe('BurialSiteName filter', () => {
|
||||
it('returns startsWith filter', () => {
|
||||
await describe('functions.sqlFilters', async () => {
|
||||
await describe('BurialSiteName filter', async () => {
|
||||
await it('returns startsWith filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause('TEST1 TEST2', 'startsWith', 'l');
|
||||
assert.strictEqual(filter.sqlWhereClause, " and l.burialSiteName like ? || '%'");
|
||||
assert.strictEqual(filter.sqlParameters.length, 1);
|
||||
assert.ok(filter.sqlParameters.includes('TEST1 TEST2'));
|
||||
});
|
||||
it('returns endsWith filter', () => {
|
||||
await it('returns endsWith filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause('TEST1 TEST2', 'endsWith', 'l');
|
||||
assert.strictEqual(filter.sqlWhereClause, " and l.burialSiteName like '%' || ?");
|
||||
assert.strictEqual(filter.sqlParameters.length, 1);
|
||||
assert.strictEqual(filter.sqlParameters[0], 'TEST1 TEST2');
|
||||
});
|
||||
it('returns contains filter', () => {
|
||||
await it('returns contains filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause('TEST1 TEST2', '', 'l');
|
||||
assert.strictEqual(filter.sqlWhereClause, ' and instr(lower(l.burialSiteName), ?) and instr(lower(l.burialSiteName), ?)');
|
||||
assert.ok(filter.sqlParameters.includes('test1'));
|
||||
assert.ok(filter.sqlParameters.includes('test2'));
|
||||
});
|
||||
it('handles empty filter', () => {
|
||||
await it('handles empty filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause('', '');
|
||||
assert.strictEqual(filter.sqlWhereClause, '');
|
||||
assert.strictEqual(filter.sqlParameters.length, 0);
|
||||
});
|
||||
it('handles undefined filter', () => {
|
||||
await it('handles undefined filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause(undefined, undefined, 'l');
|
||||
assert.strictEqual(filter.sqlWhereClause, '');
|
||||
assert.strictEqual(filter.sqlParameters.length, 0);
|
||||
});
|
||||
});
|
||||
describe('OccupancyTime filter', () => {
|
||||
it('creates three different filters', () => {
|
||||
await describe('OccupancyTime filter', async () => {
|
||||
await it('creates three different filters', () => {
|
||||
const currentFilter = sqlFilterFunctions.getContractTimeWhereClause('current');
|
||||
assert.notStrictEqual(currentFilter.sqlWhereClause, '');
|
||||
const pastFilter = sqlFilterFunctions.getContractTimeWhereClause('past');
|
||||
|
|
@ -156,50 +154,50 @@ describe('functions.sqlFilters', () => {
|
|||
assert.notStrictEqual(currentFilter.sqlWhereClause, futureFilter.sqlWhereClause);
|
||||
assert.notStrictEqual(pastFilter.sqlWhereClause, futureFilter.sqlWhereClause);
|
||||
});
|
||||
it('handles empty filter', () => {
|
||||
await it('handles empty filter', () => {
|
||||
const filter = sqlFilterFunctions.getContractTimeWhereClause('');
|
||||
assert.strictEqual(filter.sqlWhereClause, '');
|
||||
assert.strictEqual(filter.sqlParameters.length, 0);
|
||||
});
|
||||
it('handles undefined filter', () => {
|
||||
await it('handles undefined filter', () => {
|
||||
const filter = sqlFilterFunctions.getContractTimeWhereClause(undefined, 'o');
|
||||
assert.strictEqual(filter.sqlWhereClause, '');
|
||||
assert.strictEqual(filter.sqlParameters.length, 0);
|
||||
});
|
||||
});
|
||||
describe('DeceasedName filter', () => {
|
||||
it('returns filter', () => {
|
||||
await describe('DeceasedName filter', async () => {
|
||||
await it('returns filter', () => {
|
||||
const filter = sqlFilterFunctions.getDeceasedNameWhereClause('TEST1 TEST2', 'o');
|
||||
assert.strictEqual(filter.sqlWhereClause, ' and instr(lower(o.deceasedName), ?) and instr(lower(o.deceasedName), ?)');
|
||||
assert.ok(filter.sqlParameters.length === 2);
|
||||
assert.ok(filter.sqlParameters.includes('test1'));
|
||||
assert.ok(filter.sqlParameters.includes('test2'));
|
||||
});
|
||||
it('handles empty filter', () => {
|
||||
await it('handles empty filter', () => {
|
||||
const filter = sqlFilterFunctions.getDeceasedNameWhereClause('');
|
||||
assert.strictEqual(filter.sqlWhereClause, '');
|
||||
assert.strictEqual(filter.sqlParameters.length, 0);
|
||||
});
|
||||
it('handles undefined filter', () => {
|
||||
await it('handles undefined filter', () => {
|
||||
const filter = sqlFilterFunctions.getDeceasedNameWhereClause(undefined, 'o');
|
||||
assert.strictEqual(filter.sqlWhereClause, '');
|
||||
assert.strictEqual(filter.sqlParameters.length, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('functions.user', () => {
|
||||
describe('unauthenticated, no user in session', () => {
|
||||
await describe('functions.user', async () => {
|
||||
await describe('unauthenticated, no user in session', async () => {
|
||||
const noUserRequest = {
|
||||
session: {}
|
||||
};
|
||||
it('can not update', () => {
|
||||
await it('can not update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(noUserRequest), false);
|
||||
});
|
||||
it('is not admin', () => {
|
||||
await it('is not admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(noUserRequest), false);
|
||||
});
|
||||
});
|
||||
describe('read only user, no update, no admin', () => {
|
||||
await describe('read only user, no update, no admin', async () => {
|
||||
const readOnlyRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -212,14 +210,14 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
};
|
||||
it('can not update', () => {
|
||||
await it('can not update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(readOnlyRequest), false);
|
||||
});
|
||||
it('is not admin', () => {
|
||||
await it('is not admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(readOnlyRequest), false);
|
||||
});
|
||||
});
|
||||
describe('update only user, no admin', () => {
|
||||
await describe('update only user, no admin', async () => {
|
||||
const updateOnlyRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -232,14 +230,14 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
};
|
||||
it('can update', () => {
|
||||
await it('can update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(updateOnlyRequest), true);
|
||||
});
|
||||
it('is not admin', () => {
|
||||
await it('is not admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(updateOnlyRequest), false);
|
||||
});
|
||||
});
|
||||
describe('admin only user, no update', () => {
|
||||
await describe('admin only user, no update', async () => {
|
||||
const adminOnlyRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -252,14 +250,14 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
};
|
||||
it('can not update', () => {
|
||||
await it('can not update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(adminOnlyRequest), false);
|
||||
});
|
||||
it('is admin', () => {
|
||||
await it('is admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(adminOnlyRequest), true);
|
||||
});
|
||||
});
|
||||
describe('update admin user', () => {
|
||||
await describe('update admin user', async () => {
|
||||
const updateAdminRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -272,15 +270,15 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
};
|
||||
it('can update', () => {
|
||||
await it('can update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(updateAdminRequest), true);
|
||||
});
|
||||
it('is admin', () => {
|
||||
await it('is admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(updateAdminRequest), true);
|
||||
});
|
||||
});
|
||||
describe('API key check', () => {
|
||||
it('authenticates with a valid API key', async () => {
|
||||
await describe('API key check', async () => {
|
||||
await it('authenticates with a valid API key', async () => {
|
||||
const apiKeysJSON = JSON.parse(fs.readFileSync('data/apiKeys.json', 'utf8'));
|
||||
const apiKey = Object.values(apiKeysJSON)[0];
|
||||
const apiRequest = {
|
||||
|
|
@ -290,7 +288,7 @@ describe('functions.user', () => {
|
|||
};
|
||||
assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), true);
|
||||
});
|
||||
it('fails to authenticate with an invalid API key', async () => {
|
||||
await it('fails to authenticate with an invalid API key', async () => {
|
||||
const apiRequest = {
|
||||
params: {
|
||||
apiKey: 'badKey'
|
||||
|
|
@ -298,7 +296,7 @@ describe('functions.user', () => {
|
|||
};
|
||||
assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), false);
|
||||
});
|
||||
it('fails to authenticate with no API key', async () => {
|
||||
await it('fails to authenticate with no API key', async () => {
|
||||
const apiRequest = {
|
||||
params: {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import assert from 'node:assert'
|
||||
import fs from 'node:fs'
|
||||
import { before, describe, it } from 'node:test'
|
||||
|
||||
// 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('functions.cache', () => {
|
||||
await describe('functions.cache', async () => {
|
||||
const badId = -3
|
||||
// eslint-disable-next-line no-secrets/no-secrets
|
||||
const badName = 'qwertyuiopasdfghjklzxcvbnm'
|
||||
|
|
@ -17,8 +15,8 @@ describe('functions.cache', () => {
|
|||
cacheFunctions.clearCaches()
|
||||
})
|
||||
|
||||
describe('Burial Site Statuses', () => {
|
||||
it('returns Burial Site Statuses', async () => {
|
||||
await describe('Burial Site Statuses', async () => {
|
||||
await it('returns Burial Site Statuses', async () => {
|
||||
cacheFunctions.clearCacheByTableName('BurialSiteStatuses')
|
||||
|
||||
const burialSiteStatuses = await cacheFunctions.getBurialSiteStatuses()
|
||||
|
|
@ -29,28 +27,36 @@ describe('functions.cache', () => {
|
|||
const byId = await cacheFunctions.getBurialSiteStatusById(
|
||||
burialSiteStatus.burialSiteStatusId
|
||||
)
|
||||
assert.strictEqual(burialSiteStatus.burialSiteStatusId, byId?.burialSiteStatusId)
|
||||
assert.strictEqual(
|
||||
burialSiteStatus.burialSiteStatusId,
|
||||
byId?.burialSiteStatusId
|
||||
)
|
||||
|
||||
const byName = await cacheFunctions.getBurialSiteStatusByBurialSiteStatus(
|
||||
const byName =
|
||||
await cacheFunctions.getBurialSiteStatusByBurialSiteStatus(
|
||||
burialSiteStatus.burialSiteStatus
|
||||
)
|
||||
assert.strictEqual(burialSiteStatus.burialSiteStatus, byName?.burialSiteStatus)
|
||||
assert.strictEqual(
|
||||
burialSiteStatus.burialSiteStatus,
|
||||
byName?.burialSiteStatus
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('returns undefined with a bad burialSiteStatusId', async () => {
|
||||
await it('returns undefined with a bad burialSiteStatusId', async () => {
|
||||
const byBadId = await cacheFunctions.getBurialSiteStatusById(badId)
|
||||
assert.ok(byBadId === undefined)
|
||||
})
|
||||
|
||||
it('returns undefined with a bad lotStatus', async () => {
|
||||
const byBadName = await cacheFunctions.getBurialSiteStatusByBurialSiteStatus(badName)
|
||||
await it('returns undefined with a bad lotStatus', async () => {
|
||||
const byBadName =
|
||||
await cacheFunctions.getBurialSiteStatusByBurialSiteStatus(badName)
|
||||
assert.ok(byBadName === undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Lot Types', () => {
|
||||
it('returns Lot Types', async () => {
|
||||
await describe('Burial Site Types', async () => {
|
||||
await it('returns Burial Site Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('BurialSiteTypes')
|
||||
|
||||
const burialSiteTypes = await cacheFunctions.getBurialSiteTypes()
|
||||
|
|
@ -58,29 +64,38 @@ describe('functions.cache', () => {
|
|||
assert.ok(burialSiteTypes.length > 0)
|
||||
|
||||
for (const burialSiteType of burialSiteTypes) {
|
||||
const byId = await cacheFunctions.getBurialSiteTypeById(burialSiteType.burialSiteTypeId)
|
||||
assert.strictEqual(burialSiteType.burialSiteTypeId, byId?.burialSiteTypeId)
|
||||
const byId = await cacheFunctions.getBurialSiteTypeById(
|
||||
burialSiteType.burialSiteTypeId
|
||||
)
|
||||
assert.strictEqual(
|
||||
burialSiteType.burialSiteTypeId,
|
||||
byId?.burialSiteTypeId
|
||||
)
|
||||
|
||||
const byName = await cacheFunctions.getBurialSiteTypesByBurialSiteType(
|
||||
burialSiteType.burialSiteType
|
||||
)
|
||||
assert.strictEqual(burialSiteType.burialSiteType, byName?.burialSiteType)
|
||||
assert.strictEqual(
|
||||
burialSiteType.burialSiteType,
|
||||
byName?.burialSiteType
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('returns undefined with a bad burialSiteTypeId', async () => {
|
||||
await it('returns undefined with a bad burialSiteTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getBurialSiteTypeById(badId)
|
||||
assert.ok(byBadId === undefined)
|
||||
})
|
||||
|
||||
it('returns undefined with a bad lotType', async () => {
|
||||
const byBadName = await cacheFunctions.getBurialSiteTypesByBurialSiteType(badName)
|
||||
await it('returns undefined with a bad lotType', async () => {
|
||||
const byBadName =
|
||||
await cacheFunctions.getBurialSiteTypesByBurialSiteType(badName)
|
||||
assert.ok(byBadName === undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Occupancy Types', () => {
|
||||
it('returns Contract Types', async () => {
|
||||
await describe('Contract Types', async () => {
|
||||
await it('returns Contract Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('ContractTypes')
|
||||
|
||||
const contractTypes = await cacheFunctions.getContractTypes()
|
||||
|
|
@ -100,21 +115,20 @@ describe('functions.cache', () => {
|
|||
}
|
||||
})
|
||||
|
||||
it('returns undefined with a bad contractTypeId', async () => {
|
||||
await it('returns undefined with a bad contractTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getContractTypeById(badId)
|
||||
assert.ok(byBadId === undefined)
|
||||
})
|
||||
|
||||
it('returns undefined with a bad contractType', async () => {
|
||||
const byBadName = await cacheFunctions.getContractTypeByContractType(
|
||||
badName
|
||||
)
|
||||
await it('returns undefined with a bad contractType', async () => {
|
||||
const byBadName =
|
||||
await cacheFunctions.getContractTypeByContractType(badName)
|
||||
assert.ok(byBadName === undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Work Order Types', () => {
|
||||
it('returns Work Order Types', async () => {
|
||||
await describe('Work Order Types', async () => {
|
||||
await it('returns Work Order Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('WorkOrderTypes')
|
||||
|
||||
const workOrderTypes = await cacheFunctions.getWorkOrderTypes()
|
||||
|
|
@ -129,14 +143,14 @@ describe('functions.cache', () => {
|
|||
}
|
||||
})
|
||||
|
||||
it('returns undefined with a bad workOrderTypeId', async () => {
|
||||
await it('returns undefined with a bad workOrderTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getWorkOrderTypeById(badId)
|
||||
assert.ok(byBadId === undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Work Order Milestone Types', () => {
|
||||
it('returns Work Order Milestone Types', async () => {
|
||||
await describe('Work Order Milestone Types', async () => {
|
||||
await it('returns Work Order Milestone Types', async () => {
|
||||
cacheFunctions.clearCacheByTableName('WorkOrderMilestoneTypes')
|
||||
|
||||
const workOrderMilestoneTypes =
|
||||
|
|
@ -164,12 +178,12 @@ describe('functions.cache', () => {
|
|||
}
|
||||
})
|
||||
|
||||
it('returns undefined with a bad workOrderMilestoneTypeId', async () => {
|
||||
await it('returns undefined with a bad workOrderMilestoneTypeId', async () => {
|
||||
const byBadId = await cacheFunctions.getWorkOrderMilestoneTypeById(badId)
|
||||
assert.ok(byBadId === undefined)
|
||||
})
|
||||
|
||||
it('returns undefined with a bad workOrderMilestoneType', async () => {
|
||||
await it('returns undefined with a bad workOrderMilestoneType', async () => {
|
||||
const byBadName =
|
||||
await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType(
|
||||
badName
|
||||
|
|
@ -179,33 +193,39 @@ describe('functions.cache', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('functions.sqlFilters', () => {
|
||||
describe('BurialSiteName filter', () => {
|
||||
it('returns startsWith filter', () => {
|
||||
await describe('functions.sqlFilters', async () => {
|
||||
await describe('BurialSiteName filter', async () => {
|
||||
await it('returns startsWith filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause(
|
||||
'TEST1 TEST2',
|
||||
'startsWith',
|
||||
'l'
|
||||
)
|
||||
|
||||
assert.strictEqual(filter.sqlWhereClause, " and l.burialSiteName like ? || '%'")
|
||||
assert.strictEqual(
|
||||
filter.sqlWhereClause,
|
||||
" and l.burialSiteName like ? || '%'"
|
||||
)
|
||||
assert.strictEqual(filter.sqlParameters.length, 1)
|
||||
assert.ok(filter.sqlParameters.includes('TEST1 TEST2'))
|
||||
})
|
||||
|
||||
it('returns endsWith filter', () => {
|
||||
await it('returns endsWith filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause(
|
||||
'TEST1 TEST2',
|
||||
'endsWith',
|
||||
'l'
|
||||
)
|
||||
|
||||
assert.strictEqual(filter.sqlWhereClause, " and l.burialSiteName like '%' || ?")
|
||||
assert.strictEqual(
|
||||
filter.sqlWhereClause,
|
||||
" and l.burialSiteName like '%' || ?"
|
||||
)
|
||||
assert.strictEqual(filter.sqlParameters.length, 1)
|
||||
assert.strictEqual(filter.sqlParameters[0], 'TEST1 TEST2')
|
||||
})
|
||||
|
||||
it('returns contains filter', () => {
|
||||
await it('returns contains filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause(
|
||||
'TEST1 TEST2',
|
||||
'',
|
||||
|
|
@ -220,14 +240,14 @@ describe('functions.sqlFilters', () => {
|
|||
assert.ok(filter.sqlParameters.includes('test2'))
|
||||
})
|
||||
|
||||
it('handles empty filter', () => {
|
||||
await it('handles empty filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause('', '')
|
||||
|
||||
assert.strictEqual(filter.sqlWhereClause, '')
|
||||
assert.strictEqual(filter.sqlParameters.length, 0)
|
||||
})
|
||||
|
||||
it('handles undefined filter', () => {
|
||||
await it('handles undefined filter', () => {
|
||||
const filter = sqlFilterFunctions.getBurialSiteNameWhereClause(
|
||||
undefined,
|
||||
undefined,
|
||||
|
|
@ -239,8 +259,8 @@ describe('functions.sqlFilters', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('OccupancyTime filter', () => {
|
||||
it('creates three different filters', () => {
|
||||
await describe('OccupancyTime filter', async () => {
|
||||
await it('creates three different filters', () => {
|
||||
const currentFilter =
|
||||
sqlFilterFunctions.getContractTimeWhereClause('current')
|
||||
assert.notStrictEqual(currentFilter.sqlWhereClause, '')
|
||||
|
|
@ -266,13 +286,13 @@ describe('functions.sqlFilters', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('handles empty filter', () => {
|
||||
await it('handles empty filter', () => {
|
||||
const filter = sqlFilterFunctions.getContractTimeWhereClause('')
|
||||
assert.strictEqual(filter.sqlWhereClause, '')
|
||||
assert.strictEqual(filter.sqlParameters.length, 0)
|
||||
})
|
||||
|
||||
it('handles undefined filter', () => {
|
||||
await it('handles undefined filter', () => {
|
||||
const filter = sqlFilterFunctions.getContractTimeWhereClause(
|
||||
undefined,
|
||||
'o'
|
||||
|
|
@ -282,8 +302,8 @@ describe('functions.sqlFilters', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('DeceasedName filter', () => {
|
||||
it('returns filter', () => {
|
||||
await describe('DeceasedName filter', async () => {
|
||||
await it('returns filter', () => {
|
||||
const filter = sqlFilterFunctions.getDeceasedNameWhereClause(
|
||||
'TEST1 TEST2',
|
||||
'o'
|
||||
|
|
@ -300,14 +320,14 @@ describe('functions.sqlFilters', () => {
|
|||
assert.ok(filter.sqlParameters.includes('test2'))
|
||||
})
|
||||
|
||||
it('handles empty filter', () => {
|
||||
await it('handles empty filter', () => {
|
||||
const filter = sqlFilterFunctions.getDeceasedNameWhereClause('')
|
||||
|
||||
assert.strictEqual(filter.sqlWhereClause, '')
|
||||
assert.strictEqual(filter.sqlParameters.length, 0)
|
||||
})
|
||||
|
||||
it('handles undefined filter', () => {
|
||||
await it('handles undefined filter', () => {
|
||||
const filter = sqlFilterFunctions.getDeceasedNameWhereClause(
|
||||
undefined,
|
||||
'o'
|
||||
|
|
@ -319,22 +339,22 @@ describe('functions.sqlFilters', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('functions.user', () => {
|
||||
describe('unauthenticated, no user in session', () => {
|
||||
await describe('functions.user', async () => {
|
||||
await describe('unauthenticated, no user in session', async () => {
|
||||
const noUserRequest = {
|
||||
session: {}
|
||||
}
|
||||
|
||||
it('can not update', () => {
|
||||
await it('can not update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(noUserRequest), false)
|
||||
})
|
||||
|
||||
it('is not admin', () => {
|
||||
await it('is not admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(noUserRequest), false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('read only user, no update, no admin', () => {
|
||||
await describe('read only user, no update, no admin', async () => {
|
||||
const readOnlyRequest: userFunctions.UserRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -348,16 +368,16 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
|
||||
it('can not update', () => {
|
||||
await it('can not update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(readOnlyRequest), false)
|
||||
})
|
||||
|
||||
it('is not admin', () => {
|
||||
await it('is not admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(readOnlyRequest), false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('update only user, no admin', () => {
|
||||
await describe('update only user, no admin', async () => {
|
||||
const updateOnlyRequest: userFunctions.UserRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -371,16 +391,16 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
|
||||
it('can update', () => {
|
||||
await it('can update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(updateOnlyRequest), true)
|
||||
})
|
||||
|
||||
it('is not admin', () => {
|
||||
await it('is not admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(updateOnlyRequest), false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('admin only user, no update', () => {
|
||||
await describe('admin only user, no update', async () => {
|
||||
const adminOnlyRequest: userFunctions.UserRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -394,16 +414,16 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
|
||||
it('can not update', () => {
|
||||
await it('can not update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(adminOnlyRequest), false)
|
||||
})
|
||||
|
||||
it('is admin', () => {
|
||||
await it('is admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(adminOnlyRequest), true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('update admin user', () => {
|
||||
await describe('update admin user', async () => {
|
||||
const updateAdminRequest: userFunctions.UserRequest = {
|
||||
session: {
|
||||
user: {
|
||||
|
|
@ -417,17 +437,17 @@ describe('functions.user', () => {
|
|||
}
|
||||
}
|
||||
|
||||
it('can update', () => {
|
||||
await it('can update', () => {
|
||||
assert.strictEqual(userFunctions.userCanUpdate(updateAdminRequest), true)
|
||||
})
|
||||
|
||||
it('is admin', () => {
|
||||
await it('is admin', () => {
|
||||
assert.strictEqual(userFunctions.userIsAdmin(updateAdminRequest), true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('API key check', () => {
|
||||
it('authenticates with a valid API key', async () => {
|
||||
await describe('API key check', async () => {
|
||||
await it('authenticates with a valid API key', async () => {
|
||||
const apiKeysJSON: Record<string, string> = JSON.parse(
|
||||
fs.readFileSync('data/apiKeys.json', 'utf8')
|
||||
) as Record<string, string>
|
||||
|
|
@ -443,7 +463,7 @@ describe('functions.user', () => {
|
|||
assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), true)
|
||||
})
|
||||
|
||||
it('fails to authenticate with an invalid API key', async () => {
|
||||
await it('fails to authenticate with an invalid API key', async () => {
|
||||
const apiRequest: userFunctions.APIRequest = {
|
||||
params: {
|
||||
apiKey: 'badKey'
|
||||
|
|
@ -453,7 +473,7 @@ describe('functions.user', () => {
|
|||
assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), false)
|
||||
})
|
||||
|
||||
it('fails to authenticate with no API key', async () => {
|
||||
await it('fails to authenticate with no API key', async () => {
|
||||
const apiRequest: userFunctions.APIRequest = {
|
||||
params: {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import assert from 'node:assert';
|
||||
import fs from 'node:fs';
|
||||
import { describe, it } from 'node:test';
|
||||
import { version } from '../version.js';
|
||||
describe('version', () => {
|
||||
it('has a version that matches the package.json', () => {
|
||||
await describe('version', async () => {
|
||||
await it('has a version that matches the package.json', () => {
|
||||
const packageJSON = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
||||
assert.strictEqual(version, packageJSON.version);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import assert from 'node:assert'
|
||||
import fs from 'node:fs'
|
||||
import { describe, it } from 'node:test'
|
||||
|
||||
import { version } from '../version.js'
|
||||
|
||||
describe('version', () => {
|
||||
it('has a version that matches the package.json', () => {
|
||||
await describe('version', async () => {
|
||||
await it('has a version that matches the package.json', () => {
|
||||
const packageJSON = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
||||
assert.strictEqual(version, packageJSON.version)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ export interface Config {
|
|||
settings: {
|
||||
cityDefault?: string;
|
||||
provinceDefault?: string;
|
||||
latitudeMin?: number;
|
||||
latitudeMax?: number;
|
||||
longitudeMin?: number;
|
||||
longitudeMax?: number;
|
||||
fees: {
|
||||
taxPercentageDefault?: number;
|
||||
};
|
||||
|
|
@ -31,6 +35,7 @@ export interface Config {
|
|||
contracts: {
|
||||
burialSiteIdIsRequired?: boolean;
|
||||
contractEndDateIsRequired?: boolean;
|
||||
purchaserRelationships?: string[];
|
||||
deathAgePeriods?: string[];
|
||||
prints?: string[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ export interface Config {
|
|||
settings: {
|
||||
cityDefault?: string
|
||||
provinceDefault?: string
|
||||
latitudeMin?: number
|
||||
latitudeMax?: number
|
||||
longitudeMin?: number
|
||||
longitudeMax?: number
|
||||
fees: {
|
||||
taxPercentageDefault?: number
|
||||
}
|
||||
|
|
@ -32,6 +36,7 @@ export interface Config {
|
|||
contracts: {
|
||||
burialSiteIdIsRequired?: boolean
|
||||
contractEndDateIsRequired?: boolean
|
||||
purchaserRelationships?: string[]
|
||||
deathAgePeriods?: string[]
|
||||
prints?: string[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,14 +208,14 @@ export interface ContractInterment extends Record {
|
|||
recordUpdate_timeMillisMax?: number;
|
||||
}
|
||||
export interface ContractComment extends Record {
|
||||
contractCommentId?: number;
|
||||
contractCommentId: number;
|
||||
contractId?: number;
|
||||
commentDate?: number;
|
||||
commentDateString?: string;
|
||||
commentTime?: number;
|
||||
commentTimeString?: string;
|
||||
commentTimePeriodString?: string;
|
||||
comment?: string;
|
||||
commentDate: number;
|
||||
commentDateString: string;
|
||||
commentTime: number;
|
||||
commentTimeString: string;
|
||||
commentTimePeriodString: string;
|
||||
comment: string;
|
||||
}
|
||||
export interface ContractField extends ContractTypeField, Record {
|
||||
contractId: number;
|
||||
|
|
|
|||
|
|
@ -267,17 +267,17 @@ export interface ContractInterment extends Record {
|
|||
}
|
||||
|
||||
export interface ContractComment extends Record {
|
||||
contractCommentId?: number
|
||||
contractCommentId: number
|
||||
contractId?: number
|
||||
|
||||
commentDate?: number
|
||||
commentDateString?: string
|
||||
commentDate: number
|
||||
commentDateString: string
|
||||
|
||||
commentTime?: number
|
||||
commentTimeString?: string
|
||||
commentTimePeriodString?: string
|
||||
commentTime: number
|
||||
commentTimeString: string
|
||||
commentTimePeriodString: string
|
||||
|
||||
comment?: string
|
||||
comment: string
|
||||
}
|
||||
|
||||
export interface ContractField extends ContractTypeField, Record {
|
||||
|
|
|
|||
|
|
@ -343,13 +343,19 @@
|
|||
<div class="field">
|
||||
<label class="label" for="burialSite--burialSiteLatitude">Latitude</label>
|
||||
<div class="control">
|
||||
<input class="input" id="burialSite--burialSiteLatitude" name="burialSiteLatitude" type="number" min="-90" max="90" step="0.00000001" value="<%= burialSite.burialSiteLatitude %>" onwheel="return false" />
|
||||
<input class="input" id="burialSite--burialSiteLatitude" name="burialSiteLatitude" type="number"
|
||||
min="<%= configFunctions.getConfigProperty('settings.latitudeMin') %>"
|
||||
max="<%= configFunctions.getConfigProperty('settings.latitudeMax') %>"
|
||||
step="0.00000001" value="<%= burialSite.burialSiteLatitude %>" onwheel="return false" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="burialSite--burialSiteLongitude">Longitude</label>
|
||||
<div class="control">
|
||||
<input class="input" id="burialSite--burialSiteLongitude" name="burialSiteLongitude" type="number" min="-180" max="180" step="0.00000001" value="<%= burialSite.burialSiteLongitude %>" onwheel="return false" />
|
||||
<input class="input" id="burialSite--burialSiteLongitude" name="burialSiteLongitude" type="number"
|
||||
min="<%= configFunctions.getConfigProperty('settings.longitudeMin') %>"
|
||||
max="<%= configFunctions.getConfigProperty('settings.longitudeMax') %>"
|
||||
step="0.00000001" value="<%= burialSite.burialSiteLongitude %>" onwheel="return false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<form id="form--cemetery">
|
||||
|
|
@ -106,7 +105,13 @@
|
|||
<label class="label" for="cemetery--cemeteryKey">Cemetery Key</label>
|
||||
<div class="control">
|
||||
<input class="input" id="cemetery--cemeteryKey" name="cemeteryKey" type="text"
|
||||
value="<%= cemetery.cemeteryKey %>" maxlength="20" required />
|
||||
value="<%= cemetery.cemeteryKey %>" maxlength="20"
|
||||
<%= configFunctions.getConfigProperty('settings.burialSites.burialSiteNameSegments.includeCemeteryKey') ? ' required' : '' %> />
|
||||
<% if (configFunctions.getConfigProperty('settings.burialSites.burialSiteNameSegments.includeCemeteryKey')) { %>
|
||||
<p class="help">
|
||||
The cemetery key is prepended to the burial site names.
|
||||
</p>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
|
@ -181,13 +186,19 @@
|
|||
<div class="field">
|
||||
<label class="label" for="cemetery--cemeteryLatitude">Latitude</label>
|
||||
<div class="control">
|
||||
<input class="input" id="cemetery--cemeteryLatitude" name="cemeteryLatitude" type="number" min="-90" max="90" step="0.00000001" value="<%= cemetery.cemeteryLatitude %>" />
|
||||
<input class="input" id="cemetery--cemeteryLatitude" name="cemeteryLatitude" type="number"
|
||||
min="<%= configFunctions.getConfigProperty('settings.latitudeMin') %>"
|
||||
max="<%= configFunctions.getConfigProperty('settings.latitudeMax') %>"
|
||||
step="0.00000001" value="<%= cemetery.cemeteryLatitude %>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="cemetery--cemeteryLongitude">Longitude</label>
|
||||
<div class="control">
|
||||
<input class="input" id="cemetery--cemeteryLongitude" name="cemeteryLongitude" type="number" min="-180" max="180" step="0.00000001" value="<%= cemetery.cemeteryLongitude %>" />
|
||||
<input class="input" id="cemetery--cemeteryLongitude" name="cemeteryLongitude" type="number"
|
||||
min="<%= configFunctions.getConfigProperty('settings.longitudeMin') %>"
|
||||
max="<%= configFunctions.getConfigProperty('settings.longitudeMax') %>"
|
||||
step="0.00000001" value="<%= cemetery.cemeteryLongitude %>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -216,7 +227,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<% if (!isCreate) { %>
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@
|
|||
required accesskey="f"
|
||||
<%= (isCreate ? " autofocus" : "") %>>
|
||||
<% if (isCreate) { %>
|
||||
<option value="" data-is-preneed="false">(No Type)</option>
|
||||
<option value="" data-is-preneed="false">(Select a Type)</option>
|
||||
<% } %>
|
||||
<% let typeIsFound = false; %>
|
||||
<% for (const contractType of contractTypes) { %>
|
||||
|
|
@ -498,9 +498,17 @@
|
|||
</span>
|
||||
</label>
|
||||
<div class="control">
|
||||
<input class="input" id="contract--purchaserRelationship" name="purchaserRelationship" type="text" maxlength="100" autocomplete="off" value="<%= contract.purchaserRelationship %>" />
|
||||
<input class="input" id="contract--purchaserRelationship" name="purchaserRelationship" type="text"
|
||||
maxlength="100" autocomplete="off"
|
||||
list="datalist--purchaserRelationships"
|
||||
value="<%= contract.purchaserRelationship %>" />
|
||||
</div>
|
||||
</div>
|
||||
<datalist id="datalist--purchaserRelationships">
|
||||
<% for (const relationship of configFunctions.getConfigProperty('settings.contracts.purchaserRelationships')) { %>
|
||||
<option value="<%= relationship %>">
|
||||
<% } %>
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -254,20 +254,28 @@
|
|||
<strong>Birth:</strong>
|
||||
</div>
|
||||
<div class="column">
|
||||
<%= contractInterment.birthDateString ?? '(No Birth Date)' %><br />
|
||||
<%= contractInterment.birthPlace ?? '(No Birth Place)' %>
|
||||
<% if (contractInterment.birthDateString === '') { %>
|
||||
<span class="has-text-grey">(No Birth Date)</span>
|
||||
<% } else { %>
|
||||
<%= contractInterment.birthDateString %>
|
||||
<% } %><br />
|
||||
<%= contractInterment.birthPlace %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="columns mb-0">
|
||||
<div class="column">
|
||||
<strong>Death:</strong>
|
||||
</div>
|
||||
<div class="column">
|
||||
<%= contractInterment.deathDateString ?? '(No Death Date)' %><br />
|
||||
<%= contractInterment.deathPlace ?? '(No Death Place)' %>
|
||||
<% if (contractInterment.deathDateString === '') { %>
|
||||
<span class="has-text-grey">(No Death Date)</span>
|
||||
<% } else { %>
|
||||
<%= contractInterment.deathDateString %>
|
||||
<% } %><br />
|
||||
<%= contractInterment.deathPlace %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="columns mb-0">
|
||||
<div class="column">
|
||||
<strong>Age:</strong>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -94,30 +94,23 @@
|
|||
<div class="column">
|
||||
<div class="columns is-desktop">
|
||||
<div class="column">
|
||||
<div class="card is-hover-container">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/workOrders">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="fa-layers fa-4x fa-fw">
|
||||
<i class="fas fa-fw fa-hard-hat" aria-hidden="true"></i>
|
||||
<% if (workOrderCount > 0) { %>
|
||||
<a class="fa-layers-counter has-background-success has-text-white" href="<%= urlPrefix %>/workOrders/?workOrderOpenDateString=<%= dateTimeFunctions.dateToString(new Date()) %>"><%= workOrderCount %></a>
|
||||
<% } %>
|
||||
</span>
|
||||
<i class="fa-solid fa-4x fa-fw fa-hard-hat" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/workOrders">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Work Orders
|
||||
</h2>
|
||||
<p>
|
||||
View and maintain work orders.<br />
|
||||
<span class="tags has-addons is-invisible is-visible-hover">
|
||||
<span class="tag is-link is-light">Shortcut</span>
|
||||
<kbd class="tag">1</kbd>
|
||||
</span>
|
||||
View and maintain work orders.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="panel-block is-block">
|
||||
<% if (user.userProperties.canUpdate) { %>
|
||||
<a class="button is-fullwidth is-success is-light mb-2" href="<%= urlPrefix %>/workOrders/new">
|
||||
<span class="icon">
|
||||
|
|
@ -137,31 +130,26 @@
|
|||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="card is-hover-container">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/contracts">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
|
||||
<i class="fas fa-vector-square"></i>
|
||||
<i class="fas fa-user" data-fa-transform="shrink-10"></i>
|
||||
<% if (contractCount > 0) { %>
|
||||
<span class="fa-layers-counter has-background-success"><%= contractCount %></span>
|
||||
<% } %>
|
||||
</span>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/contracts">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Contracts
|
||||
</h2>
|
||||
<p>
|
||||
View and maintain current and past contracts.<br />
|
||||
<span class="tags has-addons is-invisible is-visible-hover">
|
||||
<span class="tag is-link is-light">Shortcut</span>
|
||||
<kbd class="tag">2</kbd>
|
||||
</span>
|
||||
View and maintain current and past contracts.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="panel-block is-block">
|
||||
<% if (user.userProperties.canUpdate) { %>
|
||||
<a class="button is-fullwidth is-success is-light mb-2" href="<%= urlPrefix %>/contracts/new">
|
||||
<span class="icon">
|
||||
|
|
@ -182,89 +170,98 @@
|
|||
</div>
|
||||
<div class="columns is-desktop">
|
||||
<div class="column">
|
||||
<div class="card is-hover-container">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/burialSites">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="fas fa-4x fa-fw fa-vector-square" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/burialSites">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Burial Sites
|
||||
</h2>
|
||||
<p>
|
||||
View and maintain burial sites within a cemetery.<br />
|
||||
<span class="tags has-addons is-invisible is-visible-hover">
|
||||
<span class="tag is-link is-light">Shortcut</span>
|
||||
<kbd class="tag">3</kbd>
|
||||
</span>
|
||||
View and maintain burial sites within a cemetery.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<% if (user.userProperties.canUpdate) { %>
|
||||
<div class="panel-block is-block">
|
||||
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/burialSites/new">
|
||||
<span class="icon">
|
||||
<i class="fas fa-plus" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span>New Burial Site</span>
|
||||
</a>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="card is-hover-container">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/cemeteries">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="far fa-4x fa-fw fa-map" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/cemeteries">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Cemeteries
|
||||
</h2>
|
||||
<p>
|
||||
View and maintain cemeteries.
|
||||
<span class="tags has-addons is-invisible is-visible-hover">
|
||||
<span class="tag is-link is-light">Shortcut</span>
|
||||
<kbd class="tag">4</kbd>
|
||||
</span>
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<% if (user.userProperties.canUpdate) { %>
|
||||
<div class="panel-block is-block">
|
||||
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/cemeteries/new">
|
||||
<span class="icon">
|
||||
<i class="fas fa-plus" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span>New Cemetery</span>
|
||||
</a>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-desktop">
|
||||
<div class="column">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/reports">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="fas fa-4x fa-fw fa-file" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/reports">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Report Library
|
||||
</h2>
|
||||
<p>Produce reports and export data.</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="card is-hover-container">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<a class="panel-block" href="https://cityssm.github.io/sunrise-cms/docs" rel="noopener noreferrer" target="_blank">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="fas fa-4x fa-fw fa-circle-question" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Help Documentation
|
||||
</h2>
|
||||
<p>Tips and tricks to get the most out of Sunrise CMS.</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="panel-block is-block">
|
||||
<a class="button is-fullwidth is-link is-light has-tooltip-bottom" data-tooltip="Latest Updates, Issue Tracker, Say Hello"
|
||||
href="https://github.com/cityssm/sunrise-cms" target="_blank" rel="noreferrer">
|
||||
<span class="icon">
|
||||
|
|
@ -278,10 +275,11 @@
|
|||
</div>
|
||||
|
||||
<% if (user.userProperties.isAdmin) { %>
|
||||
<h2 class="title is-3">Administrator Tools</h2>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
Administrator Tools
|
||||
</div>
|
||||
<a class="panel-block" href="<%= urlPrefix %>/admin/fees">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
|
||||
|
|
@ -289,7 +287,7 @@
|
|||
<i class="fas fa-cog" data-fa-transform="shrink-8 right-8 down-5" data-fa-glow="10"></i>
|
||||
</span>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/admin/fees">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Fee Management
|
||||
</h2>
|
||||
|
|
@ -297,10 +295,10 @@
|
|||
Manage fees for contracts
|
||||
and specific burial site types.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/admin/contractTypes">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
|
||||
|
|
@ -308,7 +306,7 @@
|
|||
<i class="fas fa-cog" data-fa-transform="shrink-8 right-8 down-5" data-fa-glow="10"></i>
|
||||
</span>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/admin/contractTypes">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Contract Type Management
|
||||
</h2>
|
||||
|
|
@ -317,10 +315,10 @@
|
|||
the fields associated with them,
|
||||
and their available print options.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/admin/burialSiteTypes">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
|
||||
|
|
@ -328,17 +326,17 @@
|
|||
<i class="fas fa-cog" data-fa-transform="shrink-8 right-8 down-5" data-fa-glow="10"></i>
|
||||
</span>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/admin/burialSiteTypes">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Burial Site Type Management
|
||||
</h2>
|
||||
<p>
|
||||
Manage burial site types and fields associated with them.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/admin/tables">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
|
||||
|
|
@ -346,7 +344,7 @@
|
|||
<i class="fas fa-cog" data-fa-transform="shrink-8 right-8 down-5" data-fa-glow="10"></i>
|
||||
</span>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/admin/tables">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Config Table Management
|
||||
</h2>
|
||||
|
|
@ -355,15 +353,15 @@
|
|||
work order types
|
||||
and burial site statuses.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/admin/database">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="fas fa-4x fa-fw fa-database" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/admin/database">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Database Maintenance
|
||||
</h2>
|
||||
|
|
@ -371,25 +369,25 @@
|
|||
Backup the database before making significant updates.
|
||||
Permanently delete records that have been previously deleted from the database.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<% if (configFunctions.getConfigProperty("application.ntfyStartup")) { %>
|
||||
<div class="card-content">
|
||||
<a class="panel-block" href="<%= urlPrefix %>/admin/ntfyStartup">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="far fa-4x fa-fw fa-comment-alt" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a class="media-content" href="<%= urlPrefix %>/admin/ntfyStartup">
|
||||
<div class="media-content">
|
||||
<h2 class="title is-4 mb-0 has-text-link">
|
||||
Ntfy Startup Notification
|
||||
</h2>
|
||||
<p>
|
||||
Subscribe to application startup notifications on a phone or a desktop computer.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">Open Work Orders</h2>
|
||||
<h2 class="title is-5 mb-0">Open Work Orders</h2>
|
||||
<p>
|
||||
All active work orders without completion dates.
|
||||
</p>
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
<span class="tag is-info">ICS</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">Work Order Milestone Calendar</h2>
|
||||
<h2 class="title is-5 mb-0">Work Order Milestone Calendar</h2>
|
||||
<p>
|
||||
Upcoming and recently passed work order milestones,
|
||||
compatible with Microsoft Outlook and other calendar tools.
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">
|
||||
<h2 class="title is-5 mb-0">
|
||||
Current Contract By Cemetery
|
||||
</h2>
|
||||
<div class="field has-addons mt-2">
|
||||
|
|
@ -161,7 +161,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">Transactions by Date</h2>
|
||||
<h2 class="title is-5 mb-0">Transactions by Date</h2>
|
||||
<div class="field has-addons mt-2">
|
||||
<div class="control">
|
||||
<label class="button is-small is-static" for="contractTransactions-byTransactionDateString--transactionDateString">
|
||||
|
|
@ -193,7 +193,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">
|
||||
<h2 class="title is-5 mb-0">
|
||||
Burial Sites By Cemetery
|
||||
</h2>
|
||||
<div class="field has-addons mt-2">
|
||||
|
|
@ -229,7 +229,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">Burial Sites By Type</h2>
|
||||
<h2 class="title is-5 mb-0">Burial Sites By Type</h2>
|
||||
<div class="field has-addons mt-2">
|
||||
<div class="control">
|
||||
<label class="button is-small is-static" for="burialSites-byBurialSiteTypeId--burialSiteTypeId">
|
||||
|
|
@ -263,7 +263,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">Burial Sites By Status</h2>
|
||||
<h2 class="title is-5 mb-0">Burial Sites By Status</h2>
|
||||
<div class="field has-addons mt-2">
|
||||
<div class="control">
|
||||
<label class="button is-small is-static" for="burialSites-byBurialSiteStatusId--burialSiteStatusId">
|
||||
|
|
@ -302,7 +302,7 @@
|
|||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="title is-5 is-marginless">Full Cemetery List</h2>
|
||||
<h2 class="title is-5 mb-0">Full Cemetery List</h2>
|
||||
<p>
|
||||
All active cemeteries.
|
||||
</p>
|
||||
|
|
@ -389,6 +389,17 @@
|
|||
<h3 class="title is-5 is-marginless">Full ContractTransactions Table</h3>
|
||||
</div>
|
||||
</a>
|
||||
<a class="panel-block align-items-flex-start" href="<%= urlPrefix %>/reports/funeralHomes-all" download>
|
||||
<div class="has-text-centered my-2 ml-2 mr-3">
|
||||
<span class="icon has-text-info">
|
||||
<i class="fas fa-2x fa-table" aria-hidden="true"></i>
|
||||
</span><br />
|
||||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="title is-5 is-marginless">Full FuneralHomes Table</h3>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
|
|
@ -586,6 +597,17 @@
|
|||
<h3 class="title is-5 is-marginless">Full ContractTypeFields Table</h3>
|
||||
</div>
|
||||
</a>
|
||||
<a class="panel-block align-items-flex-start" href="<%= urlPrefix %>/reports/intermentContainerTypes-all" download>
|
||||
<div class="has-text-centered my-2 ml-2 mr-3">
|
||||
<span class="icon has-text-info">
|
||||
<i class="fas fa-2x fa-table" aria-hidden="true"></i>
|
||||
</span><br />
|
||||
<span class="tag is-info">CSV</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="title is-5 is-marginless">Full IntermentContainerTypes Table</h3>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<h2 class="panel-heading">Work Order Tables</h2>
|
||||
|
|
|
|||
Loading…
Reference in New Issue