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;
}
}
}