710 lines
32 KiB
C#
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;
|
|
}
|
|
}
|
|
} |