development

deepsource-autofix-76c6eb20
Dan Gowans 2022-08-19 10:47:23 -04:00
parent 14f996233d
commit f51d1bff49
40 changed files with 701 additions and 76 deletions

View File

@ -1,4 +1,5 @@
import { config as cemeteryConfig } from "./config.cemetery.ontario.js";
export const config = Object.assign({}, cemeteryConfig);
config.settings.lotOccupancy.occupantCityDefault = "Sault Ste. Marie";
config.aliases.externalReceiptNumber = "GP Receipt Number";
export default config;

View File

@ -4,4 +4,6 @@ export const config = Object.assign({}, cemeteryConfig);
config.settings.lotOccupancy.occupantCityDefault = "Sault Ste. Marie";
config.aliases.externalReceiptNumber = "GP Receipt Number";
export default config;

View File

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

View File

@ -0,0 +1,11 @@
import { addLotOccupancyTransaction } from "../../helpers/lotOccupancyDB/addLotOccupancyTransaction.js";
import { getLotOccupancyTransactions } from "../../helpers/lotOccupancyDB/getLotOccupancyTransactions.js";
export const handler = async (request, response) => {
addLotOccupancyTransaction(request.body, request.session);
const lotOccupancyTransactions = getLotOccupancyTransactions(request.body.lotOccupancyId);
response.json({
success: true,
lotOccupancyTransactions
});
};
export default handler;

View File

@ -0,0 +1,27 @@
import type {
RequestHandler
} from "express";
import {
addLotOccupancyTransaction
} from "../../helpers/lotOccupancyDB/addLotOccupancyTransaction.js";
import {
getLotOccupancyTransactions
} from "../../helpers/lotOccupancyDB/getLotOccupancyTransactions.js";
export const handler: RequestHandler = async (request, response) => {
addLotOccupancyTransaction(request.body, request.session);
const lotOccupancyTransactions = getLotOccupancyTransactions(request.body.lotOccupancyId);
response.json({
success: true,
lotOccupancyTransactions
});
};
export default handler;

View File

@ -1,10 +1,10 @@
import { deleteLotOccupancyOccupant } from "../../helpers/lotOccupancyDB/deleteLotOccupancyOccupant.js";
import { getLotOccupancyOccupants } from "../../helpers/lotOccupancyDB/getLotOccupancyOccupants.js";
export const handler = async (request, response) => {
deleteLotOccupancyOccupant(request.body.lotOccupancyId, request.body.lotOccupantIndex, request.session);
const success = deleteLotOccupancyOccupant(request.body.lotOccupancyId, request.body.lotOccupantIndex, request.session);
const lotOccupancyOccupants = getLotOccupancyOccupants(request.body.lotOccupancyId);
response.json({
success: true,
success,
lotOccupancyOccupants
});
};

View File

