import { getFilterObject, getSortObject, PageQueryParams } from "../pagination"; import { generateId } from "../utils/id"; import { CreatePermitInput, permitFields, permitModel, UpdatePermitInput, } from "./permit.schema"; import { ChangeEvent, dbEvents } from "../realtime"; import { permitPipeline } from "../utils/pipeline"; import { AuthenticatedUser } from "../auth"; import mongoose from "mongoose"; import { noteModel } from "../note/note.schema"; import { getUser } from "../user/user.service"; import { createNote } from "../note/note.service"; import { createAlert } from "../alert/alert.service"; export async function createPermit( input: CreatePermitInput, user: AuthenticatedUser ) { if (!input.stage) { input.stage = { pipeline: permitPipeline, currentStage: 0, }; } const permit = await permitModel.create({ tenantId: user.tenantId, pid: generateId(), createdAt: new Date(), createdBy: user.userId, ...input, }); dbEvents.emit( "change", { type: "insert", collection: "permits", document: permit, } as ChangeEvent, ["permit:read"] ); return permit; } export async function getPermit(permitId: string, tenantId: string) { return await permitModel .findOne({ $and: [{ tenantId: tenantId }, { pid: permitId }], }) //.populate({ path: "county", select: "pid name avatar" }) //.populate({ path: "client", select: "pid name avatar" }) .populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "createdBy", select: "pid name avatar" }); } export async function listPermits( params: PageQueryParams, user: AuthenticatedUser ) { const page = params.page || 1; const pageSize = params.pageSize || 10; const sortObj = getSortObject(params, permitFields); const filterObj = getFilterObject(params) || []; if (user.role == "client") { filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) }); } const permitsList = await permitModel.aggregate([ { $match: { $and: [{ tenantId: user.tenantId }, ...filterObj] }, }, { $lookup: { from: "users", localField: "assignedTo", foreignField: "_id", as: "assignedRec", }, }, { $project: { _id: 1, pid: 1, permitNumber: 1, permitDate: 1, stage: 1, status: 1, manualStatus: 1, cleanStatus: 1, permitType: 1, utility: 1, link: 1, address: 1, recordType: 1, description: 1, applicationDetails: 1, applicationInfo: 1, applicationInfoTable: 1, conditions: 1, ownerDetails: 1, parcelInfo: 1, paymentData: 1, inspections: 1, newProcessingStatus: 1, newPayment: 1, newConditions: 1, professionals: 1, recordid: 1, relatedRecords: 1, accelaStatus: 1, createdAt: 1, county: 1, client: 1, clientData: 1, openDate: 1, lastUpdateDate: 1, statusUpdated: 1, issuedDate: 1, communityName: 1, lot: 1, block: 1, jobNumber: 1, startDate: 1, history: 1, assignedTo: { $let: { vars: { assigned: { $arrayElemAt: ["$assignedRec", 0] } }, in: { _id: "$$assigned._id", pid: "$$assigned.pid", name: "$$assigned.name", avatar: "$$assigned.avatar", }, }, }, }, }, { $facet: { metadata: [{ $count: "count" }], data: [ { $sort: sortObj }, { $skip: (page - 1) * pageSize }, { $limit: pageSize }, ], }, }, ]); if (permitsList[0].data.length === 0) return { permits: [], metadata: { count: 0, page, pageSize } }; return { permits: permitsList[0]?.data, metadata: { count: permitsList[0].metadata[0].count, page, pageSize, }, }; } export async function updatePermit( input: UpdatePermitInput, permitId: string, user: AuthenticatedUser ) { const updatePermitResult = await permitModel .findOneAndUpdate( { $and: [{ tenantId: user.tenantId }, { pid: permitId }], }, { ...input, lastUpdateDate: new Date() }, { new: true } ) .populate({ path: "county", select: "pid name avatar" }) .populate({ path: "client", select: "pid name avatar" }) .populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "createdBy", select: "pid name avatar" }); if (updatePermitResult) { for (const key in input) { if (["manualStatus", "utility", "assignedTo"].includes(key)) { let msg = ""; if (input[key] === null) { msg = `Cleared ${key}`; } else if (key == "assignedTo") { const user = await getUser(input.assignedTo); if (!user) continue; msg = `Assigned to ${user.firstName + " " + user.lastName}`; } else { msg = `Updated ${key} to '${input[key]}'`; } await createNote( { content: msg, }, permitId, user ); if (key == "assignedTo") { await createAlert( user.tenantId, `You are assigned to ${updatePermitResult.permitNumber}`, "user", user.userId, updatePermitResult.pid, "permits" ); } } } dbEvents.emit( "change", { type: "update", collection: "permits", document: updatePermitResult, } as ChangeEvent, ["permit:read"] ); } return updatePermitResult; } export async function deletePermit(permitId: string, tenantId: string) { const res = await permitModel.deleteOne({ $and: [{ tenantId: tenantId }, { pid: permitId }], }); dbEvents.emit( "change", { type: "delete", collection: "permits", document: { pid: permitId, }, } as ChangeEvent, ["permit:read"] ); return res; } export async function searchPermit( params: PageQueryParams, user: AuthenticatedUser ) { const page = params.page || 1; const pageSize = params.pageSize || 10; const sortObj = getSortObject(params, permitFields); const filterObj = getFilterObject(params) || []; if (user.role == "client") { filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) }); } if (!params.searchToken) return { permits: [], metadata: { count: 0, page, pageSize } }; const regex = new RegExp(params.searchToken, "i"); const permitsList = await permitModel.aggregate([ { $match: { $and: [{ tenantId: user.tenantId }, ...filterObj] }, }, { $match: { $or: [ { permitNumber: { $regex: regex } }, { link: { $regex: regex } }, { "address.full_address": { $regex: regex } }, ], }, }, { $lookup: { from: "users", localField: "assignedTo", foreignField: "_id", as: "assignedRec", }, }, { $project: { _id: 1, pid: 1, permitNumber: 1, permitDate: 1, stage: 1, status: 1, manualStatus: 1, cleanStatus: 1, permitType: 1, utility: 1, link: 1, address: 1, recordType: 1, description: 1, applicationDetails: 1, applicationInfo: 1, applicationInfoTable: 1, conditions: 1, ownerDetails: 1, parcelInfo: 1, paymentData: 1, inspections: 1, newProcessingStatus: 1, newPayment: 1, newConditions: 1, professionals: 1, recordid: 1, relatedRecords: 1, accelaStatus: 1, createdAt: 1, county: 1, client: 1, clientData: 1, openDate: 1, lastUpdateDate: 1, statusUpdated: 1, issuedDate: 1, communityName: 1, lot: 1, block: 1, jobNumber: 1, startDate: 1, history: 1, assignedTo: { $let: { vars: { assigned: { $arrayElemAt: ["$assignedRec", 0] } }, in: { _id: "$$assigned._id", pid: "$$assigned.pid", name: "$$assigned.name", avatar: "$$assigned.avatar", }, }, }, }, }, { $facet: { metadata: [{ $count: "count" }], data: [ { $sort: sortObj }, { $skip: (page - 1) * pageSize }, { $limit: pageSize }, ], }, }, ]); if (permitsList[0].data.length === 0) return { permits: [], metadata: { count: 0, page, pageSize } }; return { permits: permitsList[0]?.data, metadata: { count: permitsList[0].metadata[0].count, page, pageSize, }, }; }