Skip to content

Add withdrawn job candidates automation logic #419

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,5 +214,17 @@ module.exports = {
FIX_DELAY_STEP_ASSIGN_MEMBER: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_ASSIGN_MEMBER || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500),
// the fix delay after step of activate challenge, unit: ms
FIX_DELAY_STEP_ACTIVATE_CHALLENGE: parseInt(process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP_ACTIVATE_CHALLENGE || process.env.PAYMENT_PROCESSING_FIX_DELAY_STEP || 500)
},
// if a job reach this critier, system will automatically withdrawn other job applications.
JOBS_HOUR_PER_WEEK: 20,
// the mapping includes the status transformation when auto-withdrawn feature is performed on job candidates.
WITHDRAWN_STATUS_CHANGE_MAPPING: {
applied: 'withdrawn-prescreen',
'skills-test': 'withdrawn-prescreen',
'phone-screen': 'withdrawn-prescreen',
open: 'withdrawn',
interview: 'withdrawn',
selected: 'withdrawn',
offered: 'withdrawn'
}
}
89 changes: 88 additions & 1 deletion src/eventHandlers/JobCandidateEventHandler.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/*
* Handle events for JobCandidate.
*/

const { Op } = require('sequelize')
const _ = require('lodash')
const config = require('config')
const models = require('../models')
const logger = require('../common/logger')
const helper = require('../common/helper')
const JobService = require('../services/JobService')
const JobCandidateService = require('../services/JobCandidateService')

/**
* Once we create at least one JobCandidate for a Job, the Job status should be changed to in-review.
Expand Down Expand Up @@ -44,6 +47,84 @@ async function inReviewJob (payload) {
}
}

/**
* Actual Update Job Candidates
*
* @param {*} statuses the source status we'll update
* @param {*} userId the userID
*/
async function updateJobCandidates (statuses, userId) {
logger.info({
component: 'JobCandidateEventHandler',
context: 'updateJobCandidates',
message: `Update jobCandidates for user ${userId}`
})
const filter = { [Op.and]: [] }
filter[Op.and].push({ status: statuses })
filter[Op.and].push({ userId: userId })
const candidates = await models.JobCandidate.findAll({
where: filter
})
if (candidates && candidates.length > 0) {
_.each(candidates, async (candidate) => {
logger.info({
component: 'JobCandidateEventHandler',
context: 'updateJobCandidates',
message: `Begin update id: ${candidate.id}' candidate with ${candidate.status} status into ${config.WITHDRAWN_STATUS_CHANGE_MAPPING[candidate.status]} for userId: ${userId}`
})
await JobCandidateService.partiallyUpdateJobCandidate(
helper.getAuditM2Muser(),
candidate.id,
{ status: config.WITHDRAWN_STATUS_CHANGE_MAPPING[candidate.status] }
).then(result => {
logger.info({
component: 'JobCandidateEventHandler',
context: 'updateJobCandidates',
message: `Finish update id: ${result.id}' candidate into ${result.status} status for userId: ${userId}`
})
})
})
} else {
logger.info({
component: 'JobCandidateEventHandler',
context: 'updateJobCandidates',
message: `There are not jobCandidates for user ${userId} that required to be updated.`
})
}
}

/**
* Update Job Candidates based on business rules
*
* @param {*} payload the updated jobCandidate info
*/
async function withDrawnJobCandidates (payload) {
const jobCandidate = payload.value
if (jobCandidate.status === 'placed') {
const job = await models.Job.findById(payload.value.jobId)
if (job.hoursPerWeek > config.JOBS_HOUR_PER_WEEK) {
// find all these user's open job Candidate and mark the status as withdrawn or withdrawn-prescreen
logger.info({
component: 'JobCandidateEventHandler',
context: 'withDrawnJobCandidates',
message: `Begin update jobCandidates as ${payload.value.id} candidate's new gig is requiring more than 20 hrs per week`
})
await updateJobCandidates(['applied', 'skills-test', 'phone-screen', 'open', 'interview', 'selected', 'offered'], payload.value.userId)
logger.info({
component: 'JobCandidateEventHandler',
context: 'withDrawnJobCandidates',
message: `Finish update jobCandidates as ${payload.value.id} candidate`
})
} else {
logger.debug({
component: 'JobCandidateEventHandler',
context: 'withDrawnJobCandidates',
message: `id: ${payload.value.id} candidate is not placing on a gig requiring 20 hrs per week`
})
}
}
}

/**
* Process job candidate create event.
*
Expand All @@ -52,6 +133,9 @@ async function inReviewJob (payload) {
*/
async function processCreate (payload) {
await inReviewJob(payload)
if (payload.value.status === 'placed') {
await withDrawnJobCandidates(payload)
}
}

/**
Expand All @@ -62,6 +146,9 @@ async function processCreate (payload) {
*/
async function processUpdate (payload) {
await inReviewJob(payload)
if (payload.value.status === 'placed' && payload.options.oldValue.status !== 'placed') {
await withDrawnJobCandidates(payload)
}
}

module.exports = {
Expand Down
3 changes: 2 additions & 1 deletion src/services/JobCandidateService.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ createJobCandidate.schema = Joi.object().keys({
*/
async function updateJobCandidate (currentUser, id, data) {
const jobCandidate = await JobCandidate.findById(id)
const oldValue = jobCandidate.toJSON()
const userId = await helper.getUserId(currentUser.userId)

// check user permission
Expand All @@ -155,7 +156,7 @@ async function updateJobCandidate (currentUser, id, data) {
data.updatedBy = userId

const updated = await jobCandidate.update(data)
await helper.postEvent(config.TAAS_JOB_CANDIDATE_UPDATE_TOPIC, updated.toJSON())
await helper.postEvent(config.TAAS_JOB_CANDIDATE_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue })
const result = _.assign(jobCandidate.dataValues, data)
return result
}
Expand Down