@ -13,12 +13,12 @@ import {
export const handler: RequestHandler = async (request, response) => {
deleteLotOccupancyOccupant(request.body.lotOccupancyId, request.body.lotOccupantIndex, request.session);
const success = deleteLotOccupancyOccupant(request.body.lotOccupancyId, request.body.lotOccupantIndex, request.session);
const lotOccupancyOccupants = getLotOccupancyOccupants(request.body.lotOccupancyId);
response.json({
success: true,
success,
lotOccupancyOccupants
});
};

View File

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

View File

@ -0,0 +1,11 @@
import { deleteLotOccupancyTransaction } from "../../helpers/lotOccupancyDB/deleteLotOccupancyTransaction.js";
import { getLotOccupancyTransactions } from "../../helpers/lotOccupancyDB/getLotOccupancyTransactions.js";
export const handler = async (request, response) => {
const success = deleteLotOccupancyTransaction(request.body.lotOccupancyId, request.body.transactionIndex, request.session);
const lotOccupancyTransactions = getLotOccupancyTransactions(request.body.lotOccupancyId);
response.json({
success,
lotOccupancyTransactions
});
};
export default handler;

View File

@ -0,0 +1,27 @@
import type {
RequestHandler
} from "express";
import {
deleteLotOccupancyTransaction
} from "../../helpers/lotOccupancyDB/deleteLotOccupancyTransaction.js";
import {
getLotOccupancyTransactions
} from "../../helpers/lotOccupancyDB/getLotOccupancyTransactions.js";
export const handler: RequestHandler = async (request, response) => {
const success = deleteLotOccupancyTransaction(request.body.lotOccupancyId, request.body.transactionIndex, request.session);
const lotOccupancyTransactions = getLotOccupancyTransactions(request.body.lotOccupancyId);
response.json({
success,
lotOccupancyTransactions
});
};
export default handler;

View File

@ -1,10 +1,10 @@
import { updateLotOccupancyOccupant } from "../../helpers/lotOccupancyDB/updateLotOccupancyOccupant.js";
import { getLotOccupancyOccupants } from "../../helpers/lotOccupancyDB/getLotOccupancyOccupants.js";
export const handler = async (request, response) => {
updateLotOccupancyOccupant(request.body, request.session);
const success = updateLotOccupancyOccupant(request.body, request.session);
const lotOccupancyOccupants = getLotOccupancyOccupants(request.body.lotOccupancyId);
response.json({
success: true,
success,
lotOccupancyOccupants
});
};

View File

@ -13,12 +13,12 @@ import {
export const handler: RequestHandler = async (request, response) => {
updateLotOccupancyOccupant(request.body, request.session);
const success = updateLotOccupancyOccupant(request.body, request.session);
const lotOccupancyOccupants = getLotOccupancyOccupants(request.body.lotOccupancyId);
response.json({
success: true,
success,
lotOccupancyOccupants
});
};

View File

@ -23,6 +23,7 @@ export declare function getProperty(propertyName: "aliases.occupancy"): string;
export declare function getProperty(propertyName: "aliases.occupancies"): string;
export declare function getProperty(propertyName: "aliases.occupant"): string;
export declare function getProperty(propertyName: "aliases.occupants"): string;
export declare function getProperty(propertyName: "aliases.externalReceiptNumber"): string;
export declare function getProperty(propertyName: "settings.lotOccupancy.occupancyEndDateIsRequired"): boolean;
export declare function getProperty(propertyName: "settings.lotOccupancy.occupantCityDefault"): string;
export declare function getProperty(propertyName: "settings.lotOccupancy.occupantProvinceDefault"): string;

View File

@ -23,6 +23,7 @@ configFallbackValues.set("aliases.occupancy", "Occupancy");
configFallbackValues.set("aliases.occupancies", "Occupancies");
configFallbackValues.set("aliases.occupant", "Occupant");
configFallbackValues.set("aliases.occupants", "Occupants");
configFallbackValues.set("aliases.externalReceiptNumber", "External Receipt Number");
configFallbackValues.set("settings.lotOccupancy.occupancyEndDateIsRequired", true);
configFallbackValues.set("settings.lotOccupancy.occupantCityDefault", "");
configFallbackValues.set("settings.lotOccupancy.occupantProvinceDefault", "");

View File

@ -41,6 +41,7 @@ configFallbackValues.set("aliases.occupancy", "Occupancy");
configFallbackValues.set("aliases.occupancies", "Occupancies");
configFallbackValues.set("aliases.occupant", "Occupant");
configFallbackValues.set("aliases.occupants", "Occupants");
configFallbackValues.set("aliases.externalReceiptNumber", "External Receipt Number");
configFallbackValues.set("settings.lotOccupancy.occupancyEndDateIsRequired", true);
configFallbackValues.set("settings.lotOccupancy.occupantCityDefault", "");
@ -82,6 +83,7 @@ export function getProperty(propertyName: "aliases.occupancy"): string;
export function getProperty(propertyName: "aliases.occupancies"): string;
export function getProperty(propertyName: "aliases.occupant"): string;
export function getProperty(propertyName: "aliases.occupants"): string;
export function getProperty(propertyName: "aliases.externalReceiptNumber"): string;
export function getProperty(propertyName: "settings.lotOccupancy.occupancyEndDateIsRequired"): boolean;
export function getProperty(propertyName: "settings.lotOccupancy.occupantCityDefault"): string;

View File

@ -16,7 +16,7 @@ export const addLotOccupancyOccupant = (lotOccupancyOccupantForm, requestSession
database
.prepare("insert into LotOccupancyOccupants (" +
"lotOccupancyId, lotOccupantIndex," +
"occupantName," +
" occupantName," +
" occupantAddress1, occupantAddress2," +
" occupantCity, occupantProvince, occupantPostalCode," +
" occupantPhoneNumber," +

View File

@ -43,7 +43,7 @@ export const addLotOccupancyOccupant =
database
.prepare("insert into LotOccupancyOccupants (" +
"lotOccupancyId, lotOccupantIndex," +
"occupantName," +
" occupantName," +
" occupantAddress1, occupantAddress2," +
" occupantCity, occupantProvince, occupantPostalCode," +
" occupantPhoneNumber," +

View File

@ -0,0 +1,11 @@
import type * as recordTypes from "../../types/recordTypes";
interface AddLotOccupancyTransactionForm {
lotOccupancyId: string | number;
transactionDateString?: string;
transactionTimeString?: string;
transactionAmount: string | number;
externalReceiptNumber: string;
transactionNote: string;
}
export declare const addLotOccupancyTransaction: (lotOccupancyTransactionForm: AddLotOccupancyTransactionForm, requestSession: recordTypes.PartialSession) => number;
export default addLotOccupancyTransaction;

View File

@ -0,0 +1,36 @@
import { dateStringToInteger, dateToInteger, dateToTimeInteger, timeStringToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.js";
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const addLotOccupancyTransaction = (lotOccupancyTransactionForm, requestSession) => {
const database = sqlite(databasePath);
let transactionIndex = 0;
const maxIndexResult = database.prepare("select transactionIndex" +
" from LotOccupancyTransactions" +
" where lotOccupancyId = ?" +
" order by transactionIndex" +
" limit 1")
.get(lotOccupancyTransactionForm.lotOccupancyId);
if (maxIndexResult) {
transactionIndex = maxIndexResult.transactionIndex + 1;
}
const rightNow = new Date();
const transactionDate = lotOccupancyTransactionForm.transactionDateString ?
dateStringToInteger(lotOccupancyTransactionForm.transactionDateString) :
dateToInteger(rightNow);
const transactionTime = lotOccupancyTransactionForm.transactionTimeString ?
timeStringToInteger(lotOccupancyTransactionForm.transactionTimeString) :
dateToTimeInteger(rightNow);
database
.prepare("insert into LotOccupancyTransactions (" +
"lotOccupancyId, transactionIndex," +
" transactionDate, transactionTime," +
" transactionAmount, externalReceiptNumber," +
" transactionNote," +
" recordCreate_userName, recordCreate_timeMillis," +
" recordUpdate_userName, recordUpdate_timeMillis)" +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
.run(lotOccupancyTransactionForm.lotOccupancyId, transactionIndex, transactionDate, transactionTime, lotOccupancyTransactionForm.transactionAmount, lotOccupancyTransactionForm.externalReceiptNumber, lotOccupancyTransactionForm.transactionNote, requestSession.user.userName, rightNow.getTime(), requestSession.user.userName, rightNow.getTime());
database.close();
return transactionIndex;
};
export default addLotOccupancyTransaction;

View File

@ -0,0 +1,81 @@
import {
dateStringToInteger,
dateToInteger,
dateToTimeInteger,
timeStringToInteger
} from "@cityssm/expressjs-server-js/dateTimeFns.js";
import sqlite from "better-sqlite3";
import {
lotOccupancyDB as databasePath
} from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
interface AddLotOccupancyTransactionForm {
lotOccupancyId: string | number;
transactionDateString ? : string;
transactionTimeString ? : string;
transactionAmount: string | number;
externalReceiptNumber: string;
transactionNote: string;
}
export const addLotOccupancyTransaction =
(lotOccupancyTransactionForm: AddLotOccupancyTransactionForm, requestSession: recordTypes.PartialSession): number => {
const database = sqlite(databasePath);
let transactionIndex = 0;
const maxIndexResult = database.prepare("select transactionIndex" +
" from LotOccupancyTransactions" +
" where lotOccupancyId = ?" +
" order by transactionIndex" +
" limit 1")
.get(lotOccupancyTransactionForm.lotOccupancyId);
if (maxIndexResult) {
transactionIndex = maxIndexResult.transactionIndex + 1;
}
const rightNow = new Date();
const transactionDate = lotOccupancyTransactionForm.transactionDateString ?
dateStringToInteger(lotOccupancyTransactionForm.transactionDateString) :
dateToInteger(rightNow);
const transactionTime = lotOccupancyTransactionForm.transactionTimeString ?
timeStringToInteger(lotOccupancyTransactionForm.transactionTimeString) :
dateToTimeInteger(rightNow);
database
.prepare("insert into LotOccupancyTransactions (" +
"lotOccupancyId, transactionIndex," +
" transactionDate, transactionTime," +
" transactionAmount, externalReceiptNumber," +
" transactionNote," +
" recordCreate_userName, recordCreate_timeMillis," +
" recordUpdate_userName, recordUpdate_timeMillis)" +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
.run(lotOccupancyTransactionForm.lotOccupancyId,
transactionIndex,
transactionDate,
transactionTime,
lotOccupancyTransactionForm.transactionAmount,
lotOccupancyTransactionForm.externalReceiptNumber,
lotOccupancyTransactionForm.transactionNote,
requestSession.user.userName,
rightNow.getTime(),
requestSession.user.userName,
rightNow.getTime());
database.close();
return transactionIndex;
};
export default addLotOccupancyTransaction;

View File

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

View File

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

View File

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

41
package-lock.json generated
View File

@ -49,7 +49,6 @@
"@types/http-errors": "^1.8.2",
"@types/leaflet": "^1.7.11",
"@types/mocha": "^9.1.1",
"@types/mssql": "^8.0.3",
"@types/node-windows": "^0.1.2",
"@types/papaparse": "^5.3.3",
"@types/session-file-store": "^1.2.2",
@ -984,17 +983,6 @@
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
"dev": true
},
"node_modules/@types/mssql": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-8.0.3.tgz",
"integrity": "sha512-jh1owWcsq/fdkVFrgNEgDOy4H82PCMF3OmTydfPabC8W4MgCPMTzBSbW7SMNcxz6mizGBkI8h72SwgQz7To64Q==",
"dev": true,
"dependencies": {
"@types/node": "*",
"@types/tedious": "*",
"tarn": "^3.0.1"
}
},
"node_modules/@types/node": {
"version": "18.0.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz",
@ -1090,15 +1078,6 @@
"@types/express-session": "*"
}
},
"node_modules/@types/tedious": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.8.tgz",
"integrity": "sha512-CWCNlKiX2/fqFb1uiEXTRQ33yqqa0wKP/SDQbHKrPaIfKji4lWAx1Y2jNNjcBFLMh/8MWpQCGseM25M8GTyHvg==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/tunnel": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz",
@ -11470,17 +11449,6 @@
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
"dev": true
},
"@types/mssql": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-8.0.3.tgz",
"integrity": "sha512-jh1owWcsq/fdkVFrgNEgDOy4H82PCMF3OmTydfPabC8W4MgCPMTzBSbW7SMNcxz6mizGBkI8h72SwgQz7To64Q==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/tedious": "*",
"tarn": "^3.0.1"
}
},
"@types/node": {
"version": "18.0.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz",
@ -11575,15 +11543,6 @@
"@types/express-session": "*"
}
},
"@types/tedious": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.8.tgz",
"integrity": "sha512-CWCNlKiX2/fqFb1uiEXTRQ33yqqa0wKP/SDQbHKrPaIfKji4lWAx1Y2jNNjcBFLMh/8MWpQCGseM25M8GTyHvg==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/tunnel": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz",

View File

@ -70,7 +70,6 @@
"@types/http-errors": "^1.8.2",
"@types/leaflet": "^1.7.11",
"@types/mocha": "^9.1.1",
"@types/mssql": "^8.0.3",
"@types/node-windows": "^0.1.2",
"@types/papaparse": "^5.3.3",
"@types/session-file-store": "^1.2.2",

View File

@ -590,6 +590,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
if (!isCreate) {
let lotOccupancyFees = exports.lotOccupancyFees;
const lotOccupancyFeesContainerElement = document.querySelector("#container--lotOccupancyFees");
const getFeeGrandTotal = () => {
let feeGrandTotal = 0;
for (const lotOccupancyFee of lotOccupancyFees) {
feeGrandTotal += (lotOccupancyFee.feeAmount + lotOccupancyFee.taxAmount) * lotOccupancyFee.quantity;
}
return feeGrandTotal;
};
const deleteLotOccupancyFee = (clickEvent) => {
const feeId = clickEvent.currentTarget.closest(".container--lotOccupancyFee").dataset.feeId;
const doDelete = () => {
@ -673,6 +680,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
lotOccupancyFeesContainerElement.querySelector("#lotOccupancyFees--feeAmountTotal").textContent = "$" + feeAmountTotal.toFixed(2);
lotOccupancyFeesContainerElement.querySelector("#lotOccupancyFees--taxAmountTotal").textContent = "$" + taxAmountTotal.toFixed(2);
lotOccupancyFeesContainerElement.querySelector("#lotOccupancyFees--grandTotal").textContent = "$" + (feeAmountTotal + taxAmountTotal).toFixed(2);
renderLotOccupancyTransactions();
};
document.querySelector("#button--addFee").addEventListener("click", () => {
if (hasUnsavedChanges) {
@ -805,6 +813,131 @@ Object.defineProperty(exports, "__esModule", { value: true });
}
});
});
let lotOccupancyTransactions = exports.lotOccupancyTransactions;
const lotOccupancyTransactionsContainerElement = document.querySelector("#container--lotOccupancyTransactions");
const getTransactionGrandTotal = () => {
let transactionGrandTotal = 0;
for (const lotOccupancyTransaction of lotOccupancyTransactions) {
transactionGrandTotal += lotOccupancyTransaction.transactionAmount;
}
return transactionGrandTotal;
};
const deleteLotOccupancyTransaction = (clickEvent) => {
const transactionIndex = clickEvent.currentTarget.closest(".container--lotOccupancyTransaction").dataset.transactionIndex;
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/lotOccupancies/doDeleteLotOccupancyTransaction", {
lotOccupancyId,
transactionIndex
}, (responseJSON) => {
if (responseJSON.success) {
lotOccupancyTransactions = responseJSON.lotOccupancyTransactions;
renderLotOccupancyTransactions();
}
else {
bulmaJS.alert({
title: "Error Deleting Transaction",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
bulmaJS.confirm({
title: "Delete Trasnaction",
message: "Are you sure you want to delete this transaction?",
contextualColorName: "warning",
okButton: {
text: "Yes, Delete Transaction",
callbackFunction: doDelete,
}
});
};
const renderLotOccupancyTransactions = () => {
if (lotOccupancyTransactions.length === 0) {
lotOccupancyTransactionsContainerElement.innerHTML = "<div class=\"message " + (lotOccupancyFees.length === 0 ? "is-info" : "is-warning") + "\">" +
"<p class=\"message-body\">There are no transactions associated with this record.</p>" +
"</div>";
return;
}
lotOccupancyTransactionsContainerElement.innerHTML = "<table class=\"table is-fullwidth is-striped is-hoverable\">" +
"<thead><tr>" +
"<th class=\"has-width-1\">Date</th>" +
"<th>" + cityssm.escapeHTML(exports.aliases.externalReceiptNumber) + "</th>" +
"<th class=\"has-text-right has-width-1\">Amount</th>" +
"<th class=\"has-width-1\"><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=\"lotOccupancyTransactions--grandTotal\"></td>" +
"<td></td>" +
"</tr></tfoot>") +
"</table>";
let transactionGrandTotal = 0;
for (const lotOccupancyTransaction of lotOccupancyTransactions) {
transactionGrandTotal += lotOccupancyTransaction.transactionAmount;
const tableRowElement = document.createElement("tr");
tableRowElement.className = "container--lotOccupancyTransaction";
tableRowElement.dataset.transactionIndex = lotOccupancyTransaction.transactionIndex.toString();
tableRowElement.innerHTML = "<td>" + lotOccupancyTransaction.transactionDateString + "</td>" +
("<td>" +
cityssm.escapeHTML(lotOccupancyTransaction.externalReceiptNumber) + "<br />" +
"<small>" + cityssm.escapeHTML(lotOccupancyTransaction.transactionNote) + "</small>" +
"</td>") +
("<td class=\"has-text-right\">$" + lotOccupancyTransaction.transactionAmount.toFixed(2) + "</td>") +
("<td>" +
"<button class=\"button is-small is-danger is-light\" data-tooltip=\"Delete Transaction\" type=\"button\">" +
"<i class=\"fas fa-trash\" aria-hidden=\"true\"></i>" +
"</button>" +
"</td>");
tableRowElement.querySelector("button").addEventListener("click", deleteLotOccupancyTransaction);
lotOccupancyTransactionsContainerElement.querySelector("tbody").append(tableRowElement);
}
lotOccupancyTransactionsContainerElement.querySelector("#lotOccupancyTransactions--grandTotal").textContent = "$" + transactionGrandTotal.toFixed(2);
const feeGrandTotal = getFeeGrandTotal();
if (feeGrandTotal > transactionGrandTotal) {
}
};
document.querySelector("#button--addTransaction").addEventListener("click", () => {
let addCloseModalFunction;
const doAddTransaction = (submitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/lotOccupancies/doAddLotOccupancyTransaction", submitEvent.currentTarget, (responseJSON) => {
if (responseJSON.success) {
lotOccupancyTransactions = responseJSON.lotOccupancyTransactions;
addCloseModalFunction();
renderLotOccupancyTransactions();
}
else {
bulmaJS.confirm({
title: "Error Adding Transaction",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("lotOccupancy-addTransaction", {
onshow: (modalElement) => {
los.populateAliases(modalElement);
modalElement.querySelector("#lotOccupancyTransactionAdd--lotOccupancyId").value = lotOccupancyId.toString();
const feeGrandTotal = getFeeGrandTotal();
const transactionGrandTotal = getTransactionGrandTotal();
const transactionAmountElement = modalElement.querySelector("#lotOccupancyTransactionAdd--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);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddTransaction);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
renderLotOccupancyFees();
}
})();

View File

@ -90,20 +90,22 @@ declare const bulmaJS: BulmaJS;
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/lotOccupancies/doDeleteLotOccupancy", {
lotOccupancyId
},
(responseJSON: {success: boolean; errorMessage?: string;}) => {
lotOccupancyId
},
(responseJSON: {
success: boolean;errorMessage ? : string;
}) => {
if (responseJSON.success) {
window.location.href = urlPrefix + "/lotOccupancies?t=" + Date.now();
} else {
bulmaJS.alert({
title: "Error Deleting Record",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
if (responseJSON.success) {
window.location.href = urlPrefix + "/lotOccupancies?t=" + Date.now();
} else {
bulmaJS.alert({
title: "Error Deleting Record",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
}
bulmaJS.confirm({
@ -832,7 +834,7 @@ declare const bulmaJS: BulmaJS;
}
/*
* Fees
* Fees / Transactions
*/
if (!isCreate) {
@ -840,6 +842,17 @@ declare const bulmaJS: BulmaJS;
let lotOccupancyFees: recordTypes.LotOccupancyFee[] = exports.lotOccupancyFees;
const lotOccupancyFeesContainerElement = document.querySelector("#container--lotOccupancyFees") as HTMLElement;
const getFeeGrandTotal = (): number => {
let feeGrandTotal = 0;
for (const lotOccupancyFee of lotOccupancyFees) {
feeGrandTotal += (lotOccupancyFee.feeAmount + lotOccupancyFee.taxAmount) * lotOccupancyFee.quantity;
}
return feeGrandTotal;
};
const deleteLotOccupancyFee = (clickEvent: Event) => {
const feeId = ((clickEvent.currentTarget as HTMLElement).closest(".container--lotOccupancyFee") as HTMLElement).dataset.feeId;
@ -874,7 +887,7 @@ declare const bulmaJS: BulmaJS;
text: "Yes, Delete Fee",
callbackFunction: doDelete,
}
})
});
};
const renderLotOccupancyFees = () => {
@ -941,6 +954,8 @@ declare const bulmaJS: BulmaJS;
(lotOccupancyFeesContainerElement.querySelector("#lotOccupancyFees--feeAmountTotal") as HTMLElement).textContent = "$" + feeAmountTotal.toFixed(2);
(lotOccupancyFeesContainerElement.querySelector("#lotOccupancyFees--taxAmountTotal") as HTMLElement).textContent = "$" + taxAmountTotal.toFixed(2);
(lotOccupancyFeesContainerElement.querySelector("#lotOccupancyFees--grandTotal") as HTMLElement).textContent = "$" + (feeAmountTotal + taxAmountTotal).toFixed(2);
renderLotOccupancyTransactions();
};
document.querySelector("#button--addFee").addEventListener("click", () => {
@ -1120,10 +1135,183 @@ declare const bulmaJS: BulmaJS;
});
});
let lotOccupancyTransactions: recordTypes.LotOccupancyTransaction[] = exports.lotOccupancyTransactions;
const lotOccupancyTransactionsContainerElement = document.querySelector("#container--lotOccupancyTransactions") as HTMLElement;
const getTransactionGrandTotal = (): number => {
let transactionGrandTotal = 0;
for (const lotOccupancyTransaction of lotOccupancyTransactions) {
transactionGrandTotal += lotOccupancyTransaction.transactionAmount;
}
return transactionGrandTotal;
};
const deleteLotOccupancyTransaction = (clickEvent: Event) => {
const transactionIndex = ((clickEvent.currentTarget as HTMLElement).closest(".container--lotOccupancyTransaction") as HTMLElement).dataset.transactionIndex;
const doDelete = () => {
cityssm.postJSON(urlPrefix + "/lotOccupancies/doDeleteLotOccupancyTransaction", {
lotOccupancyId,
transactionIndex
},
(responseJSON: {
success: boolean;
errorMessage ? : string;
lotOccupancyTransactions ? : recordTypes.LotOccupancyTransaction[];
}) => {
if (responseJSON.success) {
lotOccupancyTransactions = responseJSON.lotOccupancyTransactions;
renderLotOccupancyTransactions();
} else {
bulmaJS.alert({
title: "Error Deleting Transaction",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
bulmaJS.confirm({
title: "Delete Trasnaction",
message: "Are you sure you want to delete this transaction?",
contextualColorName: "warning",
okButton: {
text: "Yes, Delete Transaction",
callbackFunction: doDelete,
}
});
};
const renderLotOccupancyTransactions = () => {
if (lotOccupancyTransactions.length === 0) {
lotOccupancyTransactionsContainerElement.innerHTML = "<div class=\"message " + (lotOccupancyFees.length === 0 ? "is-info" : "is-warning") + "\">" +
"<p class=\"message-body\">There are no transactions associated with this record.</p>" +
"</div>";
return;
}
lotOccupancyTransactionsContainerElement.innerHTML = "<table class=\"table is-fullwidth is-striped is-hoverable\">" +
"<thead><tr>" +
"<th class=\"has-width-1\">Date</th>" +
"<th>" + cityssm.escapeHTML(exports.aliases.externalReceiptNumber) + "</th>" +
"<th class=\"has-text-right has-width-1\">Amount</th>" +
"<th class=\"has-width-1\"><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=\"lotOccupancyTransactions--grandTotal\"></td>" +
"<td></td>" +
"</tr></tfoot>") +
"</table>";
let transactionGrandTotal = 0;
for (const lotOccupancyTransaction of lotOccupancyTransactions) {
transactionGrandTotal += lotOccupancyTransaction.transactionAmount;
const tableRowElement = document.createElement("tr");
tableRowElement.className = "container--lotOccupancyTransaction";
tableRowElement.dataset.transactionIndex = lotOccupancyTransaction.transactionIndex.toString();
tableRowElement.innerHTML = "<td>" + lotOccupancyTransaction.transactionDateString + "</td>" +
("<td>" +
cityssm.escapeHTML(lotOccupancyTransaction.externalReceiptNumber) + "<br />" +
"<small>" + cityssm.escapeHTML(lotOccupancyTransaction.transactionNote) + "</small>" +
"</td>") +
("<td class=\"has-text-right\">$" + lotOccupancyTransaction.transactionAmount.toFixed(2) + "</td>") +
("<td>" +
"<button class=\"button is-small is-danger is-light\" data-tooltip=\"Delete Transaction\" type=\"button\">" +
"<i class=\"fas fa-trash\" aria-hidden=\"true\"></i>" +
"</button>" +
"</td>");
tableRowElement.querySelector("button").addEventListener("click", deleteLotOccupancyTransaction);
lotOccupancyTransactionsContainerElement.querySelector("tbody").append(tableRowElement);
}
(lotOccupancyTransactionsContainerElement.querySelector("#lotOccupancyTransactions--grandTotal") as HTMLElement).textContent = "$" + transactionGrandTotal.toFixed(2);
const feeGrandTotal = getFeeGrandTotal();
if (feeGrandTotal > transactionGrandTotal) {
/*
lotOccupancyTransactionsContainerElement.insertAdjacentHTML("afterbegin",
"<div ")
*/
}
};
document.querySelector("#button--addTransaction").addEventListener("click", () => {
let addCloseModalFunction: () => void;
const doAddTransaction = (submitEvent: SubmitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/lotOccupancies/doAddLotOccupancyTransaction",
submitEvent.currentTarget,
(responseJSON: {
success: boolean;
errorMessage ? : string;
lotOccupancyTransactions ? : recordTypes.LotOccupancyTransaction[];
}) => {
if (responseJSON.success) {
lotOccupancyTransactions = responseJSON.lotOccupancyTransactions;
addCloseModalFunction();
renderLotOccupancyTransactions();
} else {
bulmaJS.confirm({
title: "Error Adding Transaction",
message: responseJSON.errorMessage,
contextualColorName: "danger"
});
}
});
};
cityssm.openHtmlModal("lotOccupancy-addTransaction", {
onshow: (modalElement) => {
los.populateAliases(modalElement);
(modalElement.querySelector("#lotOccupancyTransactionAdd--lotOccupancyId") as HTMLInputElement).value = lotOccupancyId.toString();
const feeGrandTotal = getFeeGrandTotal();
const transactionGrandTotal = getTransactionGrandTotal();
const transactionAmountElement = modalElement.querySelector("#lotOccupancyTransactionAdd--transactionAmount") as HTMLInputElement;
transactionAmountElement.min = (-1 * transactionGrandTotal).toFixed(2);
transactionAmountElement.max = Math.max(feeGrandTotal - transactionGrandTotal, 0).toFixed(2);
transactionAmountElement.value = Math.max(feeGrandTotal - transactionGrandTotal, 0).toFixed(2);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form").addEventListener("submit", doAddTransaction);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
renderLotOccupancyFees();
}
/*
* Transactions
*/
})();

View File

@ -63,6 +63,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
case "occupant":
aliasElement.textContent = exports.aliases.occupant.toLowerCase();
break;
case "ExternalReceiptNumber":
aliasElement.textContent = exports.aliases.externalReceiptNumber;
break;
}
}
};

View File

@ -99,6 +99,10 @@ import type * as globalTypes from "../types/globalTypes";
case "occupant":
aliasElement.textContent = exports.aliases.occupant.toLowerCase();
break;
case "ExternalReceiptNumber":
aliasElement.textContent = exports.aliases.externalReceiptNumber;
break;
}
}
};

View File

@ -0,0 +1,47 @@
<div class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<h3 class="modal-card-title">
Add Transaction
</h3>
<button class="delete is-close-modal-button" aria-label="close" type="button"></button>
</header>
<section class="modal-card-body">
<form id="form--lotOccupancyTransactionAdd">
<input id="lotOccupancyTransactionAdd--lotOccupancyId" name="lotOccupancyId" type="hidden" value="" />
<div class="field">
<label class="label" for="lotOccupancyTransactionAdd--transactionAmount">Transaction Amount</label>
<div class="control has-icons-left">
<input class="input has-text-right" id="lotOccupancyTransactionAdd--transactionAmount" name="transactionAmount" type="number" step="0.01" required />
<span class="icon is-small is-left">
<i class="fas fa-dollar-sign" aria-hidden="true"></i>
</span>
</div>
</div>
<div class="field">
<label class="label" for="lotOccupancyTransactionAdd--externalReceiptNumber">
<span class="alias" data-alias="ExternalReceiptNumber"></span>
</label>
<div class="control">
<input class="input" id="lotOccupancyTransactionAdd--externalReceiptNumber" name="externalReceiptNumber" maxlength="100" />
</div>
</div>
<div class="field">
<label class="label" for="lotOccupancyTransactionAdd--transactionNote">Note</label>
<div class="control">
<textarea class="textarea" id="lotOccupancyTransactionAdd--transactionNote" name="transactionNote"></textarea>
</div>
</div>
</form>
</section>
<footer class="modal-card-foot justify-right">
<button class="button is-success" type="submit" form="form--lotOccupancyTransactionAdd">
<span class="icon"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Transaction</span>
</button>
<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

@ -1 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=e=>{const t=e.currentTarget.closest(".field").querySelector("input, select");if("INPUT"===t.tagName)t.disabled=!1;else{const e=t.querySelectorAll("option");for(const t of e)t.disabled=!1}t.focus()},t={highlightMap:(e,t,o)=>{let s,l=t;for(;!(s=e.querySelector("#"+l))&&l.includes("-");)l=l.slice(0,Math.max(0,l.lastIndexOf("-"))),console.log(l);if(s){s.style.fill=null,s.classList.add("highlight","is-"+o);const e=s.querySelectorAll("path");for(const t of e)t.style.fill=null}},initializeUnlockFieldButtons:t=>{const o=t.querySelectorAll(".is-unlock-field-button");for(const t of o)t.addEventListener("click",e)},populateAliases:e=>{const t=e.querySelectorAll(".alias");for(const e of t)switch(e.dataset.alias){case"Lot":e.textContent=exports.aliases.lot;break;case"lot":e.textContent=exports.aliases.lot.toLowerCase();break;case"Occupancy":e.textContent=exports.aliases.occupancy;break;case"occupancy":e.textContent=exports.aliases.occupancy.toLowerCase();break;case"Occupant":e.textContent=exports.aliases.occupant;break;case"occupant":e.textContent=exports.aliases.occupant.toLowerCase()}}};exports.los=t})();
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=e=>{const t=e.currentTarget.closest(".field").querySelector("input, select");if("INPUT"===t.tagName)t.disabled=!1;else{const e=t.querySelectorAll("option");for(const t of e)t.disabled=!1}t.focus()},t={highlightMap:(e,t,s)=>{let o,l=t;for(;!(o=e.querySelector("#"+l))&&l.includes("-");)l=l.slice(0,Math.max(0,l.lastIndexOf("-"))),console.log(l);if(o){o.style.fill=null,o.classList.add("highlight","is-"+s);const e=o.querySelectorAll("path");for(const t of e)t.style.fill=null}},initializeUnlockFieldButtons:t=>{const s=t.querySelectorAll(".is-unlock-field-button");for(const t of s)t.addEventListener("click",e)},populateAliases:e=>{const t=e.querySelectorAll(".alias");for(const e of t)switch(e.dataset.alias){case"Lot":e.textContent=exports.aliases.lot;break;case"lot":e.textContent=exports.aliases.lot.toLowerCase();break;case"Occupancy":e.textContent=exports.aliases.occupancy;break;case"occupancy":e.textContent=exports.aliases.occupancy.toLowerCase();break;case"Occupant":e.textContent=exports.aliases.occupant;break;case"occupant":e.textContent=exports.aliases.occupant.toLowerCase();break;case"ExternalReceiptNumber":e.textContent=exports.aliases.externalReceiptNumber}}};exports.los=t})();

View File

@ -17,6 +17,8 @@ import handler_doDeleteLotOccupancyComment from "../handlers/lotOccupancies-post
import handler_doGetFees from "../handlers/lotOccupancies-post/doGetFees.js";
import handler_doAddLotOccupancyFee from "../handlers/lotOccupancies-post/doAddLotOccupancyFee.js";
import handler_doDeleteLotOccupancyFee from "../handlers/lotOccupancies-post/doDeleteLotOccupancyFee.js";
import handler_doAddLotOccupancyTransaction from "../handlers/lotOccupancies-post/doAddLotOccupancyTransaction.js";
import handler_doDeleteLotOccupancyTransaction from "../handlers/lotOccupancies-post/doDeleteLotOccupancyTransaction.js";
import * as permissionHandlers from "../handlers/permissions.js";
export const router = Router();
router.get("/", handler_search);
@ -37,4 +39,6 @@ router.post("/doDeleteLotOccupancyComment", permissionHandlers.updatePostHandler
router.post("/doGetFees", permissionHandlers.updatePostHandler, handler_doGetFees);
router.post("/doAddLotOccupancyFee", permissionHandlers.updatePostHandler, handler_doAddLotOccupancyFee);
router.post("/doDeleteLotOccupancyFee", permissionHandlers.updatePostHandler, handler_doDeleteLotOccupancyFee);
router.post("/doAddLotOccupancyTransaction", permissionHandlers.updatePostHandler, handler_doAddLotOccupancyTransaction);
router.post("/doDeleteLotOccupancyTransaction", permissionHandlers.updatePostHandler, handler_doDeleteLotOccupancyTransaction);
export default router;

View File

@ -27,6 +27,9 @@ import handler_doGetFees from "../handlers/lotOccupancies-post/doGetFees.js";
import handler_doAddLotOccupancyFee from "../handlers/lotOccupancies-post/doAddLotOccupancyFee.js";
import handler_doDeleteLotOccupancyFee from "../handlers/lotOccupancies-post/doDeleteLotOccupancyFee.js";
import handler_doAddLotOccupancyTransaction from "../handlers/lotOccupancies-post/doAddLotOccupancyTransaction.js";
import handler_doDeleteLotOccupancyTransaction from "../handlers/lotOccupancies-post/doDeleteLotOccupancyTransaction.js";
import * as permissionHandlers from "../handlers/permissions.js";
@ -115,5 +118,14 @@ router.post("/doDeleteLotOccupancyFee",
permissionHandlers.updatePostHandler,
handler_doDeleteLotOccupancyFee);
// Transactions
router.post("/doAddLotOccupancyTransaction",
permissionHandlers.updatePostHandler,
handler_doAddLotOccupancyTransaction);
router.post("/doDeleteLotOccupancyTransaction",
permissionHandlers.updatePostHandler,
handler_doDeleteLotOccupancyTransaction);
export default router;

View File

@ -22,6 +22,7 @@ export interface Config {
occupancies?: string;
occupant?: string;
occupants?: string;
externalReceiptNumber?: string;
};
settings?: {
fees?: {

View File

@ -22,6 +22,7 @@ export interface Config {
occupancies ? : string;
occupant ? : string;
occupants ? : string;
externalReceiptNumber ?: string;
};
settings ? : {
fees ? : {

View File

@ -135,7 +135,7 @@ export interface LotOccupancyTransaction extends Record {
transactionDateString?: string;
transactionTime?: number;
transactionTimeString?: string;
tranactionAmount?: number;
transactionAmount?: number;
externalReceiptNumber?: string;
transactionNote?: string;
}

View File

@ -193,7 +193,7 @@ export interface LotOccupancyTransaction extends Record {
transactionDateString ? : string;
transactionTime ? : number;
transactionTimeString ? : string;
tranactionAmount ? : number;
transactionAmount ? : number;
externalReceiptNumber ? : string;
transactionNote ? : string;
}

View File

@ -21,7 +21,8 @@
occupancy: "<%= configFunctions.getProperty("aliases.occupancy") %>",
occupancies: "<%= configFunctions.getProperty("aliases.occupancies") %>",
occupant: "<%= configFunctions.getProperty("aliases.occupant") %>",
occupants: "<%= configFunctions.getProperty("aliases.occupants") %>"
occupants: "<%= configFunctions.getProperty("aliases.occupants") %>",
externalReceiptNumber: "<%= configFunctions.getProperty("aliases.externalReceiptNumber") %>"
};
</script>
<script src="<%= urlPrefix %>/lib/cityssm-bulma-js/bulma-js.js"></script>

View File

@ -287,6 +287,7 @@
</div>
</div>
</div>
<div class="panel-block is-block" id="container--lotOccupancyTransactions"></div>
</div>
</div>
</div>