Пример #1
0
        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);
            }
        }
Пример #2
0
        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());
        }
Пример #5
0
        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);
            }
        }
Пример #7
0
        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()));
        }
Пример #10
0
        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);
            }
        }