import mongoose from "mongoose"; import { AuthenticatedUser } from "../auth"; import { getFilterObject, getSortObject, getTaggedOrgsFilter, getTaggedUsersFilter, PageQueryParams, } from "../pagination"; import { processedFields, processedModel, UpdateProcessedInput, } from "./processed.schema"; import { createNote } from "../note/note.service"; import { createAlert } from "../alert/alert.service"; import { getUser } from "../user/user.service"; import { orgModel } from "../organization/organization.schema"; import { arrayDiff } from "../utils/diff"; export async function getProcessedPermit( permitId: String, user: AuthenticatedUser, ) { const permit = await processedModel .findOne({ $and: [{ tenantId: user.tenantId }, { pid: permitId }], }) .populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "createdBy", select: "pid name avatar" }); if ( permit && user.role == "client" && !user.orgId.includes(permit.client.toString()) ) return null; return permit; } export async function updateProcessed( input: UpdateProcessedInput, permitId: string, user: AuthenticatedUser, ) { if (input.assignedToOrg && input.assignedTo) { delete input.assignedTo; } const oldPermitResult = await processedModel.findOne( { pid: permitId }, { assignedTo: 1, assignedToOrg: 1 }, ); const updateProcessedResult = await processedModel .findOneAndUpdate( { $and: [{ tenantId: user.tenantId }, { pid: permitId }], }, { ...input, lastUpdateDate: new Date() }, { new: true }, ) .populate({ path: "county", select: "pid name avatar" }) .populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "createdBy", select: "pid name avatar" }); if (updateProcessedResult) { for (const key in input) { if (["manualStatus", "utility"].includes(key)) { let msg = ""; if (input[key] === null) { msg = `Cleared ${key}`; } else { msg = `Updated ${key} to '${input[key]}'`; } await createNote( { content: msg, }, permitId, "processed", user, ); } else if (key == "client") { const orgInDb = await orgModel.findById(input.client); if (orgInDb) { updateProcessedResult.clientData = { pid: orgInDb.pid, licenseNumber: orgInDb.licenseNumber, name: orgInDb.name, avatar: orgInDb.avatar, }; updateProcessedResult.markModified("clientData"); await updateProcessedResult.save(); await createNote( { content: `Updated client to ${orgInDb.name}`, }, permitId, "permits", user, ); } } else if (key == "assignedTo") { const newAssignees = arrayDiff( updateProcessedResult.assignedTo.map((item) => item._id), oldPermitResult.assignedTo, ); if (newAssignees.length == 0) continue; let msg = "Assigned to:\n\n"; for (const assignee of newAssignees) { const user = await getUser(assignee); if (!user) continue; msg += `${user.firstName + " " + user.lastName}\n`; await createAlert( user.tenantId, `You are assigned to ${updateProcessedResult.permitNumber}`, "user", assignee, updateProcessedResult.pid, "processed", { client: updateProcessedResult.client.toString(), county: updateProcessedResult.county.id.toString(), address: updateProcessedResult.address.full_address, }, ); } await createNote( { content: msg, }, permitId, "processed", user, ); } else if (key == "assignedToOrg") { if ( oldPermitResult.assignedToOrg == updateProcessedResult.assignedToOrg ) continue; const orgName = input.assignedToOrg == "agent" ? "Suncoast" : updateProcessedResult.clientData.name; await createAlert( user.tenantId, `${orgName} assigned to ${updateProcessedResult.permitNumber}`, "team", input.assignedToOrg == "client" ? updateProcessedResult.client.toString() : process.env.SUNCOAST_ID, updateProcessedResult.pid, "permits", { client: updateProcessedResult.client.toString(), county: updateProcessedResult.county.id.toString(), address: updateProcessedResult.address.full_address, }, ); } } return updateProcessedResult; } } export async function listProcessedPermits( params: PageQueryParams, user: AuthenticatedUser, ) { const page = params.page || 1; const pageSize = params.pageSize || 10; const sortObj = getSortObject(params, processedFields); let filterObj = getFilterObject(params) || []; if (user.role == "client") { filterObj.push({ client: { $in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)), }, }); } if (user.counties && user.counties.length > 0) { filterObj.push({ "county.id": { $in: user.counties.map((item) => new mongoose.Types.ObjectId(item)), }, }); } let { taggedUsersFilter, taggedUserFilterIndex } = getTaggedUsersFilter( filterObj, sortObj, ); let { taggedOrgsFilter, taggedOrgsFilterIndex } = getTaggedOrgsFilter( filterObj, sortObj, ); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); if (taggedOrgsFilterIndex != -1) filterObj.splice(taggedOrgsFilterIndex, 1); const pipeline: any = [ { $match: { $and: [{ tenantId: user.tenantId }, ...filterObj] }, }, ]; if (params.searchToken && params.searchToken != "") { const regex = new RegExp(params.searchToken, "i"); pipeline.push({ $match: { $or: [ { permitNumber: { $regex: regex } }, { link: { $regex: regex } }, { "address.full_address": { $regex: regex } }, ], }, }); } pipeline.push( ...[ ...taggedUsersFilter, ...taggedOrgsFilter, { $lookup: { from: "users", localField: "assignedTo", foreignField: "_id", as: "assignedTo", }, }, { $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, transferDate: 1, issuedDate: 1, history: 1, communityName: 1, lot: 1, block: 1, jobNumber: 1, taggedUsers: 1, taggedOrgs: 1, noc: 1, deed: 1, requests: 1, assignedToOrg: 1, assignedTo: { $map: { input: "$assignedTo", as: "user", in: { _id: "$$user._id", pid: "$$user.pid", name: "$$user.name", avatar: "$$user.avatar", }, }, }, }, }, { $facet: { metadata: [{ $count: "count" }], data: [ { $sort: sortObj }, { $skip: (page - 1) * pageSize }, { $limit: pageSize }, ], }, }, ], ); const permitsList = await processedModel.aggregate(pipeline); 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, }, }; }