feat: add team alerts

This commit is contained in:
2026-01-19 11:56:32 +05:30
parent 46c07e23ad
commit c10b3629fc
9 changed files with 226 additions and 70 deletions

View File

@@ -57,14 +57,11 @@ export async function getUserAlerts(
const filters: Array<object> = [ const filters: Array<object> = [
{ recipientType: "user", recipientId: user.userId }, { recipientType: "user", recipientId: user.userId },
]; {
if (user.role == "client")
filters.push({
recipientType: "team", recipientType: "team",
recipientId: { $in: [...user.orgId] }, recipientId: { $in: [...user.orgId] },
}); },
else filters.push({ recipientType: "team" }); ];
const alerts = await alertsModel const alerts = await alertsModel
.find({ .find({

View File

@@ -30,6 +30,7 @@ const notificationSchema = new mongoose.Schema({
type: [Schema.Types.ObjectId], type: [Schema.Types.ObjectId],
ref: "user", ref: "user",
}, },
assignedToOrg: String,
taggedUsers: Array, taggedUsers: Array,
}); });
@@ -53,11 +54,13 @@ const createNotificationInput = z.object({
client: z.string(), client: z.string(),
clientData: z.object({}).passthrough(), clientData: z.object({}).passthrough(),
assignedTo: z.array(z.string()).optional(), assignedTo: z.array(z.string()).optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
}); });
const updateNotificationInput = z.object({ const updateNotificationInput = z.object({
status: z.string().optional(), status: z.string().optional(),
assignedTo: z.array(z.string()).optional(), assignedTo: z.array(z.string()).optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
}); });
export type CreateNotificationInput = z.infer<typeof createNotificationInput>; export type CreateNotificationInput = z.infer<typeof createNotificationInput>;

View File

@@ -21,7 +21,7 @@ import { arrayDiff } from "../utils/diff";
export async function createNotification( export async function createNotification(
input: CreateNotificationInput, input: CreateNotificationInput,
tenantId: string tenantId: string,
) { ) {
const notification = await notificationModel.create({ const notification = await notificationModel.create({
...input, ...input,
@@ -30,6 +30,9 @@ export async function createNotification(
createdAt: new Date(), createdAt: new Date(),
}); });
if (input.assignedToOrg) {
}
return await notificationModel return await notificationModel
.findOne({ pid: notification.pid }) .findOne({ pid: notification.pid })
.populate({ path: "assignedTo", select: "pid name avatar" }); .populate({ path: "assignedTo", select: "pid name avatar" });
@@ -37,7 +40,7 @@ export async function createNotification(
export async function getNotification( export async function getNotification(
notifId: string, notifId: string,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
return await notificationModel return await notificationModel
.findOne({ .findOne({
@@ -50,11 +53,19 @@ export async function getNotification(
export async function updateNotification( export async function updateNotification(
notifId: string, notifId: string,
input: UpdateNotificationInput, 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( const oldNotification = await notificationModel.findOne(
{ pid: notifId }, { pid: notifId },
{ assignedTo: 1 } { assignedTo: 1, assignedToOrg: 1 },
); );
const updateNotificationResult = await notificationModel const updateNotificationResult = await notificationModel
@@ -64,7 +75,7 @@ export async function updateNotification(
...input, ...input,
updatedAt: new Date(), updatedAt: new Date(),
}, },
{ new: true } { new: true },
) )
.populate({ path: "assignedTo", select: "pid name avatar" }); .populate({ path: "assignedTo", select: "pid name avatar" });
@@ -85,12 +96,12 @@ export async function updateNotification(
}, },
notifId, notifId,
"notifications", "notifications",
user user,
); );
} else if (key == "assignedTo") { } else if (key == "assignedTo") {
const newAssignees = arrayDiff( const newAssignees = arrayDiff(
updateNotificationResult.assignedTo.map((item) => item._id), updateNotificationResult.assignedTo.map((item) => item._id),
oldNotification.assignedTo oldNotification.assignedTo,
); );
if (newAssignees.length > 0) { if (newAssignees.length > 0) {
@@ -112,7 +123,7 @@ export async function updateNotification(
{ {
client: updateNotificationResult.client.toString(), client: updateNotificationResult.client.toString(),
county: updateNotificationResult.county.id.toString(), county: updateNotificationResult.county.id.toString(),
} },
); );
} }
@@ -122,9 +133,35 @@ export async function updateNotification(
}, },
notifId, notifId,
"notifications", "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( export async function listNotifications(
params: PageQueryParams, params: PageQueryParams,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
@@ -173,7 +210,7 @@ export async function listNotifications(
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
filterObj, filterObj,
sortObj sortObj,
); );
if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1);
@@ -246,7 +283,7 @@ export async function listNotifications(
], ],
}, },
}, },
] ],
); );
const notifications = await notificationModel.aggregate(pipeline); const notifications = await notificationModel.aggregate(pipeline);

