EnVisageOnline/Main-RMO/Source/EnVisage/Code/BLL/MixManagers/MongoMixManager.cs

710 lines
32 KiB
C#

using System.Globalization;
using System.Web.Mvc;
using EnVisage.Code.DAL;
using EnVisage.Code.DAL.Mongo;
using EnVisage.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using NLog;
using System.Threading.Tasks;
namespace EnVisage.Code.BLL
{
public class MongoMixManager : IMixManager<DAL.Mongo.Mix>
{
protected Logger _logger = NLog.LogManager.GetCurrentClassLogger();
private string _userId = string.Empty;
private readonly EnVisageEntities _dbContext;
protected EnVisageEntities DbContext { get { return _dbContext; } }
private bool _isContexLocal;
public MongoMixManager(EnVisageEntities dbContext, string userId)
{
if (dbContext == null)
{
_dbContext = new EnVisageEntities();
_isContexLocal = true;
}
else
{
_dbContext = dbContext;
}
_userId = userId;
}
protected DAL.Mongo.Mix InitInstance()
{
return new DAL.Mongo.Mix();
}
protected DAL.Mongo.Mix RetrieveReadOnlyById(string key)
{
return MongoDataContext.Mixes.Find(t => t.Id == new ObjectId(key)).FirstOrDefaultAsync().GetAwaiter().GetResult();
}
public void Delete(string mixId)
{
if (!string.IsNullOrWhiteSpace(mixId))
{
var objectId = ObjectId.Empty;
if (ObjectId.TryParse(mixId, out objectId) && !ObjectId.Empty.Equals(objectId))
{
Delete(objectId);
}
}
}
public void Delete(ObjectId mixId)
{
if (!ObjectId.Empty.Equals(mixId))
{
var result = MongoDataContext.Mixes.DeleteOneAsync(t => t.Id == mixId).GetAwaiter().GetResult();
if (!result.IsAcknowledged)
_logger.Warn("An error occurred while removing Mix record");
}
var allocResult = MongoDataContext.ExpenditureAllocations.DeleteManyAsync(t => t.MixId == mixId).GetAwaiter().GetResult();
if (!allocResult.IsAcknowledged)
_logger.Warn("An error occurred while removing Mix expenditure allocations");
allocResult = MongoDataContext.TeamAllocations.DeleteManyAsync(t => t.MixId == mixId).GetAwaiter().GetResult();
if (!allocResult.IsAcknowledged)
_logger.Warn("An error occurred while removing Mix team allocations");
allocResult = MongoDataContext.ResourceAllocations.DeleteManyAsync(t => t.MixId == mixId).GetAwaiter().GetResult();
if (!allocResult.IsAcknowledged)
_logger.Warn("An error occurred while removing Mix resource allocations");
}
private Mix Save(Mix dbObj)
{
dbObj.CreatedAtUtc = DateTime.UtcNow;
dbObj.CreatedBy = _userId;
MongoDataContext.Mixes.InsertOneAsync(dbObj).GetAwaiter().GetResult();
return dbObj;
}
public Mix SaveWithChildren(MixSaveModel model)
{
#region step 0. Load old mix object
var savedMix = RetrieveWithChildren(model.Id);
#endregion
#region step 1. Save Mix object
Mix dbObj = InitInstance();
model.CopyTo(dbObj);
dbObj = Save(dbObj);
#endregion
#region step 2. Save Allocations
try
{
var expAllocations2Insert = new List<MixExpenditureAllocation>();
var teamAllocations2Insert = new List<MixTeamAllocation>();
var resAllocations2Insert = new List<MixResourceAllocation>();
// get all scenarios in mix
var scenariosInMix = model.Calendar.Projects.Where(x => x.Value != null && x.Value.Scenario != null)
.Select(x => x.Value.Scenario.Id).ToList();
// check which scenarios from mix still exist in the live database
var existenceScenarios = DbContext.Scenarios.Where(x => scenariosInMix.Contains(x.Id)).Select(x => x.Id).ToList();
foreach (var projectId in model.Calendar.Projects.Keys)
{
var project = model.Calendar.Projects[projectId];
if (project.Scenario == null)
continue;
var currentScenario = project.Scenario;
#region Determining expenditures for saving
var expenditures = currentScenario.Expenditures;
// expenditures can be empty if user didn't edit this project befor saving this mix in current moment
if (expenditures == null || expenditures.Count <= 0)
{
// if mix has been saved earlier and it contains expenditures we should to save them for the current mix
if (savedMix != null && savedMix.Calendar != null && savedMix.Calendar.Projects != null)
{
if (savedMix.Calendar.Projects.ContainsKey(projectId))
{
var savedProject = savedMix.Calendar.Projects[projectId];
if (savedProject.Scenario != null)
expenditures = savedProject.Scenario.Expenditures;
}
}
}
if (expenditures == null || expenditures.Count <= 0)
{
// TODO: review for ability to change GetFullAllocationInfoByScenario method for retrieving information for a couple of scenarios
if (existenceScenarios.Contains(currentScenario.Id))
expenditures = (new ScenarioManager(DbContext)).GetFullAllocationInfoByScenario(currentScenario.Id, _userId);
}
#endregion
if (expenditures == null || expenditures.Count <= 0)
continue;
foreach (var expCat in expenditures)
{
// insert expenditure allocations
var expenditureAllocation = new MixExpenditureAllocation
{
MixId = dbObj.Id,
ScenarioId = currentScenario.Id,
CreatedAtUtc = DateTime.UtcNow,
CreatedBy = _userId
};
expCat.Value.CopyTo(expenditureAllocation);
expAllocations2Insert.Add(expenditureAllocation);
// insert team allocations
foreach (var expenditureDetailsTeam in expCat.Value.Teams)
{
var teamAllocation = new MixTeamAllocation()
{
MixId = dbObj.Id,
ScenarioId = currentScenario.Id,
ExpCatId = expenditureAllocation.ExpCatId,
CreatedAtUtc = DateTime.UtcNow,
CreatedBy = _userId,
};
expenditureDetailsTeam.Value.CopyTo(teamAllocation);
teamAllocations2Insert.Add(teamAllocation);
foreach (var teamResource in expenditureDetailsTeam.Value.Resources)
{
var resAllocation = new MixResourceAllocation
{
MixId = dbObj.Id,
ScenarioId = currentScenario.Id,
ExpCatId = expenditureAllocation.ExpCatId,
TeamId = teamAllocation.TeamId,
CreatedAtUtc = DateTime.UtcNow,
CreatedBy = _userId,
};
teamResource.Value.CopyTo(resAllocation);
resAllocations2Insert.Add(resAllocation);
}
}
}
}
SaveAllocations(expAllocations2Insert, teamAllocations2Insert, resAllocations2Insert);
}
catch (Exception exception)
{
_logger.Fatal(exception);
// if any error occurred while saving new Mix then remove it and all it's children.
Delete(dbObj.Id);
// Then throw exception to ask user to try again later
throw;
}
#endregion
#region step 3. Update QuickLinks
try
{
// try to update quick links
var query = DbContext.UserQuickLinks.Where(t => t.Url.Contains(model.Id));
foreach (var item in query)
{
item.Url = item.Url.Replace(model.Id, dbObj.Id.ToString());
DbContext.Entry(item).State = EntityState.Modified;
}
}
catch (Exception exception)
{
// if any error occurred while updating quick links then do nothing except error logging
_logger.Fatal(exception);
}
#endregion
#region step 4. Delete previous Mix with children
try
{
// try to delete previous Mix record
Delete(model.Id);
}
catch (Exception exception)
{
// if any error occurred while removing old Mix then do nothing except error logging
_logger.Fatal(exception);
}
#endregion
return dbObj;
}
private void SaveAllocations(List<MixExpenditureAllocation> expenditures, List<MixTeamAllocation> teamAllocations, List<MixResourceAllocation> resourceAllocations)
{
var tasks = new List<Task>();
if (expenditures != null && expenditures.Count > 0)
tasks.Add(MongoDataContext.ExpenditureAllocations.InsertManyAsync(expenditures));
if (teamAllocations != null && teamAllocations.Count > 0)
tasks.Add(MongoDataContext.TeamAllocations.InsertManyAsync(teamAllocations));
if (resourceAllocations != null && resourceAllocations.Count > 0)
tasks.Add(MongoDataContext.ResourceAllocations.InsertManyAsync(resourceAllocations));
Task.WaitAll(tasks.ToArray());
}
public DAL.Mongo.Mix Retrieve(string mixId)
{
if (string.IsNullOrWhiteSpace(mixId))
return null;
return MongoDataContext.Mixes.Find(t => t.Id == new ObjectId(mixId)).FirstOrDefaultAsync().GetAwaiter().GetResult();
}
public MixSaveModel RetrieveModel(string mixId)
{
if (string.IsNullOrWhiteSpace(mixId))
return null;
var mix = Retrieve(mixId);
if (null == mix)
return null;
MixSaveModel model = new MixSaveModel();
model.Id = mix.Id.ToString();
model.Name = mix.Name;
model.StartDate = mix.StartDate;
model.EndDate = mix.EndDate;
model.Filter.Selection.StartDate = mix.StartDate;
model.Filter.Selection.EndDate = mix.EndDate;
model.Filter.Selection.TeamsViews = mix.TeamsViews.Select(x => new MixTeamViewModel()
{
Id = x.Id,
TVName = x.Name,
Group = new SelectListGroup() { Disabled = false, Name = x.Group },
IsNew = x.IsNew,
CapacityTeamId = x.CapacityTeamId,
CompanyId = x.CompanyId,
CopyPlanned = x.CopyPlanned,
CostCenterId = x.CostCenterId,
Data = x.Data,
UserId = x.UserId
}).ToList();
model.Users = mix.Users;
model.Calendar.AssignFrom(mix);
return model;
}
public MixSaveModel RetrieveWithChildren(string mixId)
{
var model = RetrieveModel(mixId);
if (model == null)
return null;
#region Load Allocations
var scenarios = model.Calendar.Projects.Where(x => x.Value != null && x.Value.Scenario != null)
.Select(x => x.Value.Scenario.Id)
.ToList();
var allocations = GetAllocations4Scenarios(mixId, scenarios);
if (allocations != null && allocations.Count > 0)
{
foreach (var projectId in model.Calendar.Projects.Keys)
{
var project = model.Calendar.Projects[projectId];
if (project.Scenario == null || !allocations.ContainsKey(project.Scenario.Id))
continue;
project.Scenario.Expenditures = allocations[project.Scenario.Id];
}
}
#endregion
return model;
}
public List<MixProjectModel> GetProjectModel(List<Guid> projects)
{
var scenarioManager = (new ScenarioManager(DbContext));
var result = new List<MixProjectModel>();
var availableProjects = DbContext.Projects.Where(x => projects.Contains(x.Id))
.Include(x => x.Team2Project)
.Include(x => x.ParentProject)
.Include(x => x.Scenarios)
.Include(x => x.Scenarios.Select(s => s.CostSavings1))
.ToList();
string defaultColor = "";
var settings = DbContext.SystemSettings.Where(
item =>
item.Type == (int)SystemSettingType.DefaultProjectColorType).FirstOrDefault();
if (settings != null)
{
defaultColor = settings.Value;
}
var projectsModel = availableProjects.Select(x => new
{
Id = x.Id,
Name = x.ParentProjectId.HasValue ? x.Name + ": " + x.ParentProject.Name : x.Name,
Color = (x.ParentProjectId.HasValue && (x.Color == null || x.Color.Trim() == "")) ? ((x.ParentProject.Color == null || x.ParentProject.Color.Trim() == "") ? defaultColor : x.ParentProject.Color) : ((x.Color == null || x.Color.Trim() == "") ? defaultColor : x.Color),
Deadline = x.Deadline,
Teams = x.Team2Project.Select(ts => ts.TeamId).Distinct().ToList(),
ActiveScenario = x.Scenarios.FirstOrDefault(s => s.StartDate.HasValue && s.EndDate.HasValue && s.Type == (int)ScenarioType.Portfolio && s.Status == (int)ScenarioStatus.Active),
InactiveScenarios = x.Scenarios.Where(s => s.StartDate.HasValue && s.EndDate.HasValue && s.Type == (int)ScenarioType.Portfolio && s.Status == (int)ScenarioStatus.Inactive).ToList()
}).ToList();
var activeScenariosIds = projectsModel.Where(x => x.ActiveScenario != null).Select(x => x.ActiveScenario.Id).ToList();
var inactiveScenariosIds = projectsModel.Where(x => x.InactiveScenarios != null).SelectMany(x => x.InactiveScenarios.Select(s => s.Id).ToList()).ToList();
var scenarios = activeScenariosIds.Union(inactiveScenariosIds).ToList();
var rates = (new RateManager(_dbContext)).Get4Parents(scenarios, RateModel.RateType.Derived);
foreach (var project in projectsModel)
{
var strColor = !String.IsNullOrEmpty(project.Color) ? string.Format("#{0}", project.Color) : String.Empty;
var color = System.Drawing.ColorTranslator.FromHtml(strColor);
var activeScenario = (ScenarioCalendarMixModel)project.ActiveScenario;
var inactiveScenarios = project.InactiveScenarios.OrderBy(z => z.Name).ToDictionary(x => x.Id.ToString(), x => (ScenarioCalendarMixModel)x);
if (activeScenario != null && rates.ContainsKey(activeScenario.Id))
{
var expRates = rates[activeScenario.Id].GroupBy(x => x.ExpenditureCategoryId).ToDictionary(x => x.Key, g => g.ToList());
activeScenario.Rates = scenarioManager.GetRatesModel(expRates);
}
if (inactiveScenarios != null && inactiveScenarios.Count > 0)
{
foreach (var scenario in inactiveScenarios)
{
if (rates.ContainsKey(scenario.Value.Id))
{
var expRates = rates[scenario.Value.Id].GroupBy(x => x.ExpenditureCategoryId).ToDictionary(x => x.Key, g => g.ToList());
scenario.Value.Rates = scenarioManager.GetRatesModel(expRates);
}
}
}
result.Add(new MixProjectModel()
{
Id = project.Id,
Name = project.Name,
Color = strColor,
ColorRGB = !color.IsEmpty ? string.Format("{0}, {1}, {2}", color.R, color.G, color.B) : String.Empty,
Deadline = project.Deadline.HasValue ? Utils.ConvertToUnixDate(project.Deadline.Value) : (long?)null,
Teams = project.Teams,
Scenario = activeScenario,
InactiveScenarios = inactiveScenarios
});
}
return result;
}
public void ActivateMix(string mixId)
{
if (string.IsNullOrWhiteSpace(mixId))
throw new ArgumentNullException("mixId");
var mix = RetrieveWithChildren(mixId);
if (mix == null)
throw new InvalidOperationException(string.Format("Mix with Id [{0}] can not be activated because it does not exists.", mixId));
if (mix.Calendar == null)
return;
if (mix.Calendar.Teams != null && mix.Calendar.Teams.Any(x => x.IsNew))
{
var teamManager = (new TeamManager(DbContext));
var rateManager = (new RateManager(DbContext));
var newTeams = mix.Calendar.Teams.FindAll(x => x.IsNew);
var expCatsInTeams = newTeams.Where(x => x.PlannedCapacity != null).SelectMany(x => x.PlannedCapacity.Select(t => t.ExpCatId)).ToList();
var expCatsInTeamsGuid = new List<Guid>();
foreach (var expCatString in expCatsInTeams)
{
Guid expCatId;
if (string.IsNullOrWhiteSpace(expCatString) || !Guid.TryParse(expCatString, out expCatId) || expCatId == Guid.Empty)
continue;
expCatsInTeamsGuid.Add(expCatId);
}
var rates = rateManager.GetRates(expCatsInTeamsGuid, RateModel.RateType.Global);
Guid currentUser = (_userId.Length > 0) ? new Guid(_userId) : Guid.Empty; // SA. ENV-1083
foreach (var team in newTeams)
{
// SA. ENV-1083. Automatically add current user to team contributors.
if (!currentUser.Equals(Guid.Empty))
{
if (team.UserId == null)
team.UserId = new Guid[1] { currentUser };
else
if (!team.UserId.Contains(currentUser))
{
List<Guid> tmpUsersList = team.UserId.ToList();
tmpUsersList.Add(currentUser);
team.UserId = tmpUsersList.ToArray();
}
}
var savedTeam = teamManager.Save((TeamModel)team, true);
if (savedTeam == null || !savedTeam.PlannedCapacityScenarioId.HasValue)
continue;
if (team.PlannedCapacity == null || team.PlannedCapacity.Count <= 0)
continue;
foreach (var capacity in team.PlannedCapacity)
{
if (capacity.Values == null || capacity.Values.Count <= 0)
continue;
Guid expCatId;
if (string.IsNullOrWhiteSpace(capacity.ExpCatId) || !Guid.TryParse(capacity.ExpCatId, out expCatId) || expCatId == Guid.Empty)
continue;
foreach (var value in capacity.Values)
{
long weekEnding;
if (!long.TryParse(value.Key, out weekEnding) || weekEnding <= 0)
continue;
DbContext.ScenarioDetail.Add(new ScenarioDetail()
{
Id = Guid.NewGuid(),
ParentID = savedTeam.PlannedCapacityScenarioId.Value,
ExpenditureCategoryId = expCatId,
WeekEndingDate = Utils.ConvertFromUnixDate(weekEnding),
Quantity = value.Value,
Cost = value.Value * rateManager.GetRateValue(rates, expCatId, Utils.ConvertFromUnixDate(weekEnding)),
LastUpdate = DateTime.UtcNow
});
}
}
}
// we should to save all new teams in one separate transaction because every scenario will be saved in the own transaction
// and it need actual information abuout teams
DbContext.SaveChanges();
}
if (mix.Calendar.Projects != null && mix.Calendar.Projects.Count > 0)
{
// SA. ENV-1159. Get list of projects for activation
List<Guid> projectsToActivate = new List<Guid>();
if ((mix.Calendar.ManagedProjects != null) && (mix.Calendar.ManagedProjects.Count > 0))
// All managed projects
projectsToActivate.AddRange(mix.Calendar.ManagedProjects);
if ((mix.Calendar.QueuedProjects != null) && (mix.Calendar.QueuedProjects.Count > 0))
{
// Include queued projects, that have newly created scenarios in the Mix
projectsToActivate.AddRange(mix.Calendar.QueuedProjects.Where(x =>
mix.Calendar.Projects.ContainsKey(x.ToString()) &&
(mix.Calendar.Projects[x.ToString()].Scenario != null) &&
mix.Calendar.Projects[x.ToString()].Scenario.IsNew));
}
var savedTeamsInProjects = DbContext.Team2Project.Where(x => projectsToActivate.Contains(x.ProjectId))
.Select(x => new
{
ProjectId = x.ProjectId,
TeamId = x.TeamId
})
.ToList()
.GroupBy(x => x.ProjectId)
.ToDictionary(x => x.Key, g => g.Select(s => s.TeamId).ToList());
foreach (var projectId in projectsToActivate)
{
if (!mix.Calendar.Projects.ContainsKey(projectId.ToString()))
continue;
var project = mix.Calendar.Projects[projectId.ToString()];
if (project == null || project.Scenario == null)
continue;
if (project.Teams == null)
project.Teams = new List<Guid>();
// we should preserve all teams for project and all its scenarios, we can remove only team allocations
if (savedTeamsInProjects.ContainsKey(project.Id))
{
var requiredTeams = savedTeamsInProjects[projectId].Where(x => !project.Teams.Any(s => s == x)).ToList();
project.Teams.AddRange(requiredTeams);
}
ActivateScenario(project.Scenario, mix.Name, project.Teams);
DbContext.SaveChanges();
}
}
}
public void ActivateScenario(ScenarioCalendarMixModel scenario, string name, List<Guid> teams)
{
if (scenario == null)
throw new ArgumentNullException("scenario");
var scenarioManager = (new ScenarioManager(DbContext));
var scenarioSaveModel = (ScenarioDetailsSnapshotSaveModel)scenario;
if (scenarioSaveModel == null || scenarioSaveModel.Calendar == null)
return;
if ((scenario.Expenditures == null || scenario.Expenditures.Count <= 0) && scenario.Id != Guid.Empty)
scenarioSaveModel.Calendar.Expenditures = (new ScenarioManager(DbContext)).GetFullAllocationInfoByScenario(scenario.Id, _userId);
if (teams != null && teams.Count > 0)
{
scenarioSaveModel.TeamsInScenario = teams.Select(x => new TeamInScenarioModel()
{
TeamId = x
}).ToList();
}
// new scenario should be created with name equals to mix name
scenarioSaveModel.Scenario.Name = name;
var scenarioId = scenarioManager.Save(scenarioSaveModel);
if (scenarioId == Guid.Empty)
throw new InvalidOperationException("Save scenario method returned empty");
// save local rates for this scenario
if (scenario.Rates != null && scenario.Rates.Count > 0)
{
var rates = scenarioManager.GetRatesFromModel(scenario.Rates);
foreach(var rate in rates)
{
rate.Id = Guid.NewGuid();
rate.ParentId = scenarioId;
rate.Type = (short)RateModel.RateType.Derived;
}
DbContext.Rates.AddRange(rates);
}
}
public Dictionary<string, ExpenditureDetail> GetFullAllocationInfoByScenario(string mixId, Guid scenarioId)
{
var allocations = new Dictionary<string, ExpenditureDetail>();
if (scenarioId == Guid.Empty)
return allocations;
if (!string.IsNullOrWhiteSpace(mixId))
allocations = GetAllocations4Scenario(mixId, scenarioId);
if (allocations == null || allocations.Count <= 0)
allocations = (new ScenarioManager(DbContext)).GetFullAllocationInfoByScenario(scenarioId, _userId);
return allocations;
}
public List<MixModelBase> GetMixesByUser()
{
Guid userId;
if (!string.IsNullOrWhiteSpace(_userId) && Guid.TryParse(_userId, out userId) && userId != Guid.Empty)
{
return MongoDataContext.Mixes.Find(t => t.Users.Contains(userId))
.SortBy(o => o.Name)
.ToListAsync()
.GetAwaiter()
.GetResult()
.Select(t => new MixModelBase()
{
Id = t.Id.ToString(),
Name = t.Name,
StartDate = t.StartDate,
EndDate = t.EndDate
}).ToList();
}
return new List<MixModelBase>();
}
private Dictionary<string, ExpenditureDetail> GetAllocations4Scenario(string mixId, Guid scenarioId)
{
var allocations = GetAllocations4Scenarios(mixId, new List<Guid>() { scenarioId });
if (allocations == null || !allocations.ContainsKey(scenarioId))
return new Dictionary<string, ExpenditureDetail>();
return allocations[scenarioId];
}
private Dictionary<Guid, Dictionary<string, ExpenditureDetail>> GetAllocations4Scenarios(string mixId, List<Guid> scenarios)
{
var allocations = new Dictionary<Guid, Dictionary<string, ExpenditureDetail>>();
if (string.IsNullOrWhiteSpace(mixId) || scenarios == null || scenarios.Count <= 0)
return allocations;
var mid = new ObjectId(mixId);
var expenditureAllocations = MongoDataContext.ExpenditureAllocations
.Find(t => t.MixId == mid && scenarios.Contains(t.ScenarioId))
.ToListAsync().GetAwaiter().GetResult()
.GroupBy(x => x.ScenarioId)
.ToDictionary(x => x.Key, g => g.ToList());
var teamAllocations = MongoDataContext.TeamAllocations
.Find(t => t.MixId == mid && scenarios.Contains(t.ScenarioId))
.ToListAsync().GetAwaiter().GetResult()
.GroupBy(x => x.ScenarioId)
.ToDictionary(x => x.Key, g => g.ToList());
var resourceAllocations = MongoDataContext.ResourceAllocations
.Find(t => t.MixId == mid && scenarios.Contains(t.ScenarioId))
.ToListAsync().GetAwaiter().GetResult()
.GroupBy(x => x.ScenarioId)
.ToDictionary(x => x.Key, g => g.ToList());
foreach (var scenarioId in scenarios)
{
if (!expenditureAllocations.ContainsKey(scenarioId))
continue;
var expenditures = expenditureAllocations[scenarioId].ToDictionary(x => x.ExpCatId.ToString(), g => (ExpenditureDetail)g);
allocations.Add(scenarioId, expenditures);
if (!teamAllocations.ContainsKey(scenarioId))
continue;
foreach (var expCatId in allocations[scenarioId].Keys)
{
var ec = allocations[scenarioId][expCatId];
ec.Teams = teamAllocations[scenarioId].Where(x => x.ExpCatId.ToString() == expCatId)
.ToDictionary(x => x.TeamId, g => (ExpenditureDetailsTeam)g);
if (!resourceAllocations.ContainsKey(scenarioId))
continue;
foreach (var teamId in ec.Teams.Keys)
{
ec.Teams[teamId].Resources = resourceAllocations[scenarioId].Where(x => x.ExpCatId.ToString() == expCatId && x.TeamId == teamId)
.ToDictionary(x => x.ResourceId, g => (TeamResource)g);
}
}
}
return allocations;
}
}
}