diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx
index 94dc2b945..1f7e10fcb 100644
--- a/client/src/components/header/header.component.jsx
+++ b/client/src/components/header/header.component.jsx
@@ -208,28 +208,32 @@ function Header({
key: "allpayments",
id: "header-accounting-allpayments",
icon: ,
- label: (
-
-
- {t("menus.header.allpayments")}
-
-
- )
+ label: {t("menus.header.allpayments")}
},
{
key: "enterpayments",
id: "header-accounting-enterpayments",
- icon: ,
- label: (
-
- {t("menus.header.enterpayment")}
-
- ),
- onClick: () =>
- HasFeatureAccess({ featureName: "payments", bodyshop }) &&
+ icon: ,
+ label: t("menus.header.enterpayment"),
+ onClick: () => {
setPaymentContext({
actions: {},
context: null
+ });
+ }
+ }
+ );
+
+ if (ImEXPay.treatment === "on") {
+ accountingChildren.push({
+ key: "entercardpayments",
+ id: "header-accounting-entercardpayments",
+ icon: ,
+ label: t("menus.header.entercardpayment"),
+ onClick: () => {
+ setCardPaymentContext({
+ actions: {},
+ context: null
})
},
...(ImEXPay.treatment === "on"
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
index 325a16ffc..bfa85dfb2 100644
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
+++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
@@ -28,11 +28,10 @@ import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
import LockerWrapperComponent from "../lock-wrapper/lock-wrapper.component";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
+import ShareToTeamsButton from "../share-to-teams/share-to-teams.component.jsx";
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
import JobsDetailHeaderActionsToggleProduction from "./jobs-detail-header-actions.toggle-production";
-import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
-import ShareToTeamsButton from "../share-to-teams/share-to-teams.component.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -775,15 +774,14 @@ export function JobsDetailHeaderActions({
key: "enterpayments",
id: "job-actions-enterpayments",
disabled: !job.converted,
- label: {t("menus.header.enterpayment")},
+ label: t("menus.header.enterpayment"),
onClick: () => {
logImEXEvent("job_header_enter_payment");
- HasFeatureAccess({ featureName: "payments", bodyshop }) &&
- setPaymentContext({
- actions: {},
- context: { jobid: job.id }
- });
+ setPaymentContext({
+ actions: {},
+ context: { jobid: job.id }
+ });
}
});
diff --git a/client/src/pages/payments-all/payments-all.container.page.jsx b/client/src/pages/payments-all/payments-all.container.page.jsx
index 2b67c4737..61105bed7 100644
--- a/client/src/pages/payments-all/payments-all.container.page.jsx
+++ b/client/src/pages/payments-all/payments-all.container.page.jsx
@@ -1,6 +1,6 @@
import { useQuery } from "@apollo/client";
import queryString from "query-string";
-import React, { useEffect } from "react";
+import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
@@ -10,23 +10,17 @@ import PaymentsListPaginated from "../../components/payments-list-paginated/paym
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { QUERY_ALL_PAYMENTS_PAGINATED } from "../../graphql/payments.queries";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
-import { selectBodyshop } from "../../redux/user/user.selectors";
import { pageLimit } from "../../utils/config";
-import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
-import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
-import { Card } from "antd";
-const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop
-});
+const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
});
-export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
+export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, searchObj } = searchParams;
@@ -60,25 +54,15 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
if (error) return ;
return (
-
-
-
- }
- z
- >
-
-
-
-
+
+
+
);
}
diff --git a/client/src/utils/jobNotificationScenarios.js b/client/src/utils/jobNotificationScenarios.js
index 52519977b..aeab82861 100644
--- a/client/src/utils/jobNotificationScenarios.js
+++ b/client/src/utils/jobNotificationScenarios.js
@@ -1,10 +1,13 @@
+/** Notification Scenarios
+ * @description This file contains the scenarios for job notifications.
+ * @type {string[]}
+ */
const notificationScenarios = [
"job-assigned-to-me",
"bill-posted",
"critical-parts-status-changed",
"part-marked-back-ordered",
"new-note-added",
- "supplement-imported",
"schedule-dates-changed",
"tasks-updated-created",
"new-media-added-reassigned",
@@ -14,6 +17,7 @@ const notificationScenarios = [
"job-status-change",
"payment-collected-completed",
"alternate-transport-changed"
+ // "supplement-imported", // Disabled for now
];
export { notificationScenarios };
diff --git a/server/notifications/scenarioBuilders.js b/server/notifications/scenarioBuilders.js
index a9dd54d2d..19b1d9f72 100644
--- a/server/notifications/scenarioBuilders.js
+++ b/server/notifications/scenarioBuilders.js
@@ -6,624 +6,20 @@ const Dinero = require("dinero.js");
Dinero.globalRoundingMode = "HALF_EVEN";
/**
- * Populates the recipients for app, email, and FCM notifications based on scenario watchers.
- *
- * @param {Object} data - The data object containing scenarioWatchers and bodyShopId.
- * @param {Object} result - The result object to populate with recipients for app, email, and FCM notifications.
+ * Creates a standard notification object with app, email, and FCM properties and populates recipients.
+ * @param {Object} data - Input data containing jobId, jobRoNumber, bodyShopId, bodyShopName, and scenarioWatchers
+ * @param {string} key - Notification key for the app
+ * @param {string} body - Notification body text
+ * @param {Object} [variables={}] - Variables for the app notification
+ * @returns {Object} Notification object with populated recipients
*/
-const populateWatchers = (data, result) => {
- data.scenarioWatchers.forEach((recipients) => {
- const { user, app, fcm, email, firstName, lastName, employeeId, associationId } = recipients;
- if (app === true)
- result.app.recipients.push({
- user,
- bodyShopId: data.bodyShopId,
- employeeId,
- associationId
- });
- if (fcm === true) result.fcm.recipients.push(user);
- if (email === true) result.email.recipients.push({ user, firstName, lastName });
- });
-};
-
-/**
- * Builds notification data for changes to alternate transport.
- */
-const alternateTransportChangedBuilder = (data) => {
- const body = `The alternate transportation has been changed from ${data.changedFields.alt_transport?.old || "unset"} to ${data?.changedFields?.alt_transport?.new || "unset"}.`;
- const result = {
- app: {
- jobId: data.jobId,
- bodyShopId: data.bodyShopId,
- jobRoNumber: data.jobRoNumber,
- key: "notifications.job.alternateTransportChanged",
- body,
- variables: {
- alternateTransport: data?.changedFields?.alt_transport?.new,
- oldAlternateTransport: data?.changedFields?.alt_transport?.old
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for bill posted events.
- */
-const billPostedHandler = (data) => {
- const facing = data?.data?.isinhouse ? "in-house" : "vendor";
- const body = `An ${facing} ${data?.data?.is_credit_memo ? "credit memo" : "bill"} has been posted.`.trim();
-
+const buildNotification = (data, key, body, variables = {}) => {
const result = {
app: {
jobId: data.jobId,
jobRoNumber: data.jobRoNumber,
bodyShopId: data.bodyShopId,
- key: "notifications.job.billPosted",
- body,
- variables: {
- isInHouse: data?.data?.isinhouse,
- isCreditMemo: data?.data?.is_credit_memo
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for changes to critical parts status.
- */
-//
-const criticalPartsStatusChangedBuilder = (data) => {
- const body = `The status on a critical part line (${data?.data?.line_desc}) has changed to ${data?.data?.status || "unset"}.`;
-
- const result = {
- app: {
- jobId: data.jobId,
- bodyShopId: data.bodyShopId,
- jobRoNumber: data.jobRoNumber,
- key: "notifications.job.criticalPartsStatusChanged",
- body,
- variables: {
- joblineId: data?.data?.id, // If we want to deeplink to the jobline
- status: data?.data?.status,
- line_desc: data?.data?.line_desc
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for completed intake or delivery checklists.
- */
-const intakeDeliveryChecklistCompletedBuilder = (data) => {
- const checklistType = data?.changedFields?.intakechecklist ? "intake" : "delivery";
- const body = `The ${checklistType.charAt(0).toUpperCase() + checklistType.slice(1)} checklist has been completed.`;
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.checklistCompleted",
- body,
- variables: {
- checklistType,
- completed: true
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for job assignment events.
- */
-const jobAssignedToMeBuilder = (data) => {
- const body = `You have been assigned to ${getJobAssignmentType(data.scenarioFields?.[0])}.`;
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.assigned",
- body,
- variables: {
- type: data.scenarioFields?.[0]
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for jobs added to production.
- */
-const jobsAddedToProductionBuilder = (data) => {
- const body = `Job is now in production.`;
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.addedToProduction",
- body,
- variables: {},
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for job status changes.
- */
-const jobStatusChangeBuilder = (data) => {
- const body = `The status has changed from ${data?.changedFields?.status?.old || "unset"} to ${data?.changedFields?.status?.new || "unset"}`;
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.statusChanged",
- body,
- variables: {
- status: data.changedFields.status.new,
- oldStatus: data.changedFields.status.old
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for new media added or reassigned events.
- */
-const newMediaAddedReassignedBuilder = (data) => {
- // Determine if it's an image or document
- const mediaType = data?.data?.type?.startsWith("image") ? "Image" : "Document";
-
- // Determine the action
- let action;
-
- if (data?.data?._documentMoved) {
- action = "moved to another job"; // Special case for document moved from this job
- } else if (data.isNew) {
- action = "added"; // New media
- } else if (data.changedFields?.jobid && data.changedFields.jobid.old !== data.changedFields.jobid.new) {
- action = "moved to this job";
- } else {
- action = "updated";
- }
-
- // Construct the body string
- const body = `An ${mediaType} has been ${action}.`;
-
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.newMediaAdded",
- body,
- variables: {
- mediaType,
- action,
- movedToJob: data?.data?._movedToJob
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for new notes added to a job.
- */
-const newNoteAddedBuilder = (data) => {
- const body = [
- "A",
- data?.data?.critical && "critical",
- data?.data?.private && "private",
- data?.data?.type,
- "note has been added by",
- `${data.data.created_by}`
- ]
- .filter(Boolean)
- .join(" ");
-
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.newNoteAdded",
- body,
- variables: {
- createdBy: data?.data?.created_by,
- critical: data?.data?.critical,
- type: data?.data?.type,
- private: data?.data?.private
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for new time tickets posted.
- */
-const newTimeTicketPostedBuilder = (data) => {
- const type = data?.data?.cost_center;
- const body = `A ${startCase(type.toLowerCase())} time ticket for ${data?.data?.date} has been posted.`.trim();
-
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.newTimeTicketPosted",
- body,
- variables: {
- type,
- date: data?.data?.date
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for parts marked as back-ordered.
- */
-const partMarkedBackOrderedBuilder = (data) => {
- const body = `A part ${data?.data?.line_desc} has been marked as back-ordered.`;
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.partBackOrdered",
- body,
- variables: {
- line_desc: data?.data?.line_desc
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for payment collection events.
- */
-const paymentCollectedCompletedBuilder = (data) => {
- const momentFormat = "MM/DD/YYYY";
-
- // Format amount using Dinero.js
- const amountDinero = Dinero({
- amount: Math.round((data.data.amount || 0) * 100) // Convert to cents, default to 0 if missing
- });
-
- const amountFormatted = amountDinero.toFormat();
-
- const payer = data.data.payer;
- const paymentType = data.data.type;
- const paymentDate = moment(data.data.date).format(momentFormat);
-
- const body = `Payment of ${amountFormatted} has been collected from ${payer} via ${paymentType} on ${paymentDate}`;
-
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.paymentCollected",
- body,
- variables: {
- amount: data.data.amount,
- payer: data.data.payer,
- type: data.data.type,
- date: data.data.date
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for changes to scheduled dates.
- */
-const scheduledDatesChangedBuilder = (data) => {
- const changedFields = data.changedFields;
-
- // Define field configurations
- const fieldConfigs = {
- scheduled_in: "Scheduled In",
- scheduled_completion: "Scheduled Completion",
- scheduled_delivery: "Scheduled Delivery"
- };
-
- // Helper function to format date and time with "at"
- const formatDateTime = (date) => {
- if (!date) return "unset";
- const formatted = moment(date).tz(data.bodyShopTimezone);
- const datePart = formatted.format("MM/DD/YYYY");
- const timePart = formatted.format("hh:mm a");
- return `${datePart} at ${timePart}`;
- };
-
- // Build field messages dynamically
- const fieldMessages = Object.entries(fieldConfigs)
- .filter(([field]) => changedFields[field]) // Only include changed fields
- .map(([field, label]) => {
- const { old, new: newValue } = changedFields[field];
-
- // Case 1: Scheduled date cancelled (from value to null)
- if (old && !newValue) {
- return `${label} was cancelled (previously ${formatDateTime(old)}).`;
- }
- // Case 2: Scheduled date set (from null to value)
- else if (!old && newValue) {
- return `${label} was set to ${formatDateTime(newValue)}.`;
- }
- // Case 3: Scheduled date changed (from value to value)
- else if (old && newValue) {
- return `${label} changed from ${formatDateTime(old)} to ${formatDateTime(newValue)}.`;
- }
- return ""; // Fallback, though this shouldn't happen with the filter
- })
- .filter(Boolean); // Remove any empty strings
-
- const body = fieldMessages.length > 0 ? fieldMessages.join(" ") : "Scheduled dates have been updated.";
-
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.scheduledDatesChanged",
- body,
- variables: {
- scheduledIn: changedFields.scheduled_in?.new,
- oldScheduledIn: changedFields.scheduled_in?.old,
- scheduledCompletion: changedFields.scheduled_completion?.new,
- oldScheduledCompletion: changedFields.scheduled_completion?.old,
- scheduledDelivery: changedFields.scheduled_delivery?.new,
- oldScheduledDelivery: changedFields.scheduled_delivery?.old
- },
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
-};
-
-/**
- * Builds notification data for tasks updated or created.
- */
-const tasksUpdatedCreatedBuilder = (data) => {
- const momentFormat = "MM/DD/YYYY hh:mm a";
- const timezone = data.bodyShopTimezone;
- const taskTitle = data?.data?.title ? `"${data.data.title}"` : "Unnamed Task";
-
- let body;
- let variables;
-
- if (data.isNew) {
- // Created case
- const priority = formatTaskPriority(data?.data?.priority);
- const createdBy = data?.data?.created_by || "Unknown"; // Fallback for undefined created_by
- const dueDate = data.data.due_date ? ` due on ${moment(data.data.due_date).tz(timezone).format(momentFormat)}` : "";
- const completedOnCreation = data.data.completed === true;
- body = `A ${priority} task ${taskTitle} has been created${completedOnCreation ? " and marked completed" : ""} by ${createdBy}${dueDate}.`;
- variables = {
- isNew: data.isNew,
- roNumber: data.jobRoNumber,
- title: data?.data?.title,
- priority: data?.data?.priority,
- createdBy: data?.data?.created_by,
- dueDate: data?.data?.due_date,
- completed: completedOnCreation ? data?.data?.completed : undefined // Only include if true
- };
- } else {
- // Updated case
- const changedFields = data.changedFields;
- const fieldNames = Object.keys(changedFields);
- const oldTitle = changedFields.title ? `"${changedFields.title.old || "Unnamed Task"}"` : taskTitle;
-
- // Special case: Only 'completed' changed
- if (fieldNames.length === 1 && changedFields.completed) {
- body = `Task ${oldTitle} was marked ${changedFields.completed.new ? "complete" : "incomplete"}`;
- variables = {
- isNew: data.isNew,
- roNumber: data.jobRoNumber,
- title: data?.data?.title,
- changedCompleted: data?.changedFields?.completed?.new
- };
- } else {
- // General update case
- const fieldMessages = [];
-
- if (changedFields.title) {
- fieldMessages.push(`Task ${oldTitle} changed title to "${changedFields.title.new || "unnamed task"}".`);
- }
- if (changedFields.description) {
- fieldMessages.push("Description updated.");
- }
- if (changedFields.priority) {
- fieldMessages.push(`Priority changed to ${formatTaskPriority(changedFields.priority.new)}.`);
- }
- if (changedFields.due_date) {
- fieldMessages.push(`Due date set to ${moment(changedFields.due_date.new).tz(timezone).format(momentFormat)}.`);
- }
- if (changedFields.completed) {
- fieldMessages.push(`Status changed to ${changedFields.completed.new ? "complete" : "incomplete"}.`);
- }
-
- body =
- fieldMessages.length > 0
- ? fieldMessages.length === 1 && changedFields.title
- ? fieldMessages[0] // If only title changed, use it standalone
- : `Task ${oldTitle} updated: ${fieldMessages.join(", ")}`
- : `Task ${oldTitle} has been updated.`;
- variables = {
- isNew: data.isNew,
- roNumber: data.jobRoNumber,
- title: data?.data?.title,
- changedTitleOld: data?.changedFields?.title?.old,
- changedTitleNew: data?.changedFields?.title?.new,
- changedPriority: data?.changedFields?.priority?.new,
- changedDueDate: data?.changedFields?.due_date?.new,
- changedCompleted: data?.changedFields?.completed?.new
- };
- }
- }
-
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: data.isNew ? "notifications.job.taskCreated" : "notifications.job.taskUpdated",
+ key,
body,
variables,
recipients: []
@@ -638,43 +34,369 @@ const tasksUpdatedCreatedBuilder = (data) => {
fcm: { recipients: [] }
};
- populateWatchers(data, result);
+ // Populate recipients from scenarioWatchers
+ data.scenarioWatchers.forEach((recipients) => {
+ const { user, app, fcm, email, firstName, lastName, employeeId, associationId } = recipients;
+ if (app === true)
+ result.app.recipients.push({
+ user,
+ bodyShopId: data.bodyShopId,
+ employeeId,
+ associationId
+ });
+ if (fcm === true) result.fcm.recipients.push(user);
+ if (email === true) result.email.recipients.push({ user, firstName, lastName });
+ });
+
return result;
};
/**
- * Builds notification data for supplement imported events.
- * TODO: This is an advanced case and will be done later
+ * Creates a notification for when the alternate transport is changed.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const alternateTransportChangedBuilder = (data) => {
+ const oldTransport = data?.changedFields?.alt_transport?.old;
+ const newTransport = data?.changedFields?.alt_transport?.new;
+ let body;
+
+ if (oldTransport && newTransport)
+ body = `The alternate transportation has been changed from ${oldTransport} to ${newTransport}.`;
+ else if (!oldTransport && newTransport) body = `The alternate transportation has been set to ${newTransport}.`;
+ else if (oldTransport && !newTransport)
+ body = `The alternate transportation has been canceled (previously ${oldTransport}).`;
+ else body = `The alternate transportation has been updated.`;
+
+ return buildNotification(data, "notifications.job.alternateTransportChanged", body, {
+ alternateTransport: newTransport,
+ oldAlternateTransport: oldTransport
+ });
+};
+
+/**
+ * Creates a notification for when a bill is posted.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const billPostedBuilder = (data) => {
+ const facing = data?.data?.isinhouse ? "in-house" : "vendor";
+ const body = `An ${facing} ${data?.data?.is_credit_memo ? "credit memo" : "bill"} has been posted.`.trim();
+
+ return buildNotification(data, "notifications.job.billPosted", body, {
+ isInHouse: data?.data?.isinhouse,
+ isCreditMemo: data?.data?.is_credit_memo
+ });
+};
+
+/**
+ * Creates a notification for when the status of critical parts changes.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const criticalPartsStatusChangedBuilder = (data) => {
+ const lineDesc = data?.data?.line_desc;
+ const status = data?.data?.status;
+ const body = status
+ ? `The status on a critical part line (${lineDesc}) has been set to ${status}.`
+ : `The status on a critical part line (${lineDesc}) has been cleared.`;
+
+ return buildNotification(data, "notifications.job.criticalPartsStatusChanged", body, {
+ joblineId: data?.data?.id,
+ status: data?.data?.status,
+ line_desc: lineDesc
+ });
+};
+
+/**
+ * Creates a notification for when the intake or delivery checklist is completed.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const intakeDeliveryChecklistCompletedBuilder = (data) => {
+ const checklistType = data?.changedFields?.intakechecklist ? "intake" : "delivery";
+ const body = `The ${checklistType.charAt(0).toUpperCase() + checklistType.slice(1)} checklist has been completed.`;
+
+ return buildNotification(data, "notifications.job.checklistCompleted", body, {
+ checklistType,
+ completed: true
+ });
+};
+
+/**
+ * Creates a notification for when a job is assigned to the user.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const jobAssignedToMeBuilder = (data) => {
+ const body = `You have been assigned to ${getJobAssignmentType(data.scenarioFields?.[0])}.`;
+
+ return buildNotification(data, "notifications.job.assigned", body, {
+ type: data.scenarioFields?.[0]
+ });
+};
+
+/**
+ * Creates a notification for when jobs are added to production.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const jobsAddedToProductionBuilder = (data) => {
+ const body = `Job is now in production.`;
+ return buildNotification(data, "notifications.job.addedToProduction", body);
+};
+
+/**
+ * Creates a notification for when the job status changes.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const jobStatusChangeBuilder = (data) => {
+ const oldStatus = data?.changedFields?.status?.old;
+ const newStatus = data?.changedFields?.status?.new;
+ let body;
+
+ if (oldStatus && newStatus) body = `The status has been changed from ${oldStatus} to ${newStatus}.`;
+ else if (!oldStatus && newStatus) body = `The status has been set to ${newStatus}.`;
+ else if (oldStatus && !newStatus) body = `The status has been cleared (previously ${oldStatus}).`;
+ else body = `The status has been updated.`;
+
+ return buildNotification(data, "notifications.job.statusChanged", body, {
+ status: newStatus,
+ oldStatus: oldStatus
+ });
+};
+
+/**
+ * Creates a notification for when new media is added or reassigned.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const newMediaAddedReassignedBuilder = (data) => {
+ const mediaType = data?.data?.type?.startsWith("image") ? "Image" : "Document";
+ const action = data?.data?._documentMoved
+ ? "moved to another job"
+ : data.isNew
+ ? "added"
+ : data.changedFields?.jobid && data.changedFields.jobid.old !== data.changedFields.jobid.new
+ ? "moved to this job"
+ : "updated";
+ const body = `An ${mediaType} has been ${action}.`;
+
+ return buildNotification(data, "notifications.job.newMediaAdded", body, {
+ mediaType,
+ action,
+ movedToJob: data?.data?._movedToJob
+ });
+};
+
+/**
+ * Creates a notification for when a new note is added.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const newNoteAddedBuilder = (data) => {
+ const body = [
+ "A",
+ data?.data?.critical && "critical",
+ data?.data?.private && "private",
+ data?.data?.type,
+ "note has been added by",
+ `${data.data.created_by}`
+ ]
+ .filter(Boolean)
+ .join(" ");
+
+ return buildNotification(data, "notifications.job.newNoteAdded", body, {
+ createdBy: data?.data?.created_by,
+ critical: data?.data?.critical,
+ type: data?.data?.type,
+ private: data?.data?.private
+ });
+};
+
+/**
+ * Creates a notification for when a new time ticket is posted.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const newTimeTicketPostedBuilder = (data) => {
+ const type = data?.data?.cost_center;
+ const body = `A ${startCase(type.toLowerCase())} time ticket for ${data?.data?.date} has been posted.`.trim();
+
+ return buildNotification(data, "notifications.job.newTimeTicketPosted", body, {
+ type,
+ date: data?.data?.date
+ });
+};
+
+/**
+ * Creates a notification for when a part is marked as back-ordered.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const partMarkedBackOrderedBuilder = (data) => {
+ const body = `A part ${data?.data?.line_desc} has been marked as back-ordered.`;
+
+ return buildNotification(data, "notifications.job.partBackOrdered", body, {
+ line_desc: data?.data?.line_desc
+ });
+};
+
+/**
+ * Creates a notification for when payment is collected or completed.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const paymentCollectedCompletedBuilder = (data) => {
+ const momentFormat = "MM/DD/YYYY";
+ const amountDinero = Dinero({ amount: Math.round((data.data.amount || 0) * 100) });
+ const amountFormatted = amountDinero.toFormat();
+ const payer = data.data.payer;
+ const paymentType = data.data.type;
+ const paymentDate = moment(data.data.date).format(momentFormat);
+ const body = `Payment of ${amountFormatted} has been collected from ${payer} via ${paymentType} on ${paymentDate}`;
+
+ return buildNotification(data, "notifications.job.paymentCollected", body, {
+ amount: data.data.amount,
+ payer: data.data.payer,
+ type: data.data.type,
+ date: data.data.date
+ });
+};
+
+/**
+ * Creates a notification for when scheduled dates are changed.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const scheduledDatesChangedBuilder = (data) => {
+ const changedFields = data.changedFields;
+ const fieldConfigs = {
+ scheduled_in: "Scheduled In",
+ scheduled_completion: "Scheduled Completion",
+ scheduled_delivery: "Scheduled Delivery"
+ };
+ const formatDateTime = (date) => {
+ if (!date) return "(no date set)";
+ const formatted = moment(date).tz(data.bodyShopTimezone);
+ return `${formatted.format("MM/DD/YYYY")} at ${formatted.format("hh:mm a")}`;
+ };
+
+ const fieldMessages = Object.entries(fieldConfigs)
+ .filter(([field]) => changedFields[field])
+ .map(([field, label]) => {
+ const { old, new: newValue } = changedFields[field];
+ if (old && !newValue) return `${label} was cancelled (previously ${formatDateTime(old)}).`;
+ else if (!old && newValue) return `${label} was set to ${formatDateTime(newValue)}.`;
+ else if (old && newValue) return `${label} changed from ${formatDateTime(old)} to ${formatDateTime(newValue)}.`;
+ return "";
+ })
+ .filter(Boolean);
+
+ const body = fieldMessages.length > 0 ? fieldMessages.join(" ") : "Scheduled dates have been updated.";
+
+ return buildNotification(data, "notifications.job.scheduledDatesChanged", body, {
+ scheduledIn: changedFields.scheduled_in?.new,
+ oldScheduledIn: changedFields.scheduled_in?.old,
+ scheduledCompletion: changedFields.scheduled_completion?.new,
+ oldScheduledCompletion: changedFields.scheduled_completion?.old,
+ scheduledDelivery: changedFields.scheduled_delivery?.new,
+ oldScheduledDelivery: changedFields.scheduled_delivery?.old
+ });
+};
+
+/**
+ * Creates a notification for when tasks are updated or created.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
+ */
+const tasksUpdatedCreatedBuilder = (data) => {
+ const momentFormat = "MM/DD/YYYY hh:mm a";
+ const timezone = data.bodyShopTimezone;
+ const taskTitle = data?.data?.title ? `"${data.data.title}"` : "Unnamed Task";
+
+ let body, variables;
+ if (data.isNew) {
+ const priority = formatTaskPriority(data?.data?.priority);
+ const createdBy = data?.data?.created_by || "Unknown";
+ const dueDate = data.data.due_date ? ` due on ${moment(data.data.due_date).tz(timezone).format(momentFormat)}` : "";
+ const completedOnCreation = data.data.completed === true;
+ body = `A ${priority} task ${taskTitle} has been created${completedOnCreation ? " and marked completed" : ""} by ${createdBy}${dueDate}.`;
+ variables = {
+ isNew: data.isNew,
+ roNumber: data.jobRoNumber,
+ title: data?.data?.title,
+ priority: data?.data?.priority,
+ createdBy: data?.data?.created_by,
+ dueDate: data?.data?.due_date,
+ completed: completedOnCreation ? data?.data?.completed : undefined
+ };
+ } else {
+ const changedFields = data.changedFields;
+ const fieldNames = Object.keys(changedFields);
+ const oldTitle = changedFields.title ? `"${changedFields.title.old || "Unnamed Task"}"` : taskTitle;
+
+ if (fieldNames.length === 1 && changedFields.completed) {
+ body = `Task ${oldTitle} was marked ${changedFields.completed.new ? "complete" : "incomplete"}`;
+ variables = {
+ isNew: data.isNew,
+ roNumber: data.jobRoNumber,
+ title: data?.data?.title,
+ changedCompleted: changedFields.completed.new
+ };
+ } else {
+ const fieldMessages = [];
+ if (changedFields.title)
+ fieldMessages.push(`Task ${oldTitle} changed title to "${changedFields.title.new || "unnamed task"}".`);
+ if (changedFields.description) fieldMessages.push("Description updated.");
+ if (changedFields.priority)
+ fieldMessages.push(`Priority changed to ${formatTaskPriority(changedFields.priority.new)}.`);
+ if (changedFields.due_date)
+ fieldMessages.push(`Due date set to ${moment(changedFields.due_date.new).tz(timezone).format(momentFormat)}.`);
+ if (changedFields.completed)
+ fieldMessages.push(`Status changed to ${changedFields.completed.new ? "complete" : "incomplete"}.`);
+
+ body =
+ fieldMessages.length > 0
+ ? fieldMessages.length === 1 && changedFields.title
+ ? fieldMessages[0]
+ : `Task ${oldTitle} updated: ${fieldMessages.join(", ")}`
+ : `Task ${oldTitle} has been updated.`;
+ variables = {
+ isNew: data.isNew,
+ roNumber: data.jobRoNumber,
+ title: data?.data?.title,
+ changedTitleOld: changedFields.title?.old,
+ changedTitleNew: changedFields.title?.new,
+ changedPriority: changedFields.priority?.new,
+ changedDueDate: changedFields.due_date?.new,
+ changedCompleted: changedFields.completed?.new
+ };
+ }
+ }
+
+ return buildNotification(
+ data,
+ data.isNew ? "notifications.job.taskCreated" : "notifications.job.taskUpdated",
+ body,
+ variables
+ );
+};
+
+/**
+ * Creates a notification for when a supplement is imported.
+ * @param data
+ * @returns {{app: {jobId, jobRoNumber: *, bodyShopId: *, key: string, body: string, variables: Object, recipients: *[]}, email: {jobId, jobRoNumber: *, bodyShopName: *, body: string, recipients: *[]}, fcm: {recipients: *[]}}}
*/
const supplementImportedBuilder = (data) => {
const body = `A supplement has been imported.`;
- const result = {
- app: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopId: data.bodyShopId,
- key: "notifications.job.supplementImported",
- body,
- variables: {},
- recipients: []
- },
- email: {
- jobId: data.jobId,
- jobRoNumber: data.jobRoNumber,
- bodyShopName: data.bodyShopName,
- body,
- recipients: []
- },
- fcm: { recipients: [] }
- };
-
- populateWatchers(data, result);
- return result;
+ return buildNotification(data, "notifications.job.supplementImported", body);
};
module.exports = {
alternateTransportChangedBuilder,
- billPostedHandler,
+ billPostedBuilder,
criticalPartsStatusChangedBuilder,
intakeDeliveryChecklistCompletedBuilder,
jobAssignedToMeBuilder,
diff --git a/server/notifications/scenarioMapper.js b/server/notifications/scenarioMapper.js
index c125f3952..73a97cd5d 100644
--- a/server/notifications/scenarioMapper.js
+++ b/server/notifications/scenarioMapper.js
@@ -1,6 +1,6 @@
const {
jobAssignedToMeBuilder,
- billPostedHandler,
+ billPostedBuilder,
newNoteAddedBuilder,
scheduledDatesChangedBuilder,
tasksUpdatedCreatedBuilder,
@@ -30,10 +30,12 @@ const { isFunction } = require("lodash");
* - builder {Function}: A function to handle the scenario.
* - onlyTruthyValues {boolean|Array}: Specifies fields that must have truthy values for the scenario to match.
* - filterCallback {Function}: Optional callback (sync or async) to further filter the scenario based on event data (returns boolean).
+ * - enabled {boolean}: If true, the scenario is active; if false or omitted, the scenario is skipped.
*/
const notificationScenarios = [
{
key: "job-assigned-to-me",
+ enabled: true,
table: "jobs",
fields: ["employee_prep", "employee_body", "employee_csr", "employee_refinish"],
matchToUserFields: ["employee_prep", "employee_body", "employee_csr", "employee_refinish"],
@@ -41,24 +43,28 @@ const notificationScenarios = [
},
{
key: "bill-posted",
+ enabled: true,
table: "bills",
- builder: billPostedHandler,
+ builder: billPostedBuilder,
onNew: true
},
{
key: "new-note-added",
+ enabled: true,
table: "notes",
builder: newNoteAddedBuilder,
onNew: true
},
{
key: "schedule-dates-changed",
+ enabled: true,
table: "jobs",
fields: ["scheduled_in", "scheduled_completion", "scheduled_delivery"],
builder: scheduledDatesChangedBuilder
},
{
key: "tasks-updated-created",
+ enabled: true,
table: "tasks",
fields: ["updated_at"],
// onNew: true,
@@ -66,12 +72,14 @@ const notificationScenarios = [
},
{
key: "job-status-change",
+ enabled: true,
table: "jobs",
fields: ["status"],
builder: jobStatusChangeBuilder
},
{
key: "job-added-to-production",
+ enabled: true,
table: "jobs",
fields: ["inproduction"],
onlyTruthyValues: ["inproduction"],
@@ -79,36 +87,42 @@ const notificationScenarios = [
},
{
key: "alternate-transport-changed",
+ enabled: true,
table: "jobs",
fields: ["alt_transport"],
builder: alternateTransportChangedBuilder
},
{
key: "new-time-ticket-posted",
+ enabled: true,
table: "timetickets",
builder: newTimeTicketPostedBuilder
},
{
key: "intake-delivery-checklist-completed",
+ enabled: true,
table: "jobs",
fields: ["intakechecklist", "deliverchecklist"],
builder: intakeDeliveryChecklistCompletedBuilder
},
{
key: "payment-collected-completed",
+ enabled: true,
table: "payments",
onNew: true,
builder: paymentCollectedCompletedBuilder
},
{
- // MAKE SURE YOU ARE NOT ON A LMS ENVIRONMENT
+ // Only works on a non LMS ENV
key: "new-media-added-reassigned",
+ enabled: true,
table: "documents",
fields: ["jobid"],
builder: newMediaAddedReassignedBuilder
},
{
key: "critical-parts-status-changed",
+ enabled: true,
table: "joblines",
fields: ["status"],
onlyTruthyValues: ["status"],
@@ -117,6 +131,7 @@ const notificationScenarios = [
},
{
key: "part-marked-back-ordered",
+ enabled: true,
table: "joblines",
fields: ["status"],
builder: partMarkedBackOrderedBuilder,
@@ -133,12 +148,11 @@ const notificationScenarios = [
}
}
},
- // -------------- Difficult ---------------
- // Holding off on this one for now
+ // Holding off on this one for now, spans multiple tables
{
key: "supplement-imported",
+ enabled: false,
builder: supplementImportedBuilder
- // spans multiple tables,
}
];
@@ -159,6 +173,11 @@ const notificationScenarios = [
const getMatchingScenarios = async (eventData, getBodyshopFromRedis) => {
const matches = [];
for (const scenario of notificationScenarios) {
+ // Check if the scenario is enabled; skip if not explicitly true
+ if (scenario.enabled !== true) {
+ continue;
+ }
+
// If eventData has a table, then only scenarios with a table property that matches should be considered.
if (eventData.table) {
if (!scenario.table || eventData.table.name !== scenario.table) {
diff --git a/server/notifications/scenarioParser.js b/server/notifications/scenarioParser.js
index d5c9069a0..ddf1ff103 100644
--- a/server/notifications/scenarioParser.js
+++ b/server/notifications/scenarioParser.js
@@ -35,7 +35,6 @@ const scenarioParser = async (req, jobIdField) => {
} = req;
// Step 1: Validate we know what user committed the action that fired the parser
- // console.log("Step 1");
const hasuraUserRole = event?.session_variables?.["x-hasura-role"];
const hasuraUserId = event?.session_variables?.["x-hasura-user-id"];
@@ -52,7 +51,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 2: Extract just the jobId using the provided jobIdField
- // console.log("Step 2");
let jobId = null;
if (jobIdField) {
@@ -70,7 +68,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 3: Query job watchers associated with the job ID using GraphQL
- // console.log("Step 3");
const watcherData = await gqlClient.request(queries.GET_JOB_WATCHERS, {
jobid: jobId
@@ -96,7 +93,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 5: Perform the full event diff now that we know there are watchers
- // console.log("Step 5");
const eventData = await eventParser({
newData: event.data.new,
@@ -107,7 +103,6 @@ const scenarioParser = async (req, jobIdField) => {
});
// Step 6: Extract body shop information from the job data
- // console.log("Step 6");
const bodyShopId = watcherData?.job?.bodyshop?.id;
const bodyShopName = watcherData?.job?.bodyshop?.shopname;
@@ -122,7 +117,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 7: Identify scenarios that match the event data and job context
- // console.log("Step 7");
const matchingScenarios = await getMatchingScenarios(
{
@@ -155,7 +149,6 @@ const scenarioParser = async (req, jobIdField) => {
};
// Step 8: Query notification settings for the job watchers
- // console.log("Step 8");
const associationsData = await gqlClient.request(queries.GET_NOTIFICATION_ASSOCIATIONS, {
emails: jobWatchers.map((x) => x.email),
@@ -173,7 +166,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 9: Filter scenario watchers based on their enabled notification methods
- // console.log("Step 9");
finalScenarioData.matchingScenarios = finalScenarioData.matchingScenarios.map((scenario) => ({
...scenario,
@@ -213,7 +205,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 10: Build and collect scenarios to dispatch notifications for
- // console.log("Step 10");
const scenariosToDispatch = [];
@@ -240,7 +231,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 11: Filter scenario fields to include only those that changed
- // console.log("Step 11");
const filteredScenarioFields =
scenario.fields?.filter((field) => eventData.changedFieldNames.includes(field)) || [];
@@ -274,7 +264,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 12: Dispatch email notifications to the email queue
- // console.log("Step 12");
const emailsToDispatch = scenariosToDispatch.map((scenario) => scenario?.email);
if (!isEmpty(emailsToDispatch)) {
@@ -287,7 +276,6 @@ const scenarioParser = async (req, jobIdField) => {
}
// Step 13: Dispatch app notifications to the app queue
- // console.log("Step 13");
const appsToDispatch = scenariosToDispatch.map((scenario) => scenario?.app);
if (!isEmpty(appsToDispatch)) {