add, update, delete fee

deepsource-autofix-76c6eb20
Dan Gowans 2022-08-17 14:31:59 -04:00
parent 388cfcaf96
commit 727745c779
36 changed files with 1700 additions and 188 deletions

View File

@ -0,0 +1,3 @@
import type { RequestHandler } from "express";
export declare const handler: RequestHandler;
export default handler;

View File

@ -0,0 +1,14 @@
import { addFee } from "../../helpers/lotOccupancyDB/addFee.js";
import { getFeeCategories } from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler = async (request, response) => {
const feeId = addFee(request.body, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success: true,
feeId,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,31 @@
import type {
RequestHandler
} from "express";
import {
addFee
} from "../../helpers/lotOccupancyDB/addFee.js";
import {
getFeeCategories
} from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler: RequestHandler = async (request, response) => {
const feeId = addFee(request.body, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success: true,
feeId,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,3 @@
import type { RequestHandler } from "express";
export declare const handler: RequestHandler;
export default handler;

View File

@ -0,0 +1,13 @@
import { deleteFee } from "../../helpers/lotOccupancyDB/deleteFee.js";
import { getFeeCategories } from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler = async (request, response) => {
const success = deleteFee(request.body.feeId, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,30 @@
import type {
RequestHandler
} from "express";
import {
deleteFee
} from "../../helpers/lotOccupancyDB/deleteFee.js";
import {
getFeeCategories
} from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler: RequestHandler = async (request, response) => {
const success = deleteFee(request.body.feeId, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,3 @@
import type { RequestHandler } from "express";
export declare const handler: RequestHandler;
export default handler;

View File

@ -0,0 +1,13 @@
import { deleteFeeCategory } from "../../helpers/lotOccupancyDB/deleteFeeCategory.js";
import { getFeeCategories } from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler = async (request, response) => {
const success = deleteFeeCategory(request.body.feeCategoryId, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,30 @@
import type {
RequestHandler
} from "express";
import {
deleteFeeCategory
} from "../../helpers/lotOccupancyDB/deleteFeeCategory.js";
import {
getFeeCategories
} from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler: RequestHandler = async (request, response) => {
const success = deleteFeeCategory(request.body.feeCategoryId, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,3 @@
import type { RequestHandler } from "express";
export declare const handler: RequestHandler;
export default handler;

View File

@ -0,0 +1,13 @@
import { updateFee } from "../../helpers/lotOccupancyDB/updateFee.js";
import { getFeeCategories } from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler = async (request, response) => {
const success = updateFee(request.body, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,30 @@
import type {
RequestHandler
} from "express";
import {
updateFee
} from "../../helpers/lotOccupancyDB/updateFee.js";
import {
getFeeCategories
} from "../../helpers/lotOccupancyDB/getFeeCategories.js";
export const handler: RequestHandler = async (request, response) => {
const success = updateFee(request.body, request.session);
const feeCategories = getFeeCategories({}, {
includeFees: true
});
response.json({
success,
feeCategories
});
};
export default handler;

View File

@ -0,0 +1,18 @@
import type * as recordTypes from "../../types/recordTypes";
interface AddFeeForm {
feeCategoryId: string;
feeName: string;
feeDescription: string;
occupancyTypeId?: string;
lotTypeId?: string;
feeAmount?: string;
feeFunction?: string;
taxAmount?: string;
taxPercentage?: string;
includeQuantity: "" | "1";
quantityUnit?: string;
isRequired: "" | "1";
orderNumber?: number;
}
export declare const addFee: (feeForm: AddFeeForm, requestSession: recordTypes.PartialSession) => number;
export default addFee;

View File

@ -0,0 +1,21 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const addFee = (feeForm, requestSession) => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("insert into Fees (" +
"feeCategoryId, feeName, feeDescription," +
" occupancyTypeId, lotTypeId," +
" feeAmount, feeFunction," +
" taxAmount, taxPercentage," +
" includeQuantity, quantityUnit," +
" isRequired, orderNumber," +
" recordCreate_userName, recordCreate_timeMillis," +
" recordUpdate_userName, recordUpdate_timeMillis)" +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
.run(feeForm.feeCategoryId, feeForm.feeName, feeForm.feeDescription, (feeForm.occupancyTypeId || undefined), (feeForm.lotTypeId || undefined), (feeForm.feeAmount || undefined), (feeForm.feeFunction || undefined), (feeForm.taxAmount || undefined), (feeForm.taxPercentage || undefined), (feeForm.includeQuantity ? 1 : 0), feeForm.quantityUnit, (feeForm.isRequired ? 1 : 0), (feeForm.orderNumber || 0), requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis);
database.close();
return result.lastInsertRowid;
};
export default addFee;

View File

@ -0,0 +1,66 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
interface AddFeeForm {
feeCategoryId: string;
feeName: string;
feeDescription: string;
occupancyTypeId?: string;
lotTypeId?: string;
feeAmount?: string;
feeFunction?: string;
taxAmount?: string;
taxPercentage?: string;
includeQuantity: "" | "1";
quantityUnit?: string;
isRequired: "" | "1";
orderNumber?: number;
}
export const addFee =
(feeForm: AddFeeForm, requestSession: recordTypes.PartialSession): number => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("insert into Fees (" +
"feeCategoryId, feeName, feeDescription," +
" occupancyTypeId, lotTypeId," +
" feeAmount, feeFunction," +
" taxAmount, taxPercentage," +
" includeQuantity, quantityUnit," +
" isRequired, orderNumber," +
" recordCreate_userName, recordCreate_timeMillis," +
" recordUpdate_userName, recordUpdate_timeMillis)" +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
.run(feeForm.feeCategoryId,
feeForm.feeName,
feeForm.feeDescription,
(feeForm.occupancyTypeId || undefined),
(feeForm.lotTypeId || undefined),
(feeForm.feeAmount || undefined),
(feeForm.feeFunction || undefined),
(feeForm.taxAmount || undefined),
(feeForm.taxPercentage || undefined),
(feeForm.includeQuantity ? 1 : 0),
feeForm.quantityUnit,
(feeForm.isRequired ? 1 : 0),
(feeForm.orderNumber || 0),
requestSession.user.userName,
rightNowMillis,
requestSession.user.userName,
rightNowMillis);
database.close();
return result.lastInsertRowid as number;
};
export default addFee;

View File

@ -0,0 +1,3 @@
import type * as recordTypes from "../../types/recordTypes";
export declare const deleteFee: (feeId: number | string, requestSession: recordTypes.PartialSession) => boolean;
export default deleteFee;

View File

@ -0,0 +1,15 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const deleteFee = (feeId, requestSession) => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("update Fees" +
" set recordDelete_userName = ?," +
" recordDelete_timeMillis = ?" +
" where feeId = ?")
.run(requestSession.user.userName, rightNowMillis, feeId);
database.close();
return (result.changes > 0);
};
export default deleteFee;

View File

@ -0,0 +1,33 @@
import sqlite from "better-sqlite3";
import {
lotOccupancyDB as databasePath
} from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
export const deleteFee =
(feeId: number | string,
requestSession: recordTypes.PartialSession): boolean => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("update Fees" +
" set recordDelete_userName = ?," +
" recordDelete_timeMillis = ?" +
" where feeId = ?")
.run(requestSession.user.userName,
rightNowMillis,
feeId);
database.close();
return (result.changes > 0);
};
export default deleteFee;

View File

@ -0,0 +1,3 @@
import type * as recordTypes from "../../types/recordTypes";
export declare const deleteFeeCategory: (feeCategoryId: number | string, requestSession: recordTypes.PartialSession) => boolean;
export default deleteFeeCategory;

View File

@ -0,0 +1,15 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const deleteFeeCategory = (feeCategoryId, requestSession) => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("update FeeCategories" +
" set recordDelete_userName = ?," +
" recordDelete_timeMillis = ?" +
" where feeCategoryId = ?")
.run(requestSession.user.userName, rightNowMillis, feeCategoryId);
database.close();
return (result.changes > 0);
};
export default deleteFeeCategory;

View File

@ -0,0 +1,33 @@
import sqlite from "better-sqlite3";
import {
lotOccupancyDB as databasePath
} from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
export const deleteFeeCategory =
(feeCategoryId: number | string,
requestSession: recordTypes.PartialSession): boolean => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("update FeeCategories" +
" set recordDelete_userName = ?," +
" recordDelete_timeMillis = ?" +
" where feeCategoryId = ?")
.run(requestSession.user.userName,
rightNowMillis,
feeCategoryId);
database.close();
return (result.changes > 0);
};
export default deleteFeeCategory;

View File

@ -26,26 +26,30 @@ export const getFeeCategories = (filters, options) => {
" order by orderNumber, feeCategory")
.all(sqlParameters);
if (options.includeFees) {
sql = "select feeId, feeName, feeDescription," +
" occupancyTypeId, lotTypeId," +
" feeAmount, feeFunction, taxAmount, taxPercentage," +
" isRequired" +
" from Fees" +
" where recordDelete_timeMillis is null" +
" and feeCategoryId = ?";
sqlParameters = [];
for (const feeCategory of feeCategories) {
sql = "select f.feeId, f.feeName, f.feeDescription," +
" f.occupancyTypeId, o.occupancyType," +
" f.lotTypeId, l.lotType," +
" f.feeAmount, f.feeFunction, f.taxAmount, f.taxPercentage," +
" f.includeQuantity, f.quantityUnit," +
" f.isRequired" +
" from Fees f" +
" left join OccupancyTypes o on f.occupancyTypeId = o.occupancyTypeId" +
" left join LotTypes l on f.lotTypeId = l.lotTypeId" +
" where f.recordDelete_timeMillis is null" +
" and f.feeCategoryId = ?";
sqlParameters = [];
sqlParameters.push(feeCategory.feeCategoryId);
if (filters.occupancyTypeId) {
sql += " and (occupancyTypeId is null or occupancyTypeId = ?)";
sql += " and (f.occupancyTypeId is null or f.occupancyTypeId = ?)";
sqlParameters.push(filters.occupancyTypeId);
}
if (filters.lotTypeId) {
sql += " and (lotTypeId is null or lotTypeId = ?)";
sql += " and (f.lotTypeId is null or f.lotTypeId = ?)";
sqlParameters.push(filters.lotTypeId);
}
feeCategory.fees = database.prepare(sql +
" order by orderNumber, feeName")
" order by f.orderNumber, f.feeName")
.all(sqlParameters);
}
}

View File

@ -53,34 +53,38 @@ export const getFeeCategories = (filters ? : GetFeeCategoriesFilters, options ?
if (options.includeFees) {
sql = "select feeId, feeName, feeDescription," +
" occupancyTypeId, lotTypeId," +
" feeAmount, feeFunction, taxAmount, taxPercentage," +
" isRequired" +
" from Fees" +
" where recordDelete_timeMillis is null" +
" and feeCategoryId = ?";
for (const feeCategory of feeCategories) {
sql = "select f.feeId, f.feeName, f.feeDescription," +
" f.occupancyTypeId, o.occupancyType," +
" f.lotTypeId, l.lotType," +
" f.feeAmount, f.feeFunction, f.taxAmount, f.taxPercentage," +
" f.includeQuantity, f.quantityUnit," +
" f.isRequired" +
" from Fees f" +
" left join OccupancyTypes o on f.occupancyTypeId = o.occupancyTypeId" +
" left join LotTypes l on f.lotTypeId = l.lotTypeId" +
" where f.recordDelete_timeMillis is null" +
" and f.feeCategoryId = ?";
sqlParameters = [];
for (const feeCategory of feeCategories) {
sqlParameters.push(feeCategory.feeCategoryId);
if (filters.occupancyTypeId) {
sql += " and (occupancyTypeId is null or occupancyTypeId = ?)";
sql += " and (f.occupancyTypeId is null or f.occupancyTypeId = ?)";
sqlParameters.push(filters.occupancyTypeId);
}
if (filters.lotTypeId) {
sql += " and (lotTypeId is null or lotTypeId = ?)";
sql += " and (f.lotTypeId is null or f.lotTypeId = ?)";
sqlParameters.push(filters.lotTypeId);
}
feeCategory.fees = database.prepare(sql +
" order by orderNumber, feeName")
" order by f.orderNumber, f.feeName")
.all(sqlParameters);
}
}

View File

@ -0,0 +1,18 @@
import type * as recordTypes from "../../types/recordTypes";
interface UpdateFeeForm {
feeId: string;
feeCategoryId: string;
feeName: string;
feeDescription: string;
occupancyTypeId?: string;
lotTypeId?: string;
feeAmount?: string;
feeFunction?: string;
taxAmount?: string;
taxPercentage?: string;
includeQuantity: "" | "1";
quantityUnit?: string;
isRequired: "" | "1";
}
export declare const updateFee: (feeForm: UpdateFeeForm, requestSession: recordTypes.PartialSession) => boolean;
export default updateFee;

View File

@ -0,0 +1,28 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const updateFee = (feeForm, requestSession) => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("update Fees" +
" set feeCategoryId = ?," +
" feeName = ?," +
" feeDescription = ?," +
" occupancyTypeId = ?," +
" lotTypeId = ?," +
" feeAmount = ?," +
" feeFunction = ?," +
" taxAmount = ?," +
" taxPercentage = ?," +
" includeQuantity = ?," +
" quantityUnit = ?," +
" isRequired = ?," +
" recordUpdate_userName = ?," +
" recordUpdate_timeMillis = ?" +
" where recordDelete_timeMillis is null" +
" and feeId = ?")
.run(feeForm.feeCategoryId, feeForm.feeName, feeForm.feeDescription, (feeForm.occupancyTypeId || undefined), (feeForm.lotTypeId || undefined), (feeForm.feeAmount || undefined), (feeForm.feeFunction || undefined), (feeForm.taxAmount || undefined), (feeForm.taxPercentage || undefined), (feeForm.includeQuantity ? 1 : 0), feeForm.quantityUnit, (feeForm.isRequired ? 1 : 0), requestSession.user.userName, rightNowMillis, feeForm.feeId);
database.close();
return result.changes > 0;
};
export default updateFee;

View File

@ -0,0 +1,71 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
interface UpdateFeeForm {
feeId: string;
feeCategoryId: string;
feeName: string;
feeDescription: string;
occupancyTypeId?: string;
lotTypeId?: string;
feeAmount?: string;
feeFunction?: string;
taxAmount?: string;
taxPercentage?: string;
includeQuantity: "" | "1";
quantityUnit?: string;
isRequired: "" | "1";
}
export const updateFee =
(feeForm: UpdateFeeForm, requestSession: recordTypes.PartialSession): boolean => {
const database = sqlite(databasePath);
const rightNowMillis = Date.now();
const result = database
.prepare("update Fees" +
" set feeCategoryId = ?," +
" feeName = ?," +
" feeDescription = ?," +
" occupancyTypeId = ?," +
" lotTypeId = ?," +
" feeAmount = ?," +
" feeFunction = ?," +
" taxAmount = ?," +
" taxPercentage = ?," +
" includeQuantity = ?," +
" quantityUnit = ?," +
" isRequired = ?," +
" recordUpdate_userName = ?," +
" recordUpdate_timeMillis = ?" +
" where recordDelete_timeMillis is null" +
" and feeId = ?")
.run(feeForm.feeCategoryId,
feeForm.feeName,
feeForm.feeDescription,
(feeForm.occupancyTypeId || undefined),
(feeForm.lotTypeId || undefined),
(feeForm.feeAmount || undefined),
(feeForm.feeFunction || undefined),
(feeForm.taxAmount || undefined),
(feeForm.taxPercentage || undefined),
(feeForm.includeQuantity ? 1 : 0),
feeForm.quantityUnit,
(feeForm.isRequired ? 1 : 0),
requestSession.user.userName,
rightNowMillis,
feeForm.feeId);
database.close();
return result.changes > 0;
};
export default updateFee;

View File

@ -5,6 +5,150 @@ Object.defineProperty(exports, "__esModule", { value: true });
const urlPrefix = document.querySelector("main").dataset.urlPrefix;
const feeCategoriesContainerElement = document.querySelector("#container--feeCategories");
let feeCategories = exports.feeCategories;
const renderFeeCategories = () => {
if (feeCategories.length === 0) {
feeCategoriesContainerElement.innerHTML = "<div class=\"message is-warning\">" +
"<p class=\"message-body\">There are no available fees.</p>" +
"</div>";
return;
}
feeCategoriesContainerElement.innerHTML = "";
for (const feeCategory of feeCategories) {
const feeCategoryContainerElement = document.createElement("section");
feeCategoryContainerElement.className = "container--feeCategory mb-5";
feeCategoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString();
feeCategoryContainerElement.insertAdjacentHTML("beforeend", "<div class=\"level is-mobile\">" +
("<div class=\"level-left\">" +
"<div class=\"level-item\">" +
"<h2 class=\"title is-4\">" + cityssm.escapeHTML(feeCategory.feeCategory) + "</h2>" +
"</div>" +
"</div>") +
("<div class=\"level-right\">" +
(feeCategory.fees.length === 0 ?
"<div class=\"level-item\">" +
"<button class=\"button is-small is-danger button--deleteFeeCategory\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-trash\" aria-hidden=\"true\"></i></span>" +
"<span>Delete Category</span>" +
"</button>" +
"</div>" :
"") +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-primary button--editFeeCategory\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-pencil-alt\" aria-hidden=\"true\"></i></span>" +
"<span>Edit Category</span>" +
"</button>" +
"</div>" +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-success button--addFee\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-plus\" aria-hidden=\"true\"></i></span>" +
"<span>Add Fee</span>" +
"</button>" +
"</div>" +
"</div>") +
"</div>");
if (feeCategory.fees.length === 0) {
feeCategoryContainerElement.insertAdjacentHTML("beforeend", "<div class=\"message is-info\">" +
"<p class=\"message-body\">There are no fees in the \"" + cityssm.escapeHTML(feeCategory.feeCategory) + "\" category.</p>" +
"</div>");
}
else {
const panelElement = document.createElement("div");
panelElement.className = "panel";
for (const fee of feeCategory.fees) {
const panelBlockElement = document.createElement("a");
panelBlockElement.className = "panel-block is-block container--fee";
panelBlockElement.dataset.feeId = fee.feeId.toString();
panelBlockElement.innerHTML = "<div class=\"columns\">" +
("<div class=\"column is-half\">" +
"<p>" +
"<strong>" + cityssm.escapeHTML(fee.feeName) + "</strong><br />" +
"<small>" + cityssm.escapeHTML(fee.feeDescription).replace(/\n/g, "<br />") + "</small>" +
"</p>" +
"<p class=\"tags\">" +
(fee.isRequired ?
"<span class=\"tag is-warning\">Required</span>" :
"") +
(fee.occupancyTypeId ?
" <span class=\"tag has-tooltip-bottom\" data-tooltip=\"" + cityssm.escapeHTML(exports.aliases.occupancy) + " Type Filter\">" +
cityssm.escapeHTML(fee.occupancyType) + "</span>" :
"") +
(fee.lotTypeId ?
" <span class=\"tag has-tooltip-bottom\" data-tooltip=\"" + cityssm.escapeHTML(exports.aliases.lot) + " Type Filter\">" +
cityssm.escapeHTML(fee.lotType) + "</span>" :
"") +
"</p>" +
"</div>") +
("<div class=\"column has-text-centered\">" +
(fee.feeFunction ?
cityssm.escapeHTML(fee.feeFunction) + "<br />" +
"<small>Fee Function</small>" :
"$" + fee.feeAmount.toFixed(2) + "<br />" +
"<small>Fee</small>") +
"</div>") +
("<div class=\"column has-text-centered\">" +
(fee.taxPercentage ?
fee.taxPercentage + "%" :
"$" + fee.taxAmount.toFixed(2)) +
"<br /><small>Tax</small>" +
"</div>") +
("<div class=\"column has-text-centered\">" +
(fee.includeQuantity ?
cityssm.escapeHTML(fee.quantityUnit) + "<br />" +
"<small>Quantity</small>" :
"") +
"</div>") +
"</div>";
panelBlockElement.addEventListener("click", openEditFee);
panelElement.append(panelBlockElement);
}
feeCategoryContainerElement.append(panelElement);
}
feeCategoriesContainerElement.append(feeCategoryContainerElement);
}
const deleteCategoryButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--deleteFeeCategory");
for (const deleteCategoryButtonElement of deleteCategoryButtonElements) {
deleteCategoryButtonElement.addEventListener("click", confirmDeleteFeeCategory);
}
const editCategoryButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--editFeeCategory");
for (const editCategoryButtonElement of editCategoryButtonElements) {
editCategoryButtonElement.addEventListener("click", openEditFeeCategory);
}
const addFeeButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--addFee");
for (const addFeeButtonElement of addFeeButtonElements) {
addFeeButtonElement.addEventListener("click", openAddFee);
}
};
document.querySelector("#button--addFeeCategory").addEventListener("click", () => {
let addCloseModalFunction;
const doAddFeeCategory = (submitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/admin/doAddFeeCategory", submitEvent.currentTarget, (responseJSON) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
addCloseModalFunction();
renderFeeCategories();
}
else {
bulmaJS.alert({
title: "Error Creating Fee Category",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("adminFees-addFeeCategory", {
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
modalElement.querySelector("#feeCategoryAdd--feeCategory").focus();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddFeeCategory);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
const openEditFeeCategory = (clickEvent) => {
const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest(".container--feeCategory").dataset.feeCategoryId, 10);
const feeCategory = feeCategories.find((currentFeeCategory) => {
@ -43,11 +187,54 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
});
};
const confirmDeleteFeeCategory = (clickEvent) => {
const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest(".container--feeCategory").dataset.feeCategoryId, 10);
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/admin/doDeleteFeeCategory", {
feeCategoryId
}, (responseJSON) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
renderFeeCategories();
}
else {
bulmaJS.alert({
title: "Error Updating Fee Category",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
bulmaJS.confirm({
title: "Delete Fee Category?",
message: "Are you sure you want to delete this fee category?",
contextualColorName: "warning",
okButton: {
text: "Yes, Delete the Fee Category",
callbackFunction: doDelete
}
});
};
const openAddFee = (clickEvent) => {
const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest(".container--feeCategory").dataset.feeCategoryId, 10);
let addCloseModalFunction;
const doAddFee = (submitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/admin/doAddFee", submitEvent.currentTarget, (responseJSON) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
addCloseModalFunction();
renderFeeCategories();
}
else {
bulmaJS.alert({
title: "Error Adding Fee",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("adminFees-addFee", {
onshow: (modalElement) => {
@ -75,102 +262,209 @@ Object.defineProperty(exports, "__esModule", { value: true });
optionElement.textContent = lotType.lotType;
lotTypeElement.append(optionElement);
}
modalElement.querySelector("#feeAdd--taxPercentage").value = exports.taxPercentageDefault.toString();
los.populateAliases(modalElement);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddFee);
modalElement.querySelector("#feeAdd--feeFunction").addEventListener("change", () => {
const feeAmountElement = modalElement.querySelector("#feeAdd--feeAmount");
const feeFunctionElement = modalElement.querySelector("#feeAdd--feeFunction");
if (feeFunctionElement.value === "") {
feeFunctionElement.closest(".select").classList.remove("is-success");
feeAmountElement.classList.add("is-success");
feeAmountElement.disabled = false;
}
else {
feeFunctionElement.closest(".select").classList.add("is-success");
feeAmountElement.classList.remove("is-success");
feeAmountElement.disabled = true;
}
});
modalElement.querySelector("#feeAdd--taxPercentage").addEventListener("keyup", () => {
const taxAmountElement = modalElement.querySelector("#feeAdd--taxAmount");
const taxPercentageElement = modalElement.querySelector("#feeAdd--taxPercentage");
if (taxPercentageElement.value === "") {
taxPercentageElement.classList.remove("is-success");
taxAmountElement.classList.add("is-success");
taxAmountElement.disabled = false;
}
else {
taxPercentageElement.classList.add("is-success");
taxAmountElement.classList.remove("is-success");
taxAmountElement.disabled = true;
}
});
modalElement.querySelector("#feeAdd--includeQuantity").addEventListener("change", () => {
modalElement.querySelector("#feeAdd--quantityUnit").disabled =
modalElement.querySelector("#feeAdd--includeQuantity").value === "";
});
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
};
const renderFeeCategories = () => {
if (feeCategories.length === 0) {
feeCategoriesContainerElement.innerHTML = "<div class=\"message is-warning\">" +
"<p class=\"message-body\">There are no available fees.</p>" +
"</div>";
return;
}
feeCategoriesContainerElement.innerHTML = "";
for (const feeCategory of feeCategories) {
const feeCategoryContainerElement = document.createElement("section");
feeCategoryContainerElement.className = "container--feeCategory";
feeCategoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString();
feeCategoryContainerElement.insertAdjacentHTML("beforeend", "<div class=\"level is-mobile\">" +
("<div class=\"level-left\">" +
"<div class=\"level-item\">" +
"<h2 class=\"title is-4\">" + cityssm.escapeHTML(feeCategory.feeCategory) + "</h2>" +
"</div>" +
"</div>") +
("<div class=\"level-right\">" +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-primary button--editFeeCategory\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-pencil-alt\" aria-hidden=\"true\"></i></span>" +
"<span>Edit Category</span>" +
"</button>" +
"</div>" +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-success button--addFee\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-plus\" aria-hidden=\"true\"></i></span>" +
"<span>Add Fee</span>" +
"</button>" +
"</div>" +
"</div>") +
"</div>");
if (feeCategory.fees.length === 0) {
feeCategoryContainerElement.insertAdjacentHTML("beforeend", "<div class=\"message is-info\">" +
"<p class=\"message-body\">There are no fees in the \"" + cityssm.escapeHTML(feeCategory.feeCategory) + "\" category.</p>" +
"</div>");
}
else {
const panelElement = document.createElement("div");
panelElement.className = "panel";
feeCategoryContainerElement.append(panelElement);
}
feeCategoriesContainerElement.append(feeCategoryContainerElement);
}
const editCategoryButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--editFeeCategory");
for (const editCategoryButtonElement of editCategoryButtonElements) {
editCategoryButtonElement.addEventListener("click", openEditFeeCategory);
}
const addFeeButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--addFee");
for (const addFeeButtonElement of addFeeButtonElements) {
addFeeButtonElement.addEventListener("click", openAddFee);
}
};
renderFeeCategories();
document.querySelector("#button--addFeeCategory").addEventListener("click", () => {
let addCloseModalFunction;
const doAddFeeCategory = (submitEvent) => {
const openEditFee = (clickEvent) => {
clickEvent.preventDefault();
const feeId = Number.parseInt(clickEvent.currentTarget.dataset.feeId, 10);
const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest(".container--feeCategory").dataset.feeCategoryId);
const feeCategory = feeCategories.find((currentFeeCategory) => {
return currentFeeCategory.feeCategoryId === feeCategoryId;
});
const fee = feeCategory.fees.find((currentFee) => {
return currentFee.feeId === feeId;
});
let editCloseModalFunction;
let editModalElement;
const doUpdateFee = (submitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/admin/doAddFeeCategory", submitEvent.currentTarget, (responseJSON) => {
cityssm.postJSON(urlPrefix + "/admin/doUpdateFee", submitEvent.currentTarget, (responseJSON) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
addCloseModalFunction();
editCloseModalFunction();
renderFeeCategories();
}
else {
bulmaJS.alert({
title: "Error Creating Fee Category",
title: "Error Updating Fee",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("adminFees-addFeeCategory", {
const confirmDeleteFee = (clickEvent) => {
clickEvent.preventDefault();
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/admin/doDeleteFee", {
feeId
}, (responseJSON) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
editCloseModalFunction();
renderFeeCategories();
}
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 the Fee",
callbackFunction: doDelete
}
});
};
const toggleFeeFields = () => {
const feeAmountElement = editModalElement.querySelector("#feeEdit--feeAmount");
const feeFunctionElement = editModalElement.querySelector("#feeEdit--feeFunction");
if (feeFunctionElement.value === "") {
feeFunctionElement.closest(".select").classList.remove("is-success");
feeAmountElement.classList.add("is-success");
feeAmountElement.disabled = false;
}
else {
feeFunctionElement.closest(".select").classList.add("is-success");
feeAmountElement.classList.remove("is-success");
feeAmountElement.disabled = true;
}
};
const toggleTaxFields = () => {
const taxAmountElement = editModalElement.querySelector("#feeEdit--taxAmount");
const taxPercentageElement = editModalElement.querySelector("#feeEdit--taxPercentage");
if (taxPercentageElement.value === "") {
taxPercentageElement.classList.remove("is-success");
taxAmountElement.classList.add("is-success");
taxAmountElement.disabled = false;
}
else {
taxPercentageElement.classList.add("is-success");
taxAmountElement.classList.remove("is-success");
taxAmountElement.disabled = true;
}
};
const toggleQuantityFields = () => {
editModalElement.querySelector("#feeEdit--quantityUnit").disabled =
editModalElement.querySelector("#feeEdit--includeQuantity").value === "";
};
cityssm.openHtmlModal("adminFees-editFee", {
onshow: (modalElement) => {
editModalElement = modalElement;
modalElement.querySelector("#feeEdit--feeId").value = fee.feeId.toString();
const feeCategoryElement = modalElement.querySelector("#feeEdit--feeCategoryId");
for (const feeCategory of feeCategories) {
const optionElement = document.createElement("option");
optionElement.value = feeCategory.feeCategoryId.toString();
optionElement.textContent = feeCategory.feeCategory;
if (feeCategory.feeCategoryId === feeCategoryId) {
optionElement.selected = true;
}
feeCategoryElement.append(optionElement);
}
modalElement.querySelector("#feeEdit--feeName").value = fee.feeName;
modalElement.querySelector("#feeEdit--feeDescription").value = fee.feeDescription;
const occupancyTypeElement = modalElement.querySelector("#feeEdit--occupancyTypeId");
for (const occupancyType of exports.occupancyTypes) {
const optionElement = document.createElement("option");
optionElement.value = occupancyType.occupancyTypeId.toString();
optionElement.textContent = occupancyType.occupancyType;
if (occupancyType.occupancyTypeId === fee.occupancyTypeId) {
optionElement.selected = true;
}
occupancyTypeElement.append(optionElement);
}
const lotTypeElement = modalElement.querySelector("#feeEdit--lotTypeId");
for (const lotType of exports.lotTypes) {
const optionElement = document.createElement("option");
optionElement.value = lotType.lotTypeId.toString();
optionElement.textContent = lotType.lotType;
if (lotType.lotTypeId === fee.lotTypeId) {
optionElement.selected = true;
}
lotTypeElement.append(optionElement);
}
modalElement.querySelector("#feeEdit--feeAmount").value = fee.feeAmount ? fee.feeAmount.toFixed(2) : "";
modalElement.querySelector("#feeEdit--feeFunction").addEventListener("change", toggleFeeFields);
toggleFeeFields();
modalElement.querySelector("#feeEdit--taxAmount").value = fee.taxAmount ? fee.taxAmount.toFixed(2) : "";
const taxPercentageElement = modalElement.querySelector("#feeEdit--taxPercentage");
taxPercentageElement.value = fee.taxPercentage ? fee.taxPercentage.toString() : "";
taxPercentageElement.addEventListener("keyup", toggleTaxFields);
toggleTaxFields();
const includeQuantityElement = modalElement.querySelector("#feeEdit--includeQuantity");
if (fee.includeQuantity) {
includeQuantityElement.value = "1";
}
includeQuantityElement.addEventListener("change", toggleQuantityFields);
modalElement.querySelector("#feeEdit--quantityUnit").value = fee.quantityUnit || "";
toggleQuantityFields();
if (fee.isRequired) {
modalElement.querySelector("#feeEdit--isRequired").value = "1";
}
los.populateAliases(modalElement);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
modalElement.querySelector("#feeCategoryAdd--feeCategory").focus();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddFeeCategory);
editCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doUpdateFee);
bulmaJS.init(modalElement);
modalElement.querySelector(".button--deleteFee").addEventListener("click", confirmDeleteFee);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
};
renderFeeCategories();
})();

View File

@ -24,6 +24,189 @@ declare const bulmaJS: BulmaJS;
let feeCategories: recordTypes.FeeCategory[] = exports.feeCategories;
const renderFeeCategories = () => {
if (feeCategories.length === 0) {
feeCategoriesContainerElement.innerHTML = "<div class=\"message is-warning\">" +
"<p class=\"message-body\">There are no available fees.</p>" +
"</div>";
return;
}
feeCategoriesContainerElement.innerHTML = "";
for (const feeCategory of feeCategories) {
const feeCategoryContainerElement = document.createElement("section");
feeCategoryContainerElement.className = "container--feeCategory mb-5";
feeCategoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString();
feeCategoryContainerElement.insertAdjacentHTML("beforeend",
"<div class=\"level is-mobile\">" +
("<div class=\"level-left\">" +
"<div class=\"level-item\">" +
"<h2 class=\"title is-4\">" + cityssm.escapeHTML(feeCategory.feeCategory) + "</h2>" +
"</div>" +
"</div>") +
("<div class=\"level-right\">" +
(feeCategory.fees.length === 0 ?
"<div class=\"level-item\">" +
"<button class=\"button is-small is-danger button--deleteFeeCategory\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-trash\" aria-hidden=\"true\"></i></span>" +
"<span>Delete Category</span>" +
"</button>" +
"</div>" :
"") +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-primary button--editFeeCategory\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-pencil-alt\" aria-hidden=\"true\"></i></span>" +
"<span>Edit Category</span>" +
"</button>" +
"</div>" +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-success button--addFee\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-plus\" aria-hidden=\"true\"></i></span>" +
"<span>Add Fee</span>" +
"</button>" +
"</div>" +
"</div>") +
"</div>");
if (feeCategory.fees.length === 0) {
feeCategoryContainerElement.insertAdjacentHTML("beforeend",
"<div class=\"message is-info\">" +
"<p class=\"message-body\">There are no fees in the \"" + cityssm.escapeHTML(feeCategory.feeCategory) + "\" category.</p>" +
"</div>");
} else {
const panelElement = document.createElement("div");
panelElement.className = "panel";
for (const fee of feeCategory.fees) {
const panelBlockElement = document.createElement("a");
panelBlockElement.className = "panel-block is-block container--fee";
panelBlockElement.dataset.feeId = fee.feeId.toString();
panelBlockElement.innerHTML = "<div class=\"columns\">" +
("<div class=\"column is-half\">" +
"<p>" +
"<strong>" + cityssm.escapeHTML(fee.feeName) + "</strong><br />" +
"<small>" + cityssm.escapeHTML(fee.feeDescription).replace(/\n/g, "<br />") + "</small>" +
"</p>" +
"<p class=\"tags\">" +
(fee.isRequired ?
"<span class=\"tag is-warning\">Required</span>" :
"") +
(fee.occupancyTypeId ?
" <span class=\"tag has-tooltip-bottom\" data-tooltip=\"" + cityssm.escapeHTML(exports.aliases.occupancy) + " Type Filter\">" +
cityssm.escapeHTML(fee.occupancyType) + "</span>" :
"") +
(fee.lotTypeId ?
" <span class=\"tag has-tooltip-bottom\" data-tooltip=\"" + cityssm.escapeHTML(exports.aliases.lot) + " Type Filter\">" +
cityssm.escapeHTML(fee.lotType) + "</span>" :
"") +
"</p>" +
"</div>") +
("<div class=\"column has-text-centered\">" +
(fee.feeFunction ?
cityssm.escapeHTML(fee.feeFunction) + "<br />" +
"<small>Fee Function</small>" :
"$" + fee.feeAmount.toFixed(2) + "<br />" +
"<small>Fee</small>") +
"</div>") +
("<div class=\"column has-text-centered\">" +
(fee.taxPercentage ?
fee.taxPercentage + "%" :
"$" + fee.taxAmount.toFixed(2)) +
"<br /><small>Tax</small>" +
"</div>") +
("<div class=\"column has-text-centered\">" +
(fee.includeQuantity ?
cityssm.escapeHTML(fee.quantityUnit) + "<br />" +
"<small>Quantity</small>" :
"") +
"</div>") +
"</div>";
panelBlockElement.addEventListener("click", openEditFee);
panelElement.append(panelBlockElement);
}
feeCategoryContainerElement.append(panelElement);
}
feeCategoriesContainerElement.append(feeCategoryContainerElement);
}
const deleteCategoryButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--deleteFeeCategory");
for (const deleteCategoryButtonElement of deleteCategoryButtonElements) {
deleteCategoryButtonElement.addEventListener("click", confirmDeleteFeeCategory);
}
const editCategoryButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--editFeeCategory");
for (const editCategoryButtonElement of editCategoryButtonElements) {
editCategoryButtonElement.addEventListener("click", openEditFeeCategory);
}
const addFeeButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--addFee");
for (const addFeeButtonElement of addFeeButtonElements) {
addFeeButtonElement.addEventListener("click", openAddFee);
}
};
/*
* Fee Categories
*/
document.querySelector("#button--addFeeCategory").addEventListener("click", () => {
let addCloseModalFunction: () => void;
const doAddFeeCategory = (submitEvent: SubmitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/admin/doAddFeeCategory",
submitEvent.currentTarget,
(responseJSON: {
success: boolean;errorMessage ? : string;feeCategories: recordTypes.FeeCategory[];
}) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
addCloseModalFunction();
renderFeeCategories();
} else {
bulmaJS.alert({
title: "Error Creating Fee Category",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("adminFees-addFeeCategory", {
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
(modalElement.querySelector("#feeCategoryAdd--feeCategory") as HTMLInputElement).focus();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddFeeCategory);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
const openEditFeeCategory = (clickEvent: Event) => {
const feeCategoryId = Number.parseInt(((clickEvent.currentTarget as HTMLElement).closest(".container--feeCategory") as HTMLElement).dataset.feeCategoryId, 10);
@ -77,6 +260,45 @@ declare const bulmaJS: BulmaJS;
});
};
const confirmDeleteFeeCategory = (clickEvent: Event) => {
const feeCategoryId = Number.parseInt(((clickEvent.currentTarget as HTMLElement).closest(".container--feeCategory") as HTMLElement).dataset.feeCategoryId, 10);
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/admin/doDeleteFeeCategory", {
feeCategoryId
},
(responseJSON: {success: boolean; errorMessage?: string; feeCategories?: recordTypes.FeeCategory[];}) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
renderFeeCategories();
} else {
bulmaJS.alert({
title: "Error Updating Fee Category",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
bulmaJS.confirm({
title: "Delete Fee Category?",
message: "Are you sure you want to delete this fee category?",
contextualColorName: "warning",
okButton: {
text: "Yes, Delete the Fee Category",
callbackFunction: doDelete
}
})
};
/*
* Fees
*/
const openAddFee = (clickEvent: Event) => {
const feeCategoryId = Number.parseInt(((clickEvent.currentTarget as HTMLElement).closest(".container--feeCategory") as HTMLElement).dataset.feeCategoryId, 10);
@ -85,6 +307,25 @@ declare const bulmaJS: BulmaJS;
const doAddFee = (submitEvent: SubmitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/admin/doAddFee",
submitEvent.currentTarget,
(responseJSON: {
success: boolean;errorMessage ? : string;feeCategories: recordTypes.FeeCategory[];
}) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
addCloseModalFunction();
renderFeeCategories();
} else {
bulmaJS.alert({
title: "Error Adding Fee",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("adminFees-addFee", {
@ -125,14 +366,61 @@ declare const bulmaJS: BulmaJS;
lotTypeElement.append(optionElement);
}
(modalElement.querySelector("#feeAdd--taxPercentage") as HTMLInputElement).value = (exports.taxPercentageDefault as number).toString();
los.populateAliases(modalElement);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddFee);
modalElement.querySelector("#feeAdd--feeFunction").addEventListener("change", () => {
const feeAmountElement = modalElement.querySelector("#feeAdd--feeAmount") as HTMLInputElement;
const feeFunctionElement = modalElement.querySelector("#feeAdd--feeFunction") as HTMLSelectElement;
if (feeFunctionElement.value === "") {
feeFunctionElement.closest(".select").classList.remove("is-success");
feeAmountElement.classList.add("is-success");
feeAmountElement.disabled = false;
} else {
feeFunctionElement.closest(".select").classList.add("is-success");
feeAmountElement.classList.remove("is-success");
feeAmountElement.disabled = true;
}
});
modalElement.querySelector("#feeAdd--taxPercentage").addEventListener("keyup", () => {
const taxAmountElement = modalElement.querySelector("#feeAdd--taxAmount") as HTMLInputElement;
const taxPercentageElement = modalElement.querySelector("#feeAdd--taxPercentage") as HTMLInputElement;
if (taxPercentageElement.value === "") {
taxPercentageElement.classList.remove("is-success");
taxAmountElement.classList.add("is-success");
taxAmountElement.disabled = false;
} else {
taxPercentageElement.classList.add("is-success");
taxAmountElement.classList.remove("is-success");
taxAmountElement.disabled = true;
}
});
modalElement.querySelector("#feeAdd--includeQuantity").addEventListener("change", () => {
(modalElement.querySelector("#feeAdd--quantityUnit") as HTMLInputElement).disabled =
(modalElement.querySelector("#feeAdd--includeQuantity") as HTMLSelectElement).value === "";
});
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
@ -140,102 +428,41 @@ declare const bulmaJS: BulmaJS;
});
};
const renderFeeCategories = () => {
const openEditFee = (clickEvent: Event) => {
clickEvent.preventDefault();
if (feeCategories.length === 0) {
feeCategoriesContainerElement.innerHTML = "<div class=\"message is-warning\">" +
"<p class=\"message-body\">There are no available fees.</p>" +
"</div>";
const feeId = Number.parseInt((clickEvent.currentTarget as HTMLElement).dataset.feeId, 10);
const feeCategoryId = Number.parseInt(((clickEvent.currentTarget as HTMLElement).closest(".container--feeCategory") as HTMLElement).dataset.feeCategoryId);
return;
}
const feeCategory = feeCategories.find((currentFeeCategory) => {
return currentFeeCategory.feeCategoryId === feeCategoryId;
});
feeCategoriesContainerElement.innerHTML = "";
const fee = feeCategory.fees.find((currentFee) => {
return currentFee.feeId === feeId;
});
for (const feeCategory of feeCategories) {
let editCloseModalFunction: () => void;
let editModalElement: HTMLElement;
const feeCategoryContainerElement = document.createElement("section");
feeCategoryContainerElement.className = "container--feeCategory";
feeCategoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString();
feeCategoryContainerElement.insertAdjacentHTML("beforeend",
"<div class=\"level is-mobile\">" +
("<div class=\"level-left\">" +
"<div class=\"level-item\">" +
"<h2 class=\"title is-4\">" + cityssm.escapeHTML(feeCategory.feeCategory) + "</h2>" +
"</div>" +
"</div>") +
("<div class=\"level-right\">" +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-primary button--editFeeCategory\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-pencil-alt\" aria-hidden=\"true\"></i></span>" +
"<span>Edit Category</span>" +
"</button>" +
"</div>" +
"<div class=\"level-item\">" +
"<button class=\"button is-small is-success button--addFee\" type=\"button\">" +
"<span class=\"icon is-small\"><i class=\"fas fa-plus\" aria-hidden=\"true\"></i></span>" +
"<span>Add Fee</span>" +
"</button>" +
"</div>" +
"</div>") +
"</div>");
if (feeCategory.fees.length === 0) {
feeCategoryContainerElement.insertAdjacentHTML("beforeend",
"<div class=\"message is-info\">" +
"<p class=\"message-body\">There are no fees in the \"" + cityssm.escapeHTML(feeCategory.feeCategory) + "\" category.</p>" +
"</div>");
} else {
const panelElement = document.createElement("div");
panelElement.className = "panel";
feeCategoryContainerElement.append(panelElement);
}
feeCategoriesContainerElement.append(feeCategoryContainerElement);
}
const editCategoryButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--editFeeCategory");
for (const editCategoryButtonElement of editCategoryButtonElements) {
editCategoryButtonElement.addEventListener("click", openEditFeeCategory);
}
const addFeeButtonElements = feeCategoriesContainerElement.querySelectorAll(".button--addFee");
for (const addFeeButtonElement of addFeeButtonElements) {
addFeeButtonElement.addEventListener("click", openAddFee);
}
};
renderFeeCategories();
/*
* Fee Categories
*/
document.querySelector("#button--addFeeCategory").addEventListener("click", () => {
let addCloseModalFunction: () => void;
const doAddFeeCategory = (submitEvent: SubmitEvent) => {
const doUpdateFee = (submitEvent: SubmitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/admin/doAddFeeCategory",
cityssm.postJSON(urlPrefix + "/admin/doUpdateFee",
submitEvent.currentTarget,
(responseJSON: {
success: boolean;errorMessage ? : string;feeCategories: recordTypes.FeeCategory[];
success: boolean;
errorMessage ? : string;
feeCategories ? : recordTypes.FeeCategory[];
}) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
addCloseModalFunction();
editCloseModalFunction();
renderFeeCategories();
} else {
bulmaJS.alert({
title: "Error Creating Fee Category",
title: "Error Updating Fee",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
@ -243,18 +470,196 @@ declare const bulmaJS: BulmaJS;
});
};
cityssm.openHtmlModal("adminFees-addFeeCategory", {
const confirmDeleteFee = (clickEvent: Event) => {
clickEvent.preventDefault();
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/admin/doDeleteFee", {
feeId
},
(responseJSON: {
success: boolean;
errorMessage ? : string;
feeCategories ? : recordTypes.FeeCategory[];
}) => {
if (responseJSON.success) {
feeCategories = responseJSON.feeCategories;
editCloseModalFunction();
renderFeeCategories();
} 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 the Fee",
callbackFunction: doDelete
}
});
};
const toggleFeeFields = () => {
const feeAmountElement = editModalElement.querySelector("#feeEdit--feeAmount") as HTMLInputElement;
const feeFunctionElement = editModalElement.querySelector("#feeEdit--feeFunction") as HTMLSelectElement;
if (feeFunctionElement.value === "") {
feeFunctionElement.closest(".select").classList.remove("is-success");
feeAmountElement.classList.add("is-success");
feeAmountElement.disabled = false;
} else {
feeFunctionElement.closest(".select").classList.add("is-success");
feeAmountElement.classList.remove("is-success");
feeAmountElement.disabled = true;
}
};
const toggleTaxFields = () => {
const taxAmountElement = editModalElement.querySelector("#feeEdit--taxAmount") as HTMLInputElement;
const taxPercentageElement = editModalElement.querySelector("#feeEdit--taxPercentage") as HTMLInputElement;
if (taxPercentageElement.value === "") {
taxPercentageElement.classList.remove("is-success");
taxAmountElement.classList.add("is-success");
taxAmountElement.disabled = false;
} else {
taxPercentageElement.classList.add("is-success");
taxAmountElement.classList.remove("is-success");
taxAmountElement.disabled = true;
}
};
const toggleQuantityFields = () => {
(editModalElement.querySelector("#feeEdit--quantityUnit") as HTMLInputElement).disabled =
(editModalElement.querySelector("#feeEdit--includeQuantity") as HTMLSelectElement).value === "";
};
cityssm.openHtmlModal("adminFees-editFee", {
onshow: (modalElement) => {
editModalElement = modalElement;
(modalElement.querySelector("#feeEdit--feeId") as HTMLInputElement).value = fee.feeId.toString();
const feeCategoryElement = modalElement.querySelector("#feeEdit--feeCategoryId") as HTMLSelectElement;
for (const feeCategory of feeCategories) {
const optionElement = document.createElement("option");
optionElement.value = feeCategory.feeCategoryId.toString();
optionElement.textContent = feeCategory.feeCategory;
if (feeCategory.feeCategoryId === feeCategoryId) {
optionElement.selected = true;
}
feeCategoryElement.append(optionElement);
}
(modalElement.querySelector("#feeEdit--feeName") as HTMLInputElement).value = fee.feeName;
(modalElement.querySelector("#feeEdit--feeDescription") as HTMLTextAreaElement).value = fee.feeDescription;
const occupancyTypeElement = modalElement.querySelector("#feeEdit--occupancyTypeId") as HTMLSelectElement;
for (const occupancyType of exports.occupancyTypes as recordTypes.OccupancyType[]) {
const optionElement = document.createElement("option");
optionElement.value = occupancyType.occupancyTypeId.toString();
optionElement.textContent = occupancyType.occupancyType;
if (occupancyType.occupancyTypeId === fee.occupancyTypeId) {
optionElement.selected = true;
}
occupancyTypeElement.append(optionElement);
}
const lotTypeElement = modalElement.querySelector("#feeEdit--lotTypeId") as HTMLSelectElement;
for (const lotType of exports.lotTypes as recordTypes.LotType[]) {
const optionElement = document.createElement("option");
optionElement.value = lotType.lotTypeId.toString();
optionElement.textContent = lotType.lotType;
if (lotType.lotTypeId === fee.lotTypeId) {
optionElement.selected = true;
}
lotTypeElement.append(optionElement);
}
(modalElement.querySelector("#feeEdit--feeAmount") as HTMLInputElement).value = fee.feeAmount ? fee.feeAmount.toFixed(2) : "";
modalElement.querySelector("#feeEdit--feeFunction").addEventListener("change", toggleFeeFields);
toggleFeeFields();
(modalElement.querySelector("#feeEdit--taxAmount") as HTMLInputElement).value = fee.taxAmount ? fee.taxAmount.toFixed(2) : "";
const taxPercentageElement = modalElement.querySelector("#feeEdit--taxPercentage") as HTMLInputElement;
taxPercentageElement.value = fee.taxPercentage ? fee.taxPercentage.toString() : "";
taxPercentageElement.addEventListener("keyup", toggleTaxFields);
toggleTaxFields();
const includeQuantityElement = modalElement.querySelector("#feeEdit--includeQuantity") as HTMLSelectElement;
if (fee.includeQuantity) {
includeQuantityElement.value = "1";
}
includeQuantityElement.addEventListener("change", toggleQuantityFields);
(modalElement.querySelector("#feeEdit--quantityUnit") as HTMLInputElement).value = fee.quantityUnit || "";
toggleQuantityFields();
if (fee.isRequired) {
(modalElement.querySelector("#feeEdit--isRequired") as HTMLSelectElement).value = "1";
}
los.populateAliases(modalElement);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
(modalElement.querySelector("#feeCategoryAdd--feeCategory") as HTMLInputElement).focus();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddFeeCategory);
bulmaJS.toggleHtmlClipped();
editCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doUpdateFee);
bulmaJS.init(modalElement);
modalElement.querySelector(".button--deleteFee").addEventListener("click", confirmDeleteFee);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
};
/*
* Initialize
*/
renderFeeCategories();
})();

View File

@ -18,7 +18,7 @@
</div>
</div>
<div class="field">
<label class="label" for="feeAdd--feeName">Fee</label>
<label class="label" for="feeAdd--feeName">Fee Name</label>
<div class="control">
<input class="input" id="feeAdd--feeName" name="feeName" maxlength="100" required />
</div>
@ -29,6 +29,16 @@
<textarea class="textarea" id="feeAdd--feeDescription" name="feeDescription"></textarea>
</div>
</div>
<div class="message is-info is-small">
<p class="message-body">
Filters can be used to show or hide available filters 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.
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
@ -55,12 +65,20 @@
</div>
</div>
</div>
<div class="message is-info is-small">
<p class="message-body">
Fees can be simply flat amounts,
or calculated by functions defined by the application administrator.
Note that if both an amount and a function are set,
<strong>the function will be used.</strong>
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeAdd--feeAmount">Fee Amount</label>
<div class="control has-icons-left">
<input class="input has-text-right" id="feeAdd--feeAmount" name="feeAmount" type="number" step="0.01" min="0" max="9999.99" value="0" onwheel="return false" />
<input class="input has-text-right is-success" id="feeAdd--feeAmount" name="feeAmount" type="number" step="0.01" min="0" max="9999.99" value="0" onwheel="return false" />
<span class="icon is-small is-left">
<i class="fas fa-dollar-sign" aria-hidden="true"></i>
</span>
@ -72,18 +90,29 @@
<label class="label" for="feeAdd--feeFunction">Fee Function</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeAdd--feeFunction" name="feeFunction"></select>
<select id="feeAdd--feeFunction" name="feeFunction">
<option value="">(No Function Selected)</option>
<option value="t">test</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="message is-info is-small">
<p class="message-body">
Taxes can be defined as flat amounts,
or as percentages of the fee amount.
Note that if both an amount and a percentage are set,
<strong>the percentage will be used.</strong>
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeAdd--taxAmount">Tax Amount</label>
<div class="control has-icons-left">
<input class="input has-text-right" id="feeAdd--taxAmount" name="taxAmount" type="number" step="0.01" min="0" max="9999.99" onwheel="return false" />
<input class="input has-text-right" id="feeAdd--taxAmount" name="taxAmount" type="number" step="0.01" min="0" max="9999.99" onwheel="return false" disabled />
<span class="icon is-small is-left">
<i class="fas fa-dollar-sign" aria-hidden="true"></i>
</span>
@ -94,7 +123,7 @@
<div class="field">
<label class="label" for="feeAdd--taxPercentage">Tax Percentage</label>
<div class="control has-icons-right">
<input class="input has-text-right" id="feeAdd--taxPercentage" name="taxPercentage" type="number" step="0.01" min="0" max="100" value="0" onwheel="return false" />
<input class="input has-text-right is-success" id="feeAdd--taxPercentage" name="taxPercentage" type="number" step="0.01" min="0" max="100" value="0" onwheel="return false" />
<span class="icon is-small is-right">
<i class="fas fa-percent" aria-hidden="true"></i>
</span>
@ -102,6 +131,40 @@
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeAdd--includeQuantity">Include Quantity</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeAdd--includeQuantity" name="includeQuantity">
<option value="" selected>No Quantity</option>
<option value="1">Quantity Available</option>
</select>
</div>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="feeAdd--quantityUnit">Quantity Unit</label>
<div class="control">
<input class="input" id="feeAdd--quantityUnit" name="quantityUnit" maxlength="30" disabled required />
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="feeAdd--isRequired">Fee Is Required</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeAdd--isRequired" name="isRequired">
<option value="" selected>No, Fee is Optional</option>
<option value="1">Yes, Fee is Required</option>
</select>
</div>
</div>
</div>
</form>
</section>
<footer class="modal-card-foot justify-right">

View File

@ -0,0 +1,196 @@
<div class="modal">
<div class="modal-background"></div>
<div class="modal-card" style="width:900px">
<header class="modal-card-head">
<h3 class="modal-card-title">
Update Fee
</h3>
<button class="delete is-close-modal-button" aria-label="close" type="button"></button>
</header>
<section class="modal-card-body">
<form id="form--feeEdit">
<input id="feeEdit--feeId" name="feeId" type="hidden" />
<div class="field">
<label class="label" for="feeEdit--feeCategoryId">Fee Category</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeEdit--feeCategoryId" name="feeCategoryId" required></select>
</div>
</div>
</div>
<div class="field">
<label class="label" for="feeEdit--feeName">Fee Name</label>
<div class="control">
<input class="input" id="feeEdit--feeName" name="feeName" maxlength="100" required />
</div>
</div>
<div class="field">
<label class="label" for="feeEdit--feeDescription">Fee Description</label>
<div class="control">
<textarea class="textarea" id="feeEdit--feeDescription" name="feeDescription"></textarea>
</div>
</div>
<div class="message is-info is-small">
<p class="message-body">
Filters can be used to show or hide available filters 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.
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeEdit--occupancyTypeId"><span class="alias" data-alias="Occupancy"></span> Type Filter</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeEdit--occupancyTypeId" name="occupancyTypeId">
<option value="">(All Types)</option>
</select>
</div>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="feeEdit--lotTypeId"><span class="alias" data-alias="Lot"></span> Type Filter</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeEdit--lotTypeId" name="lotTypeId">
<option value="">(All Types)</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="message is-info is-small">
<p class="message-body">
Fees can be simply flat amounts,
or calculated by functions defined by the application administrator.
Note that if both an amount and a function are set,
<strong>the function will be used.</strong>
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeEdit--feeAmount">Fee Amount</label>
<div class="control has-icons-left">
<input class="input has-text-right" id="feeEdit--feeAmount" name="feeAmount" type="number" step="0.01" min="0" max="9999.99" value="0" onwheel="return false" />
<span class="icon is-small is-left">
<i class="fas fa-dollar-sign" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="feeEdit--feeFunction">Fee Function</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeEdit--feeFunction" name="feeFunction">
<option value="">(No Function Selected)</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="message is-info is-small">
<p class="message-body">
Taxes can be defined as flat amounts,
or as percentages of the fee amount.
Note that if both an amount and a percentage are set,
<strong>the percentage will be used.</strong>
</p>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeEdit--taxAmount">Tax Amount</label>
<div class="control has-icons-left">
<input class="input has-text-right" id="feeEdit--taxAmount" name="taxAmount" type="number" step="0.01" min="0" max="9999.99" onwheel="return false" />
<span class="icon is-small is-left">
<i class="fas fa-dollar-sign" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="feeEdit--taxPercentage">Tax Percentage</label>
<div class="control has-icons-right">
<input class="input has-text-right" id="feeEdit--taxPercentage" name="taxPercentage" type="number" step="0.01" min="0" max="100" value="0" onwheel="return false" />
<span class="icon is-small is-right">
<i class="fas fa-percent" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="feeEdit--includeQuantity">Include Quantity</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeEdit--includeQuantity" name="includeQuantity">
<option value="" selected>No Quantity</option>
<option value="1">Quantity Available</option>
</select>
</div>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="feeEdit--quantityUnit">Quantity Unit</label>
<div class="control">
<input class="input" id="feeEdit--quantityUnit" name="quantityUnit" maxlength="30" required />
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="feeEdit--isRequired">Fee Is Required</label>
<div class="control">
<div class="select is-fullwidth">
<select id="feeEdit--isRequired" name="isRequired">
<option value="" selected>No, Fee is Optional</option>
<option value="1">Yes, Fee is Required</option>
</select>
</div>
</div>
</div>
</form>
</section>
<footer class="modal-card-foot justify-right">
<button class="button is-success" type="submit" form="form--feeEdit">
<span class="icon"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Update Fee</span>
</button>
<div class="dropdown is-up is-right mr-2">
<div class="dropdown-trigger">
<button class="button" type="button">
<span>More Options</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu">
<div class="dropdown-content">
<a class="dropdown-item button--deleteFee" href="#">
<span class="icon is-small"><i class="fas fa-trash has-text-danger" aria-hidden="true"></i></span>
<span>Delete Fee</span>
</a>
</div>
</div>
</div>
<button class="button is-close-modal-button" type="button">Cancel</button>
</footer>
</div>
</div>

File diff suppressed because one or more lines are too long

View File

@ -3,8 +3,16 @@ import * as permissionHandlers from "../handlers/permissions.js";
import handler_fees from "../handlers/admin-get/fees.js";
import handler_doAddFeeCategory from "../handlers/admin-post/doAddFeeCategory.js";
import handler_doUpdateFeeCategory from "../handlers/admin-post/doUpdateFeeCategory.js";
import handler_doDeleteFeeCategory from "../handlers/admin-post/doDeleteFeeCategory.js";
import handler_doAddFee from "../handlers/admin-post/doAddFee.js";
import handler_doUpdateFee from "../handlers/admin-post/doUpdateFee.js";
import handler_doDeleteFee from "../handlers/admin-post/doDeleteFee.js";
export const router = Router();
router.get("/fees", permissionHandlers.adminGetHandler, handler_fees);
router.post("/doAddFeeCategory", permissionHandlers.adminPostHandler, handler_doAddFeeCategory);
router.post("/doUpdateFeeCategory", permissionHandlers.adminPostHandler, handler_doUpdateFeeCategory);
router.post("/doDeleteFeeCategory", permissionHandlers.adminPostHandler, handler_doDeleteFeeCategory);
router.post("/doAddFee", permissionHandlers.adminPostHandler, handler_doAddFee);
router.post("/doUpdateFee", permissionHandlers.adminPostHandler, handler_doUpdateFee);
router.post("/doDeleteFee", permissionHandlers.adminPostHandler, handler_doDeleteFee);
export default router;

View File

@ -7,6 +7,11 @@ import * as permissionHandlers from "../handlers/permissions.js";
import handler_fees from "../handlers/admin-get/fees.js";
import handler_doAddFeeCategory from "../handlers/admin-post/doAddFeeCategory.js";
import handler_doUpdateFeeCategory from "../handlers/admin-post/doUpdateFeeCategory.js";
import handler_doDeleteFeeCategory from "../handlers/admin-post/doDeleteFeeCategory.js";
import handler_doAddFee from "../handlers/admin-post/doAddFee.js";
import handler_doUpdateFee from "../handlers/admin-post/doUpdateFee.js";
import handler_doDeleteFee from "../handlers/admin-post/doDeleteFee.js";
export const router = Router();
@ -26,5 +31,21 @@ router.post("/doUpdateFeeCategory",
permissionHandlers.adminPostHandler,
handler_doUpdateFeeCategory);
router.post("/doDeleteFeeCategory",
permissionHandlers.adminPostHandler,
handler_doDeleteFeeCategory);
router.post("/doAddFee",
permissionHandlers.adminPostHandler,
handler_doAddFee);
router.post("/doUpdateFee",
permissionHandlers.adminPostHandler,
handler_doUpdateFee);
router.post("/doDeleteFee",
permissionHandlers.adminPostHandler,
handler_doDeleteFee);
export default router;

View File

@ -109,7 +109,9 @@ export interface Fee extends Record {
feeName?: string;
feeDescription?: string;
occupancyTypeId?: number;
occupancyType?: string;
lotTypeId?: number;
lotType?: string;
includeQuantity?: boolean;
quantityUnit?: string;
feeAmount?: number;
@ -141,7 +143,7 @@ export interface LotOccupancyOccupant extends Record {
lotOccupancyId?: number;
lotOccupantIndex?: number;
lotOccupantTypeId?: number;
lotOccupantType?: string | LotOccupantType;
lotOccupantType?: string;
occupantName?: string;
occupantAddress1?: string;
occupantAddress2?: string;
@ -167,7 +169,7 @@ export interface LotOccupancyField extends OccupancyTypeField, Record {
export interface LotOccupancy extends Record {
lotOccupancyId?: number;
occupancyTypeId?: number;
occupancyType?: OccupancyType | string;
occupancyType?: string;
lotId?: number;
lotName?: string;
mapId?: number;

View File

@ -156,7 +156,10 @@ export interface Fee extends Record {
feeDescription ? : string;
occupancyTypeId ? : number;
occupancyType ? : string;
lotTypeId ? : number;
lotType ? : string;
includeQuantity ? : boolean;
quantityUnit ? : string;
@ -201,7 +204,7 @@ export interface LotOccupancyOccupant extends Record {
lotOccupantIndex ? : number;
lotOccupantTypeId ? : number;
lotOccupantType ? : string | LotOccupantType;
lotOccupantType ? : string;
occupantName ? : string;
occupantAddress1 ? : string;
@ -238,7 +241,7 @@ export interface LotOccupancy extends Record {
lotOccupancyId ? : number;
occupancyTypeId ? : number;
occupancyType ? : OccupancyType | string;
occupancyType ? : string;
lotId ? : number;
lotName ? : string;

View File

@ -44,6 +44,8 @@
exports.feeCategories = <%- JSON.stringify(feeCategories) %>;
exports.occupancyTypes = <%- JSON.stringify(occupancyTypes) %>;
exports.lotTypes = <%- JSON.stringify(lotTypes) %>;
exports.taxPercentageDefault = <%= configFunctions.getProperty("settings.fees.taxPercentageDefault") %>;
</script>
<script src="<%= urlPrefix %>/javascripts/adminFees.min.js"></script>