public void Execute() { GreenHouseDataStore.Instance.Refresh(); Mapper.CreateMap <ApiJobApplication, JobApplication>() .ForMember(dst => dst.ReviewStatus, opt => opt.UseValue(ReviewStatus.New)) .ForMember(dst => dst.RecorededAt, opt => opt.UseValue(DateTime.UtcNow)) .ForMember(dst => dst.RemindCount, opt => opt.UseValue(0)) .ForMember(dst => dst.Source, opt => opt.MapFrom(src => src.Source.Name)) .ForMember(dst => dst.CandidateName, opt => opt.MapFrom(src => ResolveCandidateName(src))) .ForMember(dst => dst.JobId, opt => opt.MapFrom(src => ResolveJobId(src))) .ForMember(dst => dst.JobName, opt => opt.MapFrom(src => ResolveJobName(src))); var openningJobs = GreenHouseDataStore.Instance.Jobs.Where(m => !string.IsNullOrEmpty(m.Status) && m.Status == JobStates.Open).ToArray(); if (openningJobs == null || openningJobs.Length == 0) { _logger.InfoFormat("There is not openning job currently. GreenHouseDataStore has been updated at {0}.", GreenHouseDataStore.Instance.LastUpdateAt); return; } var applicantsService = new JobApplicationProvider(); lock (_applicantsSyncRoot) { var newAplicants = GreenHouseDataStore.Instance.Applicants .Where(ap => IsNewApplicant(ap, openningJobs) && applicantsService.Get(ap.Id) == null) .Select(Mapper.Map <ApiJobApplication, JobApplication>) .ToArray(); applicantsService.AddRange(newAplicants); } }
public void Execute() { var applicantsProvider = new JobApplicationProvider(); var reviewerProvider = new ReviewerProvider(); var configs = AppConfigsProvider.EscalationConfigs; Reviewer reviewer = null; var unhandledApplicants = applicantsProvider .GetList(a => a.ReviewStatus == Models.ReviewStatus.Assigned && a.RemindCount >= configs.RemindTheshold); if (unhandledApplicants.Count() == 0) { return; } foreach (var applicant in unhandledApplicants) { if (applicant.ReviewerId.HasValue) { reviewer = reviewerProvider.Get(applicant.ReviewerId.Value); } var email = new TimeOutApplicationEscalationEmail() { JobApplication = applicant, Reviewer = reviewer, EscalationTo = configs.ReportToEmails, }; BackgroundEmailService.Create().Send(email); _logger.InfoFormat("Reviewing for applicant {0} has been escalated as reviewer {1} did not finish his review after {2} of reminds", applicant.Id, reviewer.Id, applicant.RemindCount); } }
private void AssignToReviewer(Models.JobApplication applicant) { if (applicant == null || applicant.ReviewStatus != ReviewStatus.New) { return; } var applicantService = new JobApplicationProvider(); var positionTypeService = new JobPositionTypeProvider(); var reviewerService = new ReviewerProvider(); var ghDataStore = GreenHouseDataStore.Instance; var job = ghDataStore.GetJobById(applicant.JobId); if (job == null || job.Status != JobStates.Open) { applicant.ReviewStatus = ReviewStatus.JobClosed; applicantService.Update(applicant); _logger.InfoFormat("Applicant {0} is closed because it's job ({1}) is either deleted or not opened", applicant.Id, job?.Id); return; } if (applicant.Source == ApplicantSources.Referral && AppConfigsProvider.ReferralsHandlingConfigs.IsEnabled) { applicant.ReviewStatus = ReviewStatus.HandledAsReferral; applicantService.Update(applicant); SendEmailForReferral(applicant, job); _logger.InfoFormat("Applicant {0} of job {1} has been handled as a referral", applicant.Id, job.Id); return; } var positionTypeStr = job.GetCustomFieldValue(JobCustomFields.PositionType); var positionType = positionTypeService.GetList(p => p.Name == positionTypeStr).FirstOrDefault(); if (positionType == null) { _logger.WarnFormat("Position Type '{0}' is not available.", positionTypeStr); return; } var selectedReviewer = GetNextReviewer(positionType); if (selectedReviewer == null) { _logger.WarnFormat("Can not get any reviewers for the applicant {0}. It's either because there is no reviewers configured for this position type or all reviewers all not in working hours.", applicant.Id); return; } selectedReviewer.RecentAssignedAt = DateTime.UtcNow; selectedReviewer.AssignedCount++; applicant.ReviewerId = selectedReviewer.Id; applicant.ReviewStatus = ReviewStatus.Assigned; applicant.AssignedToReviewerAt = DateTime.UtcNow; applicantService.Update(applicant); reviewerService.Update(selectedReviewer); _logger.InfoFormat("Applicant {0} has been assigned to reviewer {1}", applicant.Id, selectedReviewer.Id); SendAssignmentEmail(selectedReviewer, applicant, job); }
public JobApplication[] GetTimeOutApplicants() { var applicantsProvider = new JobApplicationProvider(); var remindDelayTime = AppConfigsProvider.RemindReviewersConfigs.DelayTime; return(applicantsProvider.GetList(a => a.ReviewStatus == Models.ReviewStatus.Assigned) .Where(a => a.NeedToRemind(remindDelayTime)) .ToArray()); }
public ActionResult Index(string order) { var jobApplicantService = new JobApplicationProvider(); var reviewerResourceServuce = new ReviewerProvider(); var results = jobApplicantService.GetList().OrderByDescending(m => m.AppliedAt) .Select(applicant => new ApplicantViewModel() { Applicant = applicant, Reviewer = applicant.ReviewerId.HasValue ? reviewerResourceServuce.Get(applicant.ReviewerId.Value) : null }); return(View(results)); }
public void Execute() { var applicantsProvider = new JobApplicationProvider(); var commonConfigs = AppConfigsProvider.CommonConfigs; var remindConfigs = AppConfigsProvider.RemindReviewersConfigs; var reviewerProvider = new ReviewerProvider(); //var greenHouseApi = DiContainers.Global.Resolve<IWebApiClient>(); var applicants = GetTimeOutApplicants(); var ghStore = GreenHouseDataStore.Instance; if (applicants.Count() == 0) { return; } Reviewer reviewer = null; foreach (var applicant in applicants) { if (applicant.ReviewerId.HasValue) { reviewer = reviewerProvider.Get(applicant.ReviewerId.Value); } if (reviewer == null) { applicant.ReviewStatus = ReviewStatus.Error; applicantsProvider.Update(applicant); continue; } if (!reviewer.IsInWorkingHours(commonConfigs.StartTimeOfDay, commonConfigs.EndTimeOfDay, commonConfigs.EnabledDays)) { _logger.InfoFormat("Don't remind reviewer {0} ({1} because he's not in working hour", reviewer.Id, reviewer.Name); continue; } applicant.RemindCount++; applicant.RecentRemindAt = DateTime.UtcNow; applicantsProvider.Update(applicant); var email = new RemindReviewApplicationEmail() { JobApplication = applicant, Reviewer = reviewer, Job = ghStore.GetJobById(applicant.JobId) }; BackgroundEmailService.Create().Send(email); } }
public void Execute() { var applicantsProvider = new JobApplicationProvider(); var applicants2Update = applicantsProvider.GetList(a => a.ReviewStatus == ReviewStatus.Assigned || a.ReviewStatus == ReviewStatus.New); if (!applicants2Update.Any()) { return; } foreach (var applicant in applicants2Update) { ProcUpdate(applicant); } }
public void Execute() { if (!CanExecute()) { return; } var applicantService = new JobApplicationProvider(); JobApplication[] freshApplicants = applicantService.GetList(ap => ap.ReviewStatus == Models.ReviewStatus.New); foreach (var applicant in freshApplicants) { AssignToReviewer(applicant); } }
public ActionResult Index() { var reviewers = new ReviewerProvider(); var jobApplicants = new JobApplicationProvider(); var avgDurations = jobApplicants.GetList() .GroupBy(rvw => rvw.ReviewerId) .Select(g => new { g.Key, AvgDuration = g.Average( x => ((x.RejectedOrAcceptedAt ?? DateTime.UtcNow) - x.AssignedToReviewerAt).HasValue ? Math.Max( ((x.RejectedOrAcceptedAt ?? DateTime.UtcNow) - x.AssignedToReviewerAt).Value .TotalSeconds / 3600, 0) : 0) }); //var results = reviewers.GetList() // .Join(avgDurations, rvw => rvw.Id, ad => ad.Key, (rvw, ad) => new ReviewerViewModel { Reviewer = rvw, AvgTime = ad.AvgDuration }); var results = reviewers.GetList() .GroupJoin(avgDurations, rvw => rvw.Id, ad => ad.Key, (rvw, ms) => new { rvw, ms = ms.DefaultIfEmpty() }) .SelectMany( z => z.ms.Select(ad => new { rvw = z.rvw, ad })) .Select(x => new ReviewerViewModel() { Reviewer = x.rvw, AvgTime = x.ad == null? 0 : Math.Round(x.ad.AvgDuration, 2) }); return(View(results.ToList())); }
private void ProcUpdate(JobApplication applicant) { var applicantsProvider = new JobApplicationProvider(); var reviewerProvider = new ReviewerProvider(); var ghStore = GreenHouseDataStore.Instance; Reviewer reviewer = null; if (applicant == null || applicant.Id == 0) { return; } var apiJobApplication = ghStore.GetApplicationById(applicant.Id.ToString()); var appliedJob = ghStore.GetJobById(applicant.JobId); if (applicant.ReviewerId.HasValue) { reviewer = reviewerProvider.Get(applicant.ReviewerId.Value); } //applicant deleted if (apiJobApplication == null || apiJobApplication.Id == 0) { applicant.ReviewStatus = Models.ReviewStatus.Deleted; applicantsProvider.Update(applicant); _logger.WarnFormat("Applicant {0} has been deleted from Greenhosue", applicant.Id); return; } if (apiJobApplication.CurrentStage == null) { applicant.ReviewStatus = ReviewStatus.Error; applicantsProvider.Update(applicant); _logger.WarnFormat("Cant not resolve current stage for applicant {0}", applicant.Id); return; } //applicant accepted and moved to another stage if (apiJobApplication.CurrentStage.Name != ApplicationStages.ApplicationReviewCV) { applicant.ReviewStatus = ReviewStatus.Accepted; applicant.RejectedOrAcceptedAt = apiJobApplication.AcceptedAt; applicantsProvider.Update(applicant); if (reviewer != null) { reviewer.AdvanceCount++; reviewerProvider.Update(reviewer); } _logger.WarnFormat("Applicant {0} has been accepted and moved to next stage by reviewer {1}", applicant.Id, reviewer != null ? reviewer.Id : 0); } //applicant is still at CV / Review stage and was rejected if (apiJobApplication.CurrentStage.Name == ApplicationStages.ApplicationReviewCV && apiJobApplication.RejectedAt.HasValue) { applicant.ReviewStatus = ReviewStatus.Rejected; applicant.RejectAt = apiJobApplication.RejectedAt.Value; applicant.RejectedOrAcceptedAt = apiJobApplication.RejectedAt.Value; applicant.RejectionReason = apiJobApplication.RejectionReason; applicantsProvider.Update(applicant); if (reviewer != null) { reviewer.RejectCount++; reviewerProvider.Update(reviewer); } _logger.WarnFormat("Applicant {0} has been rejected by reviewer {1}", applicant.Id, reviewer?.Id ?? 0); } //Applied job was removed or closed if (appliedJob == null || appliedJob.Status != JobStates.Open) { applicant.ReviewStatus = ReviewStatus.JobClosed; applicantsProvider.Update(applicant); _logger.WarnFormat("Applicant {0} has been closed because its job {1} is either deleted or closed", applicant.Id, applicant.JobId); } }