View File

@@ -41,6 +41,7 @@ const permitSchema = new mongoose.Schema({
type: [Schema.Types.ObjectId], type: [Schema.Types.ObjectId],
ref: "user", ref: "user",
}, },
assignedToOrg: String,
link: String, link: String,
address: Object, address: Object,
recordType: String, recordType: String,
@@ -160,6 +161,7 @@ const permitCore = {
permitType: z.string().optional(), permitType: z.string().optional(),
utility: z.string().nullable().optional(), utility: z.string().nullable().optional(),
assignedTo: z.array(z.string()).nullable().optional(), assignedTo: z.array(z.string()).nullable().optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
link: z.string().optional(), link: z.string().optional(),
address: z address: z
.object({ .object({
@@ -272,6 +274,7 @@ const updatePermitInput = z.object({
manualStatus: z.string().nullable().optional(), manualStatus: z.string().nullable().optional(),
utility: z.string().nullable().optional(), utility: z.string().nullable().optional(),
assignedTo: z.string().nullable().optional(), assignedTo: z.string().nullable().optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
newPayment: z.array(z.any()).optional(), newPayment: z.array(z.any()).optional(),
communityName: z.string().nullable().optional(), communityName: z.string().nullable().optional(),
lot: z.string().nullable().optional(), lot: z.string().nullable().optional(),

View File

@@ -24,7 +24,7 @@ import { arrayDiff } from "../utils/diff";
export async function createPermit( export async function createPermit(
input: CreatePermitInput, input: CreatePermitInput,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
if (!input.stage) { if (!input.stage) {
input.stage = { input.stage = {
@@ -63,7 +63,7 @@ export async function createPermit(
orgId: permit.client.toString(), orgId: permit.client.toString(),
document: permit, document: permit,
} as ChangeEvent, } as ChangeEvent,
["permit:read"] ["permit:read"],
); );
return await permit.populate({ return await permit.populate({
@@ -88,7 +88,7 @@ export async function createPermit(
orgId: permit.client.toString(), orgId: permit.client.toString(),
document: permit, document: permit,
} as ChangeEvent, } as ChangeEvent,
["permit:read"] ["permit:read"],
); );
return await permit.populate({ return await permit.populate({
@@ -130,7 +130,7 @@ export async function getPermit(permitId: string, user: AuthenticatedUser) {
export async function listPermits( export async function listPermits(
params: PageQueryParams, params: PageQueryParams,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
@@ -155,7 +155,7 @@ export async function listPermits(
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
filterObj, filterObj,
sortObj sortObj,
); );
if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1);
@@ -264,11 +264,19 @@ export async function listPermits(
export async function updatePermit( export async function updatePermit(
input: CreatePermitInput, input: CreatePermitInput,
permitId: string, 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( const oldPermitResult = await permitModel.findOne(
{ pid: permitId }, { pid: permitId },
{ assignedTo: 1 } { assignedTo: 1, assignedToOrg: 1 },
); );
const updatePermitResult = await permitModel const updatePermitResult = await permitModel
.findOneAndUpdate( .findOneAndUpdate(
@@ -276,7 +284,7 @@ export async function updatePermit(
$and: [{ tenantId: user.tenantId }, { pid: permitId }], $and: [{ tenantId: user.tenantId }, { pid: permitId }],
}, },
{ ...input, lastUpdateDate: new Date() }, { ...input, lastUpdateDate: new Date() },
{ new: true } { new: true },
) )
.populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "assignedTo", select: "pid name avatar" })
.populate({ path: "createdBy", select: "pid name avatar" }); .populate({ path: "createdBy", select: "pid name avatar" });
@@ -300,7 +308,7 @@ export async function updatePermit(
}, },
permitId, permitId,
"permits", "permits",
user user,
); );
if (key == "requests" && input[key] != null) { if (key == "requests" && input[key] != null) {
@@ -323,7 +331,7 @@ export async function updatePermit(
client: updatePermitResult.client.toString(), client: updatePermitResult.client.toString(),
county: updatePermitResult.county.id.toString(), county: updatePermitResult.county.id.toString(),
address: updatePermitResult.address, address: updatePermitResult.address,
} },
); );
} }
} }
@@ -346,13 +354,13 @@ export async function updatePermit(
}, },
permitId, permitId,
"permits", "permits",
user user,
); );
} }
} else if (key == "assignedTo") { } else if (key == "assignedTo") {
const newAssignees = arrayDiff( const newAssignees = arrayDiff(
updatePermitResult.assignedTo.map((item) => item._id), updatePermitResult.assignedTo.map((item) => item._id),
oldPermitResult.assignedTo oldPermitResult.assignedTo,
); );
if (newAssignees.length == 0) continue; if (newAssignees.length == 0) continue;
@@ -376,7 +384,7 @@ export async function updatePermit(
client: updatePermitResult.client.toString(), client: updatePermitResult.client.toString(),
county: updatePermitResult.county.id.toString(), county: updatePermitResult.county.id.toString(),
address: updatePermitResult.address.full_address, address: updatePermitResult.address.full_address,
} },
); );
} }
@@ -386,7 +394,34 @@ export async function updatePermit(
}, },
permitId, permitId,
"permits", "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(), orgId: updatePermitResult.client._id.toString(),
document: updatePermitResult, document: updatePermitResult,
} as ChangeEvent, } as ChangeEvent,
["permit:read"] ["permit:read"],
); );
} }
@@ -423,7 +458,7 @@ export async function deletePermit(permitId: string, tenantId: string) {
pid: permitId, pid: permitId,
}, },
} as ChangeEvent, } as ChangeEvent,
["permit:read"] ["permit:read"],
); );
return res; return res;
@@ -431,7 +466,7 @@ export async function deletePermit(permitId: string, tenantId: string) {
export async function searchPermit( export async function searchPermit(
params: PageQueryParams, params: PageQueryParams,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
@@ -629,7 +664,7 @@ export async function bulkImport(csvData: any[], user: AuthenticatedUser) {
clientCache[clientName] = clientData; clientCache[clientName] = clientData;
} else { } else {
errors.push( 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; countyCache[countyName] = countyData;
} else { } else {
errors.push( 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",
); );
} }
} }

