major refactoring

mostly finished, see #1
deepsource-autofix-76c6eb20
Dan Gowans 2025-03-07 15:42:38 -05:00
parent 5f6c6a0be5
commit 7dc95ef90f
150 changed files with 6706 additions and 6319 deletions

1
app.js
View File

@ -75,7 +75,6 @@ if (urlPrefix !== '') {
debug(`urlPrefix = ${urlPrefix}`);
}
app.use(urlPrefix, express.static(path.join('public')));
app.use(`${urlPrefix}/lib/bulma-calendar`, express.static(path.join('node_modules', 'bulma-calendar', 'dist')));
app.use(`${urlPrefix}/lib/cityssm-bulma-js/bulma-js.js`, express.static(path.join('node_modules', '@cityssm', 'bulma-js', 'dist', 'bulma-js.js')));
app.use(`${urlPrefix}/lib/cityssm-bulma-webapp-js`, express.static(path.join('node_modules', '@cityssm', 'bulma-webapp-js', 'dist')));
app.use(`${urlPrefix}/lib/fa`, express.static(path.join('node_modules', '@fortawesome', 'fontawesome-free')));

5
app.ts
View File

@ -104,11 +104,6 @@ if (urlPrefix !== '') {
app.use(urlPrefix, express.static(path.join('public')))
app.use(
`${urlPrefix}/lib/bulma-calendar`,
express.static(path.join('node_modules', 'bulma-calendar', 'dist'))
)
app.use(
`${urlPrefix}/lib/cityssm-bulma-js/bulma-js.js`,
express.static(

View File

@ -1,11 +1,11 @@
import { testAdmin } from '../../../test/_globals.js';
import { login, logout } from '../../support/index.js';
describe('Admin - Lot Type Management', () => {
describe('Admin - Burial Site Type Management', () => {
beforeEach('Loads page', () => {
logout();
login(testAdmin);
cy.visit('/admin/lotTypes');
cy.location('pathname').should('equal', '/admin/lotTypes');
cy.visit('/admin/burialSiteTypes');
cy.location('pathname').should('equal', '/admin/burialSiteTypes');
});
afterEach(logout);
it('Has no detectable accessibility issues', () => {

View File

@ -1,12 +1,12 @@
import { testAdmin } from '../../../test/_globals.js'
import { login, logout } from '../../support/index.js'
describe('Admin - Lot Type Management', () => {
describe('Admin - Burial Site Type Management', () => {
beforeEach('Loads page', () => {
logout()
login(testAdmin)
cy.visit('/admin/lotTypes')
cy.location('pathname').should('equal', '/admin/lotTypes')
cy.visit('/admin/burialSiteTypes')
cy.location('pathname').should('equal', '/admin/burialSiteTypes')
})
afterEach(logout)

View File

@ -1,17 +1,17 @@
import { testUpdate } from '../../../test/_globals.js';
import { login, logout } from '../../support/index.js';
describe('Update - Lots', () => {
describe('Update - Burial Sites', () => {
beforeEach('Loads page', () => {
logout();
login(testUpdate);
});
afterEach(logout);
it('Has a "Create" link on the Lot Search', () => {
cy.visit('/lots');
cy.location('pathname').should('equal', '/lots');
it('Has a "Create" link on the Burial Site Search', () => {
cy.visit('/burialSites');
cy.location('pathname').should('equal', '/burialSites');
cy.get("a[href$='/burialSites/new']").should('exist');
});
describe('Update a New Lot', () => {
describe('Creates a New Burial Site', () => {
it('Has no detectable accessibility issues', () => {
cy.visit('/burialSites/new');
cy.injectAxe();

View File

@ -1,7 +1,7 @@
import { testUpdate } from '../../../test/_globals.js'
import { login, logout } from '../../support/index.js'
describe('Update - Lots', () => {
describe('Update - Burial Sites', () => {
beforeEach('Loads page', () => {
logout()
login(testUpdate)
@ -9,13 +9,13 @@ describe('Update - Lots', () => {
afterEach(logout)
it('Has a "Create" link on the Lot Search', () => {
cy.visit('/lots')
cy.location('pathname').should('equal', '/lots')
it('Has a "Create" link on the Burial Site Search', () => {
cy.visit('/burialSites')
cy.location('pathname').should('equal', '/burialSites')
cy.get("a[href$='/burialSites/new']").should('exist')
})
describe('Update a New Lot', () => {
describe('Creates a New Burial Site', () => {
it('Has no detectable accessibility issues', () => {
cy.visit('/burialSites/new')
cy.injectAxe()

View File

@ -1,17 +1,17 @@
import { testUpdate } from '../../../test/_globals.js';
import { login, logout } from '../../support/index.js';
describe('Update - Lot Occupancies', () => {
describe('Update - Contracts', () => {
beforeEach(() => {
logout();
login(testUpdate);
});
afterEach(logout);
it('Has a "Create" link on the Lot Occupancy Search', () => {
cy.visit('/lotOccupancies');
cy.location('pathname').should('equal', '/lotOccupancies');
it('Has a "Create" link on the Contract Search', () => {
cy.visit('/contracts');
cy.location('pathname').should('equal', '/contracts');
cy.get("a[href$='/contracts/new']").should('exist');
});
describe('Update a New Lot Occupancy', () => {
describe('Creates a New Contract', () => {
it('Has no detectable accessibility issues', () => {
cy.visit('/contracts/new');
cy.injectAxe();

View File

@ -1,7 +1,7 @@
import { testUpdate } from '../../../test/_globals.js'
import { login, logout } from '../../support/index.js'
describe('Update - Lot Occupancies', () => {
describe('Update - Contracts', () => {
beforeEach(() => {
logout()
login(testUpdate)
@ -9,13 +9,13 @@ describe('Update - Lot Occupancies', () => {
afterEach(logout)
it('Has a "Create" link on the Lot Occupancy Search', () => {
cy.visit('/lotOccupancies')
cy.location('pathname').should('equal', '/lotOccupancies')
it('Has a "Create" link on the Contract Search', () => {
cy.visit('/contracts')
cy.location('pathname').should('equal', '/contracts')
cy.get("a[href$='/contracts/new']").should('exist')
})
describe('Update a New Lot Occupancy', () => {
describe('Creates a New Contract', () => {
it('Has no detectable accessibility issues', () => {
cy.visit('/contracts/new')
cy.injectAxe()

View File

@ -11,7 +11,7 @@ describe('Update - Work Orders', () => {
cy.location('pathname').should('equal', '/workOrders');
cy.get("a[href$='/workOrders/new']").should('exist');
});
describe('Update a New Work Order', () => {
describe('Creates a New Work Order', () => {
it('Has no detectable accessibility issues', () => {
cy.visit('/workOrders/new');
cy.location('pathname').should('equal', '/workOrders/new');

View File

@ -15,7 +15,7 @@ describe('Update - Work Orders', () => {
cy.get("a[href$='/workOrders/new']").should('exist')
})
describe('Update a New Work Order', () => {
describe('Creates a New Work Order', () => {
it('Has no detectable accessibility issues', () => {
cy.visit('/workOrders/new')
cy.location('pathname').should('equal', '/workOrders/new')

View File

@ -14,7 +14,7 @@ export default async function addContractComment(commentForm, user) {
}
const database = await acquireConnection();
const result = database
.prepare(`insert into BurialSiteContactComments (
.prepare(`insert into ContractComments (
contractId,
commentDate, commentTime,
comment,

View File

@ -41,7 +41,7 @@ export default async function addContractComment(
const result = database
.prepare(
`insert into BurialSiteContactComments (
`insert into ContractComments (
contractId,
commentDate, commentTime,
comment,

View File

@ -0,0 +1,16 @@
import { type DateString } from '@cityssm/utils-datetime';
export interface AddForm {
contractId: string | number;
deceasedName: string;
deceasedAddress1: string;
deceasedAddress2: string;
deceasedCity: string;
deceasedProvince: string;
deceasedPostalCode: string;
birthDateString: DateString | '';
birthPlace: string;
deathDateString: DateString | '';
deathPlace: string;
intermentContainerTypeId: string | number;
}
export default function addContractInterment(contractForm: AddForm, user: User): Promise<number>;

View File

@ -0,0 +1,30 @@
import { dateStringToInteger } from '@cityssm/utils-datetime';
import { acquireConnection } from './pool.js';
export default async function addContractInterment(contractForm, user) {
const database = await acquireConnection();
const maxIntermentNumber = (database
.prepare(`select max(intermentNumber) as maxIntermentNumber
from ContractInterments
where contractId = ?`)
.pluck()
.get(contractForm.contractId) ?? 0);
const newIntermentNumber = maxIntermentNumber + 1;
const rightNowMillis = Date.now();
database
.prepare(`insert into ContractInterments
(contractId, intermentNumber,
deceasedName, deceasedAddress1, deceasedAddress2, deceasedCity, deceasedProvince, deceasedPostalCode,
birthDate, birthPlace, deathDate, deathPlace, intermentContainerTypeId,
recordCreate_userName, recordCreate_timeMillis,
recordUpdate_userName, recordUpdate_timeMillis)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
.run(contractForm.contractId, newIntermentNumber, contractForm.deceasedName, contractForm.deceasedAddress1, contractForm.deceasedAddress2, contractForm.deceasedCity, contractForm.deceasedProvince, contractForm.deceasedPostalCode, contractForm.birthDateString === ''
? undefined
: dateStringToInteger(contractForm.birthDateString), contractForm.birthPlace, contractForm.deathDateString === ''
? undefined
: dateStringToInteger(contractForm.deathDateString), contractForm.deathPlace, contractForm.intermentContainerTypeId === ''
? undefined
: contractForm.intermentContainerTypeId, user.userName, rightNowMillis, user.userName, rightNowMillis);
database.release();
return newIntermentNumber;
}

View File

@ -0,0 +1,77 @@
import { type DateString, dateStringToInteger } from '@cityssm/utils-datetime'
import { acquireConnection } from './pool.js'
export interface AddForm {
contractId: string | number
deceasedName: string
deceasedAddress1: string
deceasedAddress2: string
deceasedCity: string
deceasedProvince: string
deceasedPostalCode: string
birthDateString: DateString | ''
birthPlace: string
deathDateString: DateString | ''
deathPlace: string
intermentContainerTypeId: string | number
}
export default async function addContractInterment(
contractForm: AddForm,
user: User
): Promise<number> {
const database = await acquireConnection()
const maxIntermentNumber = (database
.prepare(
`select max(intermentNumber) as maxIntermentNumber
from ContractInterments
where contractId = ?`
)
.pluck()
.get(contractForm.contractId) ?? 0) as number
const newIntermentNumber = maxIntermentNumber + 1
const rightNowMillis = Date.now()
database
.prepare(
`insert into ContractInterments
(contractId, intermentNumber,
deceasedName, deceasedAddress1, deceasedAddress2, deceasedCity, deceasedProvince, deceasedPostalCode,
birthDate, birthPlace, deathDate, deathPlace, intermentContainerTypeId,
recordCreate_userName, recordCreate_timeMillis,
recordUpdate_userName, recordUpdate_timeMillis)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
)
.run(
contractForm.contractId,
newIntermentNumber,
contractForm.deceasedName,
contractForm.deceasedAddress1,
contractForm.deceasedAddress2,
contractForm.deceasedCity,
contractForm.deceasedProvince,
contractForm.deceasedPostalCode,
contractForm.birthDateString === ''
? undefined
: dateStringToInteger(contractForm.birthDateString),
contractForm.birthPlace,
contractForm.deathDateString === ''
? undefined
: dateStringToInteger(contractForm.deathDateString),
contractForm.deathPlace,
contractForm.intermentContainerTypeId === ''
? undefined
: contractForm.intermentContainerTypeId,
user.userName,
rightNowMillis,
user.userName,
rightNowMillis
)
database.release()
return newIntermentNumber
}

View File

@ -1,5 +1,5 @@
export interface AddWorkOrderLotForm {
export interface AddForm {
workOrderId: number | string;
burialSiteId: number | string;
}
export default function addWorkOrderBurialSite(workOrderLotForm: AddWorkOrderLotForm, user: User): Promise<boolean>;
export default function addWorkOrderBurialSite(workOrderLotForm: AddForm, user: User): Promise<boolean>;

View File

@ -1,12 +1,12 @@
import { acquireConnection } from './pool.js'
export interface AddWorkOrderLotForm {
export interface AddForm {
workOrderId: number | string
burialSiteId: number | string
}
export default async function addWorkOrderBurialSite(
workOrderLotForm: AddWorkOrderLotForm,
workOrderLotForm: AddForm,
user: User
): Promise<boolean> {
const database = await acquireConnection()

View File

@ -1,5 +1,5 @@
export interface AddWorkOrderCommentForm {
workOrderId: string;
workOrderComment: string;
comment: string;
}
export default function addWorkOrderComment(workOrderCommentForm: AddWorkOrderCommentForm, user: User): Promise<number>;

View File

@ -6,12 +6,12 @@ export default async function addWorkOrderComment(workOrderCommentForm, user) {
const result = database
.prepare(`insert into WorkOrderComments (
workOrderId,
workOrderCommentDate, workOrderCommentTime,
workOrderComment,
commentDate, commentTime,
comment,
recordCreate_userName, recordCreate_timeMillis,
recordUpdate_userName, recordUpdate_timeMillis)
values (?, ?, ?, ?, ?, ?, ?, ?)`)
.run(workOrderCommentForm.workOrderId, dateToInteger(rightNow), dateToTimeInteger(rightNow), workOrderCommentForm.workOrderComment, user.userName, rightNow.getTime(), user.userName, rightNow.getTime());
.run(workOrderCommentForm.workOrderId, dateToInteger(rightNow), dateToTimeInteger(rightNow), workOrderCommentForm.comment, user.userName, rightNow.getTime(), user.userName, rightNow.getTime());
database.release();
return result.lastInsertRowid;
}

View File

@ -4,7 +4,7 @@ import { acquireConnection } from './pool.js'
export interface AddWorkOrderCommentForm {
workOrderId: string
workOrderComment: string
comment: string
}
export default async function addWorkOrderComment(
@ -19,8 +19,8 @@ export default async function addWorkOrderComment(
.prepare(
`insert into WorkOrderComments (
workOrderId,
workOrderCommentDate, workOrderCommentTime,
workOrderComment,
commentDate, commentTime,
comment,
recordCreate_userName, recordCreate_timeMillis,
recordUpdate_userName, recordUpdate_timeMillis)
values (?, ?, ?, ?, ?, ?, ?, ?)`
@ -29,7 +29,7 @@ export default async function addWorkOrderComment(
workOrderCommentForm.workOrderId,
dateToInteger(rightNow),
dateToTimeInteger(rightNow),
workOrderCommentForm.workOrderComment,
workOrderCommentForm.comment,
user.userName,
rightNow.getTime(),
user.userName,

View File

@ -1,6 +1,6 @@
import type { PoolConnection } from 'better-sqlite-pool';
export interface AddWorkOrderContractOccupancyForm {
export interface AddForm {
workOrderId: number | string;
contractId: number | string;
}
export default function addWorkOrderContract(addForm: AddWorkOrderContractOccupancyForm, user: User, connectedDatabase?: PoolConnection): Promise<boolean>;
export default function addWorkOrderContract(addForm: AddForm, user: User, connectedDatabase?: PoolConnection): Promise<boolean>;

View File

@ -2,13 +2,13 @@ import type { PoolConnection } from 'better-sqlite-pool'
import { acquireConnection } from './pool.js'
export interface AddWorkOrderContractOccupancyForm {
export interface AddForm {
workOrderId: number | string
contractId: number | string
}
export default async function addWorkOrderContract(
addForm: AddWorkOrderContractOccupancyForm,
addForm: AddForm,
user: User,
connectedDatabase?: PoolConnection
): Promise<boolean> {

View File

@ -2,7 +2,7 @@ import { acquireConnection } from './pool.js';
export default async function deleteContractFee(contractId, feeId, user) {
const database = await acquireConnection();
const result = database
.prepare(`update BurialSteContractFees
.prepare(`update ContractFees
set recordDelete_userName = ?,
recordDelete_timeMillis = ?
where contractId = ?

View File

@ -9,7 +9,7 @@ export default async function deleteContractFee(
const result = database
.prepare(
`update BurialSteContractFees
`update ContractFees
set recordDelete_userName = ?,
recordDelete_timeMillis = ?
where contractId = ?

View File

@ -21,12 +21,15 @@ export default async function getContract(contractId, connectedDatabase) {
o.purchaserCity, o.purchaserProvince, o.purchaserPostalCode,
o.purchaserPhoneNumber, o.purchaserEmail, o.purchaserRelationship,
o.funeralHomeId, o.funeralDirectorName,
f.funeralHomeName, f.funeralHomeAddress1, f.funeralHomeAddress2,
f.funeralHomeCity, f.funeralHomeProvince, f.funeralHomePostalCode,
o.funeralDate, userFn_dateIntegerToString(o.funeralDate) as funeralDateString,
o.funeralTime, userFn_timeIntegerToString(o.funeralTime) as funeralTimeString,
o.committalTypeId, c.committalType,
o.recordUpdate_timeMillis
from Contracts o
left join ContractTypes t on o.contractTypeId = t.contractTypeId
left join FuneralHomes f on o.funeralHomeId = f.funeralHomeId
left join CommittalTypes c on o.committalTypeId = c.committalTypeId
left join BurialSites l on o.burialSiteId = l.burialSiteId
left join Cemeteries m on l.cemeteryId = m.cemeteryId

View File

@ -32,12 +32,15 @@ export default async function getContract(
o.purchaserCity, o.purchaserProvince, o.purchaserPostalCode,
o.purchaserPhoneNumber, o.purchaserEmail, o.purchaserRelationship,
o.funeralHomeId, o.funeralDirectorName,
f.funeralHomeName, f.funeralHomeAddress1, f.funeralHomeAddress2,
f.funeralHomeCity, f.funeralHomeProvince, f.funeralHomePostalCode,
o.funeralDate, userFn_dateIntegerToString(o.funeralDate) as funeralDateString,
o.funeralTime, userFn_timeIntegerToString(o.funeralTime) as funeralTimeString,
o.committalTypeId, c.committalType,
o.recordUpdate_timeMillis
from Contracts o
left join ContractTypes t on o.contractTypeId = t.contractTypeId
left join FuneralHomes f on o.funeralHomeId = f.funeralHomeId
left join CommittalTypes c on o.committalTypeId = c.committalTypeId
left join BurialSites l on o.burialSiteId = l.burialSiteId
left join Cemeteries m on l.cemeteryId = m.cemeteryId

View File

@ -3,10 +3,10 @@ import type { PoolConnection } from 'better-sqlite-pool';
import type { Contract } from '../types/recordTypes.js';
export interface GetContractsFilters {
burialSiteId?: number | string;
occupancyTime?: '' | 'past' | 'current' | 'future';
contractTime?: '' | 'past' | 'current' | 'future';
contractStartDateString?: DateString;
occupancyEffectiveDateString?: string;
occupantName?: string;
contractEffectiveDateString?: string;
deceasedName?: string;
contractTypeId?: number | string;
cemeteryId?: number | string;
burialSiteNameSearchType?: '' | 'startsWith' | 'endsWith';

View File

@ -1,7 +1,7 @@
import { dateIntegerToString, dateStringToInteger, timeIntegerToString } from '@cityssm/utils-datetime';
import { getConfigProperty } from '../helpers/config.helpers.js';
import { getContractTypeById } from '../helpers/functions.cache.js';
import { getBurialSiteNameWhereClause, getOccupancyTimeWhereClause, getOccupantNameWhereClause } from '../helpers/functions.sqlFilters.js';
import { getBurialSiteNameWhereClause, getContractTimeWhereClause, getDeceasedNameWhereClause, } from '../helpers/functions.sqlFilters.js';
import getContractFees from './getContractFees.js';
import getContractInterments from './getContractInterments.js';
import getContractTransactions from './getContractTransactions.js';
@ -16,31 +16,31 @@ function buildWhereClause(filters) {
const burialSiteNameFilters = getBurialSiteNameWhereClause(filters.burialSiteName, filters.burialSiteNameSearchType ?? '', 'l');
sqlWhereClause += burialSiteNameFilters.sqlWhereClause;
sqlParameters.push(...burialSiteNameFilters.sqlParameters);
const occupantNameFilters = getOccupantNameWhereClause(filters.occupantName, 'o');
if (occupantNameFilters.sqlParameters.length > 0) {
const deceasedNameFilters = getDeceasedNameWhereClause(filters.deceasedName, 'o');
if (deceasedNameFilters.sqlParameters.length > 0) {
sqlWhereClause += ` and o.contractId in (
select contractId from LotOccupancyOccupants o
select contractId from ContractInterments o
where recordDelete_timeMillis is null
${occupantNameFilters.sqlWhereClause})`;
sqlParameters.push(...occupantNameFilters.sqlParameters);
${deceasedNameFilters.sqlWhereClause})`;
sqlParameters.push(...deceasedNameFilters.sqlParameters);
}
if ((filters.contractTypeId ?? '') !== '') {
sqlWhereClause += ' and o.contractTypeId = ?';
sqlParameters.push(filters.contractTypeId);
}
const occupancyTimeFilters = getOccupancyTimeWhereClause(filters.occupancyTime ?? '', 'o');
sqlWhereClause += occupancyTimeFilters.sqlWhereClause;
sqlParameters.push(...occupancyTimeFilters.sqlParameters);
const contractTimeFilters = getContractTimeWhereClause(filters.contractTime ?? '', 'o');
sqlWhereClause += contractTimeFilters.sqlWhereClause;
sqlParameters.push(...contractTimeFilters.sqlParameters);
if ((filters.contractStartDateString ?? '') !== '') {
sqlWhereClause += ' and o.contractStartDate = ?';
sqlParameters.push(dateStringToInteger(filters.contractStartDateString));
}
if ((filters.occupancyEffectiveDateString ?? '') !== '') {
if ((filters.contractEffectiveDateString ?? '') !== '') {
sqlWhereClause += ` and (
o.contractEndDate is null
or (o.contractStartDate <= ? and o.contractEndDate >= ?)
)`;
sqlParameters.push(dateStringToInteger(filters.occupancyEffectiveDateString), dateStringToInteger(filters.occupancyEffectiveDateString));
sqlParameters.push(dateStringToInteger(filters.contractEffectiveDateString), dateStringToInteger(filters.contractEffectiveDateString));
}
if ((filters.cemeteryId ?? '') !== '') {
sqlWhereClause += ' and l.cemeteryId = ?';

View File

@ -10,8 +10,8 @@ import { getConfigProperty } from '../helpers/config.helpers.js'
import { getContractTypeById } from '../helpers/functions.cache.js'
import {
getBurialSiteNameWhereClause,
getOccupancyTimeWhereClause,
getOccupantNameWhereClause
getContractTimeWhereClause,
getDeceasedNameWhereClause,
} from '../helpers/functions.sqlFilters.js'
import type { Contract } from '../types/recordTypes.js'
@ -22,10 +22,10 @@ import { acquireConnection } from './pool.js'
export interface GetContractsFilters {
burialSiteId?: number | string
occupancyTime?: '' | 'past' | 'current' | 'future'
contractTime?: '' | 'past' | 'current' | 'future'
contractStartDateString?: DateString
occupancyEffectiveDateString?: string
occupantName?: string
contractEffectiveDateString?: string
deceasedName?: string
contractTypeId?: number | string
cemeteryId?: number | string
burialSiteNameSearchType?: '' | 'startsWith' | 'endsWith'
@ -64,16 +64,16 @@ function buildWhereClause(filters: GetContractsFilters): {
sqlWhereClause += burialSiteNameFilters.sqlWhereClause
sqlParameters.push(...burialSiteNameFilters.sqlParameters)
const occupantNameFilters = getOccupantNameWhereClause(
filters.occupantName,
const deceasedNameFilters = getDeceasedNameWhereClause(
filters.deceasedName,
'o'
)
if (occupantNameFilters.sqlParameters.length > 0) {
if (deceasedNameFilters.sqlParameters.length > 0) {
sqlWhereClause += ` and o.contractId in (
select contractId from LotOccupancyOccupants o
select contractId from ContractInterments o
where recordDelete_timeMillis is null
${occupantNameFilters.sqlWhereClause})`
sqlParameters.push(...occupantNameFilters.sqlParameters)
${deceasedNameFilters.sqlWhereClause})`
sqlParameters.push(...deceasedNameFilters.sqlParameters)
}
if ((filters.contractTypeId ?? '') !== '') {
@ -81,12 +81,12 @@ function buildWhereClause(filters: GetContractsFilters): {
sqlParameters.push(filters.contractTypeId)
}
const occupancyTimeFilters = getOccupancyTimeWhereClause(
filters.occupancyTime ?? '',
const contractTimeFilters = getContractTimeWhereClause(
filters.contractTime ?? '',
'o'
)
sqlWhereClause += occupancyTimeFilters.sqlWhereClause
sqlParameters.push(...occupancyTimeFilters.sqlParameters)
sqlWhereClause += contractTimeFilters.sqlWhereClause
sqlParameters.push(...contractTimeFilters.sqlParameters)
if ((filters.contractStartDateString ?? '') !== '') {
sqlWhereClause += ' and o.contractStartDate = ?'
@ -95,14 +95,14 @@ function buildWhereClause(filters: GetContractsFilters): {
)
}
if ((filters.occupancyEffectiveDateString ?? '') !== '') {
if ((filters.contractEffectiveDateString ?? '') !== '') {
sqlWhereClause += ` and (
o.contractEndDate is null
or (o.contractStartDate <= ? and o.contractEndDate >= ?)
)`
sqlParameters.push(
dateStringToInteger(filters.occupancyEffectiveDateString as DateString),
dateStringToInteger(filters.occupancyEffectiveDateString as DateString)
dateStringToInteger(filters.contractEffectiveDateString as DateString),
dateStringToInteger(filters.contractEffectiveDateString as DateString)
)
}

View File

@ -7,16 +7,16 @@ export default async function getWorkOrderComments(workOrderId, connectedDatabas
database.function('userFn_timeIntegerToPeriodString', timeIntegerToPeriodString);
const workOrderComments = database
.prepare(`select workOrderCommentId,
workOrderCommentDate, userFn_dateIntegerToString(workOrderCommentDate) as workOrderCommentDateString,
workOrderCommentTime,
userFn_timeIntegerToString(workOrderCommentTime) as workOrderCommentTimeString,
userFn_timeIntegerToPeriodString(workOrderCommentTime) as workOrderCommentTimePeriodString,
workOrderComment,
commentDate, userFn_dateIntegerToString(commentDate) as commentDateString,
commentTime,
userFn_timeIntegerToString(commentTime) as commentTimeString,
userFn_timeIntegerToPeriodString(commentTime) as commentTimePeriodString,
comment,
recordCreate_userName, recordUpdate_userName
from WorkOrderComments
where recordDelete_timeMillis is null
and workOrderId = ?
order by workOrderCommentDate desc, workOrderCommentTime desc, workOrderCommentId desc`)
order by commentDate desc, commentTime desc, workOrderCommentId desc`)
.all(workOrderId);
if (connectedDatabase === undefined) {
database.release();

View File

@ -25,16 +25,16 @@ export default async function getWorkOrderComments(
const workOrderComments = database
.prepare(
`select workOrderCommentId,
workOrderCommentDate, userFn_dateIntegerToString(workOrderCommentDate) as workOrderCommentDateString,
workOrderCommentTime,
userFn_timeIntegerToString(workOrderCommentTime) as workOrderCommentTimeString,
userFn_timeIntegerToPeriodString(workOrderCommentTime) as workOrderCommentTimePeriodString,
workOrderComment,
commentDate, userFn_dateIntegerToString(commentDate) as commentDateString,
commentTime,
userFn_timeIntegerToString(commentTime) as commentTimeString,
userFn_timeIntegerToPeriodString(commentTime) as commentTimePeriodString,
comment,
recordCreate_userName, recordUpdate_userName
from WorkOrderComments
where recordDelete_timeMillis is null
and workOrderId = ?
order by workOrderCommentDate desc, workOrderCommentTime desc, workOrderCommentId desc`
order by commentDate desc, commentTime desc, workOrderCommentId desc`
)
.all(workOrderId) as WorkOrderComment[]

View File

@ -4,7 +4,7 @@ export interface GetWorkOrdersFilters {
workOrderTypeId?: number | string;
workOrderOpenStatus?: '' | 'open' | 'closed';
workOrderOpenDateString?: string;
occupantName?: string;
deceasedName?: string;
burialSiteName?: string;
contractId?: number | string;
}

View File

@ -1,7 +1,7 @@
import { dateIntegerToString, dateStringToInteger } from '@cityssm/utils-datetime';
import { getBurialSiteNameWhereClause, getOccupantNameWhereClause } from '../helpers/functions.sqlFilters.js';
import getContracts from './getContracts.js';
import { getBurialSiteNameWhereClause, getDeceasedNameWhereClause } from '../helpers/functions.sqlFilters.js';
import getBurialSites from './getBurialSites.js';
import getContracts from './getContracts.js';
import getWorkOrderComments from './getWorkOrderComments.js';
import getWorkOrderMilestones from './getWorkOrderMilestones.js';
import { acquireConnection } from './pool.js';
@ -24,17 +24,17 @@ function buildWhereClause(filters) {
sqlWhereClause += ' and w.workOrderOpenDate = ?';
sqlParameters.push(dateStringToInteger(filters.workOrderOpenDateString));
}
const occupantNameFilters = getOccupantNameWhereClause(filters.occupantName, 'o');
if (occupantNameFilters.sqlParameters.length > 0) {
const deceasedNameFilters = getDeceasedNameWhereClause(filters.deceasedName, 'o');
if (deceasedNameFilters.sqlParameters.length > 0) {
sqlWhereClause +=
` and w.workOrderId in (
select workOrderId from WorkOrderContracts o
where recordDelete_timeMillis is null
and o.contractId in (
select contractId from LotOccupancyOccupants o where recordDelete_timeMillis is null
${occupantNameFilters.sqlWhereClause}
select contractId from ContractInterments o where recordDelete_timeMillis is null
${deceasedNameFilters.sqlWhereClause}
))`;
sqlParameters.push(...occupantNameFilters.sqlParameters);
sqlParameters.push(...deceasedNameFilters.sqlParameters);
}
const burialSiteNameFilters = getBurialSiteNameWhereClause(filters.burialSiteName, '', 'l');
if (burialSiteNameFilters.sqlParameters.length > 0) {
@ -119,7 +119,7 @@ export async function getWorkOrders(filters, options, connectedDatabase) {
w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString,
ifnull(m.workOrderMilestoneCount, 0) as workOrderMilestoneCount,
ifnull(m.workOrderMilestoneCompletionCount, 0) as workOrderMilestoneCompletionCount,
ifnull(l.workOrderLotCount, 0) as workOrderLotCount
ifnull(l.workOrderBurialSiteCount, 0) as workOrderBurialSiteCount
from WorkOrders w
left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId
left join (
@ -130,8 +130,8 @@ export async function getWorkOrders(filters, options, connectedDatabase) {
where recordDelete_timeMillis is null
group by workOrderId) m on w.workOrderId = m.workOrderId
left join (
select workOrderId, count(burialSiteId) as workOrderLotCount
from WorkOrderLots
select workOrderId, count(burialSiteId) as workOrderBurialSiteCount
from WorkOrderBurialSites
where recordDelete_timeMillis is null
group by workOrderId) l on w.workOrderId = l.workOrderId
${sqlWhereClause}

View File

@ -7,12 +7,12 @@ import type { PoolConnection } from 'better-sqlite-pool'
import {
getBurialSiteNameWhereClause,
getOccupantNameWhereClause
getDeceasedNameWhereClause
} from '../helpers/functions.sqlFilters.js'
import type { WorkOrder } from '../types/recordTypes.js'
import getContracts from './getContracts.js'
import getBurialSites from './getBurialSites.js'
import getContracts from './getContracts.js'
import getWorkOrderComments from './getWorkOrderComments.js'
import getWorkOrderMilestones from './getWorkOrderMilestones.js'
import { acquireConnection } from './pool.js'
@ -21,7 +21,7 @@ export interface GetWorkOrdersFilters {
workOrderTypeId?: number | string
workOrderOpenStatus?: '' | 'open' | 'closed'
workOrderOpenDateString?: string
occupantName?: string
deceasedName?: string
burialSiteName?: string
contractId?: number | string
}
@ -61,20 +61,20 @@ function buildWhereClause(filters: GetWorkOrdersFilters): {
)
}
const occupantNameFilters = getOccupantNameWhereClause(
filters.occupantName,
const deceasedNameFilters = getDeceasedNameWhereClause(
filters.deceasedName,
'o'
)
if (occupantNameFilters.sqlParameters.length > 0) {
if (deceasedNameFilters.sqlParameters.length > 0) {
sqlWhereClause +=
` and w.workOrderId in (
select workOrderId from WorkOrderContracts o
where recordDelete_timeMillis is null
and o.contractId in (
select contractId from LotOccupancyOccupants o where recordDelete_timeMillis is null
${occupantNameFilters.sqlWhereClause}
select contractId from ContractInterments o where recordDelete_timeMillis is null
${deceasedNameFilters.sqlWhereClause}
))`
sqlParameters.push(...occupantNameFilters.sqlParameters)
sqlParameters.push(...deceasedNameFilters.sqlParameters)
}
const burialSiteNameFilters = getBurialSiteNameWhereClause(filters.burialSiteName, '', 'l')
@ -202,7 +202,7 @@ export async function getWorkOrders(
w.workOrderCloseDate, userFn_dateIntegerToString(w.workOrderCloseDate) as workOrderCloseDateString,
ifnull(m.workOrderMilestoneCount, 0) as workOrderMilestoneCount,
ifnull(m.workOrderMilestoneCompletionCount, 0) as workOrderMilestoneCompletionCount,
ifnull(l.workOrderLotCount, 0) as workOrderLotCount
ifnull(l.workOrderBurialSiteCount, 0) as workOrderBurialSiteCount
from WorkOrders w
left join WorkOrderTypes t on w.workOrderTypeId = t.workOrderTypeId
left join (
@ -213,8 +213,8 @@ export async function getWorkOrders(
where recordDelete_timeMillis is null
group by workOrderId) m on w.workOrderId = m.workOrderId
left join (
select workOrderId, count(burialSiteId) as workOrderLotCount
from WorkOrderLots
select workOrderId, count(burialSiteId) as workOrderBurialSiteCount
from WorkOrderBurialSites
where recordDelete_timeMillis is null
group by workOrderId) l on w.workOrderId = l.workOrderId
${sqlWhereClause}

View File

@ -231,7 +231,7 @@ const createStatements = [
contractId integer not null,
intermentNumber integer not null,
deceasedName varchar(50) not null,
deceasedName varchar(200) not null,
isCremated bit not null default 0,
deceasedAddress1 varchar(50),

View File

@ -270,7 +270,7 @@ const createStatements = [
contractId integer not null,
intermentNumber integer not null,
deceasedName varchar(50) not null,
deceasedName varchar(200) not null,
isCremated bit not null default 0,
deceasedAddress1 varchar(50),

View File

@ -0,0 +1,17 @@
import { type DateString } from '@cityssm/utils-datetime';
export interface UpdateForm {
contractId: string | number;
intermentNumber: string | number;
deceasedName: string;
deceasedAddress1: string;
deceasedAddress2: string;
deceasedCity: string;
deceasedProvince: string;
deceasedPostalCode: string;
birthDateString: DateString | '';
birthPlace: string;
deathDateString: DateString | '';
deathPlace: string;
intermentContainerTypeId: string | number;
}
export default function updateContractInterment(contractForm: UpdateForm, user: User): Promise<boolean>;

View File

@ -0,0 +1,32 @@
import { dateStringToInteger } from '@cityssm/utils-datetime';
import { acquireConnection } from './pool.js';
export default async function updateContractInterment(contractForm, user) {
const database = await acquireConnection();
const results = database
.prepare(`update ContractInterments
set deceasedName = ?,
deceasedAddress1 = ?,
deceasedAddress2 = ?,
deceasedCity = ?,
deceasedProvince = ?,
deceasedPostalCode = ?,
birthDate = ?,
birthPlace = ?,
deathDate = ?,
deathPlace = ?,
intermentContainerTypeId = ?,
recordUpdate_userName = ?,
recordUpdate_timeMillis = ?
where recordDelete_timeMillis is null
and contractId = ?
and intermentNumber = ?`)
.run(contractForm.deceasedName, contractForm.deceasedAddress1, contractForm.deceasedAddress2, contractForm.deceasedCity, contractForm.deceasedProvince, contractForm.deceasedPostalCode, contractForm.birthDateString === ''
? undefined
: dateStringToInteger(contractForm.birthDateString), contractForm.birthPlace, contractForm.deathDateString === ''
? undefined
: dateStringToInteger(contractForm.deathDateString), contractForm.deathPlace, contractForm.intermentContainerTypeId === ''
? undefined
: contractForm.intermentContainerTypeId, user.userName, Date.now(), contractForm.contractId, contractForm.intermentNumber);
database.release();
return results.changes > 0;
}

View File

@ -0,0 +1,74 @@
import { type DateString, dateStringToInteger } from '@cityssm/utils-datetime'
import { acquireConnection } from './pool.js'
export interface UpdateForm {
contractId: string | number
intermentNumber: string | number
deceasedName: string
deceasedAddress1: string
deceasedAddress2: string
deceasedCity: string
deceasedProvince: string
deceasedPostalCode: string
birthDateString: DateString | ''
birthPlace: string
deathDateString: DateString | ''
deathPlace: string
intermentContainerTypeId: string | number
}
export default async function updateContractInterment(
contractForm: UpdateForm,
user: User
): Promise<boolean> {
const database = await acquireConnection()
const results = database
.prepare(
`update ContractInterments
set deceasedName = ?,
deceasedAddress1 = ?,
deceasedAddress2 = ?,
deceasedCity = ?,
deceasedProvince = ?,
deceasedPostalCode = ?,
birthDate = ?,
birthPlace = ?,
deathDate = ?,
deathPlace = ?,
intermentContainerTypeId = ?,
recordUpdate_userName = ?,
recordUpdate_timeMillis = ?
where recordDelete_timeMillis is null
and contractId = ?
and intermentNumber = ?`
)
.run(
contractForm.deceasedName,
contractForm.deceasedAddress1,
contractForm.deceasedAddress2,
contractForm.deceasedCity,
contractForm.deceasedProvince,
contractForm.deceasedPostalCode,
contractForm.birthDateString === ''
? undefined
: dateStringToInteger(contractForm.birthDateString),
contractForm.birthPlace,
contractForm.deathDateString === ''
? undefined
: dateStringToInteger(contractForm.deathDateString),
contractForm.deathPlace,
contractForm.intermentContainerTypeId === ''
? undefined
: contractForm.intermentContainerTypeId,
user.userName,
Date.now(),
contractForm.contractId,
contractForm.intermentNumber
)
database.release()
return results.changes > 0
}

View File

@ -1,16 +0,0 @@
export interface UpdateLotOccupancyOccupantForm {
contractId: string | number;
lotOccupantIndex: string | number;
lotOccupantTypeId: string | number;
occupantName: string;
occupantFamilyName: string;
occupantAddress1: string;
occupantAddress2: string;
occupantCity: string;
occupantProvince: string;
occupantPostalCode: string;
occupantPhoneNumber: string;
occupantEmailAddress: string;
occupantComment: string;
}
export default function updateContractOccupant(contractOccupantForm: UpdateLotOccupancyOccupantForm, user: User): Promise<boolean>;

View File

@ -1,25 +0,0 @@
import { acquireConnection } from './pool.js';
export default async function updateContractOccupant(contractOccupantForm, user) {
const database = await acquireConnection();
const results = database
.prepare(`update LotOccupancyOccupants
set occupantName = ?,
occupantFamilyName = ?,
occupantAddress1 = ?,
occupantAddress2 = ?,
occupantCity = ?,
occupantProvince = ?,
occupantPostalCode = ?,
occupantPhoneNumber = ?,
occupantEmailAddress = ?,
occupantComment = ?,
lotOccupantTypeId = ?,
recordUpdate_userName = ?,
recordUpdate_timeMillis = ?
where recordDelete_timeMillis is null
and contractId = ?
and lotOccupantIndex = ?`)
.run(contractOccupantForm.occupantName, contractOccupantForm.occupantFamilyName, contractOccupantForm.occupantAddress1, contractOccupantForm.occupantAddress2, contractOccupantForm.occupantCity, contractOccupantForm.occupantProvince, contractOccupantForm.occupantPostalCode, contractOccupantForm.occupantPhoneNumber, contractOccupantForm.occupantEmailAddress, contractOccupantForm.occupantComment, contractOccupantForm.lotOccupantTypeId, user.userName, Date.now(), contractOccupantForm.contractId, contractOccupantForm.lotOccupantIndex);
database.release();
return results.changes > 0;
}

View File

@ -1,66 +0,0 @@
import { acquireConnection } from './pool.js'
export interface UpdateLotOccupancyOccupantForm {
contractId: string | number
lotOccupantIndex: string | number
lotOccupantTypeId: string | number
occupantName: string
occupantFamilyName: string
occupantAddress1: string
occupantAddress2: string
occupantCity: string
occupantProvince: string
occupantPostalCode: string
occupantPhoneNumber: string
occupantEmailAddress: string
occupantComment: string
}
export default async function updateContractOccupant(
contractOccupantForm: UpdateLotOccupancyOccupantForm,
user: User
): Promise<boolean> {
const database = await acquireConnection()
const results = database
.prepare(
`update LotOccupancyOccupants
set occupantName = ?,
occupantFamilyName = ?,
occupantAddress1 = ?,
occupantAddress2 = ?,
occupantCity = ?,
occupantProvince = ?,
occupantPostalCode = ?,
occupantPhoneNumber = ?,
occupantEmailAddress = ?,
occupantComment = ?,
lotOccupantTypeId = ?,
recordUpdate_userName = ?,
recordUpdate_timeMillis = ?
where recordDelete_timeMillis is null
and contractId = ?
and lotOccupantIndex = ?`
)
.run(
contractOccupantForm.occupantName,
contractOccupantForm.occupantFamilyName,
contractOccupantForm.occupantAddress1,
contractOccupantForm.occupantAddress2,
contractOccupantForm.occupantCity,
contractOccupantForm.occupantProvince,
contractOccupantForm.occupantPostalCode,
contractOccupantForm.occupantPhoneNumber,
contractOccupantForm.occupantEmailAddress,
contractOccupantForm.occupantComment,
contractOccupantForm.lotOccupantTypeId,
user.userName,
Date.now(),
contractOccupantForm.contractId,
contractOccupantForm.lotOccupantIndex
)
database.release()
return results.changes > 0
}

View File

@ -1,8 +1,8 @@
import { type DateString, type TimeString } from '@cityssm/utils-datetime';
export interface UpdateWorkOrderCommentForm {
workOrderCommentId: string | number;
workOrderCommentDateString: DateString;
workOrderCommentTimeString: TimeString;
workOrderComment: string;
commentDateString: DateString;
commentTimeString: TimeString;
comment: string;
}
export default function updateWorkOrderComment(commentForm: UpdateWorkOrderCommentForm, user: User): Promise<boolean>;

View File

@ -4,14 +4,14 @@ export default async function updateWorkOrderComment(commentForm, user) {
const database = await acquireConnection();
const result = database
.prepare(`update WorkOrderComments
set workOrderCommentDate = ?,
workOrderCommentTime = ?,
workOrderComment = ?,
set commentDate = ?,
commentTime = ?,
comment = ?,
recordUpdate_userName = ?,
recordUpdate_timeMillis = ?
where recordDelete_timeMillis is null
and workOrderCommentId = ?`)
.run(dateStringToInteger(commentForm.workOrderCommentDateString), timeStringToInteger(commentForm.workOrderCommentTimeString), commentForm.workOrderComment, user.userName, Date.now(), commentForm.workOrderCommentId);
.run(dateStringToInteger(commentForm.commentDateString), timeStringToInteger(commentForm.commentTimeString), commentForm.comment, user.userName, Date.now(), commentForm.workOrderCommentId);
database.release();
return result.changes > 0;
}

View File

@ -9,9 +9,9 @@ import { acquireConnection } from './pool.js'
export interface UpdateWorkOrderCommentForm {
workOrderCommentId: string | number
workOrderCommentDateString: DateString
workOrderCommentTimeString: TimeString
workOrderComment: string
commentDateString: DateString
commentTimeString: TimeString
comment: string
}
export default async function updateWorkOrderComment(
@ -23,18 +23,18 @@ export default async function updateWorkOrderComment(
const result = database
.prepare(
`update WorkOrderComments
set workOrderCommentDate = ?,
workOrderCommentTime = ?,
workOrderComment = ?,
set commentDate = ?,
commentTime = ?,
comment = ?,
recordUpdate_userName = ?,
recordUpdate_timeMillis = ?
where recordDelete_timeMillis is null
and workOrderCommentId = ?`
)
.run(
dateStringToInteger(commentForm.workOrderCommentDateString),
timeStringToInteger(commentForm.workOrderCommentTimeString),
commentForm.workOrderComment,
dateStringToInteger(commentForm.commentDateString),
timeStringToInteger(commentForm.commentTimeString),
commentForm.comment,
user.userName,
Date.now(),
commentForm.workOrderCommentId

View File

@ -0,0 +1,3 @@
import type { Request, Response } from 'express';
import { type AddForm } from '../../database/addContractInterment.js';
export default function handler(request: Request<unknown, unknown, AddForm>, response: Response): Promise<void>;

View File

@ -0,0 +1,10 @@
import addContractInterment from '../../database/addContractInterment.js';
import getContractInterments from '../../database/getContractInterments.js';
export default async function handler(request, response) {
await addContractInterment(request.body, request.session.user);
const contractInterments = await getContractInterments(request.body.contractId);
response.json({
success: true,
contractInterments
});
}

View File

@ -0,0 +1,22 @@
import type { Request, Response } from 'express'
import addContractInterment, {
type AddForm
} from '../../database/addContractInterment.js'
import getContractInterments from '../../database/getContractInterments.js'
export default async function handler(
request: Request<unknown, unknown, AddForm>,
response: Response
): Promise<void> {
await addContractInterment(request.body, request.session.user as User)
const contractInterments = await getContractInterments(
request.body.contractId
)
response.json({
success: true,
contractInterments
})
}

View File

@ -0,0 +1,5 @@
import type { Request, Response } from 'express';
export default function handler(request: Request<unknown, unknown, {
contractId: string;
intermentNumber: string;
}>, response: Response): Promise<void>;

View File

@ -0,0 +1,10 @@
import deleteContractInterment from '../../database/deleteContractInterment.js';
import getContractInterments from '../../database/getContractInterments.js';
export default async function handler(request, response) {
const success = await deleteContractInterment(request.body.contractId, request.body.intermentNumber, request.session.user);
const contractInterments = await getContractInterments(request.body.contractId);
response.json({
success,
contractInterments
});
}

View File

@ -0,0 +1,28 @@
import type { Request, Response } from 'express'
import deleteContractInterment from '../../database/deleteContractInterment.js'
import getContractInterments from '../../database/getContractInterments.js'
export default async function handler(
request: Request<
unknown,
unknown,
{ contractId: string; intermentNumber: string }
>,
response: Response
): Promise<void> {
const success = await deleteContractInterment(
request.body.contractId,
request.body.intermentNumber,
request.session.user as User
)
const contractInterments = await getContractInterments(
request.body.contractId
)
response.json({
success,
contractInterments
})
}

View File

@ -0,0 +1,3 @@
import type { Request, Response } from 'express';
import { type UpdateForm } from '../../database/updateContractInterment.js';
export default function handler(request: Request<unknown, unknown, UpdateForm>, response: Response): Promise<void>;

View File

@ -0,0 +1,10 @@
import getContractInterments from '../../database/getContractInterments.js';
import updateContractInterment from '../../database/updateContractInterment.js';
export default async function handler(request, response) {
await updateContractInterment(request.body, request.session.user);
const contractInterments = await getContractInterments(request.body.contractId);
response.json({
success: true,
contractInterments
});
}

View File

@ -0,0 +1,24 @@
import type { Request, Response } from 'express'
import getContractInterments from '../../database/getContractInterments.js'
import updateContractInterment, {
type UpdateForm
} from '../../database/updateContractInterment.js'
export default async function handler(
request: Request<unknown, unknown, UpdateForm>,
response: Response
): Promise<void> {
await updateContractInterment(
request.body,
request.session.user as User
)
const contractInterments =
await getContractInterments(request.body.contractId)
response.json({
success: true,
contractInterments
})
}

View File

@ -17,13 +17,13 @@ export default async function handler(request, response) {
}
const workOrderTypes = await getWorkOrderTypes();
const workOrderMilestoneTypes = await getWorkOrderMilestoneTypes();
const lotStatuses = await getBurialSiteStatuses();
const burialSiteStatuses = await getBurialSiteStatuses();
response.render('workOrder-edit', {
headTitle: `Work Order #${workOrder.workOrderNumber}`,
workOrder,
isCreate: false,
workOrderTypes,
workOrderMilestoneTypes,
lotStatuses
burialSiteStatuses
});
}

View File

@ -40,7 +40,7 @@ export default async function handler(
const workOrderMilestoneTypes = await getWorkOrderMilestoneTypes()
const lotStatuses = await getBurialSiteStatuses()
const burialSiteStatuses = await getBurialSiteStatuses()
response.render('workOrder-edit', {
headTitle: `Work Order #${workOrder.workOrderNumber}`,
@ -48,6 +48,6 @@ export default async function handler(
isCreate: false,
workOrderTypes,
workOrderMilestoneTypes,
lotStatuses
burialSiteStatuses
})
}

View File

@ -5,7 +5,7 @@ export default async function handler(request, response) {
workOrderId: request.body.workOrderId,
burialSiteId: request.body.burialSiteId
}, request.session.user);
const workOrderLotsResults = await getBurialSites({
const results = await getBurialSites({
workOrderId: request.body.workOrderId
}, {
limit: -1,
@ -14,6 +14,6 @@ export default async function handler(request, response) {
});
response.json({
success,
workOrderBurialSites: workOrderLotsResults.burialSites
workOrderBurialSites: results.burialSites
});
}

View File

@ -19,7 +19,7 @@ export default async function handler(
request.session.user as User
)
const workOrderLotsResults = await getBurialSites(
const results = await getBurialSites(
{
workOrderId: request.body.workOrderId
},
@ -32,6 +32,6 @@ export default async function handler(
response.json({
success,
workOrderBurialSites: workOrderLotsResults.burialSites
workOrderBurialSites: results.burialSites
})
}

View File

@ -8,12 +8,14 @@ if (getConfigProperty('settings.dynamicsGP.integrationIsEnabled')) {
function filterCashReceipt(cashReceipt) {
const accountCodes = getConfigProperty('settings.dynamicsGP.accountCodes');
if (accountCodes.length > 0) {
for (const detail of cashReceipt.details) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
for (const detail of cashReceipt?.details ?? []) {
if (accountCodes.includes(detail.accountCode)) {
return cashReceipt;
}
}
for (const distribution of cashReceipt.distributions) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
for (const distribution of cashReceipt?.distributions ?? []) {
if (accountCodes.includes(distribution.accountCode)) {
return cashReceipt;
}

View File

@ -23,13 +23,15 @@ function filterCashReceipt(
const accountCodes = getConfigProperty('settings.dynamicsGP.accountCodes')
if (accountCodes.length > 0) {
for (const detail of cashReceipt.details) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
for (const detail of cashReceipt?.details ?? []) {
if (accountCodes.includes(detail.accountCode)) {
return cashReceipt
}
}
for (const distribution of cashReceipt.distributions) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
for (const distribution of cashReceipt?.distributions ?? []) {
if (accountCodes.includes(distribution.accountCode)) {
return cashReceipt
}

View File

@ -4,7 +4,7 @@ interface WhereClauseReturn {
sqlParameters: unknown[];
}
export declare function getBurialSiteNameWhereClause(burialSiteName?: string, burialSiteNameSearchType?: BurialSiteNameSearchType, burialSitesTableAlias?: string): WhereClauseReturn;
type OccupancyTime = '' | 'current' | 'past' | 'future';
export declare function getOccupancyTimeWhereClause(occupancyTime: OccupancyTime | undefined, lotOccupanciesTableAlias?: string): WhereClauseReturn;
export declare function getOccupantNameWhereClause(occupantName?: string, tableAlias?: string): WhereClauseReturn;
type ContractTime = '' | 'current' | 'past' | 'future';
export declare function getContractTimeWhereClause(contractTime: ContractTime | undefined, contractsTableAlias?: string): WhereClauseReturn;
export declare function getDeceasedNameWhereClause(deceasedName?: string, tableAlias?: string): WhereClauseReturn;
export {};

View File

@ -33,27 +33,27 @@ export function getBurialSiteNameWhereClause(burialSiteName = '', burialSiteName
sqlParameters
};
}
export function getOccupancyTimeWhereClause(occupancyTime, lotOccupanciesTableAlias = 'o') {
export function getContractTimeWhereClause(contractTime, contractsTableAlias = 'o') {
let sqlWhereClause = '';
const sqlParameters = [];
const currentDateString = dateToInteger(new Date());
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (occupancyTime ?? '') {
switch (contractTime ?? '') {
case 'current': {
sqlWhereClause += ` and ${lotOccupanciesTableAlias}.contractStartDate <= ?
and (${lotOccupanciesTableAlias}.contractEndDate is null or ${lotOccupanciesTableAlias}.contractEndDate >= ?)`;
sqlWhereClause += ` and ${contractsTableAlias}.contractStartDate <= ?
and (${contractsTableAlias}.contractEndDate is null or ${contractsTableAlias}.contractEndDate >= ?)`;
sqlParameters.push(currentDateString, currentDateString);
break;
}
case 'past': {
sqlWhereClause +=
` and ${lotOccupanciesTableAlias}.contractEndDate < ?`;
` and ${contractsTableAlias}.contractEndDate < ?`;
sqlParameters.push(currentDateString);
break;
}
case 'future': {
sqlWhereClause +=
` and ${lotOccupanciesTableAlias}.contractStartDate > ?`;
` and ${contractsTableAlias}.contractStartDate > ?`;
sqlParameters.push(currentDateString);
break;
}
@ -63,18 +63,18 @@ export function getOccupancyTimeWhereClause(occupancyTime, lotOccupanciesTableAl
sqlParameters
};
}
export function getOccupantNameWhereClause(occupantName = '', tableAlias = 'o') {
export function getDeceasedNameWhereClause(deceasedName = '', tableAlias = 'o') {
let sqlWhereClause = '';
const sqlParameters = [];
const usedPieces = new Set();
const occupantNamePieces = occupantName.toLowerCase().split(' ');
for (const occupantNamePiece of occupantNamePieces) {
if (occupantNamePiece === '' || usedPieces.has(occupantNamePiece)) {
const deceasedNamePieces = deceasedName.toLowerCase().split(' ');
for (const namePiece of deceasedNamePieces) {
if (namePiece === '' || usedPieces.has(namePiece)) {
continue;
}
usedPieces.add(occupantNamePiece);
sqlWhereClause += ` and (instr(lower(${tableAlias}.occupantName), ?) or instr(lower(${tableAlias}.occupantFamilyName), ?))`;
sqlParameters.push(occupantNamePiece, occupantNamePiece);
usedPieces.add(namePiece);
sqlWhereClause += ` and instr(lower(${tableAlias}.deceasedName), ?)`;
sqlParameters.push(namePiece);
}
return {
sqlWhereClause,

View File

@ -52,11 +52,11 @@ export function getBurialSiteNameWhereClause(
}
}
type OccupancyTime = '' | 'current' | 'past' | 'future'
type ContractTime = '' | 'current' | 'past' | 'future'
export function getOccupancyTimeWhereClause(
occupancyTime: OccupancyTime | undefined,
lotOccupanciesTableAlias = 'o'
export function getContractTimeWhereClause(
contractTime: ContractTime | undefined,
contractsTableAlias = 'o'
): WhereClauseReturn {
let sqlWhereClause = ''
const sqlParameters: unknown[] = []
@ -64,24 +64,24 @@ export function getOccupancyTimeWhereClause(
const currentDateString = dateToInteger(new Date())
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (occupancyTime ?? '') {
switch (contractTime ?? '') {
case 'current': {
sqlWhereClause += ` and ${lotOccupanciesTableAlias}.contractStartDate <= ?
and (${lotOccupanciesTableAlias}.contractEndDate is null or ${lotOccupanciesTableAlias}.contractEndDate >= ?)`
sqlWhereClause += ` and ${contractsTableAlias}.contractStartDate <= ?
and (${contractsTableAlias}.contractEndDate is null or ${contractsTableAlias}.contractEndDate >= ?)`
sqlParameters.push(currentDateString, currentDateString)
break
}
case 'past': {
sqlWhereClause +=
` and ${lotOccupanciesTableAlias}.contractEndDate < ?`
` and ${contractsTableAlias}.contractEndDate < ?`
sqlParameters.push(currentDateString)
break
}
case 'future': {
sqlWhereClause +=
` and ${lotOccupanciesTableAlias}.contractStartDate > ?`
` and ${contractsTableAlias}.contractStartDate > ?`
sqlParameters.push(currentDateString)
break
}
@ -93,8 +93,8 @@ export function getOccupancyTimeWhereClause(
}
}
export function getOccupantNameWhereClause(
occupantName = '',
export function getDeceasedNameWhereClause(
deceasedName = '',
tableAlias = 'o'
): WhereClauseReturn {
let sqlWhereClause = ''
@ -102,16 +102,16 @@ export function getOccupantNameWhereClause(
const usedPieces = new Set<string>()
const occupantNamePieces = occupantName.toLowerCase().split(' ')
for (const occupantNamePiece of occupantNamePieces) {
if (occupantNamePiece === '' || usedPieces.has(occupantNamePiece)) {
const deceasedNamePieces = deceasedName.toLowerCase().split(' ')
for (const namePiece of deceasedNamePieces) {
if (namePiece === '' || usedPieces.has(namePiece)) {
continue
}
usedPieces.add(occupantNamePiece)
usedPieces.add(namePiece)
sqlWhereClause += ` and (instr(lower(${tableAlias}.occupantName), ?) or instr(lower(${tableAlias}.occupantFamilyName), ?))`
sqlParameters.push(occupantNamePiece, occupantNamePiece)
sqlWhereClause += ` and instr(lower(${tableAlias}.deceasedName), ?)`
sqlParameters.push(namePiece)
}
return {

27
package-lock.json generated
View File

@ -22,7 +22,6 @@
"activedirectory2": "^2.2.0",
"better-sqlite-pool": "^0.3.2",
"better-sqlite3": "^11.8.1",
"bulma-calendar": "^6.1.19",
"camelcase": "^8.0.0",
"compression": "^1.8.0",
"cookie-parser": "^1.4.7",
@ -3735,18 +3734,8 @@
"node_modules/bulma": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.4.tgz",
"integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ=="
},
"node_modules/bulma-calendar": {
"version": "6.1.19",
"resolved": "https://registry.npmjs.org/bulma-calendar/-/bulma-calendar-6.1.19.tgz",
"integrity": "sha512-roosrqoXWGTP7MR5PW151XO4mnarov2qvfzvHfGKzT8rV+SGRZmhzbr4/xmUxRyD+vdn6mSG+ensda4mvvKDow==",
"dependencies": {
"date-fns": "^2.21.3"
},
"peerDependencies": {
"bulma": "^0.9.4"
}
"integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==",
"dev": true
},
"node_modules/bulma-divider": {
"version": "0.2.0",
@ -4876,18 +4865,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/date-fns": {
"version": "2.29.3",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
"integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==",
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/dayjs": {
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",

View File

@ -46,7 +46,6 @@
"activedirectory2": "^2.2.0",
"better-sqlite-pool": "^0.3.2",
"better-sqlite3": "^11.8.1",
"bulma-calendar": "^6.1.19",
"camelcase": "^8.0.0",
"compression": "^1.8.0",
"cookie-parser": "^1.4.7",

View File

@ -68,20 +68,16 @@
<div class="message is-info is-small">
<p class="message-body">
Filters can be used to show or hide available fees depending on the
<span class="alias" data-alias="occupancy"></span> type and
<span class="alias" data-alias="lot"></span> type selected when
creating the <span class="alias" data-alias="lot"></span>
<span class="alias" data-alias="occupancy"></span>
record.
contract type and burial site type selected when
creating the contract record.
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeAdd--contractTypeId"
><span class="alias" data-alias="Occupancy"></span> Type
Filter</label
>
<label class="label" for="feeAdd--contractTypeId">
Contract Type Filter
</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeAdd--contractTypeId" name="contractTypeId">
@ -93,9 +89,9 @@
</div>
<div class="column">
<div class="field">
<label class="label" for="feeAdd--burialSiteTypeId"
><span class="alias" data-alias="Lot"></span> Type Filter</label
>
<label class="label" for="feeAdd--burialSiteTypeId">
Burial Site Type Filter
</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeAdd--burialSiteTypeId" name="burialSiteTypeId">

View File

@ -69,11 +69,8 @@
<div class="message is-info is-small">
<p class="message-body">
Filters can be used to show or hide available fees depending on the
<span class="alias" data-alias="occupancy"></span> type and
<span class="alias" data-alias="lot"></span> type selected when
creating the <span class="alias" data-alias="lot"></span>
<span class="alias" data-alias="occupancy"></span>
record.
contract type and burial site type selected when
creating the contract record.
</p>
</div>
<div class="columns">

View File

@ -3,7 +3,7 @@
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title">
Edit <span class="alias" data-alias="Lot"></span> Status
Edit Burial Site Status
</h3>
<button
class="delete is-close-modal-button"
@ -12,26 +12,26 @@
></button>
</header>
<section class="modal-card-body">
<form id="form--lotStatusEdit">
<input id="lotStatusEdit--burialSiteId" name="burialSiteId" type="hidden" value="" />
<form id="form--burialSiteStatusEdit">
<input id="burialSiteStatusEdit--burialSiteId" name="burialSiteId" type="hidden" value="" />
<div class="field">
<label class="label" for="lotStatusEdit--burialSiteName"
><span class="alias" data-alias="Lot"></span> Name</label
>
<label class="label" for="burialSiteStatusEdit--burialSiteName">
Burial Site Name
</label>
<div class="control">
<input
class="input is-readonly"
id="lotStatusEdit--burialSiteName"
id="burialSiteStatusEdit--burialSiteName"
readonly
/>
</div>
</div>
<div class="field">
<label class="label" for="lotStatusEdit--burialSiteStatusId">Status</label>
<label class="label" for="burialSiteStatusEdit--burialSiteStatusId">Status</label>
<div class="control">
<div class="select is-fullwidth">
<select id="lotStatusEdit--burialSiteStatusId" name="burialSiteStatusId">
<select id="burialSiteStatusEdit--burialSiteStatusId" name="burialSiteStatusId">
<option value="">(No Status)</option>
</select>
</div>
@ -43,7 +43,7 @@
<button
class="button is-success"
type="submit"
form="form--lotStatusEdit"
form="form--burialSiteStatusEdit"
>
<span class="icon"><i class="fas fa-save" aria-hidden="true"></i></span>
<span>Update Status</span>

View File

@ -18,14 +18,14 @@
value=""
/>
<div class="field">
<label class="label" for="contractCommentAdd--contractComment"
<label class="label" for="contractCommentAdd--comment"
>Comment</label
>
<div class="control">
<textarea
class="textarea"
id="contractCommentAdd--contractComment"
name="contractComment"
id="contractCommentAdd--comment"
name="comment"
required
></textarea>
</div>

View File

@ -0,0 +1,203 @@
<div class="modal" role="dialog">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title">
Add Interment
</h3>
<button
class="delete is-close-modal-button"
aria-label="close"
type="button"
></button>
</header>
<section class="modal-card-body">
<form id="form--contractIntermentAdd">
<input
id="contractIntermentAdd--contractId"
name="contractId"
type="hidden"
value=""
/>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractIntermentAdd--deceasedName"
>Name</label
>
<div class="control">
<input
class="input"
id="contractIntermentAdd--deceasedName"
name="deceasedName"
type="text"
maxlength="200"
autocomplete="off"
required
/>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="contractIntermentAdd--deceasedAddress1"
>Address</label
>
<div class="control">
<input
class="input"
id="contractIntermentAdd--deceasedAddress1"
name="deceasedAddress1"
type="text"
maxlength="50"
placeholder="Line 1"
autocomplete="off"
/>
</div>
</div>
<div class="field">
<div class="control">
<input
class="input"
id="contractIntermentAdd--deceasedAddress2"
name="deceasedAddress2"
type="text"
maxlength="50"
placeholder="Line 2"
aria-label="Address Line 2"
autocomplete="off"
/>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractIntermentAdd--deceasedCity"
>City</label
>
<div class="control">
<input
class="input"
id="contractIntermentAdd--deceasedCity"
name="deceasedCity"
type="text"
maxlength="20"
/>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label
class="label"
for="contractIntermentAdd--deceasedProvince"
>Province</label
>
<div class="control">
<input
class="input"
id="contractIntermentAdd--deceasedProvince"
name="deceasedProvince"
type="text"
maxlength="2"
/>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label
class="label"
for="contractIntermentAdd--deceasedPostalCode"
>Postal Code</label
>
<div class="control">
<input
class="input"
id="contractIntermentAdd--deceasedPostalCode"
name="deceasedPostalCode"
type="text"
maxlength="7"
autocomplete="off"
/>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractIntermentAdd--birthDateString">
Date of Birth
</label>
<div class="control has-icons-left">
<input class="input" id="contractIntermentAdd--birthDateString" name="birthDateString" type="date" />
<span class="icon is-left">
<i class="fas fa-calendar" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="contractIntermentAdd--birthPlace">
Place of Birth
</label>
<div class="control">
<input class="input" id="contractIntermentAdd--birthPlace" name="birthPlace" type="text" maxlength="100" autocomplete="off" />
</div>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractIntermentAdd--deathDateString">
Date of Death
</label>
<div class="control has-icons-left">
<input class="input" id="contractIntermentAdd--deathDateString" name="deathDateString" type="date" />
<span class="icon is-left">
<i class="fas fa-calendar" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="contractIntermentAdd--deathPlace">
Place of Death
</label>
<div class="control">
<input class="input" id="contractIntermentAdd--deathPlace" name="deathPlace" type="text" maxlength="100" autocomplete="off" />
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="contractIntermentAdd--intermentContainerTypeId">Container</label>
<div class="control">
<div class="select is-fullwidth">
<select id="contractIntermentAdd--intermentContainerTypeId" name="intermentContainerTypeId">
<option value="">(No Container)</option>
<optgroup label="Non-Cremated" data-is-cremation-type="0"></optgroup>
<optgroup label="Cremated" data-is-cremation-type="1"></optgroup>
</select>
</div>
</div>
</div>
</form>
</section>
<footer class="modal-card-foot justify-right">
<button
class="button is-success"
type="submit"
form="form--contractIntermentAdd"
>
<span class="icon"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Interment</span>
</button>
<button class="button is-close-modal-button" type="button">Cancel</button>
</footer>
</div>
</div>

View File

@ -26,14 +26,14 @@
<div class="field">
<label
class="label"
for="contractCommentEdit--contractComment"
for="contractCommentEdit--comment"
>Comment</label
>
<div class="control">
<textarea
class="textarea"
id="contractCommentEdit--contractComment"
name="contractComment"
id="contractCommentEdit--comment"
name="comment"
required
></textarea>
</div>
@ -43,14 +43,14 @@
<div class="field">
<label
class="label"
for="contractCommentEdit--contractCommentDateString"
for="contractCommentEdit--commentDateString"
>Comment Date</label
>
<div class="control has-icons-left">
<input
class="input"
id="contractCommentEdit--contractCommentDateString"
name="contractCommentDateString"
id="contractCommentEdit--commentDateString"
name="commentDateString"
type="date"
required
/>
@ -64,14 +64,14 @@
<div class="field">
<label
class="label"
for="contractCommentEdit--contractCommentTimeString"
for="contractCommentEdit--commentTimeString"
>Comment Time</label
>
<div class="control has-icons-left">
<input
class="input"
id="contractCommentEdit--contractCommentTimeString"
name="contractCommentTimeString"
id="contractCommentEdit--commentTimeString"
name="commentTimeString"
type="time"
required
/>

View File

@ -3,7 +3,7 @@
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title">
Update <span class="alias" data-alias="Occupant"></span>
Update Interment
</h3>
<button
class="delete is-close-modal-button"
@ -12,47 +12,31 @@
></button>
</header>
<section class="modal-card-body">
<form id="form--contractOccupantEdit">
<form id="form--contractIntermentEdit">
<input
id="contractOccupantEdit--contractId"
id="contractIntermentEdit--contractId"
name="contractId"
type="hidden"
value=""
/>
<input
id="contractOccupantEdit--lotOccupantIndex"
name="lotOccupantIndex"
id="contractIntermentEdit--intermentNumber"
name="intermentNumber"
type="hidden"
value=""
/>
<label class="label" for="contractOccupantEdit--lotOccupantTypeId"
><span class="alias" data-alias="Occupant"></span> Type</label
>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth">
<select
id="contractOccupantEdit--lotOccupantTypeId"
name="lotOccupantTypeId"
required
></select>
</div>
</div>
<div class="control">
<span class="button is-static" id="contractOccupantEdit--fontAwesomeIconClass"></span>
</div>
</div>
<div class="columns mt-2 mb-0">
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractOccupantEdit--occupantName"
><span class="alias" data-alias="Occupant"></span> Name</label
<label class="label" for="contractIntermentEdit--deceasedName"
>Name</label
>
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantName"
name="occupantName"
id="contractIntermentEdit--deceasedName"
name="deceasedName"
type="text"
maxlength="200"
autocomplete="off"
@ -61,33 +45,16 @@
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="contractOccupantEdit--occupantFamilyName"
>Family Name</label
>
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantFamilyName"
name="occupantFamilyName"
type="text"
maxlength="200"
autocomplete="off"
/>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="contractOccupantEdit--occupantAddress1"
<label class="label" for="contractIntermentEdit--deceasedAddress1"
>Address</label
>
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantAddress1"
name="occupantAddress1"
id="contractIntermentEdit--deceasedAddress1"
name="deceasedAddress1"
type="text"
maxlength="50"
placeholder="Line 1"
@ -99,8 +66,8 @@
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantAddress2"
name="occupantAddress2"
id="contractIntermentEdit--deceasedAddress2"
name="deceasedAddress2"
type="text"
maxlength="50"
placeholder="Line 2"
@ -112,14 +79,14 @@
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractOccupantEdit--occupantCity"
<label class="label" for="contractIntermentEdit--deceasedCity"
>City</label
>
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantCity"
name="occupantCity"
id="contractIntermentEdit--deceasedCity"
name="deceasedCity"
type="text"
maxlength="20"
/>
@ -130,14 +97,14 @@
<div class="field">
<label
class="label"
for="contractOccupantEdit--occupantProvince"
for="contractIntermentEdit--deceasedProvince"
>Province</label
>
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantProvince"
name="occupantProvince"
id="contractIntermentEdit--deceasedProvince"
name="deceasedProvince"
type="text"
maxlength="2"
/>
@ -148,14 +115,14 @@
<div class="field">
<label
class="label"
for="contractOccupantEdit--occupantPostalCode"
for="contractIntermentEdit--deceasedPostalCode"
>Postal Code</label
>
<div class="control">
<input
class="input"
id="contractOccupantEdit--occupantPostalCode"
name="occupantPostalCode"
id="contractIntermentEdit--deceasedPostalCode"
name="deceasedPostalCode"
type="text"
maxlength="7"
autocomplete="off"
@ -166,63 +133,64 @@
</div>
<div class="columns">
<div class="column">
<label
class="label"
for="contractOccupantEdit--occupantPhoneNumber"
>Phone Number</label
>
<div class="field">
<label class="label" for="contractIntermentEdit--birthDateString">
Date of Birth
</label>
<div class="control has-icons-left">
<input
class="input"
id="contractOccupantEdit--occupantPhoneNumber"
name="occupantPhoneNumber"
type="text"
maxlength="30"
autocomplete="off"
/>
<span class="icon is-small is-left">
<i class="fas fa-phone" aria-hidden="true"></i>
<input class="input" id="contractIntermentEdit--birthDateString" name="birthDateString" type="date" />
<span class="icon is-left">
<i class="fas fa-calendar" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<label
class="label"
for="contractOccupantEdit--occupantEmailAddress"
>Email Address</label
>
<div class="field">
<label class="label" for="contractIntermentEdit--birthPlace">
Place of Birth
</label>
<div class="control">
<input class="input" id="contractIntermentEdit--birthPlace" name="birthPlace" type="text" maxlength="100" autocomplete="off" />
</div>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractIntermentEdit--deathDateString">
Date of Death
</label>
<div class="control has-icons-left">
<input
class="input"
id="contractOccupantEdit--occupantEmailAddress"
name="occupantEmailAddress"
type="email"
maxlength="200"
autocomplete="off"
/>
<span class="icon is-small is-left">
<i class="fas fa-envelope" aria-hidden="true"></i>
<input class="input" id="contractIntermentEdit--deathDateString" name="deathDateString" type="date" />
<span class="icon is-left">
<i class="fas fa-calendar" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="contractIntermentEdit--deathPlace">
Place of Death
</label>
<div class="control">
<input class="input" id="contractIntermentEdit--deathPlace" name="deathPlace" type="text" maxlength="100" autocomplete="off" />
</div>
</div>
</div>
</div>
<div class="field">
<label
class="label"
id="contractOccupantEdit--occupantCommentTitle"
for="contractOccupantEdit--occupantComment"
>Comment</label
>
<label class="label" for="contractIntermentEdit--intermentContainerTypeId">Container</label>
<div class="control">
<textarea
class="textarea"
id="contractOccupantEdit--occupantComment"
name="occupantComment"
></textarea>
<div class="select is-fullwidth">
<select id="contractIntermentEdit--intermentContainerTypeId" name="intermentContainerTypeId">
<option value="">(No Container)</option>
<optgroup label="Non-Cremated" data-is-cremation-type="0"></optgroup>
<optgroup label="Cremated" data-is-cremation-type="1"></optgroup>
</select>
</div>
</div>
</div>
</form>
@ -231,10 +199,10 @@
<button
class="button is-success"
type="submit"
form="form--contractOccupantEdit"
form="form--contractIntermentEdit"
>
<span class="icon"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Update <span class="alias" data-alias="Occupant"></span></span>
<span class="icon"><i class="fas fa-save" aria-hidden="true"></i></span>
<span>Update Interment</span>
</button>
<button class="button is-close-modal-button" type="button">Cancel</button>
</footer>

View File

@ -1,318 +0,0 @@
<div class="modal" role="dialog">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title">
Add <span class="alias" data-alias="Occupant"></span>
</h3>
<button
class="delete is-close-modal-button"
aria-label="close"
type="button"
></button>
</header>
<section class="modal-card-body">
<div class="tabs is-boxed">
<ul>
<li class="is-active">
<a href="#tab--contractOccupantAdd-new">
<span class="icon is-small">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>Create New</span>
</a>
</li>
<li>
<a href="#tab--contractOccupantAdd-copy">
<span class="icon is-small">
<i class="fas fa-copy" aria-hidden="true"></i>
</span>
<span>Copy Previous</span>
</a>
</li>
</ul>
</div>
<div class="tab-container">
<div id="tab--contractOccupantAdd-new">
<form id="form--contractOccupantAdd">
<input
id="contractOccupantAdd--contractId"
name="contractId"
type="hidden"
value=""
/>
<label
class="label"
for="contractOccupantAdd--lotOccupantTypeId"
><span class="alias" data-alias="Occupant"></span> Type</label
>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth">
<select
id="contractOccupantAdd--lotOccupantTypeId"
name="lotOccupantTypeId"
required
>
<option value="" data-font-awesome-icon-class="user">(Select a Type)</option>
</select>
</div>
</div>
<div class="control">
<span class="button is-static" id="contractOccupantAdd--fontAwesomeIconClass">
<i class="fas fa-fw fa-user" aria-hidden="true"></i>
</span>
</div>
</div>
<div class="columns mt-2 mb-0">
<div class="column">
<div class="field">
<label class="label" for="contractOccupantAdd--occupantName"
><span class="alias" data-alias="Occupant"></span> Name</label
>
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantName"
name="occupantName"
type="text"
maxlength="200"
autocomplete="off"
required
/>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="contractOccupantAdd--occupantFamilyName"
>Family Name</label
>
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantFamilyName"
name="occupantFamilyName"
type="text"
maxlength="200"
autocomplete="off"
/>
</div>
</div>
</div>
</div>
<div class="field">
<label
class="label"
for="contractOccupantAdd--occupantAddress1"
>Address</label
>
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantAddress1"
name="occupantAddress1"
type="text"
maxlength="50"
placeholder="Line 1"
autocomplete="off"
/>
</div>
</div>
<div class="field">
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantAddress2"
name="occupantAddress2"
type="text"
maxlength="50"
placeholder="Line 2"
autocomplete="off"
aria-label="Address Line 2"
/>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label
class="label"
for="contractOccupantAdd--occupantCity"
>City</label
>
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantCity"
name="occupantCity"
type="text"
maxlength="20"
/>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label
class="label"
for="contractOccupantAdd--occupantProvince"
>Province</label
>
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantProvince"
name="occupantProvince"
type="text"
maxlength="2"
/>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label
class="label"
for="contractOccupantAdd--occupantPostalCode"
>Postal Code</label
>
<div class="control">
<input
class="input"
id="contractOccupantAdd--occupantPostalCode"
name="occupantPostalCode"
type="text"
maxlength="7"
autocomplete="off"
/>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<label
class="label"
for="contractOccupantAdd--occupantPhoneNumber"
>Phone Number</label
>
<div class="field">
<div class="control has-icons-left">
<input
class="input"
id="contractOccupantAdd--occupantPhoneNumber"
name="occupantPhoneNumber"
type="text"
maxlength="30"
autocomplete="off"
/>
<span class="icon is-small is-left">
<i class="fas fa-phone" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<label
class="label"
for="contractOccupantAdd--occupantEmailAddress"
>Email Address</label
>
<div class="field">
<div class="control has-icons-left">
<input
class="input"
id="contractOccupantAdd--occupantEmailAddress"
name="occupantEmailAddress"
type="email"
maxlength="200"
autocomplete="off"
/>
<span class="icon is-small is-left">
<i class="fas fa-envelope" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
</div>
<div class="field">
<label
class="label"
id="contractOccupantAdd--occupantCommentTitle"
for="contractOccupantAdd--occupantComment"
>Comment</label
>
<div class="control">
<textarea
class="textarea"
id="contractOccupantAdd--occupantComment"
name="occupantComment"
></textarea>
</div>
</div>
<div class="has-text-right">
<button class="button is-success" type="submit">
<span class="icon"
><i class="fas fa-plus" aria-hidden="true"></i
></span>
<span
>Add <span class="alias" data-alias="Occupant"></span
></span>
</button>
</div>
</form>
</div>
<div class="is-hidden" id="tab--contractOccupantAdd-copy">
<div class="box">
<div class="field mb-4">
<label
class="label"
for="contractOccupantCopy--lotOccupantTypeId"
>New <span class="alias" data-alias="Occupant"></span> Type</label
>
<div class="control">
<div class="select is-fullwidth">
<select
id="contractOccupantCopy--lotOccupantTypeId"
name="lotOccupantTypeId"
required
>
<option value="">(Select a Type)</option>
</select>
</div>
</div>
</div>
<form id="form--contractOccupantCopy">
<input name="limit" type="hidden" value="50" />
<div class="field">
<label
class="label"
for="contractOccupantCopy--searchFilter"
>Find a Previously Used <span class="alias" data-alias="Occupant"></span></label
>
<div class="control has-icons-left">
<input
class="input"
id="contractOccupantCopy--searchFilter"
name="searchFilter"
type="text"
placeholder="Filter by name or address"
/>
<span class="icon is-left">
<i class="fas fa-filter" aria-hidden="true"></i>
</span>
</div>
</div>
</form>
</div>
<div id="contractOccupantCopy--searchResults"></div>
</div>
</div>
</section>
<footer class="modal-card-foot justify-right">
<button class="button is-close-modal-button" type="button">Cancel</button>
</footer>
</div>
</div>

View File

@ -3,7 +3,7 @@
<div class="modal-card has-width-900">
<header class="modal-card-head">
<h3 class="modal-card-title">
Add Related <span class="alias" data-alias="Lot"></span> to Work Order
Add Related Burial Site to Work Order
</h3>
<button
class="delete is-close-modal-button"
@ -13,11 +13,11 @@
</header>
<section class="modal-card-body">
<div class="box">
<form id="form--lotSearch">
<form id="form--burialSiteSearch">
<input name="limit" type="hidden" value="100" />
<input name="offset" type="hidden" value="0" />
<input
id="lotSearch--notWorkOrderId"
id="burialSiteSearch--notWorkOrderId"
name="notWorkOrderId"
type="hidden"
value=""
@ -26,14 +26,13 @@
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="lotSearch--burialSiteName">
<span class="alias" data-alias="Lot"></span>
Name
<label class="label" for="burialSiteSearch--burialSiteName">
Burial Site Name
</label>
<div class="control has-icons-left">
<input
class="input"
id="lotSearch--burialSiteName"
id="burialSiteSearch--burialSiteName"
name="burialSiteName"
type="text"
/>
@ -45,10 +44,10 @@
</div>
<div class="column">
<div class="field">
<label class="label" for="lotSearch--burialSiteStatusId">Status</label>
<label class="label" for="burialSiteSearch--burialSiteStatusId">Status</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="lotSearch--burialSiteStatusId" name="burialSiteStatusId">
<select id="burialSiteSearch--burialSiteStatusId" name="burialSiteStatusId">
<option value="">(All Statuses)</option>
</select>
</div>
@ -61,7 +60,7 @@
</div>
</form>
</div>
<div id="resultsContainer--lotAdd"></div>
<div id="resultsContainer--burialSiteAdd"></div>
</section>
<footer class="modal-card-foot justify-right">
<button class="button is-close-modal-button" type="button">Close</button>

View File

@ -18,14 +18,14 @@
value=""
/>
<div class="field">
<label class="label" for="workOrderCommentAdd--workOrderComment"
<label class="label" for="workOrderCommentAdd--comment"
>Comment</label
>
<div class="control">
<textarea
class="textarea"
id="workOrderCommentAdd--workOrderComment"
name="workOrderComment"
id="workOrderCommentAdd--comment"
name="comment"
required
></textarea>
</div>

View File

@ -3,8 +3,7 @@
<div class="modal-card has-width-900">
<header class="modal-card-head">
<h3 class="modal-card-title">
Add Related <span class="alias" data-alias="Occupancy"></span> to Work
Order
Add Related Contract to Work Order
</h3>
<button
class="delete is-close-modal-button"
@ -24,23 +23,22 @@
value=""
/>
<input
id="contractSearch--occupancyEffectiveDateString"
name="occupancyEffectiveDateString"
id="contractSearch--contractEffectiveDateString"
name="contractEffectiveDateString"
type="hidden"
value=""
/>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="contractSearch--occupantName">
<span class="alias" data-alias="Occupant"></span>
Name
<label class="label" for="contractSearch--deceasedName">
Interment Name
</label>
<div class="control has-icons-left">
<input
class="input"
id="contractSearch--occupantName"
name="occupantName"
id="contractSearch--deceasedName"
name="deceasedName"
type="text"
/>
<span class="icon is-small is-left">
@ -52,8 +50,7 @@
<div class="column">
<div class="field">
<label class="label" for="contractSearch--burialSiteName">
<span class="alias" data-alias="Lot"></span>
Name
Burial Site Name
</label>
<div class="control has-icons-left">
<input

View File

@ -24,14 +24,14 @@
value=""
/>
<div class="field">
<label class="label" for="workOrderCommentEdit--workOrderComment"
<label class="label" for="workOrderCommentEdit--comment"
>Comment</label
>
<div class="control">
<textarea
class="textarea"
id="workOrderCommentEdit--workOrderComment"
name="workOrderComment"
id="workOrderCommentEdit--comment"
name="comment"
required
></textarea>
</div>
@ -41,14 +41,14 @@
<div class="field">
<label
class="label"
for="workOrderCommentEdit--workOrderCommentDateString"
for="workOrderCommentEdit--commentDateString"
>Comment Date</label
>
<div class="control has-icons-left">
<input
class="input"
id="workOrderCommentEdit--workOrderCommentDateString"
name="workOrderCommentDateString"
id="workOrderCommentEdit--commentDateString"
name="commentDateString"
type="date"
required
/>
@ -62,14 +62,14 @@
<div class="field">
<label
class="label"
for="workOrderCommentEdit--workOrderCommentTimeString"
for="workOrderCommentEdit--commentTimeString"
>Comment Time</label
>
<div class="control has-icons-left">
<input
class="input"
id="workOrderCommentEdit--workOrderCommentTimeString"
name="workOrderCommentTimeString"
id="workOrderCommentEdit--commentTimeString"
name="commentTimeString"
type="time"
required
/>

View File

@ -1,19 +1,21 @@
"use strict";
// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair
/* eslint-disable max-lines */
Object.defineProperty(exports, "__esModule", { value: true });
(() => {
const los = exports.sunrise;
const sunrise = exports.sunrise;
const burialSiteId = document.querySelector('#burialSite--burialSiteId').value;
const isCreate = burialSiteId === '';
// Main form
let refreshAfterSave = isCreate;
function setUnsavedChanges() {
los.setUnsavedChanges();
sunrise.setUnsavedChanges();
document
.querySelector("button[type='submit'][form='form--burialSite']")
?.classList.remove('is-light');
}
function clearUnsavedChanges() {
los.clearUnsavedChanges();
sunrise.clearUnsavedChanges();
document
.querySelector("button[type='submit'][form='form--burialSite']")
?.classList.add('is-light');
@ -21,12 +23,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
const formElement = document.querySelector('#form--burialSite');
function updateBurialSite(formEvent) {
formEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/burialSites/${isCreate ? 'doCreateBurialSite' : 'doUpdateBurialSite'}`, formElement, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/${isCreate ? 'doCreateBurialSite' : 'doUpdateBurialSite'}`, formElement, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
clearUnsavedChanges();
if (isCreate || refreshAfterSave) {
globalThis.location.href = los.getBurialSiteURL(responseJSON.burialSiteId, true, true);
globalThis.location.href = sunrise.getBurialSiteURL(responseJSON.burialSiteId, true, true);
}
else {
bulmaJS.alert({
@ -49,19 +51,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
for (const formInputElement of formInputElements) {
formInputElement.addEventListener('change', setUnsavedChanges);
}
los.initializeUnlockFieldButtons(formElement);
sunrise.initializeUnlockFieldButtons(formElement);
document
.querySelector('#button--deleteBurialSite')
?.addEventListener('click', (clickEvent) => {
clickEvent.preventDefault();
function doDelete() {
cityssm.postJSON(`${los.urlPrefix}/burialSites/doDeleteBurialSite`, {
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/doDeleteBurialSite`, {
burialSiteId
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
clearUnsavedChanges();
globalThis.location.href = los.getBurialSiteURL();
globalThis.location.href = sunrise.getBurialSiteURL();
}
else {
bulmaJS.alert({
@ -93,7 +95,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
</div>`;
return;
}
cityssm.postJSON(`${los.urlPrefix}/burialSites/doGetBurialSiteTypeFields`, {
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/doGetBurialSiteTypeFields`, {
burialSiteTypeId: burialSiteTypeIdElement.value
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
@ -149,7 +151,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
burialSiteFieldsContainerElement.append(fieldElement);
}
burialSiteFieldsContainerElement.insertAdjacentHTML('beforeend', `<input name="burialSiteTypeFieldIds" type="hidden"
burialSiteFieldsContainerElement.insertAdjacentHTML('beforeend',
// eslint-disable-next-line no-secrets/no-secrets
`<input name="burialSiteTypeFieldIds" type="hidden"
value="${cityssm.escapeHTML(burialSiteTypeFieldIds.slice(1))}" />`);
});
});
@ -190,7 +194,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
let editCloseModalFunction;
function editComment(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/burialSites/doUpdateBurialSiteComment`, editFormElement, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/doUpdateBurialSiteComment`, editFormElement, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
burialSiteComments = responseJSON.burialSiteComments;
@ -208,7 +212,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
cityssm.openHtmlModal('burialSite-editComment', {
onshow(modalElement) {
los.populateAliases(modalElement);
sunrise.populateAliases(modalElement);
modalElement.querySelector('#burialSiteCommentEdit--burialSiteId').value = burialSiteId;
modalElement.querySelector('#burialSiteCommentEdit--burialSiteCommentId').value = burialSiteCommentId.toString();
modalElement.querySelector('#burialSiteCommentEdit--comment').value = burialSiteComment.comment ?? '';
@ -224,7 +228,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped();
los.initializeDatePickers(modalElement);
modalElement.querySelector('#burialSiteCommentEdit--comment').focus();
editFormElement = modalElement.querySelector('form');
editFormElement.addEventListener('submit', editComment);
@ -239,7 +242,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const burialSiteCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset
.burialSiteCommentId ?? '', 10);
function doDelete() {
cityssm.postJSON(`${los.urlPrefix}/burialSites/doDeleteBurialSiteComment`, {
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/doDeleteBurialSiteComment`, {
burialSiteId,
burialSiteCommentId
}, (rawResponseJSON) => {
@ -324,7 +327,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
let addCommentCloseModalFunction;
function doAddComment(formEvent) {
formEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/burialSites/doAddBurialSiteComment`, formEvent.currentTarget, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/doAddBurialSiteComment`, formEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
burialSiteComments = responseJSON.burialSiteComments;
@ -335,7 +338,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
cityssm.openHtmlModal('burialSite-addComment', {
onshow(modalElement) {
los.populateAliases(modalElement);
sunrise.populateAliases(modalElement);
modalElement.querySelector('#burialSiteCommentAdd--burialSiteId').value = burialSiteId;
modalElement
.querySelector('form')

View File

@ -1,3 +1,6 @@
// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair
/* eslint-disable max-lines */
import type { BulmaJS } from '@cityssm/bulma-js/types.js'
import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types.js'
@ -13,7 +16,7 @@ declare const bulmaJS: BulmaJS
declare const exports: Record<string, unknown>
;(() => {
const los = exports.sunrise as Sunrise
const sunrise = exports.sunrise as Sunrise
const burialSiteId = (
document.querySelector('#burialSite--burialSiteId') as HTMLInputElement
@ -25,14 +28,14 @@ declare const exports: Record<string, unknown>
let refreshAfterSave = isCreate
function setUnsavedChanges(): void {
los.setUnsavedChanges()
sunrise.setUnsavedChanges()
document
.querySelector("button[type='submit'][form='form--burialSite']")
?.classList.remove('is-light')
}
function clearUnsavedChanges(): void {
los.clearUnsavedChanges()
sunrise.clearUnsavedChanges()
document
.querySelector("button[type='submit'][form='form--burialSite']")
?.classList.add('is-light')
@ -46,7 +49,7 @@ declare const exports: Record<string, unknown>
formEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/burialSites/${isCreate ? 'doCreateBurialSite' : 'doUpdateBurialSite'}`,
`${sunrise.urlPrefix}/burialSites/${isCreate ? 'doCreateBurialSite' : 'doUpdateBurialSite'}`,
formElement,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as {
@ -59,7 +62,7 @@ declare const exports: Record<string, unknown>
clearUnsavedChanges()
if (isCreate || refreshAfterSave) {
globalThis.location.href = los.getBurialSiteURL(
globalThis.location.href = sunrise.getBurialSiteURL(
responseJSON.burialSiteId,
true,
true
@ -89,7 +92,7 @@ declare const exports: Record<string, unknown>
formInputElement.addEventListener('change', setUnsavedChanges)
}
los.initializeUnlockFieldButtons(formElement)
sunrise.initializeUnlockFieldButtons(formElement)
document
.querySelector('#button--deleteBurialSite')
@ -98,7 +101,7 @@ declare const exports: Record<string, unknown>
function doDelete(): void {
cityssm.postJSON(
`${los.urlPrefix}/burialSites/doDeleteBurialSite`,
`${sunrise.urlPrefix}/burialSites/doDeleteBurialSite`,
{
burialSiteId
},
@ -110,7 +113,7 @@ declare const exports: Record<string, unknown>
if (responseJSON.success) {
clearUnsavedChanges()
globalThis.location.href = los.getBurialSiteURL()
globalThis.location.href = sunrise.getBurialSiteURL()
} else {
bulmaJS.alert({
title: `Error Deleting Burial Site`,
@ -154,7 +157,7 @@ declare const exports: Record<string, unknown>
}
cityssm.postJSON(
`${los.urlPrefix}/burialSites/doGetBurialSiteTypeFields`,
`${sunrise.urlPrefix}/burialSites/doGetBurialSiteTypeFields`,
{
burialSiteTypeId: burialSiteTypeIdElement.value
},
@ -245,6 +248,7 @@ declare const exports: Record<string, unknown>
burialSiteFieldsContainerElement.insertAdjacentHTML(
'beforeend',
// eslint-disable-next-line no-secrets/no-secrets
`<input name="burialSiteTypeFieldIds" type="hidden"
value="${cityssm.escapeHTML(burialSiteTypeFieldIds.slice(1))}" />`
)
@ -302,7 +306,7 @@ declare const exports: Record<string, unknown>
submitEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/burialSites/doUpdateBurialSiteComment`,
`${sunrise.urlPrefix}/burialSites/doUpdateBurialSiteComment`,
editFormElement,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as {
@ -328,7 +332,7 @@ declare const exports: Record<string, unknown>
cityssm.openHtmlModal('burialSite-editComment', {
onshow(modalElement) {
los.populateAliases(modalElement)
sunrise.populateAliases(modalElement)
;(
modalElement.querySelector(
'#burialSiteCommentEdit--burialSiteId'
@ -366,9 +370,6 @@ declare const exports: Record<string, unknown>
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped()
los.initializeDatePickers(modalElement)
// los.initializeTimePickers(modalElement);
;(
modalElement.querySelector(
'#burialSiteCommentEdit--comment'
@ -395,7 +396,7 @@ declare const exports: Record<string, unknown>
function doDelete(): void {
cityssm.postJSON(
`${los.urlPrefix}/burialSites/doDeleteBurialSiteComment`,
`${sunrise.urlPrefix}/burialSites/doDeleteBurialSiteComment`,
{
burialSiteId,
burialSiteCommentId
@ -505,7 +506,7 @@ declare const exports: Record<string, unknown>
formEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/burialSites/doAddBurialSiteComment`,
`${sunrise.urlPrefix}/burialSites/doAddBurialSiteComment`,
formEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as {
@ -524,7 +525,7 @@ declare const exports: Record<string, unknown>
cityssm.openHtmlModal('burialSite-addComment', {
onshow(modalElement) {
los.populateAliases(modalElement)
sunrise.populateAliases(modalElement)
;(
modalElement.querySelector(
'#burialSiteCommentAdd--burialSiteId'

View File

@ -1,7 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
(() => {
const los = exports.sunrise;
const sunrise = exports.sunrise;
const searchFilterFormElement = document.querySelector('#form--searchFilters');
const searchResultsContainerElement = document.querySelector('#container--searchResults');
const limit = Number.parseInt(document.querySelector('#searchFilter--limit').value, 10);
@ -19,11 +19,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
// eslint-disable-next-line no-unsanitized/method
resultsTbodyElement.insertAdjacentHTML('beforeend', `<tr>
<td>
<a class="has-text-weight-bold" href="${los.getBurialSiteURL(burialSite.burialSiteId)}">
<a class="has-text-weight-bold" href="${sunrise.getBurialSiteURL(burialSite.burialSiteId)}">
${cityssm.escapeHTML(burialSite.burialSiteName ?? '')}
</a>
</td><td>
<a href="${los.getCemeteryURL(burialSite.cemeteryId)}">
<a href="${sunrise.getCemeteryURL(burialSite.cemeteryId)}">
${burialSite.cemeteryName
? cityssm.escapeHTML(burialSite.cemeteryName)
: '<span class="has-text-grey">(No Name)</span>'}
@ -49,7 +49,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
</tr></thead>
<table>`;
// eslint-disable-next-line no-unsanitized/method
searchResultsContainerElement.insertAdjacentHTML('beforeend', los.getSearchResultsPagerHTML(limit, responseJSON.offset, responseJSON.count));
searchResultsContainerElement.insertAdjacentHTML('beforeend', sunrise.getSearchResultsPagerHTML(limit, responseJSON.offset, responseJSON.count));
searchResultsContainerElement
.querySelector('table')
?.append(resultsTbodyElement);
@ -62,8 +62,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
function getBurialSites() {
// eslint-disable-next-line no-unsanitized/property
searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML(`Loading Burial Sites...`);
cityssm.postJSON(`${los.urlPrefix}/burialSites/doSearchBurialSites`, searchFilterFormElement, renderBurialSites);
searchResultsContainerElement.innerHTML = sunrise.getLoadingParagraphHTML(`Loading Burial Sites...`);
cityssm.postJSON(`${sunrise.urlPrefix}/burialSites/doSearchBurialSites`, searchFilterFormElement, renderBurialSites);
}
function resetOffsetAndGetBurialSites() {
offsetElement.value = '0';

View File

@ -8,7 +8,7 @@ declare const cityssm: cityssmGlobal
declare const exports: Record<string, unknown>
;(() => {
const los = exports.sunrise as Sunrise
const sunrise = exports.sunrise as Sunrise
const searchFilterFormElement = document.querySelector(
'#form--searchFilters'
@ -49,11 +49,11 @@ declare const exports: Record<string, unknown>
'beforeend',
`<tr>
<td>
<a class="has-text-weight-bold" href="${los.getBurialSiteURL(burialSite.burialSiteId)}">
<a class="has-text-weight-bold" href="${sunrise.getBurialSiteURL(burialSite.burialSiteId)}">
${cityssm.escapeHTML(burialSite.burialSiteName ?? '')}
</a>
</td><td>
<a href="${los.getCemeteryURL(burialSite.cemeteryId)}">
<a href="${sunrise.getCemeteryURL(burialSite.cemeteryId)}">
${
burialSite.cemeteryName
? cityssm.escapeHTML(burialSite.cemeteryName)
@ -90,7 +90,7 @@ declare const exports: Record<string, unknown>
// eslint-disable-next-line no-unsanitized/method
searchResultsContainerElement.insertAdjacentHTML(
'beforeend',
los.getSearchResultsPagerHTML(
sunrise.getSearchResultsPagerHTML(
limit,
responseJSON.offset,
responseJSON.count
@ -112,12 +112,12 @@ declare const exports: Record<string, unknown>
function getBurialSites(): void {
// eslint-disable-next-line no-unsanitized/property
searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML(
searchResultsContainerElement.innerHTML = sunrise.getLoadingParagraphHTML(
`Loading Burial Sites...`
)
cityssm.postJSON(
`${los.urlPrefix}/burialSites/doSearchBurialSites`,
`${sunrise.urlPrefix}/burialSites/doSearchBurialSites`,
searchFilterFormElement,
renderBurialSites
)

View File

@ -3,7 +3,7 @@
/* eslint-disable max-lines */
Object.defineProperty(exports, "__esModule", { value: true });
(() => {
const los = exports.sunrise;
const sunrise = exports.sunrise;
const containerElement = document.querySelector('#container--burialSiteTypes');
let burialSiteTypes = exports.burialSiteTypes;
delete exports.burialSiteTypes;
@ -44,7 +44,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
function deleteBurialSiteType(clickEvent) {
const burialSiteTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--burialSiteType').dataset.burialSiteTypeId ?? '', 10);
function doDelete() {
cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteBurialSiteType`, {
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doDeleteBurialSiteType`, {
burialSiteTypeId
}, burialSiteTypeResponseHandler);
}
@ -64,7 +64,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
let editCloseModalFunction;
function doEdit(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateBurialSiteType`, submitEvent.currentTarget, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doUpdateBurialSiteType`, submitEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
burialSiteTypeResponseHandler(responseJSON);
if (responseJSON.success) {
@ -74,7 +74,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
cityssm.openHtmlModal('adminBurialSiteTypes-edit', {
onshow(modalElement) {
los.populateAliases(modalElement);
sunrise.populateAliases(modalElement);
modalElement.querySelector('#burialSiteTypeEdit--burialSiteTypeId').value = burialSiteTypeId.toString();
modalElement.querySelector('#burialSiteTypeEdit--burialSiteType').value = burialSiteType.burialSiteType;
},
@ -94,7 +94,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
let addCloseModalFunction;
function doAdd(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/admin/doAddBurialSiteTypeField`, submitEvent.currentTarget, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doAddBurialSiteTypeField`, submitEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
expandedBurialSiteTypes.add(burialSiteTypeId);
burialSiteTypeResponseHandler(responseJSON);
@ -106,7 +106,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
cityssm.openHtmlModal('adminBurialSiteTypes-addField', {
onshow(modalElement) {
los.populateAliases(modalElement);
sunrise.populateAliases(modalElement);
if (burialSiteTypeId) {
;
modalElement.querySelector('#burialSiteTypeFieldAdd--burialSiteTypeId').value = burialSiteTypeId.toString();
@ -126,7 +126,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
function moveBurialSiteType(clickEvent) {
const buttonElement = clickEvent.currentTarget;
const burialSiteTypeId = buttonElement.closest('.container--burialSiteType').dataset.burialSiteTypeId;
cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up'
cityssm.postJSON(`${sunrise.urlPrefix}/admin/${buttonElement.dataset.direction === 'up'
? 'doMoveBurialSiteTypeUp'
: // eslint-disable-next-line no-secrets/no-secrets
'doMoveBurialSiteTypeDown'}`, {
@ -173,7 +173,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
function doUpdate(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateBurialSiteTypeField`, submitEvent.currentTarget, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doUpdateBurialSiteTypeField`, submitEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
burialSiteTypeResponseHandler(responseJSON);
if (responseJSON.success) {
@ -182,7 +182,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
});
}
function doDelete() {
cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteBurialSiteTypeField`, {
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doDeleteBurialSiteTypeField`, {
burialSiteTypeFieldId
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
@ -205,7 +205,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
cityssm.openHtmlModal('adminBurialSiteTypes-editField', {
onshow(modalElement) {
los.populateAliases(modalElement);
sunrise.populateAliases(modalElement);
modalElement.querySelector('#burialSiteTypeFieldEdit--burialSiteTypeFieldId').value = burialSiteTypeField.burialSiteTypeFieldId.toString();
modalElement.querySelector('#burialSiteTypeFieldEdit--burialSiteTypeField').value = burialSiteTypeField.burialSiteTypeField ?? '';
modalElement.querySelector('#burialSiteTypeFieldEdit--isRequired').value = burialSiteTypeField.isRequired ?? false ? '1' : '0';
@ -251,7 +251,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
function moveBurialSiteTypeField(clickEvent) {
const buttonElement = clickEvent.currentTarget;
const burialSiteTypeFieldId = buttonElement.closest('.container--burialSiteTypeField').dataset.burialSiteTypeFieldId;
cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up'
cityssm.postJSON(`${sunrise.urlPrefix}/admin/${buttonElement.dataset.direction === 'up'
? 'doMoveBurialSiteTypeFieldUp'
: // eslint-disable-next-line no-secrets/no-secrets
'doMoveBurialSiteTypeFieldDown'}`, {
@ -288,7 +288,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
</div>
<div class="level-right">
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveBurialSiteTypeFieldUp',
${sunrise.getMoveUpDownButtonFieldHTML('button--moveBurialSiteTypeFieldUp',
// eslint-disable-next-line no-secrets/no-secrets
'button--moveBurialSiteTypeFieldDown')}
</div>
@ -351,7 +351,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
</button>
</div>
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveBurialSiteTypeUp', 'button--moveBurialSiteTypeDown')}
${sunrise.getMoveUpDownButtonFieldHTML('button--moveBurialSiteTypeUp', 'button--moveBurialSiteTypeDown')}
</div>
</div>
</div>
@ -380,7 +380,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
let addCloseModalFunction;
function doAdd(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${los.urlPrefix}/admin/doAddBurialSiteType`, submitEvent.currentTarget, (rawResponseJSON) => {
cityssm.postJSON(`${sunrise.urlPrefix}/admin/doAddBurialSiteType`, submitEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
addCloseModalFunction();
@ -398,7 +398,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
cityssm.openHtmlModal('adminBurialSiteTypes-add', {
onshow(modalElement) {
los.populateAliases(modalElement);
sunrise.populateAliases(modalElement);
},
onshown(modalElement, closeModalFunction) {
addCloseModalFunction = closeModalFunction;

View File

@ -27,7 +27,7 @@ type ResponseJSON =
errorMessage?: string
}
;(() => {
const los = exports.sunrise as Sunrise
const sunrise = exports.sunrise as Sunrise
const containerElement = document.querySelector(
'#container--burialSiteTypes'
@ -98,7 +98,7 @@ type ResponseJSON =
function doDelete(): void {
cityssm.postJSON(
`${los.urlPrefix}/admin/doDeleteBurialSiteType`,
`${sunrise.urlPrefix}/admin/doDeleteBurialSiteType`,
{
burialSiteTypeId
},
@ -137,7 +137,7 @@ type ResponseJSON =
submitEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/admin/doUpdateBurialSiteType`,
`${sunrise.urlPrefix}/admin/doUpdateBurialSiteType`,
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
@ -152,7 +152,7 @@ type ResponseJSON =
cityssm.openHtmlModal('adminBurialSiteTypes-edit', {
onshow(modalElement) {
los.populateAliases(modalElement)
sunrise.populateAliases(modalElement)
;(
modalElement.querySelector(
'#burialSiteTypeEdit--burialSiteTypeId'
@ -198,7 +198,7 @@ type ResponseJSON =
submitEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/admin/doAddBurialSiteTypeField`,
`${sunrise.urlPrefix}/admin/doAddBurialSiteTypeField`,
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
@ -219,7 +219,7 @@ type ResponseJSON =
cityssm.openHtmlModal('adminBurialSiteTypes-addField', {
onshow(modalElement) {
los.populateAliases(modalElement)
sunrise.populateAliases(modalElement)
if (burialSiteTypeId) {
;(
@ -255,7 +255,7 @@ type ResponseJSON =
).dataset.burialSiteTypeId
cityssm.postJSON(
`${los.urlPrefix}/admin/${
`${sunrise.urlPrefix}/admin/${
buttonElement.dataset.direction === 'up'
? 'doMoveBurialSiteTypeUp'
: // eslint-disable-next-line no-secrets/no-secrets
@ -326,7 +326,7 @@ type ResponseJSON =
submitEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/admin/doUpdateBurialSiteTypeField`,
`${sunrise.urlPrefix}/admin/doUpdateBurialSiteTypeField`,
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
@ -341,7 +341,7 @@ type ResponseJSON =
function doDelete(): void {
cityssm.postJSON(
`${los.urlPrefix}/admin/doDeleteBurialSiteTypeField`,
`${sunrise.urlPrefix}/admin/doDeleteBurialSiteTypeField`,
{
burialSiteTypeFieldId
},
@ -371,7 +371,7 @@ type ResponseJSON =
cityssm.openHtmlModal('adminBurialSiteTypes-editField', {
onshow(modalElement) {
los.populateAliases(modalElement)
sunrise.populateAliases(modalElement)
;(
modalElement.querySelector(
'#burialSiteTypeFieldEdit--burialSiteTypeFieldId'
@ -479,7 +479,7 @@ type ResponseJSON =
).dataset.burialSiteTypeFieldId
cityssm.postJSON(
`${los.urlPrefix}/admin/${
`${sunrise.urlPrefix}/admin/${
buttonElement.dataset.direction === 'up'
? 'doMoveBurialSiteTypeFieldUp'
: // eslint-disable-next-line no-secrets/no-secrets
@ -531,7 +531,7 @@ type ResponseJSON =
</div>
<div class="level-right">
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML(
${sunrise.getMoveUpDownButtonFieldHTML(
'button--moveBurialSiteTypeFieldUp',
// eslint-disable-next-line no-secrets/no-secrets
'button--moveBurialSiteTypeFieldDown'
@ -618,7 +618,7 @@ type ResponseJSON =
</button>
</div>
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML(
${sunrise.getMoveUpDownButtonFieldHTML(
'button--moveBurialSiteTypeUp',
'button--moveBurialSiteTypeDown'
)}
@ -672,7 +672,7 @@ type ResponseJSON =
submitEvent.preventDefault()
cityssm.postJSON(
`${los.urlPrefix}/admin/doAddBurialSiteType`,
`${sunrise.urlPrefix}/admin/doAddBurialSiteType`,
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
@ -694,7 +694,7 @@ type ResponseJSON =
cityssm.openHtmlModal('adminBurialSiteTypes-add', {
onshow(modalElement) {
los.populateAliases(modalElement)
sunrise.populateAliases(modalElement)
},
onshown(modalElement, closeModalFunction) {
addCloseModalFunction = closeModalFunction

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,185 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
(() => {
const sunrise = exports.sunrise;
const contractId = document.querySelector('#contract--contractId').value;
let contractComments = exports.contractComments;
delete exports.contractComments;
function openEditContractComment(clickEvent) {
const contractCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset
.contractCommentId ?? '', 10);
const contractComment = contractComments.find((currentComment) => currentComment.contractCommentId === contractCommentId);
let editFormElement;
let editCloseModalFunction;
function editContractComment(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doUpdateContractComment`, editFormElement, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractComments = responseJSON.contractComments ?? [];
editCloseModalFunction();
renderContractComments();
}
else {
bulmaJS.alert({
title: 'Error Updating Comment',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
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 ?? '';
const contractCommentDateStringElement = modalElement.querySelector('#contractCommentEdit--commentDateString');
contractCommentDateStringElement.value =
contractComment.commentDateString ?? '';
const currentDateString = cityssm.dateToString(new Date());
contractCommentDateStringElement.max =
contractComment.commentDateString <= currentDateString
? currentDateString
: contractComment.commentDateString ?? '';
modalElement.querySelector('#contractCommentEdit--commentTimeString').value = contractComment.commentTimeString ?? '';
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped();
modalElement.querySelector('#contractCommentEdit--comment').focus();
editFormElement = modalElement.querySelector('form');
editFormElement.addEventListener('submit', editContractComment);
editCloseModalFunction = closeModalFunction;
},
onremoved() {
bulmaJS.toggleHtmlClipped();
}
});
}
function deleteContractComment(clickEvent) {
const contractCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset
.contractCommentId ?? '', 10);
function doDelete() {
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doDeleteContractComment`, {
contractId,
contractCommentId
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractComments = responseJSON.contractComments;
renderContractComments();
}
else {
bulmaJS.alert({
title: 'Error Removing Comment',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
bulmaJS.confirm({
title: 'Remove Comment?',
message: 'Are you sure you want to remove this comment?',
okButton: {
text: 'Yes, Remove Comment',
callbackFunction: doDelete
},
contextualColorName: 'warning'
});
}
function renderContractComments() {
const containerElement = document.querySelector('#container--contractComments');
if (contractComments.length === 0) {
containerElement.innerHTML = `<div class="message is-info">
<p class="message-body">There are no comments associated with this record.</p>
</div>`;
return;
}
const tableElement = document.createElement('table');
tableElement.className = 'table is-fullwidth is-striped is-hoverable';
tableElement.innerHTML = `<thead><tr>
<th>Author</th>
<th>Comment Date</th>
<th>Comment</th>
<th class="is-hidden-print"><span class="is-sr-only">Options</span></th>
</tr></thead>
<tbody></tbody>`;
for (const contractComment of contractComments) {
const tableRowElement = document.createElement('tr');
tableRowElement.dataset.contractCommentId =
contractComment.contractCommentId?.toString();
tableRowElement.innerHTML = `<td>${cityssm.escapeHTML(contractComment.recordCreate_userName ?? '')}</td>
<td>
${cityssm.escapeHTML(contractComment.commentDateString ?? '')}
${cityssm.escapeHTML(contractComment.commentTime === 0
? ''
: contractComment.commentTimePeriodString ?? '')}
</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">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit</span>
</button>
<button class="button is-light is-danger button--delete" data-tooltip="Delete Comment" type="button" aria-label="Delete">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</td>`;
tableRowElement
.querySelector('.button--edit')
?.addEventListener('click', openEditContractComment);
tableRowElement
.querySelector('.button--delete')
?.addEventListener('click', deleteContractComment);
tableElement.querySelector('tbody')?.append(tableRowElement);
}
containerElement.innerHTML = '';
containerElement.append(tableElement);
}
document
.querySelector('#button--addComment')
?.addEventListener('click', () => {
let addFormElement;
let addCloseModalFunction;
function addComment(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doAddContractComment`, addFormElement, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractComments = responseJSON.contractComments;
addCloseModalFunction();
renderContractComments();
}
else {
bulmaJS.alert({
title: 'Error Adding Comment',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
cityssm.openHtmlModal('contract-addComment', {
onshow(modalElement) {
sunrise.populateAliases(modalElement);
modalElement.querySelector('#contractCommentAdd--contractId').value = contractId;
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped();
modalElement.querySelector('#contractCommentAdd--comment').focus();
addFormElement = modalElement.querySelector('form');
addFormElement.addEventListener('submit', addComment);
addCloseModalFunction = closeModalFunction;
},
onremoved() {
bulmaJS.toggleHtmlClipped();
document.querySelector('#button--addComment').focus();
}
});
});
renderContractComments();
})();

View File

@ -0,0 +1,299 @@
import type { BulmaJS } from '@cityssm/bulma-js/types.js'
import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types.js'
import type { ContractComment } from '../../types/recordTypes.js'
import type { Sunrise } from './types.js'
declare const cityssm: cityssmGlobal
declare const bulmaJS: BulmaJS
declare const exports: Record<string, unknown>
;(() => {
const sunrise = exports.sunrise as Sunrise
const contractId = (
document.querySelector('#contract--contractId') as HTMLInputElement
).value
let contractComments = exports.contractComments as ContractComment[]
delete exports.contractComments
function openEditContractComment(clickEvent: Event): void {
const contractCommentId = Number.parseInt(
(clickEvent.currentTarget as HTMLElement).closest('tr')?.dataset
.contractCommentId ?? '',
10
)
const contractComment = contractComments.find(
(currentComment) => currentComment.contractCommentId === contractCommentId
) as ContractComment
let editFormElement: HTMLFormElement
let editCloseModalFunction: () => void
function editContractComment(submitEvent: SubmitEvent): void {
submitEvent.preventDefault()
cityssm.postJSON(
`${sunrise.urlPrefix}/contracts/doUpdateContractComment`,
editFormElement,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as {
success: boolean
errorMessage?: string
contractComments?: ContractComment[]
}
if (responseJSON.success) {
contractComments = responseJSON.contractComments ?? []
editCloseModalFunction()
renderContractComments()
} else {
bulmaJS.alert({
title: 'Error Updating Comment',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
})
}
}
)
}
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--comment'
) as HTMLInputElement
).value = contractComment.comment ?? ''
const contractCommentDateStringElement = modalElement.querySelector(
'#contractCommentEdit--commentDateString'
) as HTMLInputElement
contractCommentDateStringElement.value =
contractComment.commentDateString ?? ''
const currentDateString = cityssm.dateToString(new Date())
contractCommentDateStringElement.max =
contractComment.commentDateString! <= currentDateString
? currentDateString
: contractComment.commentDateString ?? ''
;(
modalElement.querySelector(
'#contractCommentEdit--commentTimeString'
) as HTMLInputElement
).value = contractComment.commentTimeString ?? ''
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped()
;(
modalElement.querySelector(
'#contractCommentEdit--comment'
) as HTMLTextAreaElement
).focus()
editFormElement = modalElement.querySelector('form') as HTMLFormElement
editFormElement.addEventListener('submit', editContractComment)
editCloseModalFunction = closeModalFunction
},
onremoved() {
bulmaJS.toggleHtmlClipped()
}
})
}
function deleteContractComment(clickEvent: Event): void {
const contractCommentId = Number.parseInt(
(clickEvent.currentTarget as HTMLElement).closest('tr')?.dataset
.contractCommentId ?? '',
10
)
function doDelete(): void {
cityssm.postJSON(
`${sunrise.urlPrefix}/contracts/doDeleteContractComment`,
{
contractId,
contractCommentId
},
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as {
success: boolean
errorMessage?: string
contractComments: ContractComment[]
}
if (responseJSON.success) {
contractComments = responseJSON.contractComments
renderContractComments()
} else {
bulmaJS.alert({
title: 'Error Removing Comment',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
})
}
}
)
}
bulmaJS.confirm({
title: 'Remove Comment?',
message: 'Are you sure you want to remove this comment?',
okButton: {
text: 'Yes, Remove Comment',
callbackFunction: doDelete
},
contextualColorName: 'warning'
})
}
function renderContractComments(): void {
const containerElement = document.querySelector(
'#container--contractComments'
) as HTMLElement
if (contractComments.length === 0) {
containerElement.innerHTML = `<div class="message is-info">
<p class="message-body">There are no comments associated with this record.</p>
</div>`
return
}
const tableElement = document.createElement('table')
tableElement.className = 'table is-fullwidth is-striped is-hoverable'
tableElement.innerHTML = `<thead><tr>
<th>Author</th>
<th>Comment Date</th>
<th>Comment</th>
<th class="is-hidden-print"><span class="is-sr-only">Options</span></th>
</tr></thead>
<tbody></tbody>`
for (const contractComment of contractComments) {
const tableRowElement = document.createElement('tr')
tableRowElement.dataset.contractCommentId =
contractComment.contractCommentId?.toString()
tableRowElement.innerHTML = `<td>${cityssm.escapeHTML(contractComment.recordCreate_userName ?? '')}</td>
<td>
${cityssm.escapeHTML(contractComment.commentDateString ?? '')}
${cityssm.escapeHTML(
contractComment.commentTime === 0
? ''
: contractComment.commentTimePeriodString ?? ''
)}
</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">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit</span>
</button>
<button class="button is-light is-danger button--delete" data-tooltip="Delete Comment" type="button" aria-label="Delete">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</td>`
tableRowElement
.querySelector('.button--edit')
?.addEventListener('click', openEditContractComment)
tableRowElement
.querySelector('.button--delete')
?.addEventListener('click', deleteContractComment)
tableElement.querySelector('tbody')?.append(tableRowElement)
}
containerElement.innerHTML = ''
containerElement.append(tableElement)
}
document
.querySelector('#button--addComment')
?.addEventListener('click', () => {
let addFormElement: HTMLFormElement
let addCloseModalFunction: () => void
function addComment(submitEvent: SubmitEvent): void {
submitEvent.preventDefault()
cityssm.postJSON(
`${sunrise.urlPrefix}/contracts/doAddContractComment`,
addFormElement,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as {
success: boolean
errorMessage?: string
contractComments: ContractComment[]
}
if (responseJSON.success) {
contractComments = responseJSON.contractComments
addCloseModalFunction()
renderContractComments()
} else {
bulmaJS.alert({
title: 'Error Adding Comment',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
})
}
}
)
}
cityssm.openHtmlModal('contract-addComment', {
onshow(modalElement) {
sunrise.populateAliases(modalElement)
;(
modalElement.querySelector(
'#contractCommentAdd--contractId'
) as HTMLInputElement
).value = contractId
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped()
;(
modalElement.querySelector(
'#contractCommentAdd--comment'
) as HTMLTextAreaElement
).focus()
addFormElement = modalElement.querySelector('form') as HTMLFormElement
addFormElement.addEventListener('submit', addComment)
addCloseModalFunction = closeModalFunction
},
onremoved() {
bulmaJS.toggleHtmlClipped()
;(
document.querySelector('#button--addComment') as HTMLButtonElement
).focus()
}
})
})
renderContractComments()
})()

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,668 @@
"use strict";
// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair
/* eslint-disable max-lines */
Object.defineProperty(exports, "__esModule", { value: true });
(() => {
const sunrise = exports.sunrise;
const contractId = document.querySelector('#contract--contractId').value;
let contractFees = exports.contractFees;
delete exports.contractFees;
const contractFeesContainerElement = document.querySelector('#container--contractFees');
function getFeeGrandTotal() {
let feeGrandTotal = 0;
for (const contractFee of contractFees) {
feeGrandTotal +=
((contractFee.feeAmount ?? 0) + (contractFee.taxAmount ?? 0)) *
(contractFee.quantity ?? 0);
}
return feeGrandTotal;
}
function editContractFeeQuantity(clickEvent) {
const feeId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset
.feeId ?? '', 10);
const fee = contractFees.find((possibleFee) => possibleFee.feeId === feeId);
let updateCloseModalFunction;
function doUpdateQuantity(formEvent) {
formEvent.preventDefault();
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doUpdateContractFeeQuantity`, formEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractFees = responseJSON.contractFees;
renderContractFees();
updateCloseModalFunction();
}
else {
bulmaJS.alert({
title: 'Error Updating Quantity',
message: 'Please try again.',
contextualColorName: 'danger'
});
}
});
}
cityssm.openHtmlModal('contract-editFeeQuantity', {
onshow(modalElement) {
;
modalElement.querySelector('#contractFeeQuantity--contractId').value = contractId;
modalElement.querySelector('#contractFeeQuantity--feeId').value = fee.feeId.toString();
modalElement.querySelector('#contractFeeQuantity--quantity').valueAsNumber = fee.quantity ?? 0;
modalElement.querySelector('#contractFeeQuantity--quantityUnit').textContent = fee.quantityUnit ?? '';
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped();
updateCloseModalFunction = closeModalFunction;
modalElement.querySelector('#contractFeeQuantity--quantity').focus();
modalElement
.querySelector('form')
?.addEventListener('submit', doUpdateQuantity);
},
onremoved() {
bulmaJS.toggleHtmlClipped();
}
});
}
function deleteContractFee(clickEvent) {
const feeId = clickEvent.currentTarget.closest('.container--contractFee').dataset.feeId;
function doDelete() {
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doDeleteContractFee`, {
contractId,
feeId
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractFees = responseJSON.contractFees;
renderContractFees();
}
else {
bulmaJS.alert({
title: 'Error Deleting Fee',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
bulmaJS.confirm({
title: 'Delete Fee',
message: 'Are you sure you want to delete this fee?',
contextualColorName: 'warning',
okButton: {
text: 'Yes, Delete Fee',
callbackFunction: doDelete
}
});
}
// eslint-disable-next-line complexity
function renderContractFees() {
if (contractFees.length === 0) {
contractFeesContainerElement.innerHTML = `<div class="message is-info">
<p class="message-body">There are no fees associated with this record.</p>
</div>`;
renderContractTransactions();
return;
}
contractFeesContainerElement.innerHTML = `<table class="table is-fullwidth is-striped is-hoverable">
<thead><tr>
<th>Fee</th>
<th><span class="is-sr-only">Unit Cost</span></th>
<th class="has-width-1"><span class="is-sr-only">&times;</span></th>
<th class="has-width-1"><span class="is-sr-only">Quantity</span></th>
<th class="has-width-1"><span class="is-sr-only">equals</span></th>
<th class="has-width-1 has-text-right">Total</th>
<th class="has-width-1 is-hidden-print"><span class="is-sr-only">Options</span></th>
</tr></thead>
<tbody></tbody>
<tfoot><tr>
<th colspan="5">Subtotal</th>
<td class="has-text-weight-bold has-text-right" id="contractFees--feeAmountTotal"></td>
<td class="is-hidden-print"></td>
</tr><tr>
<th colspan="5">Tax</th>
<td class="has-text-right" id="contractFees--taxAmountTotal"></td>
<td class="is-hidden-print"></td>
</tr><tr>
<th colspan="5">Grand Total</th>
<td class="has-text-weight-bold has-text-right" id="contractFees--grandTotal"></td>
<td class="is-hidden-print"></td>
</tr></tfoot></table>`;
let feeAmountTotal = 0;
let taxAmountTotal = 0;
for (const contractFee of contractFees) {
const tableRowElement = document.createElement('tr');
tableRowElement.className = 'container--contractFee';
tableRowElement.dataset.feeId = contractFee.feeId.toString();
tableRowElement.dataset.includeQuantity =
contractFee.includeQuantity ?? false ? '1' : '0';
// eslint-disable-next-line no-unsanitized/property
tableRowElement.innerHTML = `<td colspan="${contractFee.quantity === 1 ? '5' : '1'}">
${cityssm.escapeHTML(contractFee.feeName ?? '')}<br />
<span class="tag">${cityssm.escapeHTML(contractFee.feeCategory ?? '')}</span>
</td>
${contractFee.quantity === 1
? ''
: `<td class="has-text-right">
$${contractFee.feeAmount?.toFixed(2)}
</td>
<td>&times;</td>
<td class="has-text-right">${contractFee.quantity?.toString()}</td>
<td>=</td>`}
<td class="has-text-right">
$${((contractFee.feeAmount ?? 0) * (contractFee.quantity ?? 0)).toFixed(2)}
</td>
<td class="is-hidden-print">
<div class="buttons are-small is-flex-wrap-nowrap is-justify-content-end">
${contractFee.includeQuantity ?? false
? `<button class="button is-primary button--editQuantity">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit</span>
</button>`
: ''}
<button class="button is-danger is-light button--delete" data-tooltip="Delete Fee" type="button">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</td>`;
tableRowElement
.querySelector('.button--editQuantity')
?.addEventListener('click', editContractFeeQuantity);
tableRowElement
.querySelector('.button--delete')
?.addEventListener('click', deleteContractFee);
contractFeesContainerElement
.querySelector('tbody')
?.append(tableRowElement);
feeAmountTotal +=
(contractFee.feeAmount ?? 0) * (contractFee.quantity ?? 0);
taxAmountTotal +=
(contractFee.taxAmount ?? 0) * (contractFee.quantity ?? 0);
}
;
contractFeesContainerElement.querySelector('#contractFees--feeAmountTotal').textContent = `$${feeAmountTotal.toFixed(2)}`;
contractFeesContainerElement.querySelector('#contractFees--taxAmountTotal').textContent = `$${taxAmountTotal.toFixed(2)}`;
contractFeesContainerElement.querySelector('#contractFees--grandTotal').textContent = `$${(feeAmountTotal + taxAmountTotal).toFixed(2)}`;
renderContractTransactions();
}
const addFeeButtonElement = document.querySelector('#button--addFee');
addFeeButtonElement.addEventListener('click', () => {
if (sunrise.hasUnsavedChanges()) {
bulmaJS.alert({
message: 'Please save all unsaved changes before adding fees.',
contextualColorName: 'warning'
});
return;
}
let feeCategories;
let feeFilterElement;
let feeFilterResultsElement;
function doAddFeeCategory(clickEvent) {
clickEvent.preventDefault();
const feeCategoryId = Number.parseInt(clickEvent.currentTarget.dataset.feeCategoryId ?? '', 10);
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doAddContractFeeCategory`, {
contractId,
feeCategoryId
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractFees = responseJSON.contractFees;
renderContractFees();
bulmaJS.alert({
message: 'Fee Group Added Successfully',
contextualColorName: 'success'
});
}
else {
bulmaJS.alert({
title: 'Error Adding Fee',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
function doAddFee(feeId, quantity = 1) {
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doAddContractFee`, {
contractId,
feeId,
quantity
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractFees = responseJSON.contractFees;
renderContractFees();
filterFees();
}
else {
bulmaJS.alert({
title: 'Error Adding Fee',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
function doSetQuantityAndAddFee(fee) {
let quantityElement;
let quantityCloseModalFunction;
function doSetQuantity(submitEvent) {
submitEvent.preventDefault();
doAddFee(fee.feeId, quantityElement.value);
quantityCloseModalFunction();
}
cityssm.openHtmlModal('contract-setFeeQuantity', {
onshow(modalElement) {
;
modalElement.querySelector('#contractFeeQuantity--quantityUnit').textContent = fee.quantityUnit ?? '';
},
onshown(modalElement, closeModalFunction) {
quantityCloseModalFunction = closeModalFunction;
quantityElement = modalElement.querySelector('#contractFeeQuantity--quantity');
modalElement
.querySelector('form')
?.addEventListener('submit', doSetQuantity);
}
});
}
function tryAddFee(clickEvent) {
clickEvent.preventDefault();
const feeId = Number.parseInt(clickEvent.currentTarget.dataset.feeId ?? '', 10);
const feeCategoryId = Number.parseInt(clickEvent.currentTarget.dataset.feeCategoryId ?? '', 10);
const feeCategory = feeCategories.find((currentFeeCategory) => currentFeeCategory.feeCategoryId === feeCategoryId);
const fee = feeCategory.fees.find((currentFee) => currentFee.feeId === feeId);
if (fee.includeQuantity ?? false) {
doSetQuantityAndAddFee(fee);
}
else {
doAddFee(feeId);
}
}
function filterFees() {
const filterStringPieces = feeFilterElement.value
.trim()
.toLowerCase()
.split(' ');
feeFilterResultsElement.innerHTML = '';
for (const feeCategory of feeCategories) {
const categoryContainerElement = document.createElement('div');
categoryContainerElement.className = 'container--feeCategory';
categoryContainerElement.dataset.feeCategoryId =
feeCategory.feeCategoryId.toString();
categoryContainerElement.innerHTML = `<div class="columns is-vcentered">
<div class="column">
<h4 class="title is-5">
${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}
</h4>
</div>
</div>
<div class="panel mb-5"></div>`;
if (feeCategory.isGroupedFee) {
// eslint-disable-next-line no-unsanitized/method
categoryContainerElement
.querySelector('.columns')
?.insertAdjacentHTML('beforeend', `<div class="column is-narrow has-text-right">
<button class="button is-small is-success" type="button" data-fee-category-id="${feeCategory.feeCategoryId}">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Fee Group</span>
</button>
</div>`);
categoryContainerElement
.querySelector('button')
?.addEventListener('click', doAddFeeCategory);
}
let hasFees = false;
for (const fee of feeCategory.fees) {
// Don't include already applied fees that limit quantity
if (contractFeesContainerElement.querySelector(`.container--contractFee[data-fee-id='${fee.feeId}'][data-include-quantity='0']`) !== null) {
continue;
}
let includeFee = true;
const feeSearchString = `${feeCategory.feeCategory ?? ''} ${fee.feeName ?? ''} ${fee.feeDescription ?? ''}`.toLowerCase();
for (const filterStringPiece of filterStringPieces) {
if (!feeSearchString.includes(filterStringPiece)) {
includeFee = false;
break;
}
}
if (!includeFee) {
continue;
}
hasFees = true;
const panelBlockElement = document.createElement(feeCategory.isGroupedFee ? 'div' : 'a');
panelBlockElement.className = 'panel-block is-block container--fee';
panelBlockElement.dataset.feeId = fee.feeId.toString();
panelBlockElement.dataset.feeCategoryId =
feeCategory.feeCategoryId.toString();
// eslint-disable-next-line no-unsanitized/property
panelBlockElement.innerHTML = `<strong>${cityssm.escapeHTML(fee.feeName ?? '')}</strong><br />
<small>
${cityssm
.escapeHTML(fee.feeDescription ?? '')
.replaceAll('\n', '<br />')}
</small>`;
if (!feeCategory.isGroupedFee) {
;
panelBlockElement.href = '#';
panelBlockElement.addEventListener('click', tryAddFee);
}
;
categoryContainerElement.querySelector('.panel').append(panelBlockElement);
}
if (hasFees) {
feeFilterResultsElement.append(categoryContainerElement);
}
}
}
cityssm.openHtmlModal('contract-addFee', {
onshow(modalElement) {
feeFilterElement = modalElement.querySelector('#feeSelect--feeName');
feeFilterResultsElement = modalElement.querySelector('#resultsContainer--feeSelect');
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doGetFees`, {
contractId
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
feeCategories = responseJSON.feeCategories;
feeFilterElement.disabled = false;
feeFilterElement.addEventListener('keyup', filterFees);
feeFilterElement.focus();
filterFees();
});
},
onshown() {
bulmaJS.toggleHtmlClipped();
},
onhidden() {
renderContractFees();
},
onremoved() {
bulmaJS.toggleHtmlClipped();
addFeeButtonElement.focus();
}
});
});
let contractTransactions = exports.contractTransactions;
delete exports.contractTransactions;
const contractTransactionsContainerElement = document.querySelector('#container--contractTransactions');
function getTransactionGrandTotal() {
let transactionGrandTotal = 0;
for (const contractTransaction of contractTransactions) {
transactionGrandTotal += contractTransaction.transactionAmount;
}
return transactionGrandTotal;
}
function editContractTransaction(clickEvent) {
const transactionIndex = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset
.transactionIndex ?? '', 10);
const transaction = contractTransactions.find((possibleTransaction) => possibleTransaction.transactionIndex === transactionIndex);
let editCloseModalFunction;
function doEdit(formEvent) {
formEvent.preventDefault();
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doUpdateContractTransaction`, formEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractTransactions = responseJSON.contractTransactions;
renderContractTransactions();
editCloseModalFunction();
}
else {
bulmaJS.alert({
title: 'Error Updating Transaction',
message: 'Please try again.',
contextualColorName: 'danger'
});
}
});
}
cityssm.openHtmlModal('contract-editTransaction', {
onshow(modalElement) {
sunrise.populateAliases(modalElement);
modalElement.querySelector('#contractTransactionEdit--contractId').value = contractId;
modalElement.querySelector('#contractTransactionEdit--transactionIndex').value = transaction.transactionIndex?.toString() ?? '';
modalElement.querySelector('#contractTransactionEdit--transactionAmount').value = transaction.transactionAmount.toFixed(2);
modalElement.querySelector('#contractTransactionEdit--externalReceiptNumber').value = transaction.externalReceiptNumber ?? '';
modalElement.querySelector('#contractTransactionEdit--transactionNote').value = transaction.transactionNote ?? '';
modalElement.querySelector('#contractTransactionEdit--transactionDateString').value = transaction.transactionDateString ?? '';
modalElement.querySelector('#contractTransactionEdit--transactionTimeString').value = transaction.transactionTimeString ?? '';
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped();
modalElement.querySelector('#contractTransactionEdit--transactionAmount').focus();
modalElement.querySelector('form')?.addEventListener('submit', doEdit);
editCloseModalFunction = closeModalFunction;
},
onremoved() {
bulmaJS.toggleHtmlClipped();
}
});
}
function deleteContractTransaction(clickEvent) {
const transactionIndex = clickEvent.currentTarget.closest('.container--contractTransaction').dataset.transactionIndex;
function doDelete() {
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doDeleteContractTransaction`, {
contractId,
transactionIndex
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractTransactions = responseJSON.contractTransactions;
renderContractTransactions();
}
else {
bulmaJS.alert({
title: 'Error Deleting Transaction',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
bulmaJS.confirm({
title: 'Delete Transaction',
message: 'Are you sure you want to delete this transaction?',
contextualColorName: 'warning',
okButton: {
text: 'Yes, Delete Transaction',
callbackFunction: doDelete
}
});
}
function renderContractTransactions() {
if (contractTransactions.length === 0) {
// eslint-disable-next-line no-unsanitized/property
contractTransactionsContainerElement.innerHTML = `<div class="message ${contractFees.length === 0 ? 'is-info' : 'is-warning'}">
<p class="message-body">There are no transactions associated with this record.</p>
</div>`;
return;
}
// eslint-disable-next-line no-unsanitized/property
contractTransactionsContainerElement.innerHTML = `<table class="table is-fullwidth is-striped is-hoverable">
<thead><tr>
<th class="has-width-1">Date</th>
<th>${sunrise.escapedAliases.ExternalReceiptNumber}</th>
<th class="has-text-right has-width-1">Amount</th>
<th class="has-width-1 is-hidden-print"><span class="is-sr-only">Options</span></th>
</tr></thead>
<tbody></tbody>
<tfoot><tr>
<th colspan="2">Transaction Total</th>
<td class="has-text-weight-bold has-text-right" id="contractTransactions--grandTotal"></td>
<td class="is-hidden-print"></td>
</tr></tfoot>
</table>`;
let transactionGrandTotal = 0;
for (const contractTransaction of contractTransactions) {
transactionGrandTotal += contractTransaction.transactionAmount;
const tableRowElement = document.createElement('tr');
tableRowElement.className = 'container--contractTransaction';
tableRowElement.dataset.transactionIndex =
contractTransaction.transactionIndex?.toString();
let externalReceiptNumberHTML = '';
if (contractTransaction.externalReceiptNumber !== '') {
externalReceiptNumberHTML = cityssm.escapeHTML(contractTransaction.externalReceiptNumber ?? '');
if (sunrise.dynamicsGPIntegrationIsEnabled) {
if (contractTransaction.dynamicsGPDocument === undefined) {
externalReceiptNumberHTML += ` <span data-tooltip="No Matching Document Found">
<i class="fas fa-times-circle has-text-danger" aria-label="No Matching Document Found"></i>
</span>`;
}
else if (contractTransaction.dynamicsGPDocument.documentTotal.toFixed(2) ===
contractTransaction.transactionAmount.toFixed(2)) {
externalReceiptNumberHTML += ` <span data-tooltip="Matching Document Found">
<i class="fas fa-check-circle has-text-success" aria-label="Matching Document Found"></i>
</span>`;
}
else {
externalReceiptNumberHTML += ` <span data-tooltip="Matching Document: $${contractTransaction.dynamicsGPDocument.documentTotal.toFixed(2)}">
<i class="fas fa-check-circle has-text-warning" aria-label="Matching Document: $${contractTransaction.dynamicsGPDocument.documentTotal.toFixed(2)}"></i>
</span>`;
}
}
externalReceiptNumberHTML += '<br />';
}
// eslint-disable-next-line no-unsanitized/property
tableRowElement.innerHTML = `<td>
${cityssm.escapeHTML(contractTransaction.transactionDateString ?? '')}
</td>
<td>
${externalReceiptNumberHTML}
<small>${cityssm.escapeHTML(contractTransaction.transactionNote ?? '')}</small>
</td>
<td class="has-text-right">
$${cityssm.escapeHTML(contractTransaction.transactionAmount.toFixed(2))}
</td>
<td class="is-hidden-print">
<div class="buttons are-small is-flex-wrap-nowrap is-justify-content-end">
<button class="button is-primary button--edit" type="button">
<span class="icon"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit</span>
</button>
<button class="button is-danger is-light button--delete" data-tooltip="Delete Transaction" type="button">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</td>`;
tableRowElement
.querySelector('.button--edit')
?.addEventListener('click', editContractTransaction);
tableRowElement
.querySelector('.button--delete')
?.addEventListener('click', deleteContractTransaction);
contractTransactionsContainerElement
.querySelector('tbody')
?.append(tableRowElement);
}
;
contractTransactionsContainerElement.querySelector('#contractTransactions--grandTotal').textContent = `$${transactionGrandTotal.toFixed(2)}`;
const feeGrandTotal = getFeeGrandTotal();
if (feeGrandTotal.toFixed(2) !== transactionGrandTotal.toFixed(2)) {
contractTransactionsContainerElement.insertAdjacentHTML('afterbegin', `<div class="message is-warning">
<div class="message-body">
<div class="level">
<div class="level-left">
<div class="level-item">Outstanding Balance</div>
</div>
<div class="level-right">
<div class="level-item">
$${cityssm.escapeHTML((feeGrandTotal - transactionGrandTotal).toFixed(2))}
</div>
</div>
</div>
</div></div>`);
}
}
const addTransactionButtonElement = document.querySelector('#button--addTransaction');
addTransactionButtonElement.addEventListener('click', () => {
let transactionAmountElement;
let externalReceiptNumberElement;
let addCloseModalFunction;
function doAddTransaction(submitEvent) {
submitEvent.preventDefault();
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doAddContractTransaction`, submitEvent.currentTarget, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (responseJSON.success) {
contractTransactions = responseJSON.contractTransactions;
addCloseModalFunction();
renderContractTransactions();
}
else {
bulmaJS.confirm({
title: 'Error Adding Transaction',
message: responseJSON.errorMessage ?? '',
contextualColorName: 'danger'
});
}
});
}
// eslint-disable-next-line @typescript-eslint/naming-convention
function dynamicsGP_refreshExternalReceiptNumberIcon() {
const externalReceiptNumber = externalReceiptNumberElement.value;
const iconElement = externalReceiptNumberElement
.closest('.control')
?.querySelector('.icon');
const helpTextElement = externalReceiptNumberElement
.closest('.field')
?.querySelector('.help');
if (externalReceiptNumber === '') {
helpTextElement.innerHTML = '&nbsp;';
iconElement.innerHTML =
'<i class="fas fa-minus" aria-hidden="true"></i>';
return;
}
cityssm.postJSON(`${sunrise.urlPrefix}/contracts/doGetDynamicsGPDocument`, {
externalReceiptNumber
}, (rawResponseJSON) => {
const responseJSON = rawResponseJSON;
if (!responseJSON.success ||
responseJSON.dynamicsGPDocument === undefined) {
helpTextElement.textContent = 'No Matching Document Found';
iconElement.innerHTML =
'<i class="fas fa-times-circle" aria-hidden="true"></i>';
}
else if (transactionAmountElement.valueAsNumber ===
responseJSON.dynamicsGPDocument.documentTotal) {
helpTextElement.textContent = 'Matching Document Found';
iconElement.innerHTML =
'<i class="fas fa-check-circle" aria-hidden="true"></i>';
}
else {
helpTextElement.textContent = `Matching Document: $${responseJSON.dynamicsGPDocument.documentTotal.toFixed(2)}`;
iconElement.innerHTML =
'<i class="fas fa-exclamation-triangle" aria-hidden="true"></i>';
}
});
}
cityssm.openHtmlModal('contract-addTransaction', {
onshow(modalElement) {
sunrise.populateAliases(modalElement);
modalElement.querySelector('#contractTransactionAdd--contractId').value = contractId.toString();
const feeGrandTotal = getFeeGrandTotal();
const transactionGrandTotal = getTransactionGrandTotal();
transactionAmountElement = modalElement.querySelector('#contractTransactionAdd--transactionAmount');
transactionAmountElement.min = (-1 * transactionGrandTotal).toFixed(2);
transactionAmountElement.max = Math.max(feeGrandTotal - transactionGrandTotal, 0).toFixed(2);
transactionAmountElement.value = Math.max(feeGrandTotal - transactionGrandTotal, 0).toFixed(2);
if (sunrise.dynamicsGPIntegrationIsEnabled) {
externalReceiptNumberElement = modalElement.querySelector('#contractTransactionAdd--externalReceiptNumber');
const externalReceiptNumberControlElement = externalReceiptNumberElement.closest('.control');
externalReceiptNumberControlElement.classList.add('has-icons-right');
externalReceiptNumberControlElement.insertAdjacentHTML('beforeend', '<span class="icon is-small is-right"></span>');
externalReceiptNumberControlElement.insertAdjacentHTML('afterend', '<p class="help has-text-right"></p>');
externalReceiptNumberElement.addEventListener('change', dynamicsGP_refreshExternalReceiptNumberIcon);
transactionAmountElement.addEventListener('change', dynamicsGP_refreshExternalReceiptNumberIcon);
dynamicsGP_refreshExternalReceiptNumberIcon();
}
},
onshown(modalElement, closeModalFunction) {
bulmaJS.toggleHtmlClipped();
transactionAmountElement.focus();
addCloseModalFunction = closeModalFunction;
modalElement
.querySelector('form')
?.addEventListener('submit', doAddTransaction);
},
onremoved() {
bulmaJS.toggleHtmlClipped();
addTransactionButtonElement.focus();
}
});
});
renderContractFees();
})();

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More