using EnVisage.Models; using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using EnVisage.Code.BLL; using EnVisage.Models.Dashboard; namespace EnVisage.Code.ForecastDashboard { public class ForecastDashboardManager { private readonly EnVisageEntities DbContext; public ForecastDashboardManager(EnVisageEntities dbContext) { DbContext = dbContext; } /// /// Returns data for main dashboard table /// public IEnumerable GetScenarios(Guid userId, out int totalRecordCount, out int searchRecordCount, string searchString, ForecastDashboardFilterModel filter, int? startIndex = null, int? pageSize = null) { var startDate = (filter.StartDate ?? DateTime.Today).Date; var endDate = (filter.EndDate ?? DateTime.Today).Date; if (filter.AdditionalParams != null && filter.AdditionalParams.ContainsKey("mode")) { filter.Teams = new List(); filter.Views = new List(); if (filter.AdditionalParams["mode"] == "team" && filter.AdditionalParams.ContainsKey("teamId")) { Guid teamId; if (Guid.TryParse(filter.AdditionalParams["teamId"], out teamId)) filter.Teams.Add(teamId); } else if (filter.AdditionalParams["mode"] == "view" && filter.AdditionalParams.ContainsKey("viewId")) { Guid viewId; if (Guid.TryParse(filter.AdditionalParams["viewId"], out viewId)) filter.Views.Add(viewId); } else if (filter.AdditionalParams["mode"] == "company" && filter.AdditionalParams.ContainsKey("viewId")) { Guid companyId; if (Guid.TryParse(filter.AdditionalParams["viewId"], out companyId)) filter.Companies.Add(companyId); } } #region convert incoming params to teams var teamManager = new TeamManager(DbContext); var filteredTeams = teamManager.GetTeamsByUserFiltered(userId.ToString(), filter.Teams, filter.Views, filter.Companies); #endregion var projectManager = new ProjectManager(DbContext); var projects = projectManager.GetProjectsWithChildrenByTeams(filteredTeams.Select(t => t.TeamId), filter.Tags, includedItems: ProjectManager.LoadProjectItems.Goals).AsQueryable(); if (filter.ProjectTypes != null && filter.ProjectTypes.Count > 0) projects = projects.Where(i => filter.ProjectTypes.Contains(i.TypeId)); if (filter.ProjectStatuses != null && filter.ProjectStatuses.Count > 0) projects = projects.Where(i => filter.ProjectStatuses.Contains(i.StatusId)); if (filter.StrategicGoals != null && filter.StrategicGoals.Count > 0) projects = projects.Where(x => x.StrategicGoals != null && x.StrategicGoals.Any(s => filter.StrategicGoals.Contains(s))); if (filter.Clients != null && filter.Clients.Count > 0) projects = projects.Where(x => x.ClientId.HasValue && filter.Clients.Contains(x.ClientId.Value)); var query = new List(); var teams = filter.FilterGroupByTeam ? filteredTeams : new List() { new TeamWithPermissionsModel() { TeamId = Guid.Empty } }; var projectTypes = DbContext.Types.AsNoTracking().ToDictionary(x => x.Id); var projectList = projects.ToList(); var projectIds = projectList.Select(x => x.Id).ToArray(); var projectTeams = DbContext.Team2Project.AsNoTracking() .Where(x => projectIds.Contains(x.ProjectId)) .Select(x => new { x.ProjectId, x.Team }) .ToList(); var projectStrategicGoals = DbContext.StrategicGoal2Project.AsNoTracking() .Where(x => projectIds.Contains(x.ProjectId)) .Select(x => new { x.ProjectId, x.StrategicGoal }) .ToList(); var scenarios = DbContext.Scenarios.AsNoTracking() .Where(x => x.ParentId.HasValue && projectIds.Contains(x.ParentId.Value) && x.StartDate <= endDate && x.EndDate >= startDate && x.Type == (int)ScenarioType.Portfolio); if (filter.HasProjectNetImpact) scenarios = scenarios.Include(x => x.Project).Where(x => (x.Project != null) && x.Project.IsRevenueGenerating && (((x.ProjectedRevenue ?? 0) + (x.CostSavings ?? 0) - (x.BUDirectCosts ?? 0)) != 0)); if (filter.HasProjectedRevenue) scenarios = scenarios.Where(x => (x.Project != null) && x.Project.IsRevenueGenerating && (x.ProjectedRevenue ?? 0) != 0); if (filter.HasCostSavings) scenarios = scenarios.Where(x => (x.CostSavings ?? 0) != 0); if (filter.HasProjectCost) scenarios = scenarios.Where(x => (x.BUDirectCosts ?? 0) != 0 || (x.TDDirectCosts ?? 0) != 0); if (filter.FilterGroups != null && filter.FilterGroups.Any()) scenarios = scenarios.Where(x => x.Scenario2Group.Any(s => filter.FilterGroups.Contains(s.GroupId))); var scenarioList = scenarios.Include(x => x.Scenario2Group).ToList(); //var expCatIds = dashboardCharthManager.GetExpenditureCategories(true); var expCatIds = from e in DbContext.ExpenditureCategory where e.Type == (int)ExpenditureCategoryModel.CategoryTypes.Labor select e.Id; foreach (var team in teams) { var projectsByTeamIds = (filter.FilterGroupByTeam ? projectTeams.Where(x => x.Team.Id == team.TeamId) : projectTeams).Select(x => x.ProjectId).Distinct().ToArray(); var projectsByTeam = projectList.FindAll(x => projectsByTeamIds.Contains(x.Id)); var projectsScenarios = scenarioList.FindAll(x => x.ParentId.HasValue && projectsByTeamIds.Contains(x.ParentId.Value)); var scGroups = projectsScenarios.SelectMany(x => x.Scenario2Group).ToArray(); foreach (var project in projectsByTeam) { var activescenario = projectsScenarios.FirstOrDefault(x => x.ParentId == project.Id && x.Status == (int)ScenarioStatus.Active); if (activescenario == null) continue; var scenDetailsParentIds = DbContext.ScenarioDetail.AsNoTracking() .Where(q => q.ParentID == activescenario.Id && expCatIds.Contains(q.ExpenditureCategoryId.Value)) .Select(q => q.ParentID).ToList(); if (!scenDetailsParentIds.Contains(activescenario.Id)) continue; var currentProjectType = projectTypes.ContainsKey(project.TypeId) ? projectTypes[project.TypeId] : null; var modelItem = CreateModelItem(team, projectsScenarios, scGroups, project, activescenario, currentProjectType); if (!filter.FilterGroupByTeam) { var projTeams = projectTeams.Where(x => x.ProjectId == project.Id).ToArray(); if (projTeams != null && projTeams.Any()) modelItem.TeamName = string.Join(", ", projTeams.Select(x => x.Team.Name)); } var strategicGoals = projectStrategicGoals.Where(x => x.ProjectId == project.Id).ToArray(); if (strategicGoals.Any()) modelItem.StrategicGoals = string.Join(", ", strategicGoals.Select(x => x.StrategicGoal.Name)); if (project.PerformanceYellowThreshold.HasValue) modelItem.PerformanceThresholdYellow = project.PerformanceYellowThreshold; else if (currentProjectType?.PerformanceYellowThreshold != null) modelItem.PerformanceThresholdYellow = currentProjectType.PerformanceYellowThreshold; if (project.PerformanceRedThreshold.HasValue) modelItem.PerformanceThresholdRed = project.PerformanceRedThreshold; else if (currentProjectType?.PerformanceRedThreshold != null) modelItem.PerformanceThresholdRed = currentProjectType.PerformanceRedThreshold; // SA. ENV-607. End query.Add(modelItem); } } totalRecordCount = query.Count; searchRecordCount = query.Count; // SA. ENV-607. Performance Indication. Begin //List rowsToDisplay = query.Skip((startIndex -1) * pageSize).Take(pageSize).ToList(); List rowsToDisplay = query.ToList(); var scenarioIds = rowsToDisplay.Select(x => x.Id); Dictionary performanceData = DbContext.VW_ScenarioPerformance.Where(x => scenarioIds.Contains(x.ForecastScenarioId)) .AsNoTracking().ToDictionary(x => x.ForecastScenarioId); foreach (ForecastDashboardModel scenarioRow in rowsToDisplay) { if (performanceData.ContainsKey(scenarioRow.Id) && scenarioRow.PerformanceThresholdYellow.HasValue && scenarioRow.PerformanceThresholdRed.HasValue) { decimal? variationPercent = performanceData[scenarioRow.Id].VariationPercent; if (variationPercent.HasValue) { if (variationPercent >= scenarioRow.PerformanceThresholdRed.Value) scenarioRow.PerformanceColor = "perf-red"; else if ((variationPercent < scenarioRow.PerformanceThresholdRed.Value) && (variationPercent >= scenarioRow.PerformanceThresholdYellow.Value)) scenarioRow.PerformanceColor = "perf-yellow"; //if ((variationPercent < scenarioRow.PerformanceThresholdYellow.Value) && // (variationPercent >= scenarioRow.PerformanceThresholdGreen.Value)) else scenarioRow.PerformanceColor = "perf-green"; } } } // SA. ENV-607. End; return rowsToDisplay; } //private IQueryable QueryProjects(Guid userId, IEnumerable filteredTeamsIds) //{ // var projects = // (from proj in DbContext.Projects.AsNoTracking() // join sc in DbContext.VW_ProjectAccessByUserExtended on proj.Id equals sc.Id // where sc.UserId.Equals(userId) && !proj.HasChildren && proj.Team2Project.Any(p => filteredTeamsIds.Contains(p.TeamId)) // select proj).Distinct(); // return projects; //} private static ForecastDashboardModel CreateModelItem(TeamWithPermissionsModel team, List projectsScenarios, Scenario2Group[] scGroups, ProjectWithChildrenView project, Scenario activescenario, Type currentProjectType) { var useLMMargin = (activescenario.UseLMMargin ?? 0) > 0; var costSavings = activescenario.CostSavings ?? 0; var buDirectCosts = activescenario.BUDirectCosts ?? 0; var projectedRevenue = activescenario.ProjectedRevenue ?? 0; var modelItem = new ForecastDashboardModel() { Id = activescenario.Id, ProjectId = project.ParentProject?.Id ?? project.Id, // fill part only if project has parent project, otherwise it may be null PartId = project.ParentProject != null ? project.Id : (Guid?)null, ProjectName = project.Name + (project.ParentProject != null ? ": " + project.ParentProject.Name : ""), TeamName = team.Name, TeamId = team.TeamId.ToString(), ClientId = project.ClientId, ClientName = project.ClientName, CompanyId = project.CompanyId, CompanyName = project.CompanyName, Name = activescenario.Name, Type = (ScenarioType?)activescenario.Type, Duration = activescenario.Duration, ProjectedRevenue = activescenario.ProjectedRevenue, ExpectedGrossMargin = activescenario.ExpectedGrossMargin ?? 0, ExpectedGrossMargin_LM = activescenario.ExpectedGrossMargin_LM ?? 0, CalculatedGrossMargin = activescenario.CalculatedGrossMargin, CalculatedGrossMargin_LM = activescenario.CalculatedGrossMargin_LM, CalculatedMargin = useLMMargin ? activescenario.CalculatedGrossMargin_LM : activescenario.CalculatedGrossMargin, UseLMMargin = activescenario.UseLMMargin, CGSplit = activescenario.CGSplit, EFXSplit = activescenario.EFXSplit, StartDate = activescenario.StartDate, EndDate = activescenario.EndDate, ProjectType = currentProjectType == null ? string.Empty : currentProjectType.Name, Priority = project.Priority, Probability = project.Probability, TDDirectCosts = activescenario.TDDirectCosts, TDDirectCosts_LM = activescenario.TDDirectCosts_LM, BUDirectCosts = activescenario.BUDirectCosts, BUDirectCosts_LM = activescenario.BUDirectCosts_LM, ProjectNetImpact = projectedRevenue + costSavings - buDirectCosts, ScenarioStatus = (ScenarioStatus?)activescenario.Status, Color = activescenario.Color, CostSavings = activescenario.CostSavings, CostSavingsDuration = (activescenario.CostSavingsEndDate.HasValue && activescenario.CostSavingsStartDate.HasValue) ? (activescenario.CostSavingsEndDate.Value.Month - activescenario.CostSavingsStartDate.Value.Month) + 12 * (activescenario.CostSavingsEndDate.Value.Year - activescenario.CostSavingsStartDate.Value.Year) + 1 : (int?)null, ROIDate = activescenario.ROIDate, HardSoftSavings = (activescenario.CostSavingsType.HasValue && activescenario.CostSavingsStartDate.HasValue && activescenario.CostSavingsEndDate.HasValue) ? (activescenario.CostSavingsType == 1 ? "Hard" : "Soft") : string.Empty, ProjectDeadline = project.Deadline, ProjectStatus = project.StatusName, Groups = scGroups.Where(x => x.ScenarioId == activescenario.Id).Select(x => x.GroupId).ToList(), InactiveScenarios = (projectsScenarios .Where(x => x.ParentId == project.Id && x.Status == (int?) ScenarioStatus.Inactive && x.Id != activescenario.Id) .Select(x => new InactiveScenarioInProjectModel { Id = x.Id, Name = x.Name, StartDate = x.StartDate.HasValue ? Utils.ConvertToUnixDate(x.StartDate.Value) : (long?) null, EndDate = x.EndDate.HasValue ? Utils.ConvertToUnixDate(x.EndDate.Value) : (long?) null, })).OrderBy(x => x.Name).ToList(), }; return modelItem; } public IEnumerable GetResourceAvailability(ForecastDashboardFilterModel forecastFilter, Guid userId) { if (!forecastFilter.StartDate.HasValue && !forecastFilter.EndDate.HasValue) { forecastFilter.StartDate = DateTime.Today.AddMonths(-1); forecastFilter.EndDate = forecastFilter.StartDate.Value.AddYears(1); } var query = DbContext.resourceAvailability_f(forecastFilter.StartDate, forecastFilter.EndDate, "0", null, false); #region convert incoming params to teams var teamManager = new TeamManager(DbContext); var filteredTeams = teamManager.GetTeamsByUserFiltered(userId.ToString(), forecastFilter.Teams, forecastFilter.Views, forecastFilter.Companies); #endregion var filteredTeamsStr = filteredTeams.Select(x => x.TeamId.ToString()).ToList(); var result = query.Where(x => filteredTeamsStr.Contains(x.TeamId)) .Select(x => new ForecastResourceAvailabilityGridItem { ExpenditureCategory = x.ExpenditureCategory, TeamName = x.TeamName, ResourceAvailability = x.ResourceAvailability, AvailableHours = x.AvailableHours, NonProjectTimeHours = x.NonProjectTimeHours, AllocatedHours = x.AllocatedHours, FirstName = x.FirstName, LastName = x.LastName, TeamId = x.TeamId.ToLower(), ExpenditureCategoryId = x.ExpenditureCategoryId.ToLower() }).ToList(); return result; } } }