View File

@@ -30,7 +30,7 @@ const processedSchema = new mongoose.Schema({
pipeline: Array, pipeline: Array,
currentStage: Number, currentStage: Number,
}, },
{ _id: false } { _id: false },
), ),
status: String, status: String,
manualStatus: String, manualStatus: String,
@@ -41,6 +41,7 @@ const processedSchema = new mongoose.Schema({
type: [Schema.Types.ObjectId], type: [Schema.Types.ObjectId],
ref: "user", ref: "user",
}, },
assignedToOrg: String,
link: String, link: String,
address: Object, address: Object,
recordType: String, recordType: String,
@@ -113,13 +114,13 @@ const processedSchema = new mongoose.Schema({
}).index({ tenantId: 1, permitNumber: 1 }, { unique: true }); }).index({ tenantId: 1, permitNumber: 1 }, { unique: true });
export const processedFields = Object.keys(processedSchema.paths).filter( export const processedFields = Object.keys(processedSchema.paths).filter(
(path) => path !== "__v" (path) => path !== "__v",
); );
export const processedModel = mongoose.model( export const processedModel = mongoose.model(
"processed", "processed",
processedSchema, processedSchema,
"processed" "processed",
); );
const updateProcessedInput = z.object({ const updateProcessedInput = z.object({
@@ -133,6 +134,7 @@ const updateProcessedInput = z.object({
jobNumber: z.string().nullable().optional(), jobNumber: z.string().nullable().optional(),
startDate: z.date().nullable().optional(), startDate: z.date().nullable().optional(),
assignedTo: z.array(z.string()).nullable().optional(), assignedTo: z.array(z.string()).nullable().optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
noc: z.string().optional(), noc: z.string().optional(),
deed: z.string().optional(), deed: z.string().optional(),
requests: z.array(z.string()).optional(), requests: z.array(z.string()).optional(),
@@ -152,5 +154,5 @@ export const { schemas: processedSchemas, $ref: $processed } = buildJsonSchemas(
pageQueryParams, pageQueryParams,
updateProcessedInput, updateProcessedInput,
}, },
{ $id: "processed" } { $id: "processed" },
); );

View File

@@ -19,7 +19,7 @@ import { arrayDiff } from "../utils/diff";
export async function getProcessedPermit( export async function getProcessedPermit(
permitId: String, permitId: String,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
const permit = await processedModel const permit = await processedModel
.findOne({ .findOne({
@@ -41,11 +41,19 @@ export async function getProcessedPermit(
export async function updateProcessed( export async function updateProcessed(
input: UpdateProcessedInput, input: UpdateProcessedInput,
permitId: string, 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( const oldPermitResult = await processedModel.findOne(
{ pid: permitId }, { pid: permitId },
{ assignedTo: 1 } { assignedTo: 1, assignedToOrg: 1 },
); );
const updateProcessedResult = await processedModel const updateProcessedResult = await processedModel
.findOneAndUpdate( .findOneAndUpdate(
@@ -53,7 +61,7 @@ export async function updateProcessed(
$and: [{ tenantId: user.tenantId }, { pid: permitId }], $and: [{ tenantId: user.tenantId }, { pid: permitId }],
}, },
{ ...input, lastUpdateDate: new Date() }, { ...input, lastUpdateDate: new Date() },
{ new: true } { new: true },
) )
.populate({ path: "county", select: "pid name avatar" }) .populate({ path: "county", select: "pid name avatar" })
.populate({ path: "assignedTo", select: "pid name avatar" }) .populate({ path: "assignedTo", select: "pid name avatar" })
@@ -76,7 +84,7 @@ export async function updateProcessed(
}, },
permitId, permitId,
"processed", "processed",
user user,
); );
} else if (key == "client") { } else if (key == "client") {
const orgInDb = await orgModel.findById(input.client); const orgInDb = await orgModel.findById(input.client);
@@ -97,13 +105,13 @@ export async function updateProcessed(
}, },
permitId, permitId,
"permits", "permits",
user user,
); );
} }
} else if (key == "assignedTo") { } else if (key == "assignedTo") {
const newAssignees = arrayDiff( const newAssignees = arrayDiff(
updateProcessedResult.assignedTo.map((item) => item._id), updateProcessedResult.assignedTo.map((item) => item._id),
oldPermitResult.assignedTo oldPermitResult.assignedTo,
); );
if (newAssignees.length == 0) continue; if (newAssignees.length == 0) continue;
@@ -127,7 +135,7 @@ export async function updateProcessed(
client: updateProcessedResult.client.toString(), client: updateProcessedResult.client.toString(),
county: updateProcessedResult.county.id.toString(), county: updateProcessedResult.county.id.toString(),
address: updateProcessedResult.address.full_address, address: updateProcessedResult.address.full_address,
} },
); );
} }
@@ -137,7 +145,33 @@ export async function updateProcessed(
}, },
permitId, permitId,
"processed", "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( export async function listProcessedPermits(
params: PageQueryParams, params: PageQueryParams,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
@@ -173,7 +207,7 @@ export async function listProcessedPermits(
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
filterObj, filterObj,
sortObj sortObj,
); );
if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1);
@@ -281,7 +315,7 @@ export async function listProcessedPermits(
], ],
}, },
}, },
] ],
); );
const permitsList = await processedModel.aggregate(pipeline); const permitsList = await processedModel.aggregate(pipeline);

