///<summary>Calculates the info for the dashboard</summary> private void RefreshAll() { //Validation if (_jobSprintCur.DateStart > _jobSprintCur.DateEndTarget) { return; } this.Text = _jobSprintCur.Title; #region Variables DateTime dateStart = _jobSprintCur.DateStart; DateTime dateProgress = DateTime.Today.Date; DateTime dateEnd = _jobSprintCur.DateEndTarget; //Distill the _listJobsAll into two job subsets List <Job> listJobsNonBugEnhancement = _listJobsAll.FindAll(x => x.Category.In(JobCategory.Feature, JobCategory.InternalRequest, JobCategory.HqRequest, JobCategory.ProgramBridge)); List <Job> listJobsBugEnhancement = _listJobsAll.FindAll(x => x.Category.In(JobCategory.Bug, JobCategory.Enhancement)); //Make the actual lists we will be using List <Job> listJobsCompletedNonBugEnhancement = listJobsNonBugEnhancement.FindAll(x => x.PhaseCur.In(JobPhase.Documentation, JobPhase.Complete) && DateTimeOD.Between(x.ListJobLogs.FirstOrDefault(y => y.Description.Contains("Job implemented"))?.DateTimeEntry ?? DateTime.MinValue, dateStart, dateEnd)); List <Job> listCompletedNonBugJobsThreeMonths = _listJobsAll.FindAll(x => x.PhaseCur.In(JobPhase.Documentation, JobPhase.Complete) && x.Category.In(JobCategory.Feature, JobCategory.InternalRequest, JobCategory.HqRequest, JobCategory.ProgramBridge, JobCategory.Enhancement) && DateTimeOD.Between(x.ListJobLogs.FirstOrDefault(y => y.Description.Contains("Job implemented"))?.DateTimeEntry ?? DateTime.MinValue, DateTime.Today.AddMonths(-3), DateTime.Today)); List <Job> listRemainingNonBugJobs = listJobsNonBugEnhancement.FindAll(x => x.PhaseCur.In(JobPhase.Concept, JobPhase.Definition, JobPhase.Quote, JobPhase.Development) && x.ProposedVersion == JobProposedVersion.Current); List <Job> listCompletedBackportJobs = listJobsBugEnhancement.FindAll(x => x.PhaseCur.In(JobPhase.Documentation, JobPhase.Complete) && x.ListJobLinks.Count(y => y.LinkType == JobLinkType.Bug) > 0 && DateTimeOD.Between(x.ListJobLogs.FirstOrDefault(y => y.Description.Contains("Job implemented"))?.DateTimeEntry ?? DateTime.MinValue, dateStart, dateEnd)); List <Job> listRemainingBugJobs = listJobsBugEnhancement.FindAll(x => x.Category == JobCategory.Bug && x.PhaseCur.In(JobPhase.Concept, JobPhase.Definition, JobPhase.Quote, JobPhase.Development) && x.ListJobLinks.Count(y => y.LinkType == JobLinkType.Bug) > 0); List <Job> listRemainingEnhancementJobs = listJobsBugEnhancement.FindAll(x => x.Category == JobCategory.Enhancement && x.PhaseCur.In(JobPhase.Concept, JobPhase.Definition, JobPhase.Quote, JobPhase.Development) && x.ProposedVersion == JobProposedVersion.Current); double totalDays = (dateEnd - dateStart).TotalDays; double totalDaysElapsed = (dateProgress - dateStart).TotalDays; double totalDaysLeft = totalDays - totalDaysElapsed; double jobPercent = _jobSprintCur.JobPercent; double hoursComplete = listJobsCompletedNonBugEnhancement.Sum(x => x.HoursActual) + listRemainingNonBugJobs.Sum(x => x.HoursActual); double hoursTotal = listJobsCompletedNonBugEnhancement.Sum(x => x.HoursActual) + listRemainingNonBugJobs.Sum(x => x.HoursEstimate); double hoursRemaining = hoursTotal - hoursComplete > 0?hoursTotal - hoursComplete:0; #endregion RefreshTopPanel(listJobsNonBugEnhancement, dateStart, dateEnd); #region Left Upper Panel //Set all completed job percentages List <double> listCompletedPercents = new List <double>(); //Cast one to a double so the int doesn't truncate to 0. double percent = (double)(listJobsCompletedNonBugEnhancement.Where(x => x.Category == JobCategory.Feature).Count()) / listJobsCompletedNonBugEnhancement.Count() * 100; listCompletedPercents.Add(Math.Round(percent, 2)); textCompletedFeaturesForRange.Text = percent.ToString("0.00") + "%"; percent = (double)(listJobsCompletedNonBugEnhancement.Where(x => x.Category == JobCategory.HqRequest).Count()) / listJobsCompletedNonBugEnhancement.Count() * 100; listCompletedPercents.Add(Math.Round(percent, 2)); textCompletedHQRequestsForRange.Text = percent.ToString("0.00") + "%"; percent = (double)(listJobsCompletedNonBugEnhancement.Where(x => x.Category == JobCategory.InternalRequest).Count()) / listJobsCompletedNonBugEnhancement.Count() * 100; listCompletedPercents.Add(Math.Round(percent, 2)); textCompletedInternalRequestsForRange.Text = percent.ToString("0.00") + "%"; percent = (double)(listJobsCompletedNonBugEnhancement.Where(x => x.Category == JobCategory.ProgramBridge).Count()) / listJobsCompletedNonBugEnhancement.Count() * 100; listCompletedPercents.Add(Math.Round(percent, 2)); textCompletedBridgesForRange.Text = percent.ToString("0.00") + "%"; DrawCompletedPieChart(listCompletedPercents); textJobsComplete.Text = listJobsCompletedNonBugEnhancement.Count().ToString(); #endregion #region Right Upper Panel //Set all remaining job percentages List <double> listRemainingPercents = new List <double>(); percent = (double)(listRemainingNonBugJobs.Where(x => x.Category == JobCategory.Feature).Count()) / listRemainingNonBugJobs.Count() * 100; listRemainingPercents.Add(Math.Round(percent, 2)); textRemainingFeaturePercent.Text = percent.ToString("0.00") + "%"; percent = (double)(listRemainingNonBugJobs.Where(x => x.Category == JobCategory.HqRequest).Count()) / listRemainingNonBugJobs.Count() * 100; listRemainingPercents.Add(Math.Round(percent, 2)); textRemainingHQRequestPercent.Text = percent.ToString("0.00") + "%"; percent = (double)(listRemainingNonBugJobs.Where(x => x.Category == JobCategory.InternalRequest).Count()) / listRemainingNonBugJobs.Count() * 100; listRemainingPercents.Add(Math.Round(percent, 2)); textRemainingInternalRequestPercent.Text = percent.ToString("0.00") + "%"; percent = (double)(listRemainingNonBugJobs.Where(x => x.Category == JobCategory.ProgramBridge).Count()) / listRemainingNonBugJobs.Count() * 100; listRemainingPercents.Add(Math.Round(percent, 2)); textRemainingBridgePercent.Text = percent.ToString("0.00") + "%"; DrawRemainingPieChart(listRemainingPercents); textJobsRemaining.Text = listRemainingNonBugJobs.Count().ToString(); #endregion #region Left Lower Panel //Set all completed backport percentages List <double> listCompletedBackportPercents = new List <double>(); percent = (double)(listCompletedBackportJobs.FindAll(x => x.Category == JobCategory.Bug).Count()) / listCompletedBackportJobs.Count() * 100; listCompletedBackportPercents.Add(Math.Round(percent, 2)); textCompletedBugPercentage.Text = percent.ToString("0.00") + "%"; percent = (double)(listCompletedBackportJobs.FindAll(x => x.Category == JobCategory.Enhancement).Count()) / listCompletedBackportJobs.Count() * 100; listCompletedBackportPercents.Add(Math.Round(percent, 2)); textCompletedEnhancementPercentage.Text = percent.ToString("0.00") + "%"; DrawCompletedBackportPieChart(listCompletedBackportPercents); textCompletedBackports.Text = listCompletedBackportJobs.Count().ToString(); #endregion #region Right Lower Panel //Set all remaining backport percentages List <double> listRemainingBackportPercents = new List <double>(); int countBugEnhancement = listRemainingBugJobs.Count() + listRemainingEnhancementJobs.Count(); percent = (double)(listRemainingBugJobs.Count()) / countBugEnhancement * 100; listRemainingBackportPercents.Add(Math.Round(percent, 2)); textRemainingBugPercentage.Text = percent.ToString("0.00") + "%"; percent = (double)(listRemainingEnhancementJobs.Count()) / countBugEnhancement * 100; listRemainingBackportPercents.Add(Math.Round(percent, 2)); textRemainingEnhancementPercentage.Text = percent.ToString("0.00") + "%"; DrawRemainingBackportPieChart(listRemainingBackportPercents); textRemainingBackports.Text = countBugEnhancement.ToString(); #endregion #region Bottom Panel List <Job> listStaleBugs = listRemainingBugJobs.FindAll(x => x.ListJobTimeLogs.Count > 0 ? x.ListJobTimeLogs.Select(y => y.DateTStamp).Max() < DateTime.Today.AddDays(-7) : x.DateTimeEntry < DateTime.Today.AddDays(-7)) .OrderBy(x => x.ListJobTimeLogs.Count > 0 ? x.ListJobTimeLogs.Select(y => y.DateTStamp).Max() : x.DateTimeEntry).ToList(); List <Job> listStaleEnhancements = listRemainingEnhancementJobs.FindAll(x => x.ListJobTimeLogs.Count > 0 ? x.ListJobTimeLogs.Select(y => y.DateTStamp).Max() < DateTime.Today.AddDays(-7) : x.DateTimeEntry < DateTime.Today.AddDays(-7)) .OrderBy(x => x.ListJobTimeLogs.Count > 0 ? x.ListJobTimeLogs.Select(y => y.DateTStamp).Max() : x.DateTimeEntry).ToList(); gridBugJobs.Title = listRemainingBugJobs.Count() + " Bugs (" + listStaleBugs.Count() + " Stale)"; gridEnhancementJobs.Title = listRemainingEnhancementJobs.Count() + " Enhancements (" + listStaleEnhancements.Count() + " Stale)"; FillGridOldBugs(listStaleBugs); FillGridOldEnhancements(listStaleEnhancements); #endregion }
///<summary>Calculates the info for the dashboard</summary> private void RefreshAll() { //Validation if(_jobSprintCur.DateStart>_jobSprintCur.DateEndTarget) { return; } #region Variables _listJobSprintLinks=JobSprintLinks.GetForSprint(_jobSprintCur.JobSprintNum); _listAttachedJobs=_listJobsAll.FindAll(x => _listJobSprintLinks.Select(y => y.JobNum).Contains(x.JobNum) && x.Category.In(JobCategory.Feature,JobCategory.Enhancement,JobCategory.InternalRequest,JobCategory.HqRequest,JobCategory.ProgramBridge)); List<Job> listBugJobs=_listJobsAll.FindAll(x => x.Category==JobCategory.Bug); DateTime dateStart=_jobSprintCur.DateStart; DateTime dateProgress=DateTime.Today.Date; DateTime dateEnd=_jobSprintCur.DateEndTarget; List<Job> listCompletedBugJobs=listBugJobs.FindAll(x => x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete) && x.ListJobLinks.Count(y => y.LinkType==JobLinkType.Bug)>0 && DateTimeOD.Between(x.ListJobLogs.FirstOrDefault(y => y.Description.Contains("Job implemented"))?.DateTimeEntry??DateTime.MinValue,dateStart,dateEnd)); List<Job> listRemainingBugJobs=listBugJobs.FindAll(x => x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development) && x.ListJobLinks.Count(y => y.LinkType==JobLinkType.Bug)>0); double totalDays=(dateEnd - dateStart).TotalDays; double totalDaysElapsed=(dateProgress - dateStart).TotalDays; double totalDaysLeft=totalDays-totalDaysElapsed; int targetValuePercent=(int)(totalDaysElapsed/totalDays*100); double jobPercent=_jobSprintCur.JobPercent; double avgDevHours=_jobSprintCur.HoursAverageDevelopment; double avgBreakHours=_jobSprintCur.HoursAverageBreak; double totalAllocatedHours=0; double totalCompletedHours=0; double hoursComplete=_listAttachedJobs.Sum(x => x.HoursActual); double hoursTotal=_listAttachedJobs.Sum(x => x.HoursEstimate); double hoursRemaining=hoursTotal-hoursComplete>0?hoursTotal-hoursComplete:0; double totalJobsRemaining=_listAttachedJobs.Where(x => x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development)).Count()+listRemainingBugJobs.Count; double totalJobsCompleted=_listAttachedJobs.Where(x => x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete)).Count()+listCompletedBugJobs.Count(); #endregion #region Top Panel this.Text=_jobSprintCur.Title; textStartDate.Text=_jobSprintCur.DateStart.ToShortDateString(); textEndDate.Text=_jobSprintCur.DateEndTarget.ToShortDateString(); //Calculate hours for the list of jobs attached to the sprint foreach(Job job in _listAttachedJobs) { //Do not include "completed" jobs if(job.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete,JobPhase.Cancelled)) { continue; } double estimate=job.HoursEstimate; if(job.HoursEstimateDevelopment==0) { estimate+=avgDevHours; } totalAllocatedHours+=estimate; totalAllocatedHours-=job.HoursActual; totalCompletedHours+=job.HoursActual; } //Calculate and Set Work Complete Percent double completionPercentage=0; completionPercentage=(totalCompletedHours/totalAllocatedHours)*100; if(Double.IsNaN(completionPercentage)) { completionPercentage=0; } completionPercentage=completionPercentage>=100?100:completionPercentage; //Set Progress Bar Value and TargetValue textCompletePercentage.Text=(int)completionPercentage+"%"; progressComplete.Value=(int)completionPercentage; progressComplete.TargetValue=(int)completionPercentage; textElapsedPercentage.Text=targetValuePercent+"%"; progressElapsed.Value=targetValuePercent; progressElapsed.TargetValue=targetValuePercent; //Set Days Left textDaysLeft.Text=totalDaysLeft+" Days Left"; //textScopeChange.Text=(_listAttachedJobs.Where(x => x.ListJobLogs.Exists(y => y.Description.Contains("Changes approved."))).Count()/_listAttachedJobs.Count*100)+"%"; #endregion #region Left Panel //Set all completed job percentages List<double> listCompletedPercents=new List<double>(); listCompletedPercents.Add(Math.Round((listCompletedBugJobs.Count()/totalJobsCompleted*100),2)); textCompletedBugsForRange.Text=listCompletedPercents.Last().ToString("0.00")+"%"; listCompletedPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.Feature && x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete)).Count()/totalJobsCompleted*100),2)); textCompletedFeaturesForRange.Text=listCompletedPercents.Last().ToString("0.00")+"%"; listCompletedPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.Enhancement && x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete)).Count()/totalJobsCompleted*100),2)); textCompletedEnhancementsForRange.Text=listCompletedPercents.Last().ToString("0.00")+"%"; listCompletedPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.InternalRequest && x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete)).Count()/totalJobsCompleted*100),2)); textCompletedInternalRequestsForRange.Text=listCompletedPercents.Last().ToString("0.00")+"%"; listCompletedPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.HqRequest && x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete)).Count()/totalJobsCompleted*100),2)); textCompletedHQRequestsForRange.Text=listCompletedPercents.Last().ToString("0.00")+"%"; listCompletedPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.ProgramBridge && x.PhaseCur.In(JobPhase.Documentation,JobPhase.Complete)).Count()/totalJobsCompleted*100),2)); textCompletedBridgesForRange.Text=listCompletedPercents.Last().ToString("0.00")+"%"; DrawCompletedPieChart(listCompletedPercents); textJobsComplete.Text=totalJobsCompleted.ToString(); #endregion #region Right Panel //Set all remaining job percentages List<double> listRemainingPercents=new List<double>(); listRemainingPercents.Add(Math.Round((listRemainingBugJobs.Count()/totalJobsRemaining*100),2)); textRemainingBugPercent.Text=listRemainingPercents.Last().ToString("0.00")+"%"; listRemainingPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.Feature && x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development)).Count()/totalJobsRemaining*100),2)); textRemainingFeaturePercent.Text=listRemainingPercents.Last().ToString("0.00")+"%"; listRemainingPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.Enhancement && x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development)).Count()/totalJobsRemaining*100),2)); textRemainingEnhancementPercent.Text=listRemainingPercents.Last().ToString("0.00")+"%"; listRemainingPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.InternalRequest && x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development)).Count()/totalJobsRemaining*100),2)); textRemainingInternalRequestPercent.Text=listRemainingPercents.Last().ToString("0.00")+"%"; listRemainingPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.HqRequest && x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development)).Count()/totalJobsRemaining*100),2)); textRemainingHQRequestPercent.Text=listRemainingPercents.Last().ToString("0.00")+"%"; listRemainingPercents.Add(Math.Round((_listAttachedJobs.Where(x => x.Category==JobCategory.ProgramBridge && x.PhaseCur.In(JobPhase.Concept,JobPhase.Definition,JobPhase.Quote,JobPhase.Development)).Count()/totalJobsRemaining*100),2)); textRemainingBridgePercent.Text=listRemainingPercents.Last().ToString("0.00")+"%"; DrawRemainingPieChart(listRemainingPercents); textJobsRemaining.Text=(totalJobsRemaining-listRemainingBugJobs.Count).ToString();//Don't count bugs here #endregion #region Bottom Panel List<Job> listStaleBugs=listRemainingBugJobs.FindAll(x => x.ListJobTimeLogs.Count>0?x.ListJobTimeLogs.Select(y => y.DateTStamp).Max()<DateTime.Today.AddDays(-5):x.DateTimeEntry<DateTime.Today.AddDays(-5)) .OrderBy(x => x.ListJobTimeLogs.Count>0?x.ListJobTimeLogs.Select(y => y.DateTStamp).Max():x.DateTimeEntry).ToList(); gridBugJobs.Title=listRemainingBugJobs.Count()+" Bugs ("+listStaleBugs.Count()+" Stale)"; FillGridOldBugs(listStaleBugs); #endregion }
private void RefreshTopPanel(List <Job> listJobs, DateTime dateStart, DateTime dateEnd) { //Calculate the three month average per day //listJobsNonBugEnhancement is used because we do not want to consider bugs/enhancements (Backport jobs) as part of this version List <Job> listCompletedJobs = listJobs.FindAll(x => x.PhaseCur.In(JobPhase.Documentation, JobPhase.Complete) && DateTimeOD.Between(x.ListJobLogs.FirstOrDefault(y => y.Description.Contains("Job implemented"))?.DateTimeEntry ?? DateTime.MinValue, dateStart, dateEnd)); //We only want incomplete jobs that are marked as current version. This disregards priority. List <Job> listRemainingJobs = listJobs.FindAll(x => x.PhaseCur.In(JobPhase.Concept, JobPhase.Definition, JobPhase.Quote, JobPhase.Development) && x.ProposedVersion == JobProposedVersion.Current); //Calculate the remaining hours for the version double totalRemainingHours = listRemainingJobs.Sum(x => x.HoursEstimate - x.HoursActual); totalRemainingHours = totalRemainingHours < 0 ? 0 : totalRemainingHours; //Completed hours is only the hours actual. Should not be negative, but I check for it just in case. double totalCompletedHours = listCompletedJobs.Sum(x => x.HoursActual); totalCompletedHours = totalCompletedHours < 0 ? 0 : totalCompletedHours; //Calculate the total hours value for the version. //We use the estimate from the remaining jobs since that is the perceived total amount of time it will take. //We use the hours actual from complete jobs because we know the job is done and will take no more time than what was taken. double totalVersionHours = totalCompletedHours + listRemainingJobs.Sum(x => x.HoursEstimate); totalVersionHours = totalVersionHours < 0 ? 0 : totalVersionHours; //Calculate work complete percent double completionPercentage = ((totalCompletedHours + listRemainingJobs.Sum(x => x.HoursActual)) / totalVersionHours) * 100; //Validate that the return is a valid percentage if (Double.IsNaN(completionPercentage)) { completionPercentage = 0; } completionPercentage = completionPercentage >= 100 ? 100 : completionPercentage; //Calculate day variables double totalDays = (dateEnd - dateStart).TotalDays; double totalDaysElapsed = (DateTime.Today.Date - dateStart).TotalDays; double totalDaysLeft = totalDays - totalDaysElapsed; //We don't need to display negative days left if (totalDaysLeft < 0) { totalDaysLeft = 0; } //Calculate target percent int targetValuePercent = (int)(totalDaysElapsed / totalDays * 100); if (targetValuePercent > 100) { targetValuePercent = 100; } if (targetValuePercent < 0) { targetValuePercent = 0; } //Calculate average hours/day of job time for the last 3 months double hoursLogged = listJobs.Sum(x => x.ListJobTimeLogs.Where(y => y.DateTStamp.Between(DateTime.Today.AddMonths(-3), DateTime.Today)).Sum(y => y.Hours)); //hoursReviewed is multiplied by 2 to denote that two engineers time was expended per review double hoursReviewed = listJobs.Sum(x => x.ListJobReviews.Where(y => y.DateTStamp.Between(DateTime.Today.AddMonths(-3), DateTime.Today)).Sum(y => y.Hours)) * 2; double hoursCompletePerDay = (hoursLogged + hoursReviewed) / (DateTime.Today - DateTime.Today.AddMonths(-3)).TotalDays; //Calculate days remaining double daysRemainingEstimate = Math.Round(totalRemainingHours / hoursCompletePerDay, 0); //If for some reason we just divided by 0... if (Double.IsNaN(daysRemainingEstimate)) { daysRemainingEstimate = 0; } //Set Panel's Controls //Dates textStartDate.Text = _jobSprintCur.DateStart.ToShortDateString(); textTargetDate.Text = _jobSprintCur.DateEndTarget.ToShortDateString() + " (" + totalDaysLeft + " days)"; textProjectedRelease.Text = DateTime.Today.AddDays(daysRemainingEstimate).ToShortDateString() + " (" + Math.Abs(daysRemainingEstimate) + " days)"; //Work Complete textCompletePercentage.Text = (int)completionPercentage + "%"; progressComplete.Value = (int)completionPercentage; progressComplete.TargetValue = (int)completionPercentage; //This could be changed to the target value percent if we want //Time elapsed textElapsedPercentage.Text = targetValuePercent + "%"; progressElapsed.Value = targetValuePercent; progressElapsed.TargetValue = targetValuePercent; }