286 lines
12 KiB
C#
286 lines
12 KiB
C#
using Resources;
|
|
|
|
namespace EnVisage.Code.BLL
|
|
{
|
|
using Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Web.Mvc;
|
|
|
|
public class SupplyDemandReportManager : IDisposable
|
|
{
|
|
#region Private Variables
|
|
|
|
private readonly EnVisageEntities _dbContext;
|
|
private readonly bool _isContexLocal;
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
public SupplyDemandReportManager(EnVisageEntities dbContext)
|
|
{
|
|
if (dbContext == null)
|
|
{
|
|
_dbContext = new EnVisageEntities();
|
|
_isContexLocal = true;
|
|
}
|
|
else
|
|
{
|
|
_dbContext = dbContext;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
public ActivityCalendarModel GetReportModel(Guid userId, SupplyDemandReportRequestModel request)
|
|
{
|
|
if (userId == Guid.Empty)
|
|
throw new ArgumentException(Messages.Commonl_ArgumentEmpty, "userId");
|
|
|
|
if (request == null)
|
|
throw new ArgumentNullException("request");
|
|
|
|
if (request.Statuses == null || !request.Statuses.Any())
|
|
return null;
|
|
|
|
var clientManager = new ClientManager(_dbContext);
|
|
var projectManager = new ProjectManager(_dbContext);
|
|
var scenarioManager = new ScenarioManager(_dbContext);
|
|
var teamManager = new TeamManager(_dbContext);
|
|
var resourcesManager = new PeopleResourcesManager(_dbContext);
|
|
var fcManager = new FiscalCalendarManager(_dbContext);
|
|
var acManager = new ActivityCalendarManager(_dbContext);
|
|
|
|
if (request.Clients == null)
|
|
request.Clients = new List<Guid>();
|
|
|
|
if (!request.Clients.Any())
|
|
{
|
|
// Get clients from projects, because they are not specified by user
|
|
var extractedClients = clientManager.GetByProjectStatues(request.Statuses, userId);
|
|
request.Clients.AddRange(extractedClients.Keys);
|
|
}
|
|
|
|
// we should retrieve only requested projects
|
|
var projects = projectManager.GetProjectsWithChildrenByStatusAndClient(request.Statuses, request.Clients, request.Projects);
|
|
var scenarios = projects.Select(x => x.Scenarios.Where(s => s.Type == ScenarioType.Portfolio)
|
|
.OrderByDescending(s => s.DateCreated)
|
|
.FirstOrDefault())
|
|
.Where(x => x != null);
|
|
|
|
if (!scenarios.Any())
|
|
return null;
|
|
|
|
// we should use intersection of what was requested (if any) with what we could retrieve by passed filter
|
|
var projectIds = request.Projects != null && request.Projects.Any() ? projects.Select(x => x.Id).Intersect(request.Projects) : projects.Select(x => x.Id);
|
|
var projectTeams = teamManager.GetTeamsByProjects(userId, projectIds, request.Teams);
|
|
var visible2UserTeams = projectTeams.Select(x => x.TeamId).ToList();
|
|
|
|
var scenarioIds = scenarios.Select(x => x.Id);
|
|
//var requestContainsTeams = request.Teams != null && request.Teams.Any();
|
|
//var scenariosRange = requestContainsTeams ?
|
|
// GetScenariosRangeByTeamAllocations(scenarioIds, visible2UserTeams, request.StartDate, request.EndDate) :
|
|
// GetScenariosRangeByScenarioDetails(scenarioIds, request.StartDate, request.EndDate);
|
|
var scenariosRange = GetScenariosRangeByScenarioDetails(scenarioIds, request.StartDate, request.EndDate);
|
|
// if user hasn't selected range we should get required dates from scenarios
|
|
if (!request.StartDate.HasValue || !request.EndDate.HasValue)
|
|
{
|
|
if (!request.StartDate.HasValue)
|
|
request.StartDate = scenariosRange.StartDate ?? scenarios.Min(x => x.StartDate);
|
|
|
|
if (!request.EndDate.HasValue)
|
|
request.EndDate = scenariosRange.EndDate ?? scenarios.Max(x => x.EndDate);
|
|
}
|
|
|
|
var fcWeeks = fcManager.GetFiscalCalendar(FiscalCalendarModel.FiscalYearType.Week, request.StartDate, request.EndDate, true, false, true);
|
|
var weekEndings = fcWeeks.Select(x => x.EndDate).ToList();
|
|
if (weekEndings.Count <= 0)
|
|
return null;
|
|
|
|
var startDate = fcWeeks.Min(x => x.StartDate);
|
|
var endDate = fcWeeks.Max(x => x.EndDate);
|
|
|
|
var projectModel = acManager.ConvertProjectsToProjectModel(projects, fcWeeks, false).ToDictionary(x => x.ProjectId.ToString());
|
|
var projectScenarios = projectModel.Select(x => x.Value.ActiveScenario.Id);
|
|
|
|
var resources = resourcesManager.GetResourcesWithAllocationsByTeams(visible2UserTeams, startDate, endDate);
|
|
var resourcesECs = resources.Select(x => x.ExpenditureCategoryId).Distinct();
|
|
var superECsInScenarios = scenarioManager.GetExpendituresInScenarios(projectScenarios, true).Select(x => x.Id);
|
|
var allECs = resourcesECs.Union(superECsInScenarios).ToList();
|
|
|
|
var needAllocations = scenarioManager.GetScenarioDetails(projectScenarios, null, weekEndings);
|
|
var needAllocationsTree = acManager.ConvertNeedAllocationsToTree(needAllocations);
|
|
|
|
var teamAllocations = teamManager.GetTeamsAllocation(visible2UserTeams, projectScenarios, allECs, startDate, endDate);
|
|
var teamAllocationsTree = acManager.ConvertTeamAllocationsToTree(teamAllocations);
|
|
|
|
foreach (var project in projects)
|
|
{
|
|
if (!projectModel.ContainsKey(project.Id.ToString()))
|
|
continue;
|
|
|
|
var pModel = projectModel[project.Id.ToString()];
|
|
var actualTeams = project.Teams != null ? project.Teams.Intersect(visible2UserTeams).ToList() : new List<Guid>();
|
|
|
|
foreach (var teamId in actualTeams)
|
|
pModel.Teams.Add(teamId.ToString(), new ActivityCalendarProjectTeamWithAssignedResourcesModel());
|
|
}
|
|
|
|
var teams = teamManager.GetTeamsInfo(projectTeams, fcWeeks, true);
|
|
var model = new ActivityCalendarModel
|
|
{
|
|
WeekEndings = fcManager.CastWeekEndingsToTree(weekEndings),
|
|
Projects = projectModel,
|
|
Teams = teams.ToDictionary(x => x.Id.ToString()),
|
|
NeedAllocations = needAllocationsTree,
|
|
TeamAllocations = teamAllocationsTree,
|
|
};
|
|
|
|
return model;
|
|
}
|
|
|
|
public SupplyDemandReportFilterResponseModel GetFilterOptions(Guid userId, SupplyDemandReportFilterRequestModel request)
|
|
{
|
|
if (userId == Guid.Empty)
|
|
throw new ArgumentException(Messages.Commonl_ArgumentEmpty, "userId");
|
|
|
|
if (request == null)
|
|
throw new ArgumentNullException("request");
|
|
|
|
if ((request.Statuses == null) || !request.Statuses.Any())
|
|
return new SupplyDemandReportFilterResponseModel();
|
|
|
|
var clientManager = new ClientManager(_dbContext);
|
|
var projectManager = new ProjectManager(_dbContext);
|
|
var teamManager = new TeamManager(_dbContext);
|
|
|
|
// Get clients by project statuses
|
|
var clients = clientManager.GetByProjectStatues(request.Statuses, userId);
|
|
if ((clients == null) || !clients.Any())
|
|
return new SupplyDemandReportFilterResponseModel();
|
|
|
|
// Get clients to extract project for. Apply user selection or take all clients, if clients not specified by user
|
|
var clientsSelected = request.Clients != null && request.Clients.Any() ? request.Clients.Intersect(clients.Keys) : clients.Keys;
|
|
|
|
// we should retrieve all projects by statuses and clients to fill list with available projects
|
|
var projects = projectManager.GetProjectsWithChildrenByStatusAndClient(request.Statuses, clientsSelected, null);
|
|
// We should throw out projects, that not suit selected clients list, as well as project without scenarios and teams
|
|
projects.RemoveAll(p => !p.ClientId.HasValue || !clientsSelected.Contains(p.ClientId.Value) ||
|
|
p.Scenarios == null || p.Scenarios.All(t => t.Type != ScenarioType.Portfolio) ||
|
|
p.Teams == null || p.Teams.Count < 1);
|
|
|
|
// we should use intersection of what was requested (if any) with what we could retrieve by passed filter
|
|
var projectIds = (request.Projects != null && request.Projects.Any()) ? projects.Select(x => x.Id).Intersect(request.Projects) : projects.Select(x => x.Id);
|
|
// we should get all available teams in the list
|
|
var projectTeams = teamManager.GetTeamsByProjects(userId, projectIds, null);
|
|
|
|
// Review clients list using extracted and filtered projects collection
|
|
// ClientManager returns clients by project statuses using projects as links for that entities.
|
|
// But ClientManager taskes all projects and avoid any checks on the existance of scenarios and teams for these projects.
|
|
// As a result. The extracted list of clients may contain some not actual records.
|
|
// We should throw out these (non-actual) client records, because selecting any of that client
|
|
// in the report criteria makes Projects filter empty
|
|
var clientsByExtractedProjects = projects.Where(x => x.ClientId.HasValue).Select(x => x.ClientId.Value);
|
|
|
|
var model = new SupplyDemandReportFilterResponseModel
|
|
{
|
|
Clients = clients.Values.Where(c => clientsByExtractedProjects.Contains(c.Id)).Select(x => new SelectListItem()
|
|
{
|
|
Text = x.Name,
|
|
Value = x.Id.ToString()
|
|
}).ToList(),
|
|
|
|
Projects = projects.Select(x => new SelectListItem
|
|
{
|
|
Text = x.ParentProject != null ? string.Format("{0} : {1}", x.Name, x.ParentProject.Name) : x.Name,
|
|
Value = x.Id.ToString()
|
|
}).ToList(),
|
|
|
|
Teams = projectTeams.Select(x => new SelectListItem
|
|
{
|
|
Text = x.Name,
|
|
Value = x.TeamId.ToString()
|
|
}).ToList(),
|
|
};
|
|
|
|
return model;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private methods
|
|
|
|
protected DateRangeNullable GetScenariosRangeByScenarioDetails(IEnumerable<Guid> scenarios, DateTime? minDate, DateTime? maxDate)
|
|
{
|
|
if (scenarios == null)
|
|
throw new ArgumentNullException("scenarios");
|
|
|
|
var result = new DateRangeNullable();
|
|
var qry = _dbContext.ScenarioDetail.Where(x => x.WeekEndingDate.HasValue && x.ParentID.HasValue && scenarios.Contains(x.ParentID.Value));
|
|
|
|
if (minDate.HasValue)
|
|
qry.Where(x => x.WeekEndingDate.Value >= minDate.Value);
|
|
|
|
if (maxDate.HasValue)
|
|
{
|
|
var lastWeek = FiscalCalendarManager.GetFiscalCalendarWeekForDate(maxDate.Value, _dbContext);
|
|
qry.Where(x => x.WeekEndingDate.Value <= lastWeek.EndDate);
|
|
}
|
|
|
|
var datesQry = qry.Select(x => x.WeekEndingDate.Value);
|
|
|
|
if (datesQry.Any())
|
|
{
|
|
result.StartDate = datesQry.Min();
|
|
result.EndDate = datesQry.Max();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
protected DateRangeNullable GetScenariosRangeByTeamAllocations(IEnumerable<Guid> scenarios, IEnumerable<Guid> teams, DateTime? minDate, DateTime? maxDate)
|
|
{
|
|
if (scenarios == null)
|
|
throw new ArgumentNullException("scenarios");
|
|
|
|
if (teams == null)
|
|
throw new ArgumentNullException("teams");
|
|
|
|
var result = new DateRangeNullable();
|
|
var qry = _dbContext.TeamAllocations.Where(x => scenarios.Contains(x.ScenarioId) && teams.Contains(x.TeamId) && (x.Quantity > 0));
|
|
|
|
if (minDate.HasValue)
|
|
qry.Where(x => x.WeekEndingDate >= minDate.Value);
|
|
|
|
if (maxDate.HasValue)
|
|
{
|
|
var lastWeek = FiscalCalendarManager.GetFiscalCalendarWeekForDate(maxDate.Value, _dbContext);
|
|
qry.Where(x => x.WeekEndingDate <= lastWeek.EndDate);
|
|
}
|
|
|
|
var datesQry = qry.Select(x => x.WeekEndingDate);
|
|
|
|
if (datesQry.Any())
|
|
{
|
|
result.StartDate = datesQry.Min();
|
|
result.EndDate = datesQry.Max();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Overrides
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_isContexLocal)
|
|
_dbContext.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |