diff --git a/database/addFeeCategory.d.ts b/database/addFeeCategory.d.ts new file mode 100644 index 00000000..2101d5aa --- /dev/null +++ b/database/addFeeCategory.d.ts @@ -0,0 +1,6 @@ +export interface AddFeeCategoryForm { + feeCategory: string; + isGroupedFee?: '1'; + orderNumber?: number; +} +export default function addFeeCategory(feeCategoryForm: AddFeeCategoryForm, user: User): Promise; diff --git a/database/addFeeCategory.js b/database/addFeeCategory.js new file mode 100644 index 00000000..46b6834b --- /dev/null +++ b/database/addFeeCategory.js @@ -0,0 +1,15 @@ +import { acquireConnection } from './pool.js'; +export default async function addFeeCategory(feeCategoryForm, user) { + const database = await acquireConnection(); + const rightNowMillis = Date.now(); + const result = database + .prepare(`insert into FeeCategories ( + feeCategory, + isGroupedFee, orderNumber, + recordCreate_userName, recordCreate_timeMillis, + recordUpdate_userName, recordUpdate_timeMillis) + values (?, ?, ?, ?, ?, ?, ?)`) + .run(feeCategoryForm.feeCategory, (feeCategoryForm.isGroupedFee ?? '') === '1' ? 1 : 0, feeCategoryForm.orderNumber ?? -1, user.userName, rightNowMillis, user.userName, rightNowMillis); + database.release(); + return result.lastInsertRowid; +} diff --git a/database/addFeeCategory.ts b/database/addFeeCategory.ts new file mode 100644 index 00000000..3eca01f8 --- /dev/null +++ b/database/addFeeCategory.ts @@ -0,0 +1,39 @@ +import { acquireConnection } from './pool.js' + +export interface AddFeeCategoryForm { + feeCategory: string + isGroupedFee?: '1' + orderNumber?: number +} + +export default async function addFeeCategory( + feeCategoryForm: AddFeeCategoryForm, + user: User +): Promise { + const database = await acquireConnection() + + const rightNowMillis = Date.now() + + const result = database + .prepare( + `insert into FeeCategories ( + feeCategory, + isGroupedFee, orderNumber, + recordCreate_userName, recordCreate_timeMillis, + recordUpdate_userName, recordUpdate_timeMillis) + values (?, ?, ?, ?, ?, ?, ?)` + ) + .run( + feeCategoryForm.feeCategory, + (feeCategoryForm.isGroupedFee ?? '') === '1' ? 1 : 0, + feeCategoryForm.orderNumber ?? -1, + user.userName, + rightNowMillis, + user.userName, + rightNowMillis + ) + + database.release() + + return result.lastInsertRowid as number +} diff --git a/database/addLotOccupancyFee.d.ts b/database/addLotOccupancyFee.d.ts index fb4c5a44..6e5de22b 100644 --- a/database/addLotOccupancyFee.d.ts +++ b/database/addLotOccupancyFee.d.ts @@ -1,3 +1,4 @@ +import { type PoolConnection } from 'better-sqlite-pool'; export interface AddLotOccupancyFeeForm { lotOccupancyId: number | string; feeId: number | string; @@ -5,4 +6,4 @@ export interface AddLotOccupancyFeeForm { feeAmount?: number | string; taxAmount?: number | string; } -export default function addLotOccupancyFee(lotOccupancyFeeForm: AddLotOccupancyFeeForm, user: User): Promise; +export default function addLotOccupancyFee(lotOccupancyFeeForm: AddLotOccupancyFeeForm, user: User, connectedDatabase?: PoolConnection): Promise; diff --git a/database/addLotOccupancyFee.js b/database/addLotOccupancyFee.js index 343b3747..81e54831 100644 --- a/database/addLotOccupancyFee.js +++ b/database/addLotOccupancyFee.js @@ -2,8 +2,8 @@ import { calculateFeeAmount, calculateTaxAmount } from '../helpers/functions.fee import getFee from './getFee.js'; import getLotOccupancy from './getLotOccupancy.js'; import { acquireConnection } from './pool.js'; -export default async function addLotOccupancyFee(lotOccupancyFeeForm, user) { - const database = await acquireConnection(); +export default async function addLotOccupancyFee(lotOccupancyFeeForm, user, connectedDatabase) { + const database = connectedDatabase ?? (await acquireConnection()); const rightNowMillis = Date.now(); // Calculate fee and tax (if not set) let feeAmount; @@ -24,62 +24,66 @@ export default async function addLotOccupancyFee(lotOccupancyFeeForm, user) { ? Number.parseFloat(lotOccupancyFeeForm.taxAmount) : 0; } - // Check if record already exists - const record = database - .prepare(`select feeAmount, taxAmount, recordDelete_timeMillis - from LotOccupancyFees - where lotOccupancyId = ? - and feeId = ?`) - .get(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); - if (record) { - if (record.recordDelete_timeMillis) { - database - .prepare(`delete from LotOccupancyFees - where recordDelete_timeMillis is not null - and lotOccupancyId = ? - and feeId = ?`) - .run(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); + try { + // Check if record already exists + const record = database + .prepare(`select feeAmount, taxAmount, recordDelete_timeMillis + from LotOccupancyFees + where lotOccupancyId = ? + and feeId = ?`) + .get(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); + if (record) { + if (record.recordDelete_timeMillis) { + database + .prepare(`delete from LotOccupancyFees + where recordDelete_timeMillis is not null + and lotOccupancyId = ? + and feeId = ?`) + .run(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); + } + else if (record.feeAmount === feeAmount && + record.taxAmount === taxAmount) { + database + .prepare(`update LotOccupancyFees + set quantity = quantity + ?, + recordUpdate_userName = ?, + recordUpdate_timeMillis = ? + where lotOccupancyId = ? + and feeId = ?`) + .run(lotOccupancyFeeForm.quantity, user.userName, rightNowMillis, lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); + return true; + } + else { + const quantity = typeof lotOccupancyFeeForm.quantity === 'string' + ? Number.parseFloat(lotOccupancyFeeForm.quantity) + : lotOccupancyFeeForm.quantity; + database + .prepare(`update LotOccupancyFees + set feeAmount = (feeAmount * quantity) + ?, + taxAmount = (taxAmount * quantity) + ?, + quantity = 1, + recordUpdate_userName = ?, + recordUpdate_timeMillis = ? + where lotOccupancyId = ? + and feeId = ?`) + .run(feeAmount * quantity, taxAmount * quantity, user.userName, rightNowMillis, lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); + return true; + } } - else if (record.feeAmount === feeAmount && - record.taxAmount === taxAmount) { - database - .prepare(`update LotOccupancyFees - set quantity = quantity + ?, - recordUpdate_userName = ?, - recordUpdate_timeMillis = ? - where lotOccupancyId = ? - and feeId = ?`) - .run(lotOccupancyFeeForm.quantity, user.userName, rightNowMillis, lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); - database.release(); - return true; - } - else { - const quantity = typeof lotOccupancyFeeForm.quantity === 'string' - ? Number.parseFloat(lotOccupancyFeeForm.quantity) - : lotOccupancyFeeForm.quantity; - database - .prepare(`update LotOccupancyFees - set feeAmount = (feeAmount * quantity) + ?, - taxAmount = (taxAmount * quantity) + ?, - quantity = 1, - recordUpdate_userName = ?, - recordUpdate_timeMillis = ? - where lotOccupancyId = ? - and feeId = ?`) - .run(feeAmount * quantity, taxAmount * quantity, user.userName, rightNowMillis, lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId); + // Create new record + const result = database + .prepare(`insert into LotOccupancyFees ( + lotOccupancyId, feeId, + quantity, feeAmount, taxAmount, + recordCreate_userName, recordCreate_timeMillis, + recordUpdate_userName, recordUpdate_timeMillis) + values (?, ?, ?, ?, ?, ?, ?, ?, ?)`) + .run(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId, lotOccupancyFeeForm.quantity, feeAmount, taxAmount, user.userName, rightNowMillis, user.userName, rightNowMillis); + return result.changes > 0; + } + finally { + if (connectedDatabase === undefined) { database.release(); - return true; } } - // Create new record - const result = database - .prepare(`insert into LotOccupancyFees ( - lotOccupancyId, feeId, - quantity, feeAmount, taxAmount, - recordCreate_userName, recordCreate_timeMillis, - recordUpdate_userName, recordUpdate_timeMillis) - values (?, ?, ?, ?, ?, ?, ?, ?, ?)`) - .run(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId, lotOccupancyFeeForm.quantity, feeAmount, taxAmount, user.userName, rightNowMillis, user.userName, rightNowMillis); - database.release(); - return result.changes > 0; } diff --git a/database/addLotOccupancyFee.ts b/database/addLotOccupancyFee.ts index 760b8f4f..6804d226 100644 --- a/database/addLotOccupancyFee.ts +++ b/database/addLotOccupancyFee.ts @@ -1,3 +1,5 @@ +import { type PoolConnection } from 'better-sqlite-pool' + import { calculateFeeAmount, calculateTaxAmount @@ -18,9 +20,10 @@ export interface AddLotOccupancyFeeForm { export default async function addLotOccupancyFee( lotOccupancyFeeForm: AddLotOccupancyFeeForm, - user: User + user: User, + connectedDatabase?: PoolConnection ): Promise { - const database = await acquireConnection() + const database = connectedDatabase ?? (await acquireConnection()) const rightNowMillis = Date.now() @@ -48,109 +51,109 @@ export default async function addLotOccupancyFee( : 0 } - // Check if record already exists - const record = database - .prepare( - `select feeAmount, taxAmount, recordDelete_timeMillis - from LotOccupancyFees - where lotOccupancyId = ? - and feeId = ?` - ) - .get(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId) as { - feeAmount?: number - taxAmount?: number - recordDelete_timeMillis?: number - } - - if (record) { - if (record.recordDelete_timeMillis) { - database - .prepare( - `delete from LotOccupancyFees - where recordDelete_timeMillis is not null - and lotOccupancyId = ? - and feeId = ?` - ) - .run(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId) - } else if ( - record.feeAmount === feeAmount && - record.taxAmount === taxAmount - ) { - database - .prepare( - `update LotOccupancyFees - set quantity = quantity + ?, - recordUpdate_userName = ?, - recordUpdate_timeMillis = ? - where lotOccupancyId = ? - and feeId = ?` - ) - .run( - lotOccupancyFeeForm.quantity, - user.userName, - rightNowMillis, - lotOccupancyFeeForm.lotOccupancyId, - lotOccupancyFeeForm.feeId - ) - - database.release() + try { + // Check if record already exists + const record = database + .prepare( + `select feeAmount, taxAmount, recordDelete_timeMillis + from LotOccupancyFees + where lotOccupancyId = ? + and feeId = ?` + ) + .get(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId) as { + feeAmount?: number + taxAmount?: number + recordDelete_timeMillis?: number + } - return true - } else { - const quantity = - typeof lotOccupancyFeeForm.quantity === 'string' - ? Number.parseFloat(lotOccupancyFeeForm.quantity) - : lotOccupancyFeeForm.quantity - - database - .prepare( - `update LotOccupancyFees - set feeAmount = (feeAmount * quantity) + ?, - taxAmount = (taxAmount * quantity) + ?, - quantity = 1, - recordUpdate_userName = ?, - recordUpdate_timeMillis = ? - where lotOccupancyId = ? - and feeId = ?` - ) - .run( - feeAmount * quantity, - taxAmount * quantity, - user.userName, - rightNowMillis, - lotOccupancyFeeForm.lotOccupancyId, - lotOccupancyFeeForm.feeId - ) + if (record) { + if (record.recordDelete_timeMillis) { + database + .prepare( + `delete from LotOccupancyFees + where recordDelete_timeMillis is not null + and lotOccupancyId = ? + and feeId = ?` + ) + .run(lotOccupancyFeeForm.lotOccupancyId, lotOccupancyFeeForm.feeId) + } else if ( + record.feeAmount === feeAmount && + record.taxAmount === taxAmount + ) { + database + .prepare( + `update LotOccupancyFees + set quantity = quantity + ?, + recordUpdate_userName = ?, + recordUpdate_timeMillis = ? + where lotOccupancyId = ? + and feeId = ?` + ) + .run( + lotOccupancyFeeForm.quantity, + user.userName, + rightNowMillis, + lotOccupancyFeeForm.lotOccupancyId, + lotOccupancyFeeForm.feeId + ) + + return true + } else { + const quantity = + typeof lotOccupancyFeeForm.quantity === 'string' + ? Number.parseFloat(lotOccupancyFeeForm.quantity) + : lotOccupancyFeeForm.quantity + + database + .prepare( + `update LotOccupancyFees + set feeAmount = (feeAmount * quantity) + ?, + taxAmount = (taxAmount * quantity) + ?, + quantity = 1, + recordUpdate_userName = ?, + recordUpdate_timeMillis = ? + where lotOccupancyId = ? + and feeId = ?` + ) + .run( + feeAmount * quantity, + taxAmount * quantity, + user.userName, + rightNowMillis, + lotOccupancyFeeForm.lotOccupancyId, + lotOccupancyFeeForm.feeId + ) + + return true + } + } + // Create new record + const result = database + .prepare( + `insert into LotOccupancyFees ( + lotOccupancyId, feeId, + quantity, feeAmount, taxAmount, + recordCreate_userName, recordCreate_timeMillis, + recordUpdate_userName, recordUpdate_timeMillis) + values (?, ?, ?, ?, ?, ?, ?, ?, ?)` + ) + .run( + lotOccupancyFeeForm.lotOccupancyId, + lotOccupancyFeeForm.feeId, + lotOccupancyFeeForm.quantity, + feeAmount, + taxAmount, + user.userName, + rightNowMillis, + user.userName, + rightNowMillis + ) + + return result.changes > 0 + } finally { + if (connectedDatabase === undefined) { database.release() - - return true } } - - // Create new record - const result = database - .prepare( - `insert into LotOccupancyFees ( - lotOccupancyId, feeId, - quantity, feeAmount, taxAmount, - recordCreate_userName, recordCreate_timeMillis, - recordUpdate_userName, recordUpdate_timeMillis) - values (?, ?, ?, ?, ?, ?, ?, ?, ?)` - ) - .run( - lotOccupancyFeeForm.lotOccupancyId, - lotOccupancyFeeForm.feeId, - lotOccupancyFeeForm.quantity, - feeAmount, - taxAmount, - user.userName, - rightNowMillis, - user.userName, - rightNowMillis - ) - - database.release() - - return result.changes > 0 } diff --git a/database/addLotOccupancyFeeCategory.d.ts b/database/addLotOccupancyFeeCategory.d.ts new file mode 100644 index 00000000..d4eabba2 --- /dev/null +++ b/database/addLotOccupancyFeeCategory.d.ts @@ -0,0 +1,5 @@ +export interface AddLotOccupancyFeeCategoryForm { + lotOccupancyId: number | string; + feeCategoryId: number | string; +} +export default function addLotOccupancyFeeCategory(lotOccupancyFeeCategoryForm: AddLotOccupancyFeeCategoryForm, user: User): Promise; diff --git a/database/addLotOccupancyFeeCategory.js b/database/addLotOccupancyFeeCategory.js new file mode 100644 index 00000000..8f01321f --- /dev/null +++ b/database/addLotOccupancyFeeCategory.js @@ -0,0 +1,20 @@ +import addLotOccupancyFee from './addLotOccupancyFee.js'; +import { getFeeCategory } from './getFeeCategories.js'; +import { acquireConnection } from './pool.js'; +export default async function addLotOccupancyFeeCategory(lotOccupancyFeeCategoryForm, user) { + const database = await acquireConnection(); + const feeCategory = await getFeeCategory(lotOccupancyFeeCategoryForm.feeCategoryId, database); + let addedFeeCount = 0; + for (const fee of feeCategory?.fees ?? []) { + const success = await addLotOccupancyFee({ + lotOccupancyId: lotOccupancyFeeCategoryForm.lotOccupancyId, + feeId: fee.feeId, + quantity: 1 + }, user, database); + if (success) { + addedFeeCount += 1; + } + } + database.release(); + return addedFeeCount; +} diff --git a/database/addLotOccupancyFeeCategory.ts b/database/addLotOccupancyFeeCategory.ts new file mode 100644 index 00000000..78e7f2c5 --- /dev/null +++ b/database/addLotOccupancyFeeCategory.ts @@ -0,0 +1,42 @@ +import addLotOccupancyFee from './addLotOccupancyFee.js' +import { getFeeCategory } from './getFeeCategories.js' +import { acquireConnection } from './pool.js' + +export interface AddLotOccupancyFeeCategoryForm { + lotOccupancyId: number | string + feeCategoryId: number | string +} + +export default async function addLotOccupancyFeeCategory( + lotOccupancyFeeCategoryForm: AddLotOccupancyFeeCategoryForm, + user: User +): Promise { + const database = await acquireConnection() + + const feeCategory = await getFeeCategory( + lotOccupancyFeeCategoryForm.feeCategoryId, + database + ) + + let addedFeeCount = 0 + + for (const fee of feeCategory?.fees ?? []) { + const success = await addLotOccupancyFee( + { + lotOccupancyId: lotOccupancyFeeCategoryForm.lotOccupancyId, + feeId: fee.feeId, + quantity: 1 + }, + user, + database + ) + + if (success) { + addedFeeCount += 1 + } + } + + database.release() + + return addedFeeCount +} diff --git a/database/addRecord.d.ts b/database/addRecord.d.ts index 67bfea2d..988739f0 100644 --- a/database/addRecord.d.ts +++ b/database/addRecord.d.ts @@ -1,3 +1,3 @@ -type RecordTable = 'FeeCategories' | 'LotStatuses' | 'LotTypes' | 'OccupancyTypes' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes'; +type RecordTable = 'LotStatuses' | 'LotTypes' | 'OccupancyTypes' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes'; export declare function addRecord(recordTable: RecordTable, recordName: string, orderNumber: number | string, user: User): Promise; export {}; diff --git a/database/addRecord.js b/database/addRecord.js index 65541592..819fdec2 100644 --- a/database/addRecord.js +++ b/database/addRecord.js @@ -1,7 +1,6 @@ import { clearCacheByTableName } from '../helpers/functions.cache.js'; import { acquireConnection } from './pool.js'; const recordNameColumns = new Map(); -recordNameColumns.set('FeeCategories', 'feeCategory'); recordNameColumns.set('LotStatuses', 'lotStatus'); recordNameColumns.set('LotTypes', 'lotType'); recordNameColumns.set('OccupancyTypes', 'occupancyType'); diff --git a/database/addRecord.ts b/database/addRecord.ts index 7c5f307a..ace4111e 100644 --- a/database/addRecord.ts +++ b/database/addRecord.ts @@ -3,7 +3,6 @@ import { clearCacheByTableName } from '../helpers/functions.cache.js' import { acquireConnection } from './pool.js' type RecordTable = - | 'FeeCategories' | 'LotStatuses' | 'LotTypes' | 'OccupancyTypes' @@ -11,7 +10,6 @@ type RecordTable = | 'WorkOrderTypes' const recordNameColumns = new Map() -recordNameColumns.set('FeeCategories', 'feeCategory') recordNameColumns.set('LotStatuses', 'lotStatus') recordNameColumns.set('LotTypes', 'lotType') recordNameColumns.set('OccupancyTypes', 'occupancyType') diff --git a/database/getFeeCategories.d.ts b/database/getFeeCategories.d.ts index 78f7cd85..4bd94dfe 100644 --- a/database/getFeeCategories.d.ts +++ b/database/getFeeCategories.d.ts @@ -1,10 +1,13 @@ +import { type PoolConnection } from 'better-sqlite-pool'; import type { FeeCategory } from '../types/recordTypes.js'; interface GetFeeCategoriesFilters { occupancyTypeId?: number | string; lotTypeId?: number | string; + feeCategoryId?: number | string; } interface GetFeeCategoriesOptions { includeFees?: boolean; } -export default function getFeeCategories(filters: GetFeeCategoriesFilters, options: GetFeeCategoriesOptions): Promise; +export default function getFeeCategories(filters: GetFeeCategoriesFilters, options: GetFeeCategoriesOptions, connectedDatabase?: PoolConnection): Promise; +export declare function getFeeCategory(feeCategoryId: number | string, connectedDatabase?: PoolConnection): Promise; export {}; diff --git a/database/getFeeCategories.js b/database/getFeeCategories.js index ce0ab05e..88cb9421 100644 --- a/database/getFeeCategories.js +++ b/database/getFeeCategories.js @@ -1,7 +1,7 @@ import getFees from './getFees.js'; import { acquireConnection } from './pool.js'; import { updateRecordOrderNumber } from './updateRecordOrderNumber.js'; -export default async function getFeeCategories(filters, options) { +export default async function getFeeCategories(filters, options, connectedDatabase) { const updateOrderNumbers = !(filters.lotTypeId || filters.occupancyTypeId) && options.includeFees; const database = await acquireConnection(); let sqlWhereClause = ' where recordDelete_timeMillis is null'; @@ -17,7 +17,7 @@ export default async function getFeeCategories(filters, options) { sqlParameters.push(filters.lotTypeId); } const feeCategories = database - .prepare(`select feeCategoryId, feeCategory, orderNumber + .prepare(`select feeCategoryId, feeCategory, isGroupedFee, orderNumber from FeeCategories ${sqlWhereClause} order by orderNumber, feeCategory`) @@ -34,6 +34,19 @@ export default async function getFeeCategories(filters, options) { feeCategory.fees = await getFees(feeCategory.feeCategoryId, filters, database); } } - database.release(); + if (connectedDatabase === undefined) { + database.release(); + } return feeCategories; } +export async function getFeeCategory(feeCategoryId, connectedDatabase) { + const feeCategories = await getFeeCategories({ + feeCategoryId + }, { + includeFees: true + }, connectedDatabase); + if (feeCategories.length > 0) { + return feeCategories[0]; + } + return undefined; +} diff --git a/database/getFeeCategories.ts b/database/getFeeCategories.ts index ca031a0a..738eb7e4 100644 --- a/database/getFeeCategories.ts +++ b/database/getFeeCategories.ts @@ -1,3 +1,5 @@ +import { type PoolConnection } from 'better-sqlite-pool' + import type { FeeCategory } from '../types/recordTypes.js' import getFees from './getFees.js' @@ -7,6 +9,7 @@ import { updateRecordOrderNumber } from './updateRecordOrderNumber.js' interface GetFeeCategoriesFilters { occupancyTypeId?: number | string lotTypeId?: number | string + feeCategoryId?: number | string } interface GetFeeCategoriesOptions { @@ -15,7 +18,8 @@ interface GetFeeCategoriesOptions { export default async function getFeeCategories( filters: GetFeeCategoriesFilters, - options: GetFeeCategoriesOptions + options: GetFeeCategoriesOptions, + connectedDatabase?: PoolConnection ): Promise { const updateOrderNumbers = !(filters.lotTypeId || filters.occupancyTypeId) && options.includeFees @@ -42,7 +46,7 @@ export default async function getFeeCategories( const feeCategories = database .prepare( - `select feeCategoryId, feeCategory, orderNumber + `select feeCategoryId, feeCategory, isGroupedFee, orderNumber from FeeCategories ${sqlWhereClause} order by orderNumber, feeCategory` @@ -77,7 +81,30 @@ export default async function getFeeCategories( } } - database.release() + if (connectedDatabase === undefined) { + database.release() + } return feeCategories } + +export async function getFeeCategory( + feeCategoryId: number | string, + connectedDatabase?: PoolConnection +): Promise { + const feeCategories = await getFeeCategories( + { + feeCategoryId + }, + { + includeFees: true + }, + connectedDatabase + ) + + if (feeCategories.length > 0) { + return feeCategories[0] + } + + return undefined +} diff --git a/database/updateFeeCategory.d.ts b/database/updateFeeCategory.d.ts index a3ca19cc..e13c3755 100644 --- a/database/updateFeeCategory.d.ts +++ b/database/updateFeeCategory.d.ts @@ -1,5 +1,6 @@ export interface UpdateFeeCategoryForm { feeCategoryId: number | string; feeCategory: string; + isGroupedFee?: '1'; } export default function updateFeeCategory(feeCategoryForm: UpdateFeeCategoryForm, user: User): Promise; diff --git a/database/updateFeeCategory.js b/database/updateFeeCategory.js index 7e2961f9..8cf2a3b9 100644 --- a/database/updateFeeCategory.js +++ b/database/updateFeeCategory.js @@ -1,4 +1,15 @@ -import { updateRecord } from './updateRecord.js'; +import { acquireConnection } from './pool.js'; export default async function updateFeeCategory(feeCategoryForm, user) { - return await updateRecord('FeeCategories', feeCategoryForm.feeCategoryId, feeCategoryForm.feeCategory, user); + const database = await acquireConnection(); + const result = database + .prepare(`update FeeCategories + set feeCategory = ?, + isGroupedFee = ?, + recordUpdate_userName = ?, + recordUpdate_timeMillis = ? + where recordDelete_timeMillis is null + and feeCategoryId = ?`) + .run(feeCategoryForm.feeCategory, (feeCategoryForm.isGroupedFee ?? '') === '1' ? 1 : 0, user.userName, Date.now(), feeCategoryForm.feeCategoryId); + database.release(); + return result.changes > 0; } diff --git a/database/updateFeeCategory.ts b/database/updateFeeCategory.ts index 5d617b2a..cda6c08c 100644 --- a/database/updateFeeCategory.ts +++ b/database/updateFeeCategory.ts @@ -1,18 +1,36 @@ -import { updateRecord } from './updateRecord.js' +import { acquireConnection } from './pool.js' export interface UpdateFeeCategoryForm { feeCategoryId: number | string feeCategory: string + isGroupedFee?: '1' } export default async function updateFeeCategory( feeCategoryForm: UpdateFeeCategoryForm, user: User ): Promise { - return await updateRecord( - 'FeeCategories', - feeCategoryForm.feeCategoryId, - feeCategoryForm.feeCategory, - user - ) + const database = await acquireConnection() + + const result = database + .prepare( + `update FeeCategories + set feeCategory = ?, + isGroupedFee = ?, + recordUpdate_userName = ?, + recordUpdate_timeMillis = ? + where recordDelete_timeMillis is null + and feeCategoryId = ?` + ) + .run( + feeCategoryForm.feeCategory, + (feeCategoryForm.isGroupedFee ?? '') === '1' ? 1 : 0, + user.userName, + Date.now(), + feeCategoryForm.feeCategoryId + ) + + database.release() + + return result.changes > 0 } diff --git a/database/updateRecord.d.ts b/database/updateRecord.d.ts index 68b0d130..b70fdc17 100644 --- a/database/updateRecord.d.ts +++ b/database/updateRecord.d.ts @@ -1,3 +1,3 @@ -type RecordTable = 'FeeCategories' | 'LotStatuses' | 'LotTypes' | 'OccupancyTypes' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes'; +type RecordTable = 'LotStatuses' | 'LotTypes' | 'OccupancyTypes' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes'; export declare function updateRecord(recordTable: RecordTable, recordId: number | string, recordName: string, user: User): Promise; export {}; diff --git a/database/updateRecord.js b/database/updateRecord.js index ff1677f3..91f646ac 100644 --- a/database/updateRecord.js +++ b/database/updateRecord.js @@ -1,7 +1,6 @@ import { clearCacheByTableName } from '../helpers/functions.cache.js'; import { acquireConnection } from './pool.js'; const recordNameIdColumns = new Map(); -recordNameIdColumns.set('FeeCategories', ['feeCategory', 'feeCategoryId']); recordNameIdColumns.set('LotStatuses', ['lotStatus', 'lotStatusId']); recordNameIdColumns.set('LotTypes', ['lotType', 'lotTypeId']); recordNameIdColumns.set('OccupancyTypes', ['occupancyType', 'occupancyTypeId']); diff --git a/database/updateRecord.ts b/database/updateRecord.ts index 2f8ed4d2..9f010d4e 100644 --- a/database/updateRecord.ts +++ b/database/updateRecord.ts @@ -3,7 +3,6 @@ import { clearCacheByTableName } from '../helpers/functions.cache.js' import { acquireConnection } from './pool.js' type RecordTable = - | 'FeeCategories' | 'LotStatuses' | 'LotTypes' | 'OccupancyTypes' @@ -11,7 +10,6 @@ type RecordTable = | 'WorkOrderTypes' const recordNameIdColumns = new Map() -recordNameIdColumns.set('FeeCategories', ['feeCategory', 'feeCategoryId']) recordNameIdColumns.set('LotStatuses', ['lotStatus', 'lotStatusId']) recordNameIdColumns.set('LotTypes', ['lotType', 'lotTypeId']) recordNameIdColumns.set('OccupancyTypes', ['occupancyType', 'occupancyTypeId']) diff --git a/handlers/admin-post/doAddFeeCategory.js b/handlers/admin-post/doAddFeeCategory.js index f0f08b01..933436dc 100644 --- a/handlers/admin-post/doAddFeeCategory.js +++ b/handlers/admin-post/doAddFeeCategory.js @@ -1,7 +1,7 @@ -import { addRecord } from '../../database/addRecord.js'; +import addFeeCategory from '../../database/addFeeCategory.js'; import getFeeCategories from '../../database/getFeeCategories.js'; export default async function handler(request, response) { - const feeCategoryId = await addRecord('FeeCategories', request.body.feeCategory, request.body.orderNumber ?? -1, request.session.user); + const feeCategoryId = await addFeeCategory(request.body, request.session.user); const feeCategories = await getFeeCategories({}, { includeFees: true }); diff --git a/handlers/admin-post/doAddFeeCategory.ts b/handlers/admin-post/doAddFeeCategory.ts index d3167bcc..d8813ff0 100644 --- a/handlers/admin-post/doAddFeeCategory.ts +++ b/handlers/admin-post/doAddFeeCategory.ts @@ -1,16 +1,16 @@ import type { Request, Response } from 'express' -import { addRecord } from '../../database/addRecord.js' +import addFeeCategory, { + type AddFeeCategoryForm +} from '../../database/addFeeCategory.js' import getFeeCategories from '../../database/getFeeCategories.js' export default async function handler( request: Request, response: Response ): Promise { - const feeCategoryId = await addRecord( - 'FeeCategories', - request.body.feeCategory, - request.body.orderNumber ?? -1, + const feeCategoryId = await addFeeCategory( + request.body as AddFeeCategoryForm, request.session.user as User ) diff --git a/handlers/lotOccupancies-post/doAddLotOccupancyFee.ts b/handlers/lotOccupancies-post/doAddLotOccupancyFee.ts index 0bf3c9d6..8c6ceb61 100644 --- a/handlers/lotOccupancies-post/doAddLotOccupancyFee.ts +++ b/handlers/lotOccupancies-post/doAddLotOccupancyFee.ts @@ -15,7 +15,7 @@ export default async function handler( ) const lotOccupancyFees = await getLotOccupancyFees( - request.body.lotOccupancyId + request.body.lotOccupancyId as string ) response.json({ diff --git a/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.d.ts b/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.d.ts new file mode 100644 index 00000000..536d445f --- /dev/null +++ b/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.d.ts @@ -0,0 +1,3 @@ +/// +import type { Request, Response } from 'express'; +export default function handler(request: Request, response: Response): Promise; diff --git a/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.js b/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.js new file mode 100644 index 00000000..ea423a93 --- /dev/null +++ b/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.js @@ -0,0 +1,10 @@ +import addLotOccupancyFeeCategory from '../../database/addLotOccupancyFeeCategory.js'; +import getLotOccupancyFees from '../../database/getLotOccupancyFees.js'; +export default async function handler(request, response) { + await addLotOccupancyFeeCategory(request.body, request.session.user); + const lotOccupancyFees = await getLotOccupancyFees(request.body.lotOccupancyId); + response.json({ + success: true, + lotOccupancyFees + }); +} diff --git a/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.ts b/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.ts new file mode 100644 index 00000000..bdcf5cad --- /dev/null +++ b/handlers/lotOccupancies-post/doAddLotOccupancyFeeCategory.ts @@ -0,0 +1,25 @@ +import type { Request, Response } from 'express' + +import addLotOccupancyFeeCategory, { + type AddLotOccupancyFeeCategoryForm +} from '../../database/addLotOccupancyFeeCategory.js' +import getLotOccupancyFees from '../../database/getLotOccupancyFees.js' + +export default async function handler( + request: Request, + response: Response +): Promise { + await addLotOccupancyFeeCategory( + request.body as AddLotOccupancyFeeCategoryForm, + request.session.user as User + ) + + const lotOccupancyFees = await getLotOccupancyFees( + request.body.lotOccupancyId as string + ) + + response.json({ + success: true, + lotOccupancyFees + }) +} diff --git a/helpers/initializer.database.js b/helpers/initializer.database.js index fd63f75b..845a6c3d 100644 --- a/helpers/initializer.database.js +++ b/helpers/initializer.database.js @@ -56,7 +56,12 @@ const createStatements = [ /* * Fees and Transactions */ - `create table if not exists FeeCategories (feeCategoryId integer not null primary key autoincrement, feeCategory varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, + `create table if not exists FeeCategories ( + feeCategoryId integer not null primary key autoincrement, + feeCategory varchar(100) not null, + isGroupedFee bit not null default 0, + orderNumber smallint not null default 0, + ${recordColumns})`, `create table if not exists Fees ( feeId integer not null primary key autoincrement, feeCategoryId integer not null, diff --git a/helpers/initializer.database.ts b/helpers/initializer.database.ts index 71863dec..4d0d1fe4 100644 --- a/helpers/initializer.database.ts +++ b/helpers/initializer.database.ts @@ -69,7 +69,13 @@ const createStatements = [ * Fees and Transactions */ - `create table if not exists FeeCategories (feeCategoryId integer not null primary key autoincrement, feeCategory varchar(100) not null, orderNumber smallint not null default 0, ${recordColumns})`, + `create table if not exists FeeCategories ( + feeCategoryId integer not null primary key autoincrement, + feeCategory varchar(100) not null, + isGroupedFee bit not null default 0, + orderNumber smallint not null default 0, + ${recordColumns})`, + `create table if not exists Fees ( feeId integer not null primary key autoincrement, feeCategoryId integer not null, diff --git a/public-typescript/adminFees.js b/public-typescript/adminFees.js index c91104e5..0cc2ad64 100644 --- a/public-typescript/adminFees.js +++ b/public-typescript/adminFees.js @@ -26,7 +26,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); feeCategoryContainerElement.innerHTML = `
-

${cityssm.escapeHTML((_a = feeCategory.feeCategory) !== null && _a !== void 0 ? _a : '')}

+

${cityssm.escapeHTML((_a = feeCategory.feeCategory) !== null && _a !== void 0 ? _a : '')}

+ ${feeCategory.isGroupedFee + ? 'Grouped Fee' + : ''}
@@ -82,7 +85,9 @@ Object.defineProperty(exports, "__esModule", { value: true });

${cityssm.escapeHTML((_e = fee.feeName) !== null && _e !== void 0 ? _e : '')}
- ${cityssm + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm .escapeHTML((_f = fee.feeDescription) !== null && _f !== void 0 ? _f : '') .replaceAll('\n', '
')}
@@ -220,6 +225,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); ; modalElement.querySelector('#feeCategoryEdit--feeCategoryId').value = feeCategory.feeCategoryId.toString(); modalElement.querySelector('#feeCategoryEdit--feeCategory').value = feeCategory.feeCategory; + if (feeCategory.isGroupedFee) { + ; + modalElement.querySelector('#feeCategoryEdit--isGroupedFee').checked = true; + } }, onshown(modalElement, closeModalFunction) { var _a; diff --git a/public-typescript/adminFees.ts b/public-typescript/adminFees.ts index 59564165..794f72e3 100644 --- a/public-typescript/adminFees.ts +++ b/public-typescript/adminFees.ts @@ -59,7 +59,12 @@ declare const exports: Record feeCategoryContainerElement.innerHTML = `

-

${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}

+

${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}

+ ${ + feeCategory.isGroupedFee + ? 'Grouped Fee' + : '' + }
@@ -131,9 +136,12 @@ declare const exports: Record

${cityssm.escapeHTML(fee.feeName ?? '')}
- ${cityssm + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm .escapeHTML(fee.feeDescription ?? '') - .replaceAll('\n', '
')} + .replaceAll('\n', '
') + }

${ @@ -350,6 +358,14 @@ declare const exports: Record '#feeCategoryEdit--feeCategory' ) as HTMLInputElement ).value = feeCategory.feeCategory + + if (feeCategory.isGroupedFee) { + ;( + modalElement.querySelector( + '#feeCategoryEdit--isGroupedFee' + ) as HTMLInputElement + ).checked = true + } }, onshown(modalElement, closeModalFunction) { bulmaJS.toggleHtmlClipped() diff --git a/public-typescript/lotOccupancyEdit.js b/public-typescript/lotOccupancyEdit.js index 43dca90c..c2081815 100644 --- a/public-typescript/lotOccupancyEdit.js +++ b/public-typescript/lotOccupancyEdit.js @@ -1265,6 +1265,33 @@ Object.defineProperty(exports, "__esModule", { value: true }); let feeCategories; let feeFilterElement; let feeFilterResultsElement; + function doAddFeeCategory(clickEvent) { + var _a; + clickEvent.preventDefault(); + const feeCategoryId = Number.parseInt((_a = clickEvent.currentTarget.dataset.feeCategoryId) !== null && _a !== void 0 ? _a : '', 10); + cityssm.postJSON(`${los.urlPrefix}/lotOccupancies/doAddLotOccupancyFeeCategory`, { + lotOccupancyId, + feeCategoryId + }, (rawResponseJSON) => { + var _a; + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotOccupancyFees = responseJSON.lotOccupancyFees; + renderLotOccupancyFees(); + bulmaJS.alert({ + message: 'Fee Group Added Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Adding Fee', + message: (_a = responseJSON.errorMessage) !== null && _a !== void 0 ? _a : '', + contextualColorName: 'danger' + }); + } + }); + } function doAddFee(feeId, quantity = 1) { cityssm.postJSON(`${los.urlPrefix}/lotOccupancies/doAddLotOccupancyFee`, { lotOccupancyId, @@ -1329,7 +1356,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); } } function filterFees() { - var _a, _b, _c, _d, _e, _f; + var _a, _b, _c, _d, _e, _f, _g, _h; const filterStringPieces = feeFilterElement.value .trim() .toLowerCase() @@ -1340,10 +1367,24 @@ Object.defineProperty(exports, "__esModule", { value: true }); categoryContainerElement.className = 'container--feeCategory'; categoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString(); - categoryContainerElement.innerHTML = `

- ${cityssm.escapeHTML((_a = feeCategory.feeCategory) !== null && _a !== void 0 ? _a : '')} -

+ categoryContainerElement.innerHTML = `
+
+

+ ${cityssm.escapeHTML((_a = feeCategory.feeCategory) !== null && _a !== void 0 ? _a : '')} +

+
+
`; + if (feeCategory.isGroupedFee) { + // eslint-disable-next-line no-unsanitized/method + (_b = categoryContainerElement.querySelector('.columns')) === null || _b === void 0 ? void 0 : _b.insertAdjacentHTML('beforeend', `
+ +
`); + (_c = categoryContainerElement.querySelector('button')) === null || _c === void 0 ? void 0 : _c.addEventListener('click', doAddFeeCategory); + } let hasFees = false; for (const fee of feeCategory.fees) { // Don't include already applied fees that limit quantity @@ -1351,7 +1392,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); continue; } let includeFee = true; - const feeSearchString = `${(_b = feeCategory.feeCategory) !== null && _b !== void 0 ? _b : ''} ${(_c = fee.feeName) !== null && _c !== void 0 ? _c : ''} ${(_d = fee.feeDescription) !== null && _d !== void 0 ? _d : ''}`.toLowerCase(); + const feeSearchString = `${(_d = feeCategory.feeCategory) !== null && _d !== void 0 ? _d : ''} ${(_e = fee.feeName) !== null && _e !== void 0 ? _e : ''} ${(_f = fee.feeDescription) !== null && _f !== void 0 ? _f : ''}`.toLowerCase(); for (const filterStringPiece of filterStringPieces) { if (!feeSearchString.includes(filterStringPiece)) { includeFee = false; @@ -1362,20 +1403,26 @@ Object.defineProperty(exports, "__esModule", { value: true }); continue; } hasFees = true; - const panelBlockElement = document.createElement('a'); + const panelBlockElement = document.createElement(feeCategory.isGroupedFee ? 'div' : 'a'); panelBlockElement.className = 'panel-block is-block container--fee'; panelBlockElement.dataset.feeId = fee.feeId.toString(); panelBlockElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString(); - panelBlockElement.href = '#'; // eslint-disable-next-line no-unsanitized/property - panelBlockElement.innerHTML = `${cityssm.escapeHTML((_e = fee.feeName) !== null && _e !== void 0 ? _e : '')}
+ panelBlockElement.innerHTML = `${cityssm.escapeHTML((_g = fee.feeName) !== null && _g !== void 0 ? _g : '')}
- ${cityssm - .escapeHTML((_f = fee.feeDescription) !== null && _f !== void 0 ? _f : '') + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm + .escapeHTML((_h = fee.feeDescription) !== null && _h !== void 0 ? _h : '') .replaceAll('\n', '
')}
`; - panelBlockElement.addEventListener('click', tryAddFee); + if (!feeCategory.isGroupedFee) { + ; + panelBlockElement.href = '#'; + panelBlockElement.addEventListener('click', tryAddFee); + } + ; categoryContainerElement.querySelector('.panel').append(panelBlockElement); } if (hasFees) { diff --git a/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.js b/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.js index 24d15403..befd41af 100644 --- a/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.js +++ b/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.js @@ -194,6 +194,33 @@ addFeeButtonElement.addEventListener('click', () => { let feeCategories; let feeFilterElement; let feeFilterResultsElement; + function doAddFeeCategory(clickEvent) { + var _a; + clickEvent.preventDefault(); + const feeCategoryId = Number.parseInt((_a = clickEvent.currentTarget.dataset.feeCategoryId) !== null && _a !== void 0 ? _a : '', 10); + cityssm.postJSON(`${los.urlPrefix}/lotOccupancies/doAddLotOccupancyFeeCategory`, { + lotOccupancyId, + feeCategoryId + }, (rawResponseJSON) => { + var _a; + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotOccupancyFees = responseJSON.lotOccupancyFees; + renderLotOccupancyFees(); + bulmaJS.alert({ + message: 'Fee Group Added Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Adding Fee', + message: (_a = responseJSON.errorMessage) !== null && _a !== void 0 ? _a : '', + contextualColorName: 'danger' + }); + } + }); + } function doAddFee(feeId, quantity = 1) { cityssm.postJSON(`${los.urlPrefix}/lotOccupancies/doAddLotOccupancyFee`, { lotOccupancyId, @@ -258,7 +285,7 @@ addFeeButtonElement.addEventListener('click', () => { } } function filterFees() { - var _a, _b, _c, _d, _e, _f; + var _a, _b, _c, _d, _e, _f, _g, _h; const filterStringPieces = feeFilterElement.value .trim() .toLowerCase() @@ -269,10 +296,24 @@ addFeeButtonElement.addEventListener('click', () => { categoryContainerElement.className = 'container--feeCategory'; categoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString(); - categoryContainerElement.innerHTML = `

- ${cityssm.escapeHTML((_a = feeCategory.feeCategory) !== null && _a !== void 0 ? _a : '')} -

+ categoryContainerElement.innerHTML = `
+
+

+ ${cityssm.escapeHTML((_a = feeCategory.feeCategory) !== null && _a !== void 0 ? _a : '')} +

+
+
`; + if (feeCategory.isGroupedFee) { + // eslint-disable-next-line no-unsanitized/method + (_b = categoryContainerElement.querySelector('.columns')) === null || _b === void 0 ? void 0 : _b.insertAdjacentHTML('beforeend', `
+ +
`); + (_c = categoryContainerElement.querySelector('button')) === null || _c === void 0 ? void 0 : _c.addEventListener('click', doAddFeeCategory); + } let hasFees = false; for (const fee of feeCategory.fees) { // Don't include already applied fees that limit quantity @@ -280,7 +321,7 @@ addFeeButtonElement.addEventListener('click', () => { continue; } let includeFee = true; - const feeSearchString = `${(_b = feeCategory.feeCategory) !== null && _b !== void 0 ? _b : ''} ${(_c = fee.feeName) !== null && _c !== void 0 ? _c : ''} ${(_d = fee.feeDescription) !== null && _d !== void 0 ? _d : ''}`.toLowerCase(); + const feeSearchString = `${(_d = feeCategory.feeCategory) !== null && _d !== void 0 ? _d : ''} ${(_e = fee.feeName) !== null && _e !== void 0 ? _e : ''} ${(_f = fee.feeDescription) !== null && _f !== void 0 ? _f : ''}`.toLowerCase(); for (const filterStringPiece of filterStringPieces) { if (!feeSearchString.includes(filterStringPiece)) { includeFee = false; @@ -291,20 +332,26 @@ addFeeButtonElement.addEventListener('click', () => { continue; } hasFees = true; - const panelBlockElement = document.createElement('a'); + const panelBlockElement = document.createElement(feeCategory.isGroupedFee ? 'div' : 'a'); panelBlockElement.className = 'panel-block is-block container--fee'; panelBlockElement.dataset.feeId = fee.feeId.toString(); panelBlockElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString(); - panelBlockElement.href = '#'; // eslint-disable-next-line no-unsanitized/property - panelBlockElement.innerHTML = `${cityssm.escapeHTML((_e = fee.feeName) !== null && _e !== void 0 ? _e : '')}
+ panelBlockElement.innerHTML = `${cityssm.escapeHTML((_g = fee.feeName) !== null && _g !== void 0 ? _g : '')}
- ${cityssm - .escapeHTML((_f = fee.feeDescription) !== null && _f !== void 0 ? _f : '') + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm + .escapeHTML((_h = fee.feeDescription) !== null && _h !== void 0 ? _h : '') .replaceAll('\n', '
')}
`; - panelBlockElement.addEventListener('click', tryAddFee); + if (!feeCategory.isGroupedFee) { + ; + panelBlockElement.href = '#'; + panelBlockElement.addEventListener('click', tryAddFee); + } + ; categoryContainerElement.querySelector('.panel').append(panelBlockElement); } if (hasFees) { diff --git a/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.ts b/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.ts index a058d931..d7123d0d 100644 --- a/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.ts +++ b/public-typescript/lotOccupancyEdit/lotOccupancyEditFees.ts @@ -307,6 +307,47 @@ addFeeButtonElement.addEventListener('click', () => { let feeFilterElement: HTMLInputElement let feeFilterResultsElement: HTMLElement + function doAddFeeCategory(clickEvent: Event): void { + clickEvent.preventDefault() + + const feeCategoryId = Number.parseInt( + (clickEvent.currentTarget as HTMLElement).dataset.feeCategoryId ?? '', + 10 + ) + + cityssm.postJSON( + `${los.urlPrefix}/lotOccupancies/doAddLotOccupancyFeeCategory`, + { + lotOccupancyId, + feeCategoryId + }, + (rawResponseJSON) => { + const responseJSON = rawResponseJSON as { + success: boolean + errorMessage?: string + lotOccupancyFees: LotOccupancyFee[] + } + + if (responseJSON.success) { + lotOccupancyFees = responseJSON.lotOccupancyFees + renderLotOccupancyFees() + + bulmaJS.alert({ + message: 'Fee Group Added Successfully', + contextualColorName: 'success' + }) + + } else { + bulmaJS.alert({ + title: 'Error Adding Fee', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }) + } + } + ) + } + function doAddFee(feeId: number, quantity: number | string = 1): void { cityssm.postJSON( `${los.urlPrefix}/lotOccupancies/doAddLotOccupancyFee`, @@ -412,11 +453,30 @@ addFeeButtonElement.addEventListener('click', () => { categoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString() - categoryContainerElement.innerHTML = `

- ${cityssm.escapeHTML(feeCategory.feeCategory ?? '')} -

+ categoryContainerElement.innerHTML = `
+
+

+ ${cityssm.escapeHTML(feeCategory.feeCategory ?? '')} +

+
+
` + if (feeCategory.isGroupedFee) { + // eslint-disable-next-line no-unsanitized/method + categoryContainerElement.querySelector('.columns')?.insertAdjacentHTML( + 'beforeend', + `
+ +
` + ) + + categoryContainerElement.querySelector('button')?.addEventListener('click', doAddFeeCategory) + } + let hasFees = false for (const fee of feeCategory.fees) { @@ -447,22 +507,29 @@ addFeeButtonElement.addEventListener('click', () => { hasFees = true - const panelBlockElement = document.createElement('a') + const panelBlockElement = document.createElement( + feeCategory.isGroupedFee ? 'div' : 'a' + ) panelBlockElement.className = 'panel-block is-block container--fee' panelBlockElement.dataset.feeId = fee.feeId.toString() panelBlockElement.dataset.feeCategoryId = feeCategory.feeCategoryId.toString() - panelBlockElement.href = '#' // eslint-disable-next-line no-unsanitized/property panelBlockElement.innerHTML = `${cityssm.escapeHTML(fee.feeName ?? '')}
- ${cityssm - .escapeHTML(fee.feeDescription ?? '') - .replaceAll('\n', '
')} + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm + .escapeHTML(fee.feeDescription ?? '') + .replaceAll('\n', '
') + }
` - panelBlockElement.addEventListener('click', tryAddFee) + if (!feeCategory.isGroupedFee) { + ;(panelBlockElement as HTMLAnchorElement).href = '#' + panelBlockElement.addEventListener('click', tryAddFee) + } ;( categoryContainerElement.querySelector('.panel') as HTMLElement ).append(panelBlockElement) diff --git a/public/html/adminFees-addFeeCategory.html b/public/html/adminFees-addFeeCategory.html index 2f2c226b..691810ac 100644 --- a/public/html/adminFees-addFeeCategory.html +++ b/public/html/adminFees-addFeeCategory.html @@ -26,6 +26,10 @@ />
+
+