diff --git a/src/alert/alert.service.ts b/src/alert/alert.service.ts index 346333c..c425ef3 100644 --- a/src/alert/alert.service.ts +++ b/src/alert/alert.service.ts @@ -57,14 +57,11 @@ export async function getUserAlerts( const filters: Array = [ { recipientType: "user", recipientId: user.userId }, - ]; - - if (user.role == "client") - filters.push({ + { recipientType: "team", recipientId: { $in: [...user.orgId] }, - }); - else filters.push({ recipientType: "team" }); + }, + ]; const alerts = await alertsModel .find({ diff --git a/src/notification/notification.schema.ts b/src/notification/notification.schema.ts index 57ae789..09c50fc 100644 --- a/src/notification/notification.schema.ts +++ b/src/notification/notification.schema.ts @@ -30,6 +30,7 @@ const notificationSchema = new mongoose.Schema({ type: [Schema.Types.ObjectId], ref: "user", }, + assignedToOrg: String, taggedUsers: Array, }); @@ -53,11 +54,13 @@ const createNotificationInput = z.object({ client: z.string(), clientData: z.object({}).passthrough(), assignedTo: z.array(z.string()).optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), }); const updateNotificationInput = z.object({ status: z.string().optional(), assignedTo: z.array(z.string()).optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), }); export type CreateNotificationInput = z.infer; diff --git a/src/notification/notification.service.ts b/src/notification/notification.service.ts index 5cf7985..ada7079 100644 --- a/src/notification/notification.service.ts +++ b/src/notification/notification.service.ts @@ -21,7 +21,7 @@ import { arrayDiff } from "../utils/diff"; export async function createNotification( input: CreateNotificationInput, - tenantId: string + tenantId: string, ) { const notification = await notificationModel.create({ ...input, @@ -30,6 +30,9 @@ export async function createNotification( createdAt: new Date(), }); + if (input.assignedToOrg) { + } + return await notificationModel .findOne({ pid: notification.pid }) .populate({ path: "assignedTo", select: "pid name avatar" }); @@ -37,7 +40,7 @@ export async function createNotification( export async function getNotification( notifId: string, - user: AuthenticatedUser + user: AuthenticatedUser, ) { return await notificationModel .findOne({ @@ -50,11 +53,19 @@ export async function getNotification( export async function updateNotification( notifId: string, input: UpdateNotificationInput, - user: AuthenticatedUser + user: AuthenticatedUser, ) { + if (input.assignedToOrg && input.assignedTo) { + input.assignedTo = []; + } else if (input.assignedToOrg) { + input.assignedTo = []; + } else if (input.assignedTo) { + input.assignedToOrg = null; + } + const oldNotification = await notificationModel.findOne( { pid: notifId }, - { assignedTo: 1 } + { assignedTo: 1, assignedToOrg: 1 }, ); const updateNotificationResult = await notificationModel @@ -64,7 +75,7 @@ export async function updateNotification( ...input, updatedAt: new Date(), }, - { new: true } + { new: true }, ) .populate({ path: "assignedTo", select: "pid name avatar" }); @@ -85,12 +96,12 @@ export async function updateNotification( }, notifId, "notifications", - user + user, ); } else if (key == "assignedTo") { const newAssignees = arrayDiff( updateNotificationResult.assignedTo.map((item) => item._id), - oldNotification.assignedTo + oldNotification.assignedTo, ); if (newAssignees.length > 0) { @@ -112,7 +123,7 @@ export async function updateNotification( { client: updateNotificationResult.client.toString(), county: updateNotificationResult.county.id.toString(), - } + }, ); } @@ -122,9 +133,35 @@ export async function updateNotification( }, notifId, "notifications", - user + user, ); } + } else if (key == "assignedToOrg") { + if ( + oldNotification.assignedToOrg == + updateNotificationResult.assignedToOrg + ) + continue; + + const orgName = + input.assignedToOrg == "agent" + ? "Suncoast" + : updateNotificationResult.clientData.name; + + await createAlert( + user.tenantId, + `${orgName} assigned to ${updateNotificationResult.permitNumber}`, + "team", + input.assignedToOrg == "client" + ? updateNotificationResult.client.toString() + : process.env.SUNCOAST_ID, + updateNotificationResult.pid, + "permits", + { + client: updateNotificationResult.client.toString(), + county: updateNotificationResult.county.id.toString(), + }, + ); } } } @@ -134,7 +171,7 @@ export async function updateNotification( export async function listNotifications( params: PageQueryParams, - user: AuthenticatedUser + user: AuthenticatedUser, ) { const page = params.page || 1; const pageSize = params.pageSize || 10; @@ -173,7 +210,7 @@ export async function listNotifications( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( filterObj, - sortObj + sortObj, ); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); @@ -246,7 +283,7 @@ export async function listNotifications( ], }, }, - ] + ], ); const notifications = await notificationModel.aggregate(pipeline); diff --git a/src/permit/permit.schema.ts b/src/permit/permit.schema.ts index c490676..687d2f1 100644 --- a/src/permit/permit.schema.ts +++ b/src/permit/permit.schema.ts @@ -41,6 +41,7 @@ const permitSchema = new mongoose.Schema({ type: [Schema.Types.ObjectId], ref: "user", }, + assignedToOrg: String, link: String, address: Object, recordType: String, @@ -160,6 +161,7 @@ const permitCore = { permitType: z.string().optional(), utility: z.string().nullable().optional(), assignedTo: z.array(z.string()).nullable().optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), link: z.string().optional(), address: z .object({ @@ -272,6 +274,7 @@ const updatePermitInput = z.object({ manualStatus: z.string().nullable().optional(), utility: z.string().nullable().optional(), assignedTo: z.string().nullable().optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), newPayment: z.array(z.any()).optional(), communityName: z.string().nullable().optional(), lot: z.string().nullable().optional(), diff --git a/src/permit/permit.service.ts b/src/permit/permit.service.ts index 577fee9..e84c07b 100644 --- a/src/permit/permit.service.ts +++ b/src/permit/permit.service.ts @@ -24,7 +24,7 @@ import { arrayDiff } from "../utils/diff"; export async function createPermit( input: CreatePermitInput, - user: AuthenticatedUser + user: AuthenticatedUser, ) { if (!input.stage) { input.stage = { @@ -63,7 +63,7 @@ export async function createPermit( orgId: permit.client.toString(), document: permit, } as ChangeEvent, - ["permit:read"] + ["permit:read"], ); return await permit.populate({ @@ -88,7 +88,7 @@ export async function createPermit( orgId: permit.client.toString(), document: permit, } as ChangeEvent, - ["permit:read"] + ["permit:read"], ); return await permit.populate({ @@ -130,7 +130,7 @@ export async function getPermit(permitId: string, user: AuthenticatedUser) { export async function listPermits( params: PageQueryParams, - user: AuthenticatedUser + user: AuthenticatedUser, ) { const page = params.page || 1; const pageSize = params.pageSize || 10; @@ -155,7 +155,7 @@ export async function listPermits( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( filterObj, - sortObj + sortObj, ); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); @@ -264,11 +264,19 @@ export async function listPermits( export async function updatePermit( input: CreatePermitInput, permitId: string, - user: AuthenticatedUser + user: AuthenticatedUser, ) { + if (input.assignedToOrg && input.assignedTo) { + input.assignedTo = []; + } else if (input.assignedToOrg) { + input.assignedTo = []; + } else if (input.assignedTo) { + input.assignedToOrg = null; + } + const oldPermitResult = await permitModel.findOne( { pid: permitId }, - { assignedTo: 1 } + { assignedTo: 1, assignedToOrg: 1 }, ); const updatePermitResult = await permitModel .findOneAndUpdate( @@ -276,7 +284,7 @@ export async function updatePermit( $and: [{ tenantId: user.tenantId }, { pid: permitId }], }, { ...input, lastUpdateDate: new Date() }, - { new: true } + { new: true }, ) .populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "createdBy", select: "pid name avatar" }); @@ -300,7 +308,7 @@ export async function updatePermit( }, permitId, "permits", - user + user, ); if (key == "requests" && input[key] != null) { @@ -323,7 +331,7 @@ export async function updatePermit( client: updatePermitResult.client.toString(), county: updatePermitResult.county.id.toString(), address: updatePermitResult.address, - } + }, ); } } @@ -346,13 +354,13 @@ export async function updatePermit( }, permitId, "permits", - user + user, ); } } else if (key == "assignedTo") { const newAssignees = arrayDiff( updatePermitResult.assignedTo.map((item) => item._id), - oldPermitResult.assignedTo + oldPermitResult.assignedTo, ); if (newAssignees.length == 0) continue; @@ -376,7 +384,7 @@ export async function updatePermit( client: updatePermitResult.client.toString(), county: updatePermitResult.county.id.toString(), address: updatePermitResult.address.full_address, - } + }, ); } @@ -386,7 +394,34 @@ export async function updatePermit( }, permitId, "permits", - user + user, + ); + } else if (key == "assignedToOrg") { + if (oldPermitResult.assignedToOrg == updatePermitResult.assignedToOrg) + continue; + + console.log(oldPermitResult.assignedToOrg); + console.log(updatePermitResult.assignedToOrg); + + const orgName = + input.assignedToOrg == "agent" + ? "Suncoast" + : updatePermitResult.clientData.name; + + await createAlert( + user.tenantId, + `${orgName} assigned to ${updatePermitResult.permitNumber}`, + "team", + input.assignedToOrg == "client" + ? updatePermitResult.client.toString() + : process.env.SUNCOAST_ID, + updatePermitResult.pid, + "permits", + { + client: updatePermitResult.client.toString(), + county: updatePermitResult.county.id.toString(), + address: updatePermitResult.address.full_address, + }, ); } } @@ -401,7 +436,7 @@ export async function updatePermit( orgId: updatePermitResult.client._id.toString(), document: updatePermitResult, } as ChangeEvent, - ["permit:read"] + ["permit:read"], ); } @@ -423,7 +458,7 @@ export async function deletePermit(permitId: string, tenantId: string) { pid: permitId, }, } as ChangeEvent, - ["permit:read"] + ["permit:read"], ); return res; @@ -431,7 +466,7 @@ export async function deletePermit(permitId: string, tenantId: string) { export async function searchPermit( params: PageQueryParams, - user: AuthenticatedUser + user: AuthenticatedUser, ) { const page = params.page || 1; const pageSize = params.pageSize || 10; @@ -629,7 +664,7 @@ export async function bulkImport(csvData: any[], user: AuthenticatedUser) { clientCache[clientName] = clientData; } else { errors.push( - "Client not found. The value in Client column must exactly match the client name in Quicker Permits" + "Client not found. The value in Client column must exactly match the client name in Quicker Permits", ); } } @@ -650,7 +685,7 @@ export async function bulkImport(csvData: any[], user: AuthenticatedUser) { countyCache[countyName] = countyData; } else { errors.push( - "County not found. The value in County column must exactly match the county name in Quicker Permits" + "County not found. The value in County column must exactly match the county name in Quicker Permits", ); } } diff --git a/src/processed/processed.schema.ts b/src/processed/processed.schema.ts index 34fc95c..43f600e 100644 --- a/src/processed/processed.schema.ts +++ b/src/processed/processed.schema.ts @@ -30,7 +30,7 @@ const processedSchema = new mongoose.Schema({ pipeline: Array, currentStage: Number, }, - { _id: false } + { _id: false }, ), status: String, manualStatus: String, @@ -41,6 +41,7 @@ const processedSchema = new mongoose.Schema({ type: [Schema.Types.ObjectId], ref: "user", }, + assignedToOrg: String, link: String, address: Object, recordType: String, @@ -113,13 +114,13 @@ const processedSchema = new mongoose.Schema({ }).index({ tenantId: 1, permitNumber: 1 }, { unique: true }); export const processedFields = Object.keys(processedSchema.paths).filter( - (path) => path !== "__v" + (path) => path !== "__v", ); export const processedModel = mongoose.model( "processed", processedSchema, - "processed" + "processed", ); const updateProcessedInput = z.object({ @@ -133,6 +134,7 @@ const updateProcessedInput = z.object({ jobNumber: z.string().nullable().optional(), startDate: z.date().nullable().optional(), assignedTo: z.array(z.string()).nullable().optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), noc: z.string().optional(), deed: z.string().optional(), requests: z.array(z.string()).optional(), @@ -152,5 +154,5 @@ export const { schemas: processedSchemas, $ref: $processed } = buildJsonSchemas( pageQueryParams, updateProcessedInput, }, - { $id: "processed" } + { $id: "processed" }, ); diff --git a/src/processed/processed.service.ts b/src/processed/processed.service.ts index 98e5f76..3a8b05c 100644 --- a/src/processed/processed.service.ts +++ b/src/processed/processed.service.ts @@ -19,7 +19,7 @@ import { arrayDiff } from "../utils/diff"; export async function getProcessedPermit( permitId: String, - user: AuthenticatedUser + user: AuthenticatedUser, ) { const permit = await processedModel .findOne({ @@ -41,11 +41,19 @@ export async function getProcessedPermit( export async function updateProcessed( input: UpdateProcessedInput, permitId: string, - user: AuthenticatedUser + user: AuthenticatedUser, ) { + if (input.assignedToOrg && input.assignedTo) { + input.assignedTo = []; + } else if (input.assignedToOrg) { + input.assignedTo = []; + } else if (input.assignedTo) { + input.assignedToOrg = null; + } + const oldPermitResult = await processedModel.findOne( { pid: permitId }, - { assignedTo: 1 } + { assignedTo: 1, assignedToOrg: 1 }, ); const updateProcessedResult = await processedModel .findOneAndUpdate( @@ -53,7 +61,7 @@ export async function updateProcessed( $and: [{ tenantId: user.tenantId }, { pid: permitId }], }, { ...input, lastUpdateDate: new Date() }, - { new: true } + { new: true }, ) .populate({ path: "county", select: "pid name avatar" }) .populate({ path: "assignedTo", select: "pid name avatar" }) @@ -76,7 +84,7 @@ export async function updateProcessed( }, permitId, "processed", - user + user, ); } else if (key == "client") { const orgInDb = await orgModel.findById(input.client); @@ -97,13 +105,13 @@ export async function updateProcessed( }, permitId, "permits", - user + user, ); } } else if (key == "assignedTo") { const newAssignees = arrayDiff( updateProcessedResult.assignedTo.map((item) => item._id), - oldPermitResult.assignedTo + oldPermitResult.assignedTo, ); if (newAssignees.length == 0) continue; @@ -127,7 +135,7 @@ export async function updateProcessed( client: updateProcessedResult.client.toString(), county: updateProcessedResult.county.id.toString(), address: updateProcessedResult.address.full_address, - } + }, ); } @@ -137,7 +145,33 @@ export async function updateProcessed( }, permitId, "processed", - user + 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, + }, ); } } @@ -148,7 +182,7 @@ export async function updateProcessed( export async function listProcessedPermits( params: PageQueryParams, - user: AuthenticatedUser + user: AuthenticatedUser, ) { const page = params.page || 1; const pageSize = params.pageSize || 10; @@ -173,7 +207,7 @@ export async function listProcessedPermits( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( filterObj, - sortObj + sortObj, ); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); @@ -281,7 +315,7 @@ export async function listProcessedPermits( ], }, }, - ] + ], ); const permitsList = await processedModel.aggregate(pipeline); diff --git a/src/rts/rts.schema.ts b/src/rts/rts.schema.ts index 68bbc14..9cd2677 100644 --- a/src/rts/rts.schema.ts +++ b/src/rts/rts.schema.ts @@ -22,7 +22,7 @@ const rtsSchema = new mongoose.Schema({ ref: "user", }, }, - { _id: false } + { _id: false }, ), ], county: { @@ -39,7 +39,7 @@ const rtsSchema = new mongoose.Schema({ pipeline: Array, currentStage: Number, }, - { _id: false } + { _id: false }, ), status: String, labels: [String], @@ -54,6 +54,7 @@ const rtsSchema = new mongoose.Schema({ type: [Schema.Types.ObjectId], ref: "user", }, + assignedToOrg: String, taggedUsers: Array, fileValidationStatus: String, permitNumber: [String], @@ -61,7 +62,7 @@ const rtsSchema = new mongoose.Schema({ }); export const rtsFields = Object.keys(rtsSchema.paths).filter( - (path) => path !== "__v" + (path) => path !== "__v", ); export const rtsModel = mongoose.model("rts", rtsSchema, "rts"); @@ -82,12 +83,13 @@ const rtsCreateInput = z.object({ date: z.date().nullable().optional(), description: z.string().optional(), comment: z.string().optional(), - }) + }), ), currentStage: z.number(), }) .optional(), assignedTo: z.array(z.string()).optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), status: z.string().optional(), permitNumber: z.array(z.string()).optional(), lot: z.array(z.string()).optional(), @@ -108,12 +110,13 @@ const rtsUpdateInput = z.object({ date: z.date().nullable().optional(), description: z.string().optional(), comment: z.string().optional(), - }) + }), ), currentStage: z.number(), }) .optional(), assignedTo: z.array(z.string()).optional(), + assignedToOrg: z.enum(["client", "agent"]).nullable().optional(), status: z.string().optional(), fileValidationStatus: z.string().optional(), permitNumber: z.array(z.string()).optional(), @@ -135,5 +138,5 @@ export const { schemas: rtsSchemas, $ref: $rts } = buildJsonSchemas( rtsNewUpload, pageQueryParams, }, - { $id: "rts" } + { $id: "rts" }, ); diff --git a/src/rts/rts.service.ts b/src/rts/rts.service.ts index fed1ec1..49c08e1 100644 --- a/src/rts/rts.service.ts +++ b/src/rts/rts.service.ts @@ -19,10 +19,11 @@ import { rtsPipeline } from "../utils/pipeline"; import { createAlert } from "../alert/alert.service"; import { createNote } from "../note/note.service"; import { arrayDiff } from "../utils/diff"; +import { getOrg } from "../organization/organization.service"; export async function createRts( input: CreateRtsInput, - user: AuthenticatedUser + user: AuthenticatedUser, ) { let defaultClient = input.client; const userInDb = await getUserWithoutPopulate(user.userId); @@ -75,7 +76,7 @@ export async function getRts(id: string, tenantId: string) { export async function listRts( params: PageQueryParams, - user: AuthenticatedUser + user: AuthenticatedUser, ) { const page = params.page || 1; const pageSize = params.pageSize || 10; @@ -100,7 +101,7 @@ export async function listRts( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( filterObj, - sortObj + sortObj, ); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); @@ -236,9 +237,21 @@ export async function listRts( export async function updateRts( id: string, input: UpdateRtsInput, - user: AuthenticatedUser + user: AuthenticatedUser, ) { - const oldRts = await rtsModel.findOne({ pid: id }, { assignedTo: 1 }); + if (input.assignedToOrg && input.assignedTo) { + input.assignedTo = []; + } else if (input.assignedToOrg) { + input.assignedTo = []; + } else if (input.assignedTo) { + input.assignedToOrg = null; + } + + const oldRts = await rtsModel.findOne( + { pid: id }, + { assignedTo: 1, assignedToOrg: 1 }, + ); + const updatedRts = await rtsModel .findOneAndUpdate({ pid: id, tenantId: user.tenantId }, input, { new: true, @@ -253,14 +266,14 @@ export async function updateRts( { content: `Updated type to '${input.permitType}'` }, id, "rts", - user + user, ); } if (updatedRts && input.assignedTo) { const newAssignees = arrayDiff( updatedRts.assignedTo.map((item) => item._id), - oldRts.assignedTo + oldRts.assignedTo, ); if (newAssignees.length > 0) { @@ -285,7 +298,7 @@ export async function updateRts( //@ts-ignore county: updatedRts.county._id.toString(), permitType: updatedRts.permitType, - } + }, ); } @@ -295,11 +308,40 @@ export async function updateRts( }, id, "rts", - user + user, ); } } + if ( + updatedRts && + input.assignedToOrg && + oldRts.assignedToOrg != updatedRts.assignedToOrg + ) { + const orgName = + //@ts-ignore + input.assignedToOrg == "agent" ? "Suncoast" : updatedRts.client.name; + + await createAlert( + user.tenantId, + `${orgName} assigned to RTS`, + "team", + input.assignedToOrg == "client" + ? //@ts-ignore + updatedRts.client._id.toString() + : process.env.SUNCOAST_ID, + updatedRts.pid, + "permits", + { + //@ts-ignore + client: updatedRts.client._id.toString(), + //@ts-ignore + county: updatedRts.county._id.toString(), + permitType: updatedRts.permitType, + }, + ); + } + return updatedRts; } @@ -310,7 +352,7 @@ export async function deleteRts(id: string, tenantId: string) { export async function newUpload( id: string, newUpload: UploadRtsInput, - user: AuthenticatedUser + user: AuthenticatedUser, ) { return await rtsModel.findOneAndUpdate( { pid: id, tenantId: user.tenantId }, @@ -322,6 +364,6 @@ export async function newUpload( createdBy: user.userId, }, }, - } + }, ); }