340 lines
18 KiB
C#
340 lines
18 KiB
C#
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns data for main dashboard table
|
|
/// </summary>
|
|
public IEnumerable<ForecastDashboardModel> 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<Guid>();
|
|
filter.Views = new List<Guid>();
|
|
|
|
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<ForecastDashboardModel>();
|
|
var teams = filter.FilterGroupByTeam ? filteredTeams
|
|
: new List<TeamWithPermissionsModel>() { 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<ForecastDashboardModel> rowsToDisplay = query.Skip((startIndex -1) * pageSize).Take(pageSize).ToList();
|
|
List<ForecastDashboardModel> rowsToDisplay = query.ToList();
|
|
var scenarioIds = rowsToDisplay.Select(x => x.Id);
|
|
|
|
Dictionary<Guid, VW_ScenarioPerformance> 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<Project> QueryProjects(Guid userId, IEnumerable<Guid> 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<Scenario> 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<ForecastResourceAvailabilityGridItem> 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;
|
|
}
|
|
}
|
|
} |