From 6bbd303dc252800f7b93b42347a7a425e9eafcca Mon Sep 17 00:00:00 2001 From: Diya Wadhwani Date: Tue, 9 Jun 2026 20:28:27 -0700 Subject: [PATCH 1/2] fix(autorep): Fixed Auto-Reply emails for missed summaries --- src/helpers/userHelper.js | 573 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 573 insertions(+) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 58019ded2..0290b8990 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -1085,6 +1085,576 @@ const userHelper = function () { } }; + const missedSummaryTemplate = (firstname) => + `
+ Dear ${firstname}, +

+
When you read this, please input your summary into the software. When you do, please be sure to put it in using the tab for "Last Week".
+

+
If you also forgot to submit your weekly media files, be sure to fix that too.
+

+
Reply all to this email once you've done this, so I know to review what you've submitted. Do this before tomorrow (Monday) at 3 PM (Pacific Time) and I'll remove this blue square.
+

+
With Gratitude,
+

+
One Community
+
`; + + const completeHoursAndMissedSummary = async (emailConfig = {}) => { + try { + const query = emailConfig.targetUserId + ? { _id: emailConfig.targetUserId } + : { isActive: true }; + const users = await userProfile.find( + query, + '_id weeklycommittedHours weeklySummaries missedHours email firstName weeklySummaryOption weeklySummaryNotReq', + ); + + const pdtStartOfLastWeek = moment() + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week'); + const pdtEndOfLastWeek = moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'); + + let emailsBCCs; + const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); + if (blueSquareBCCs.length > 0) { + emailsBCCs = blueSquareBCCs + .filter((bcc) => bcc.assignedTo?.isActive) + .map((bcc) => bcc.email); + } else { + emailsBCCs = DEFAULT_BCC_EMAILS; + } + + for (let i = 0; i < users.length; i += 1) { + const user = users[i]; + let hasWeeklySummary = false; + + if (Array.isArray(user.weeklySummaries) && user.weeklySummaries.length > 1) { + const { summary } = user.weeklySummaries[1]; + if (summary) { + hasWeeklySummary = true; + } + } + + if (user?.weeklySummaryOption === 'Not Required' || user?.weeklySummaryNotReq) { + hasWeeklySummary = true; + } + + const results = await dashboardHelper.laborthisweek( + user._id, + pdtStartOfLastWeek, + pdtEndOfLastWeek, + ); + + const timeSpent = + Array.isArray(results) && results[0]?.timeSpent_hrs ? results[0].timeSpent_hrs : 0; + + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + const timeNotMet = timeSpent < weeklycommittedHours; + + const utcStartMoment = moment(pdtStartOfLastWeek).add(1, 'second'); + const utcEndMoment = moment(pdtEndOfLastWeek).subtract(1, 'day').subtract(1, 'second'); + + const requestsForTimeOff = await timeOffRequest.find({ + requestFor: user._id, + startingDate: { $lte: utcStartMoment }, + endingDate: { $gte: utcEndMoment }, + }); + const hasTimeOffRequest = requestsForTimeOff.length > 0; + + if (hasTimeOffRequest === false && timeNotMet === false && hasWeeklySummary === false) { + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + missedSummaryTemplate(user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } + } + return 'success'; + } catch (err) { + console.error(err); + return 'error'; + } + }; + + const WeeklyReminderEmailBody = (templateNo, firstName) => { + switch (templateNo) { + case 'MISSED_HOURS_BY_<15%': + return `
+ Good Morning ${firstName}, +

+
You completed close enough to your total hours for us to remove this blue square. Please be sure to complete the minimum or more of your hours from now on though.
+

+
With Gratitude,
+

+
One Community
+
`; + case 'COMPLETED_HOURS_65%_84.9%': + return `
+ Good Morning ${firstName}, +

+
We're checking in to see if everything is ok with you. You completed most but not all of your hours this last week. Is everything ok?
+

+
Please reply all to let us know.
+

+
With Gratitude,
+

+
One Community
+
`; + case 'COMPLETED_HOURS_25%_64.9%': + return `
+ Good Morning ${firstName}, +

+
This email is checking in to see if everything is ok with you. You completed some but not all of your hours this last week. Is everything ok? Is there a reason you didn't use the blue square scheduler on your Profile Page to schedule the week off?
+

+
Please reply all to let us know.
+

+
With Gratitude,
+

+
One Community
+
`; + case '<1MON_ONE_BLUESQUARE': + return `
+ Good Morning ${firstName}, +

+
It's very unusual for someone to get a blue square in their first few weeks on the team. This email is to check in with you to see if everything is ok and if you are still wanting to volunteer with us.
+

+
Please reply all to let us know.
+

+
With Gratitude,
+

+
One Community
+
`; + case '<2MON_TWO_BLUESQUARE': + return `
+ Good Morning ${firstName}, +

+
We noticed that you've received two blue squares within your first couple of months on the team, which is somewhat unusual. We're reaching out to check in, understand what happened, and see if this role still aligns with your interests, availability, and energy.
+

+
Please reply all to let us know.
+

+
Looking forward to your response.
+

+
With Gratitude,
+

+
One Community
+
`; + case '<1MON_TWO_BLUESQUARE': + return `
+ Good Morning ${firstName}, +

+
We noticed that you've received two blue squares within your first few weeks on the team, which is quite unusual. When this happens, we start to wonder whether this position is the right fit for you and if you still wish to continue volunteering with us.
+

+
Do you still feel this role aligns with your interests, availability, and energy? If so, what steps will you take to meet the requirements of being a One Community team member moving forward?
+

+
Please reply all to let us know your thoughts.
+

+
Looking forward to your response.
+

+
With Gratitude,
+

+
One Community
+
`; + case '<2MON_THREE_BLUESQUARE': + return `
+ Good Morning ${firstName}, +

+
It's very unusual for people to get 3 blue squares in less than 2 months on the team. We're writing to check in with you to see if A) everything is OK and B) if you still have the time and desire to continue with us?
+

+
Please reply all to let us know what happened and your desire/intent for continuing.
+

+
Looking forward to your response.
+

+
Sincerely,
+

+
One Community
+
`; + case '4TH_BLUE_SQUARE': + return `
+ Good Morning ${firstName}, +

+
We wanted to reach out because you've received four blue squares. As you may know, we allow a maximum of five, so we want to ensure you're aware that you are nearing the limit.
+

+
We appreciate your contributions and hope to see you avoiding any further blue squares. Please let us know if you have any concerns or need support in this.
+

+
With Gratitude,
+

+
One Community
+
`; + case 'SCHEDULED_TIME_OFF': + return `
+ Good Morning ${firstName}, +

+
Thank you for scheduling off the time you needed. Advanced notice like this is helpful and appreciated.
+

+
With Gratitude,
+

+
One Community
+
`; + case 'SCHEDULED_TIME_OFF_AND_4TH_BLUE_SQUARE': + return `
+ Good Morning ${firstName}, +

+
Thank you for scheduling off the time you needed. Advanced notice like this is helpful and appreciated. And as you may know, we allow a maximum of five blue squares.
+

+
This is your fourth blue square, so we want to ensure you're aware that you are nearing the limit. This means you won't be able to schedule any more time off, and you should take special care to not receive an additional blue square.
+

+
We appreciate your contributions, please let us know if you have any concerns or need support in this.
+

+
With Gratitude,
+

+
One Community
+
`; + default: + console.error(`Unknown email template: ${templateNo}`); + return null; + } + }; + + const inCompleteHoursEmailFunction = async (emailConfig = {}) => { + try { + const query = emailConfig.targetUserId + ? { _id: emailConfig.targetUserId } + : { isActive: true }; + const users = await userProfile.find( + query, + '_id weeklycommittedHours missedHours email firstName infringements startDate', + ); + + const pdtStartOfLastWeek = moment() + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week'); + const pdtEndOfLastWeek = moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'); + + const date = moment(); + const todayDate = date.tz('America/Los_Angeles').format('YYYY-MM-DD'); + + let emailsBCCs; + const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); + if (blueSquareBCCs.length > 0) { + emailsBCCs = blueSquareBCCs + .filter((bcc) => bcc.assignedTo?.isActive) + .map((bcc) => bcc.email); + } else { + emailsBCCs = DEFAULT_BCC_EMAILS; + } + + for (let i = 0; i < users.length; i += 1) { + const user = users[i]; + const results = await dashboardHelper.laborthisweek( + user._id, + pdtStartOfLastWeek, + pdtEndOfLastWeek, + ); + const timeSpent = + Array.isArray(results) && results[0]?.timeSpent_hrs ? results[0].timeSpent_hrs : 0; + + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + + const currentDate = moment().tz('America/Los_Angeles'); + const startDate = moment(user.startDate).tz('America/Los_Angeles'); + const startOfMonth = startDate.clone().startOf('month'); + const currentMonthStart = currentDate.clone().startOf('month'); + const daysIntoOfStartMonth = startDate.diff(startOfMonth, 'days'); + const daysIntoOfCurrentMonth = currentDate.diff(currentMonthStart, 'days'); + const numMonths = + daysIntoOfStartMonth > daysIntoOfCurrentMonth + ? currentMonthStart.diff(startOfMonth, 'months') - 1 + : currentMonthStart.diff(startOfMonth, 'months'); + + const todayBlueSquare = user.infringements.filter( + (infringement) => infringement.date === todayDate, + ); + + if ( + timeSpent >= 0.85 * weeklycommittedHours && + timeSpent < weeklycommittedHours && + user.infringements.length < 4 && + todayBlueSquare.length === 1 + ) { + console.log('Entered > 85% but < weeklycommittedHours part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('MISSED_HOURS_BY_<15%', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } else if ( + timeSpent >= 0.65 * weeklycommittedHours && + timeSpent <= 0.849 * weeklycommittedHours + ) { + console.log('Entered > 65% but < 85% part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('COMPLETED_HOURS_65%_84.9%', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } else if ( + timeSpent >= 0.25 * weeklycommittedHours && + timeSpent <= 0.649 * weeklycommittedHours && + numMonths >= 2 + ) { + console.log('Entered > 25% but < 65% part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('COMPLETED_HOURS_25%_64.9%', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } + } + } catch (error) { + console.error('Error in inCompleteHoursEmailFunction:', error); + } + }; + + const weeklyBlueSquareReminderFunction = async (emailConfig = {}) => { + try { + const query = emailConfig.targetUserId + ? { _id: emailConfig.targetUserId } + : { isActive: true }; + const users = await userProfile.find( + query, + '_id weeklycommittedHours missedHours email firstName infringements startDate', + ); + + const pdtStartOfLastWeek = moment() + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week'); + const pdtEndOfLastWeek = moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'); + + const date = moment(); + const todayDate = date.tz('America/Los_Angeles').format('YYYY-MM-DD'); + + let emailsBCCs; + const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); + if (blueSquareBCCs.length > 0) { + emailsBCCs = blueSquareBCCs + .filter((bcc) => bcc.assignedTo?.isActive) + .map((bcc) => bcc.email); + } else { + emailsBCCs = DEFAULT_BCC_EMAILS; + } + + const utcStartMoment = moment(pdtStartOfLastWeek).add(1, 'second'); + const utcEndMoment = moment(pdtEndOfLastWeek).subtract(1, 'day').subtract(1, 'second'); + + for (let i = 0; i < users.length; i += 1) { + const user = users[i]; + const results = await dashboardHelper.laborthisweek( + user._id, + pdtStartOfLastWeek, + pdtEndOfLastWeek, + ); + if (results && results[0]) { + const { timeSpent_hrs: timeSpent } = results[0]; + + const currentDate = moment().tz('America/Los_Angeles'); + const startDate = moment(user.startDate).tz('America/Los_Angeles'); + const startOfMonth = startDate.clone().startOf('month'); + const currentMonthStart = currentDate.clone().startOf('month'); + const daysIntoOfStartMonth = startDate.diff(startOfMonth, 'days'); + const daysIntoOfCurrentMonth = currentDate.diff(currentMonthStart, 'days'); + const numMonths = + daysIntoOfStartMonth > daysIntoOfCurrentMonth + ? currentMonthStart.diff(startOfMonth, 'months') - 1 + : currentMonthStart.diff(startOfMonth, 'months'); + + const requestsForTimeOff = await timeOffRequest.find({ + requestFor: user._id, + startingDate: { $lte: utcStartMoment }, + endingDate: { $gte: utcEndMoment }, + }); + const hasTimeOffRequest = requestsForTimeOff.length > 0; + + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + const timeCondition1 = + timeSpent >= 0.85 * weeklycommittedHours && timeSpent < weeklycommittedHours; + const timeCondition2 = + timeSpent >= 0.65 * weeklycommittedHours && timeSpent <= 0.849 * weeklycommittedHours; + const bluesquareEmailCondition = + hasTimeOffRequest === false && !(timeCondition1 || timeCondition2); + + const todayBlueSquare = users[i].infringements.filter( + (infringement) => infringement.date === todayDate, + ); + + if ( + bluesquareEmailCondition && + users[i].infringements.length === 1 && + todayBlueSquare.length === 1 && + numMonths < 1 + ) { + console.log('Entered <1MON_ONE_BLUESQUARE part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('<1MON_ONE_BLUESQUARE', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } else if ( + bluesquareEmailCondition && + users[i].infringements.length === 2 && + todayBlueSquare.length === 1 + ) { + if (numMonths < 1) { + console.log('Entered <1MON_TWO_BLUESQUARE part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('<1MON_TWO_BLUESQUARE', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } else if (numMonths < 2) { + console.log('Entered <2MON_TWO_BLUESQUARE part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('<2MON_TWO_BLUESQUARE', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } + } else if ( + bluesquareEmailCondition && + users[i].infringements.length === 3 && + todayBlueSquare.length === 1 && + numMonths < 2 + ) { + console.log('Entered <2MON_THREE_BLUESQUARE part'); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody('<2MON_THREE_BLUESQUARE', user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } else if ( + bluesquareEmailCondition && + users[i].infringements.length === 4 && + todayBlueSquare.length === 1 + ) { + const hasTimeOff = requestsForTimeOff.length > 0; + const templateKey = hasTimeOff + ? 'SCHEDULED_TIME_OFF_AND_4TH_BLUE_SQUARE' + : '4TH_BLUE_SQUARE'; + console.log(`Entered ${templateKey} part`); + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, + WeeklyReminderEmailBody(templateKey, user.firstName), + null, + emailConfig.ccOverride || [ + 'jae@onecommunityglobal.org', + 'onecommunityglobal@gmail.com', + ], + 'jae@onecommunityglobal.org', + emailConfig.bccOverride || [...new Set([...emailsBCCs])], + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), + }, + ); + } + } + } + } catch (error) { + console.error('Error in weeklyBlueSquareReminderFunction:', error); + } + }; + const reActivateUser = async () => { const currentFormattedDate = moment().tz('America/Los_Angeles').format(); @@ -2959,6 +3529,9 @@ const userHelper = function () { assignBlueSquareForTimeNotMet, applyMissedHourForCoreTeam, deleteBlueSquareAfterYear, + completeHoursAndMissedSummary, + inCompleteHoursEmailFunction, + weeklyBlueSquareReminderFunction, reActivateUser, sendDeactivateEmailBody, deActivateUser, From fbb09805bf350d4491979da55f5401518e6a8ca3 Mon Sep 17 00:00:00 2001 From: Diya Wadhwani Date: Wed, 10 Jun 2026 15:08:00 -0700 Subject: [PATCH 2/2] fix(sonarqube): fixed sonarqube issues - duplication --- src/helpers/userHelper.js | 583 ++++++++++++++------------------------ 1 file changed, 218 insertions(+), 365 deletions(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 0290b8990..631531197 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -1087,18 +1087,96 @@ const userHelper = function () { const missedSummaryTemplate = (firstname) => `
- Dear ${firstname}, -

-
When you read this, please input your summary into the software. When you do, please be sure to put it in using the tab for "Last Week".
-

-
If you also forgot to submit your weekly media files, be sure to fix that too.
-

-
Reply all to this email once you've done this, so I know to review what you've submitted. Do this before tomorrow (Monday) at 3 PM (Pacific Time) and I'll remove this blue square.
-

-
With Gratitude,
-

-
One Community
-
`; + Dear ${firstname}, +

+
When you read this, please input your summary into the software. When you do, please be sure to put it in using the tab for "Last Week".
+

+
If you also forgot to submit your weekly media files, be sure to fix that too.
+

+
Reply all to this email once you've done this, so I know to review what you've submitted. Do this before tomorrow (Monday) at 3 PM (Pacific Time) and I'll remove this blue square.
+

+
With Gratitude,
+

+
One Community
+ `; + + /** + * Returns de-duped BCC list: override if provided, else from DB or defaults. + */ + const resolveBCCs = async (emailConfig) => { + if (emailConfig.bccOverride) return emailConfig.bccOverride; + const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); + const fromDB = + blueSquareBCCs.length > 0 + ? blueSquareBCCs.filter((b) => b.assignedTo?.isActive).map((b) => b.email) + : DEFAULT_BCC_EMAILS; + return [...new Set(fromDB)]; + }; + + /** + * Sends a blue-square reply email with standard subject/cc/bcc. + */ + const sendBlueSquareEmail = async (emailConfig, user, weekStart, bodyHtml, resolvedBCCs) => { + await emailSender( + emailConfig.emailOverride || user.email, + `Re: New Infringement Assigned - Week of ${moment(weekStart).format('MM/DD/YYYY')}`, + bodyHtml, + null, + emailConfig.ccOverride || ['jae@onecommunityglobal.org', 'onecommunityglobal@gmail.com'], + 'jae@onecommunityglobal.org', + resolvedBCCs, + { + type: 'blue_square_assignment', + recipientUserId: String(user._id), + weekStart: moment(weekStart).format('YYYY-MM-DD'), + }, + ); + }; + + /** + * Returns { pdtStartOfLastWeek, pdtEndOfLastWeek } for the previous PDT week. + */ + const getLastWeekRange = () => ({ + pdtStartOfLastWeek: moment().tz('America/Los_Angeles').startOf('week').subtract(1, 'week'), + pdtEndOfLastWeek: moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'), + }); + + /** + * Returns how many full months the user has been on the team (PDT-aware). + */ + const getNumMonthsOnTeam = (user) => { + const currentDate = moment().tz('America/Los_Angeles'); + const startDate = moment(user.startDate).tz('America/Los_Angeles'); + const startOfMonth = startDate.clone().startOf('month'); + const currentMonthStart = currentDate.clone().startOf('month'); + const daysIntoStart = startDate.diff(startOfMonth, 'days'); + const daysIntoCurrent = currentDate.diff(currentMonthStart, 'days'); + return daysIntoStart > daysIntoCurrent + ? currentMonthStart.diff(startOfMonth, 'months') - 1 + : currentMonthStart.diff(startOfMonth, 'months'); + }; + + /** + * Returns true if user has a time-off request covering the entire last week. + */ + const userHasTimeOff = async (userId, pdtStartOfLastWeek, pdtEndOfLastWeek) => { + const utcStart = moment(pdtStartOfLastWeek).add(1, 'second'); + const utcEnd = moment(pdtEndOfLastWeek).subtract(1, 'day').subtract(1, 'second'); + const requests = await timeOffRequest.find({ + requestFor: userId, + startingDate: { $lte: utcStart }, + endingDate: { $gte: utcEnd }, + }); + return requests.length > 0; + }; + + /** + * Returns hours logged by a user in [start, end], defaulting to 0. + */ + const getUserTimeSpent = async (userId, start, end) => { + const results = await dashboardHelper.laborthisweek(userId, start, end); + return results?.[0]?.timeSpent_hrs ?? 0; + }; const completeHoursAndMissedSummary = async (emailConfig = {}) => { try { @@ -1110,78 +1188,35 @@ const userHelper = function () { '_id weeklycommittedHours weeklySummaries missedHours email firstName weeklySummaryOption weeklySummaryNotReq', ); - const pdtStartOfLastWeek = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week'); - const pdtEndOfLastWeek = moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'); + const { pdtStartOfLastWeek, pdtEndOfLastWeek } = getLastWeekRange(); + const resolvedBCCs = await resolveBCCs(emailConfig); - let emailsBCCs; - const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); - if (blueSquareBCCs.length > 0) { - emailsBCCs = blueSquareBCCs - .filter((bcc) => bcc.assignedTo?.isActive) - .map((bcc) => bcc.email); - } else { - emailsBCCs = DEFAULT_BCC_EMAILS; - } + for (const user of users) { + // 1. Does the user have a summary for last week? + const hasWeeklySummary = + user?.weeklySummaryOption === 'Not Required' || + user?.weeklySummaryNotReq || + (Array.isArray(user.weeklySummaries) && + user.weeklySummaries.length > 1 && + !!user.weeklySummaries[1].summary); - for (let i = 0; i < users.length; i += 1) { - const user = users[i]; - let hasWeeklySummary = false; + if (hasWeeklySummary) continue; - if (Array.isArray(user.weeklySummaries) && user.weeklySummaries.length > 1) { - const { summary } = user.weeklySummaries[1]; - if (summary) { - hasWeeklySummary = true; - } - } + // 2. Did they meet their hours? + const timeSpent = await getUserTimeSpent(user._id, pdtStartOfLastWeek, pdtEndOfLastWeek); + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + if (timeSpent < weeklycommittedHours) continue; - if (user?.weeklySummaryOption === 'Not Required' || user?.weeklySummaryNotReq) { - hasWeeklySummary = true; - } + // 3. Do they have time off covering the week? + if (await userHasTimeOff(user._id, pdtStartOfLastWeek, pdtEndOfLastWeek)) continue; - const results = await dashboardHelper.laborthisweek( - user._id, + await sendBlueSquareEmail( + emailConfig, + user, pdtStartOfLastWeek, - pdtEndOfLastWeek, + missedSummaryTemplate(user.firstName), + resolvedBCCs, ); - - const timeSpent = - Array.isArray(results) && results[0]?.timeSpent_hrs ? results[0].timeSpent_hrs : 0; - - const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); - const timeNotMet = timeSpent < weeklycommittedHours; - - const utcStartMoment = moment(pdtStartOfLastWeek).add(1, 'second'); - const utcEndMoment = moment(pdtEndOfLastWeek).subtract(1, 'day').subtract(1, 'second'); - - const requestsForTimeOff = await timeOffRequest.find({ - requestFor: user._id, - startingDate: { $lte: utcStartMoment }, - endingDate: { $gte: utcEndMoment }, - }); - const hasTimeOffRequest = requestsForTimeOff.length > 0; - - if (hasTimeOffRequest === false && timeNotMet === false && hasWeeklySummary === false) { - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - missedSummaryTemplate(user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } } return 'success'; } catch (err) { @@ -1334,128 +1369,63 @@ const userHelper = function () { '_id weeklycommittedHours missedHours email firstName infringements startDate', ); - const pdtStartOfLastWeek = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week'); - const pdtEndOfLastWeek = moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'); - - const date = moment(); - const todayDate = date.tz('America/Los_Angeles').format('YYYY-MM-DD'); - - let emailsBCCs; - const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); - if (blueSquareBCCs.length > 0) { - emailsBCCs = blueSquareBCCs - .filter((bcc) => bcc.assignedTo?.isActive) - .map((bcc) => bcc.email); - } else { - emailsBCCs = DEFAULT_BCC_EMAILS; - } - - for (let i = 0; i < users.length; i += 1) { - const user = users[i]; - const results = await dashboardHelper.laborthisweek( - user._id, - pdtStartOfLastWeek, - pdtEndOfLastWeek, - ); - const timeSpent = - Array.isArray(results) && results[0]?.timeSpent_hrs ? results[0].timeSpent_hrs : 0; + const { pdtStartOfLastWeek, pdtEndOfLastWeek } = getLastWeekRange(); + const todayDate = moment().tz('America/Los_Angeles').format('YYYY-MM-DD'); + const resolvedBCCs = await resolveBCCs(emailConfig); + for (const user of users) { + const timeSpent = await getUserTimeSpent(user._id, pdtStartOfLastWeek, pdtEndOfLastWeek); const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + const numMonths = getNumMonthsOnTeam(user); + const hasTodayBlueSquare = user.infringements.some((inf) => inf.date === todayDate); - const currentDate = moment().tz('America/Los_Angeles'); - const startDate = moment(user.startDate).tz('America/Los_Angeles'); - const startOfMonth = startDate.clone().startOf('month'); - const currentMonthStart = currentDate.clone().startOf('month'); - const daysIntoOfStartMonth = startDate.diff(startOfMonth, 'days'); - const daysIntoOfCurrentMonth = currentDate.diff(currentMonthStart, 'days'); - const numMonths = - daysIntoOfStartMonth > daysIntoOfCurrentMonth - ? currentMonthStart.diff(startOfMonth, 'months') - 1 - : currentMonthStart.diff(startOfMonth, 'months'); - - const todayBlueSquare = user.infringements.filter( - (infringement) => infringement.date === todayDate, + const templateKey = resolveIncompleteHoursTemplate( + timeSpent, + weeklycommittedHours, + numMonths, + user.infringements.length, + hasTodayBlueSquare, ); + if (!templateKey) continue; - if ( - timeSpent >= 0.85 * weeklycommittedHours && - timeSpent < weeklycommittedHours && - user.infringements.length < 4 && - todayBlueSquare.length === 1 - ) { - console.log('Entered > 85% but < weeklycommittedHours part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('MISSED_HOURS_BY_<15%', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } else if ( - timeSpent >= 0.65 * weeklycommittedHours && - timeSpent <= 0.849 * weeklycommittedHours - ) { - console.log('Entered > 65% but < 85% part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('COMPLETED_HOURS_65%_84.9%', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } else if ( - timeSpent >= 0.25 * weeklycommittedHours && - timeSpent <= 0.649 * weeklycommittedHours && - numMonths >= 2 - ) { - console.log('Entered > 25% but < 65% part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('COMPLETED_HOURS_25%_64.9%', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } + await sendBlueSquareEmail( + emailConfig, + user, + pdtStartOfLastWeek, + WeeklyReminderEmailBody(templateKey, user.firstName), + resolvedBCCs, + ); } } catch (error) { console.error('Error in inCompleteHoursEmailFunction:', error); } }; + /** + * Pure helper — picks the right template key for inCompleteHoursEmailFunction, + * or returns null if no email should be sent. + * Extracted to reduce cognitive complexity of the parent function. + */ + const resolveIncompleteHoursTemplate = ( + timeSpent, + weeklycommittedHours, + numMonths, + infringementCount, + hasTodayBlueSquare, + ) => { + const pct = timeSpent / weeklycommittedHours; + if (pct >= 0.85 && pct < 1 && infringementCount < 4 && hasTodayBlueSquare) { + return 'MISSED_HOURS_BY_<15%'; + } + if (pct >= 0.65 && pct <= 0.849) { + return 'COMPLETED_HOURS_65%_84.9%'; + } + if (pct >= 0.25 && pct <= 0.649 && numMonths >= 2) { + return 'COMPLETED_HOURS_25%_64.9%'; + } + return null; + }; + const weeklyBlueSquareReminderFunction = async (emailConfig = {}) => { try { const query = emailConfig.targetUserId @@ -1466,195 +1436,78 @@ const userHelper = function () { '_id weeklycommittedHours missedHours email firstName infringements startDate', ); - const pdtStartOfLastWeek = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week'); - const pdtEndOfLastWeek = moment().tz('America/Los_Angeles').endOf('week').subtract(1, 'week'); + const { pdtStartOfLastWeek, pdtEndOfLastWeek } = getLastWeekRange(); + const todayDate = moment().tz('America/Los_Angeles').format('YYYY-MM-DD'); + const resolvedBCCs = await resolveBCCs(emailConfig); - const date = moment(); - const todayDate = date.tz('America/Los_Angeles').format('YYYY-MM-DD'); + for (const user of users) { + const timeSpent = await getUserTimeSpent(user._id, pdtStartOfLastWeek, pdtEndOfLastWeek); + if (timeSpent == null) continue; - let emailsBCCs; - const blueSquareBCCs = await BlueSquareEmailAssignment.find().populate('assignedTo').exec(); - if (blueSquareBCCs.length > 0) { - emailsBCCs = blueSquareBCCs - .filter((bcc) => bcc.assignedTo?.isActive) - .map((bcc) => bcc.email); - } else { - emailsBCCs = DEFAULT_BCC_EMAILS; - } + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + const numMonths = getNumMonthsOnTeam(user); + const hasTimeOff = await userHasTimeOff(user._id, pdtStartOfLastWeek, pdtEndOfLastWeek); + const hasTodayBlueSquare = user.infringements.some((inf) => inf.date === todayDate); - const utcStartMoment = moment(pdtStartOfLastWeek).add(1, 'second'); - const utcEndMoment = moment(pdtEndOfLastWeek).subtract(1, 'day').subtract(1, 'second'); + const templateKey = resolveReminderTemplate( + timeSpent, + weeklycommittedHours, + numMonths, + user.infringements.length, + hasTodayBlueSquare, + hasTimeOff, + ); + if (!templateKey) continue; - for (let i = 0; i < users.length; i += 1) { - const user = users[i]; - const results = await dashboardHelper.laborthisweek( - user._id, + console.log(`Entered ${templateKey} part`); + await sendBlueSquareEmail( + emailConfig, + user, pdtStartOfLastWeek, - pdtEndOfLastWeek, + WeeklyReminderEmailBody(templateKey, user.firstName), + resolvedBCCs, ); - if (results && results[0]) { - const { timeSpent_hrs: timeSpent } = results[0]; - - const currentDate = moment().tz('America/Los_Angeles'); - const startDate = moment(user.startDate).tz('America/Los_Angeles'); - const startOfMonth = startDate.clone().startOf('month'); - const currentMonthStart = currentDate.clone().startOf('month'); - const daysIntoOfStartMonth = startDate.diff(startOfMonth, 'days'); - const daysIntoOfCurrentMonth = currentDate.diff(currentMonthStart, 'days'); - const numMonths = - daysIntoOfStartMonth > daysIntoOfCurrentMonth - ? currentMonthStart.diff(startOfMonth, 'months') - 1 - : currentMonthStart.diff(startOfMonth, 'months'); - - const requestsForTimeOff = await timeOffRequest.find({ - requestFor: user._id, - startingDate: { $lte: utcStartMoment }, - endingDate: { $gte: utcEndMoment }, - }); - const hasTimeOffRequest = requestsForTimeOff.length > 0; - - const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); - const timeCondition1 = - timeSpent >= 0.85 * weeklycommittedHours && timeSpent < weeklycommittedHours; - const timeCondition2 = - timeSpent >= 0.65 * weeklycommittedHours && timeSpent <= 0.849 * weeklycommittedHours; - const bluesquareEmailCondition = - hasTimeOffRequest === false && !(timeCondition1 || timeCondition2); - - const todayBlueSquare = users[i].infringements.filter( - (infringement) => infringement.date === todayDate, - ); - - if ( - bluesquareEmailCondition && - users[i].infringements.length === 1 && - todayBlueSquare.length === 1 && - numMonths < 1 - ) { - console.log('Entered <1MON_ONE_BLUESQUARE part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('<1MON_ONE_BLUESQUARE', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } else if ( - bluesquareEmailCondition && - users[i].infringements.length === 2 && - todayBlueSquare.length === 1 - ) { - if (numMonths < 1) { - console.log('Entered <1MON_TWO_BLUESQUARE part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('<1MON_TWO_BLUESQUARE', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } else if (numMonths < 2) { - console.log('Entered <2MON_TWO_BLUESQUARE part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('<2MON_TWO_BLUESQUARE', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } - } else if ( - bluesquareEmailCondition && - users[i].infringements.length === 3 && - todayBlueSquare.length === 1 && - numMonths < 2 - ) { - console.log('Entered <2MON_THREE_BLUESQUARE part'); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody('<2MON_THREE_BLUESQUARE', user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } else if ( - bluesquareEmailCondition && - users[i].infringements.length === 4 && - todayBlueSquare.length === 1 - ) { - const hasTimeOff = requestsForTimeOff.length > 0; - const templateKey = hasTimeOff - ? 'SCHEDULED_TIME_OFF_AND_4TH_BLUE_SQUARE' - : '4TH_BLUE_SQUARE'; - console.log(`Entered ${templateKey} part`); - await emailSender( - emailConfig.emailOverride || user.email, - `Re: New Infringement Assigned - Week of ${moment(pdtStartOfLastWeek).format('MM/DD/YYYY')}`, - WeeklyReminderEmailBody(templateKey, user.firstName), - null, - emailConfig.ccOverride || [ - 'jae@onecommunityglobal.org', - 'onecommunityglobal@gmail.com', - ], - 'jae@onecommunityglobal.org', - emailConfig.bccOverride || [...new Set([...emailsBCCs])], - { - type: 'blue_square_assignment', - recipientUserId: String(user._id), - weekStart: moment(pdtStartOfLastWeek).format('YYYY-MM-DD'), - }, - ); - } - } } } catch (error) { console.error('Error in weeklyBlueSquareReminderFunction:', error); } }; + /** + * Pure helper — picks the right template key for weeklyBlueSquareReminderFunction, + * or returns null if no email should be sent. + * Extracted to reduce cognitive complexity of the parent function. + */ + const resolveReminderTemplate = ( + timeSpent, + weeklycommittedHours, + numMonths, + infringementCount, + hasTodayBlueSquare, + hasTimeOff, + ) => { + const pct = timeSpent / weeklycommittedHours; + const nearMiss = pct >= 0.85 && pct < 1; + const mediumMiss = pct >= 0.65 && pct <= 0.849; + + if (!hasTodayBlueSquare) return null; + + // 4th blue square: send regardless of time-off status, but vary the template + if (infringementCount === 4) { + if (nearMiss || mediumMiss) return null; + return hasTimeOff ? 'SCHEDULED_TIME_OFF_AND_4TH_BLUE_SQUARE' : '4TH_BLUE_SQUARE'; + } + + // All other cases: skip if time-off or near/medium miss + if (hasTimeOff || nearMiss || mediumMiss) return null; + + if (infringementCount === 1 && numMonths < 1) return '<1MON_ONE_BLUESQUARE'; + if (infringementCount === 2 && numMonths < 1) return '<1MON_TWO_BLUESQUARE'; + if (infringementCount === 2 && numMonths < 2) return '<2MON_TWO_BLUESQUARE'; + if (infringementCount === 3 && numMonths < 2) return '<2MON_THREE_BLUESQUARE'; + return null; + }; + const reActivateUser = async () => { const currentFormattedDate = moment().tz('America/Los_Angeles').format();