View File

@@ -22,7 +22,7 @@ const rtsSchema = new mongoose.Schema({
ref: "user", ref: "user",
}, },
}, },
{ _id: false } { _id: false },
), ),
], ],
county: { county: {
@@ -39,7 +39,7 @@ const rtsSchema = new mongoose.Schema({
pipeline: Array, pipeline: Array,
currentStage: Number, currentStage: Number,
}, },
{ _id: false } { _id: false },
), ),
status: String, status: String,
labels: [String], labels: [String],
@@ -54,6 +54,7 @@ const rtsSchema = new mongoose.Schema({
type: [Schema.Types.ObjectId], type: [Schema.Types.ObjectId],
ref: "user", ref: "user",
}, },
assignedToOrg: String,
taggedUsers: Array, taggedUsers: Array,
fileValidationStatus: String, fileValidationStatus: String,
permitNumber: [String], permitNumber: [String],
@@ -61,7 +62,7 @@ const rtsSchema = new mongoose.Schema({
}); });
export const rtsFields = Object.keys(rtsSchema.paths).filter( export const rtsFields = Object.keys(rtsSchema.paths).filter(
(path) => path !== "__v" (path) => path !== "__v",
); );
export const rtsModel = mongoose.model("rts", rtsSchema, "rts"); export const rtsModel = mongoose.model("rts", rtsSchema, "rts");
@@ -82,12 +83,13 @@ const rtsCreateInput = z.object({
date: z.date().nullable().optional(), date: z.date().nullable().optional(),
description: z.string().optional(), description: z.string().optional(),
comment: z.string().optional(), comment: z.string().optional(),
}) }),
), ),
currentStage: z.number(), currentStage: z.number(),
}) })
.optional(), .optional(),
assignedTo: z.array(z.string()).optional(), assignedTo: z.array(z.string()).optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
status: z.string().optional(), status: z.string().optional(),
permitNumber: z.array(z.string()).optional(), permitNumber: z.array(z.string()).optional(),
lot: z.array(z.string()).optional(), lot: z.array(z.string()).optional(),
@@ -108,12 +110,13 @@ const rtsUpdateInput = z.object({
date: z.date().nullable().optional(), date: z.date().nullable().optional(),
description: z.string().optional(), description: z.string().optional(),
comment: z.string().optional(), comment: z.string().optional(),
}) }),
), ),
currentStage: z.number(), currentStage: z.number(),
}) })
.optional(), .optional(),
assignedTo: z.array(z.string()).optional(), assignedTo: z.array(z.string()).optional(),
assignedToOrg: z.enum(["client", "agent"]).nullable().optional(),
status: z.string().optional(), status: z.string().optional(),
fileValidationStatus: z.string().optional(), fileValidationStatus: z.string().optional(),
permitNumber: z.array(z.string()).optional(), permitNumber: z.array(z.string()).optional(),
@@ -135,5 +138,5 @@ export const { schemas: rtsSchemas, $ref: $rts } = buildJsonSchemas(
rtsNewUpload, rtsNewUpload,
pageQueryParams, pageQueryParams,
}, },
{ $id: "rts" } { $id: "rts" },
); );

