const { jobAssignedToMeBuilder, billPostedHandler, newNoteAddedBuilder, scheduledDatesChangedBuilder, tasksUpdatedCreatedBuilder, jobStatusChangeBuilder, jobsAddedToProductionBuilder, alternateTransportChangedBuilder, newTimeTicketPostedBuilder, intakeDeliveryChecklistCompletedBuilder, paymentCollectedCompletedBuilder, newMediaAddedReassignedBuilder, criticalPartsStatusChangedBuilder, supplementImportedBuilder, partMarkedBackOrderedBuilder } = require("./scenarioBuilders"); /** * An array of notification scenario definitions. * * Each scenario object can include the following properties: * - key {string}: The unique scenario name. * - table {string}: The table name to check for changes. * - fields {Array}: Fields to check for changes. * - matchToUserFields {Array}: Fields used to match scenarios to user data. * - onNew {boolean|Array}: Indicates whether the scenario should be triggered on new data. * - onlyTrue {Array}: Specifies fields that must be true for the scenario to match. * - builder {Function}: A function to handle the scenario. */ const notificationScenarios = [ { key: "job-assigned-to-me", table: "jobs", fields: ["employee_pre", "employee_body", "employee_csr", "employee_refinish"], matchToUserFields: ["employee_pre", "employee_body", "employee_csr", "employee_refinish"], builder: jobAssignedToMeBuilder }, { key: "bill-posted", table: "bills", builder: billPostedHandler, onNew: true }, { key: "new-note-added", table: "notes", builder: newNoteAddedBuilder, onNew: true }, { key: "schedule-dates-changed", table: "jobs", fields: ["scheduled_in", "scheduled_completion", "scheduled_delivery"], builder: scheduledDatesChangedBuilder }, { key: "tasks-updated-created", table: "tasks", fields: ["updated_at"], // onNew: true, builder: tasksUpdatedCreatedBuilder }, { key: "job-status-change", table: "jobs", fields: ["status"], builder: jobStatusChangeBuilder }, { key: "job-added-to-production", table: "jobs", fields: ["inproduction"], builder: jobsAddedToProductionBuilder }, { key: "alternate-transport-changed", table: "jobs", fields: ["alt_transport"], builder: alternateTransportChangedBuilder }, { key: "new-time-ticket-posted", table: "timetickets", builder: newTimeTicketPostedBuilder }, { // Good test for batching as this will hit multiple scenarios key: "intake-delivery-checklist-completed", table: "jobs", fields: ["intakechecklist"], builder: intakeDeliveryChecklistCompletedBuilder }, { key: "payment-collected-completed", table: "payments", onNew: true, builder: paymentCollectedCompletedBuilder }, { // MAKE SURE YOU ARE NOT ON A LMS ENVIRONMENT // Potential Callbacks / Save for last // Not question mark for Non LMS Scenario key: "new-media-added-reassigned", table: "documents", fields: ["jobid"], builder: newMediaAddedReassignedBuilder }, { key: "critical-parts-status-changed", table: "joblines", fields: ["critical"], onlyTrue: ["critical"], builder: criticalPartsStatusChangedBuilder }, // -------------- Difficult --------------- // Holding off on this one for now { key: "supplement-imported", builder: supplementImportedBuilder // spans multiple tables, }, // This one may be tricky as the jobid is not directly in the event data (this is probably wrong) // (should otherwise) // Status needs to mark meta data 'md_backorderd' for example // Double check Jobid { key: "part-marked-back-ordered", table: "joblines", builder: partMarkedBackOrderedBuilder } ]; /** * Returns an array of scenarios that match the given event data. * * @param {Object} eventData - The parsed event data. * Expected properties: * - table: an object with a `name` property (e.g. { name: "tasks", schema: "public" }) * - changedFieldNames: an array of changed field names (e.g. [ "description", "updated_at" ]) * - isNew: boolean indicating whether the record is new or updated * - data: the new data object (used to check field values) * - (other properties may be added such as jobWatchers, bodyShopId, etc.) * * @returns {Array} An array of matching scenario objects. */ function getMatchingScenarios(eventData) { return notificationScenarios.filter((scenario) => { // 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) { return false; } } // Check the onNew flag. // Allow onNew to be either a boolean or an array of booleans. if (Object.prototype.hasOwnProperty.call(scenario, "onNew")) { if (Array.isArray(scenario.onNew)) { if (!scenario.onNew.includes(eventData.isNew)) return false; } else { if (eventData.isNew !== scenario.onNew) return false; } } // If the scenario defines fields, ensure at least one of them is present in changedFieldNames. if (scenario.fields && scenario.fields.length > 0) { const hasMatchingField = scenario.fields.some((field) => eventData.changedFieldNames.includes(field)); if (!hasMatchingField) { return false; } } // OnlyTrue logic: // If a scenario defines an onlyTrue array, then at least one of those fields must have changed // and its new value (from eventData.data) must be non-falsey. if (scenario.onlyTrue && Array.isArray(scenario.onlyTrue) && scenario.onlyTrue.length > 0) { const hasTruthyChange = scenario.onlyTrue.some( (field) => eventData.changedFieldNames.includes(field) && Boolean(eventData.data[field]) ); if (!hasTruthyChange) { return false; } } return true; }); } module.exports = { notificationScenarios, getMatchingScenarios };