View File

@@ -19,10 +19,11 @@ import { rtsPipeline } from "../utils/pipeline";
import { createAlert } from "../alert/alert.service"; import { createAlert } from "../alert/alert.service";
import { createNote } from "../note/note.service"; import { createNote } from "../note/note.service";
import { arrayDiff } from "../utils/diff"; import { arrayDiff } from "../utils/diff";
import { getOrg } from "../organization/organization.service";
export async function createRts( export async function createRts(
input: CreateRtsInput, input: CreateRtsInput,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
let defaultClient = input.client; let defaultClient = input.client;
const userInDb = await getUserWithoutPopulate(user.userId); const userInDb = await getUserWithoutPopulate(user.userId);
@@ -75,7 +76,7 @@ export async function getRts(id: string, tenantId: string) {
export async function listRts( export async function listRts(
params: PageQueryParams, params: PageQueryParams,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
const page = params.page || 1; const page = params.page || 1;
const pageSize = params.pageSize || 10; const pageSize = params.pageSize || 10;
@@ -100,7 +101,7 @@ export async function listRts(
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter( let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
filterObj, filterObj,
sortObj sortObj,
); );
if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1); if (taggedUserFilterIndex != -1) filterObj.splice(taggedUserFilterIndex, 1);
@@ -236,9 +237,21 @@ export async function listRts(
export async function updateRts( export async function updateRts(
id: string, id: string,
input: UpdateRtsInput, 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 const updatedRts = await rtsModel
.findOneAndUpdate({ pid: id, tenantId: user.tenantId }, input, { .findOneAndUpdate({ pid: id, tenantId: user.tenantId }, input, {
new: true, new: true,
@@ -253,14 +266,14 @@ export async function updateRts(
{ content: `Updated type to '${input.permitType}'` }, { content: `Updated type to '${input.permitType}'` },
id, id,
"rts", "rts",
user user,
); );
} }
if (updatedRts && input.assignedTo) { if (updatedRts && input.assignedTo) {
const newAssignees = arrayDiff( const newAssignees = arrayDiff(
updatedRts.assignedTo.map((item) => item._id), updatedRts.assignedTo.map((item) => item._id),
oldRts.assignedTo oldRts.assignedTo,
); );
if (newAssignees.length > 0) { if (newAssignees.length > 0) {
@@ -285,7 +298,7 @@ export async function updateRts(
//@ts-ignore //@ts-ignore
county: updatedRts.county._id.toString(), county: updatedRts.county._id.toString(),
permitType: updatedRts.permitType, permitType: updatedRts.permitType,
} },
); );
} }
@@ -295,11 +308,40 @@ export async function updateRts(
}, },
id, id,
"rts", "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; return updatedRts;
} }
@@ -310,7 +352,7 @@ export async function deleteRts(id: string, tenantId: string) {
export async function newUpload( export async function newUpload(
id: string, id: string,
newUpload: UploadRtsInput, newUpload: UploadRtsInput,
user: AuthenticatedUser user: AuthenticatedUser,
) { ) {
return await rtsModel.findOneAndUpdate( return await rtsModel.findOneAndUpdate(
{ pid: id, tenantId: user.tenantId }, { pid: id, tenantId: user.tenantId },
@@ -322,6 +364,6 @@ export async function newUpload(
createdBy: user.userId, createdBy: user.userId,
}, },
}, },
} },
); );
} }