760 lines
38 KiB
C#
760 lines
38 KiB
C#
using EnVisage.Code.DAL.Mongo;
|
|
using EnVisage.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Linq;
|
|
using System.Web;
|
|
using System.Web.Mvc;
|
|
|
|
namespace EnVisage.Code.BLL
|
|
{
|
|
/// <summary>
|
|
/// Does merging of client changes model to server model
|
|
/// </summary>
|
|
public class MixModelsMergeManager
|
|
{
|
|
public MixModelsMergeManager(EnVisageEntities dbContext, string userId)
|
|
{
|
|
this.dbContext = dbContext;
|
|
this._userId = userId;
|
|
}
|
|
|
|
protected EnVisageEntities dbContext = null;
|
|
protected string _userId = string.Empty;
|
|
|
|
public void MergeFilters(MixFilterModel serverModel, MixFilterModel clientModel)
|
|
{
|
|
if ((clientModel == null) || (clientModel.Selection == null))
|
|
return;
|
|
|
|
if (serverModel == null)
|
|
throw new ArgumentNullException("serverModel");
|
|
|
|
if (serverModel.Selection == null)
|
|
serverModel.Selection = new MixFilterSelectionModel();
|
|
|
|
serverModel.Selection.StartDate = clientModel.Selection.StartDate;
|
|
serverModel.Selection.EndDate = clientModel.Selection.EndDate;
|
|
|
|
serverModel.Selection.TeamsViews = clientModel.Selection.TeamsViews.Select(c => new MixTeamViewModel()
|
|
{
|
|
Id = c.Id,
|
|
IsNew = c.IsNew,
|
|
TVName = c.TVName,
|
|
Group = new SelectListGroup { Name = c.Group.Name, Disabled = false },
|
|
CompanyId = c.CompanyId,
|
|
CostCenterId = c.CostCenterId,
|
|
CapacityTeamId = c.CapacityTeamId,
|
|
CopyPlanned = c.CopyPlanned,
|
|
UserId = (c.UserId != null) ? c.UserId.Select(u => u).ToArray() : null,
|
|
Data = (c.Data != null) ? c.Data.Where(d => (d != null)).Select(r => new WidgetExpCategory()
|
|
{
|
|
Id = r.Id,
|
|
Name = r.Name,
|
|
InPlan = r.InPlan,
|
|
Positions = (r.Positions != null) ? r.Positions.Where(a => (a != null)).Select(p =>
|
|
new WidgetExpCatPosition()
|
|
{
|
|
StartDate = p.StartDate,
|
|
EndDate = p.EndDate,
|
|
Need = p.Need,
|
|
SDate = null,
|
|
EDate = null
|
|
}).ToArray() : null
|
|
}).ToArray() : null
|
|
}).ToList();
|
|
}
|
|
|
|
public void MergeHeaders(MixSaveModel serverModel, MixSaveModel clientModel)
|
|
{
|
|
serverModel.Id = clientModel.Id;
|
|
serverModel.Name = clientModel.Name;
|
|
serverModel.StartDate = clientModel.StartDate;
|
|
serverModel.EndDate = clientModel.EndDate;
|
|
serverModel.CreatedBy = clientModel.CreatedBy;
|
|
|
|
if (clientModel.Users != null)
|
|
{
|
|
if (serverModel.Users == null)
|
|
serverModel.Users = new List<Guid>();
|
|
|
|
List<Guid> usersToAppend = clientModel.Users.Where(u => !serverModel.Users.Contains(u)).ToList();
|
|
serverModel.Users.AddRange(usersToAppend);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Merges two collections of data
|
|
/// </summary>
|
|
/// <param name="serverModel">Actual data taken from alive database</param>
|
|
/// <param name="clientModel">Mix data taken from Mongo</param>
|
|
/// <param name="periodStartWeekending"></param>
|
|
/// <param name="periodEndWeekending"></param>
|
|
public void MergeCalendars(MixSaveModel serverModel, MixSaveModel clientModel, DateTime periodStartWeekending, DateTime periodEndWeekending)
|
|
{
|
|
if (serverModel?.Calendar == null)
|
|
return;
|
|
|
|
if (clientModel?.Calendar == null)
|
|
return;
|
|
|
|
var mixManager = new MongoMixManager(dbContext, _userId);
|
|
// Convert period bound dates to Unix
|
|
long startDateUnix = GetUnixDate(periodStartWeekending);
|
|
long endDateUnix = GetUnixDate(periodEndWeekending);
|
|
|
|
MergeExpendituresNeedModel(serverModel.Calendar, clientModel.Calendar);
|
|
MergeTeamCollections(serverModel.Calendar, clientModel.Calendar);
|
|
MergeProjectCollections(serverModel.Calendar, clientModel.Calendar);
|
|
|
|
SortProjects(serverModel.Calendar, startDateUnix, endDateUnix);
|
|
MergeProjectLists(serverModel.Calendar, clientModel.Calendar);
|
|
MergeLayouts(serverModel.Calendar, clientModel.Calendar);
|
|
|
|
// gather deleted projects
|
|
SetDeletedFromLiveDbProjects(serverModel, clientModel.Calendar, periodStartWeekending, periodEndWeekending.AddDays(6));
|
|
|
|
// fill deleted resource names
|
|
var deletedResourceKeys = serverModel.Calendar.ModifiedObjects.DeletedResources.Keys.Select(t => Guid.Parse(t)).ToList();
|
|
if (deletedResourceKeys.Count > 0 && !string.IsNullOrWhiteSpace(clientModel.Id))
|
|
{
|
|
var resNames = mixManager.GetResourceNames(clientModel.Id, deletedResourceKeys);
|
|
if (resNames != null)
|
|
foreach (var item in resNames)
|
|
{
|
|
if (serverModel.Calendar.ModifiedObjects.DeletedResources.ContainsKey(item.Key))
|
|
serverModel.Calendar.ModifiedObjects.DeletedResources[item.Key] = item.Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void MergeProjectCollections(MixCalendarModel serverCalendarModel,
|
|
MixCalendarModel clientCalendarModel)
|
|
{
|
|
if (serverCalendarModel == null)
|
|
throw new ArgumentNullException(nameof(serverCalendarModel));
|
|
|
|
if (serverCalendarModel.Projects == null)
|
|
serverCalendarModel.Projects = new Dictionary<string, MixProjectModel>();
|
|
|
|
if (clientCalendarModel?.Projects == null)
|
|
return;
|
|
|
|
// Get project list to update (exist in both models)
|
|
List<string> projectsToUpdate = serverCalendarModel.Projects.Where(p =>
|
|
clientCalendarModel.Projects.ContainsKey(p.Key)).Select(p => p.Key).ToList();
|
|
|
|
foreach (string projectId in projectsToUpdate)
|
|
{
|
|
MixProjectModel serverProjectItem = serverCalendarModel.Projects[projectId];
|
|
MixProjectModel clientProjectItem = clientCalendarModel.Projects[projectId];
|
|
MergeSingleProjectModels(serverProjectItem, clientProjectItem,
|
|
serverCalendarModel.Teams, clientCalendarModel.Teams);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// ???
|
|
/// </summary>
|
|
/// <param name="serverProjectModel">?</param>
|
|
/// <param name="clientProjectModel">?</param>
|
|
/// <param name="serverMixTeams">A list of Teams from Mix filter which exist in SQL database.</param>
|
|
/// <param name="clientMixTeams">A list of Teams from Mix filter which exist in Mongo database.</param>
|
|
protected void MergeSingleProjectModels(MixProjectModel serverProjectModel,
|
|
MixProjectModel clientProjectModel, List<MixTeamModel> serverMixTeams,
|
|
List<MixTeamModel> clientMixTeams)
|
|
{
|
|
MergeProjectVersions(serverProjectModel, clientProjectModel);
|
|
|
|
if ((clientProjectModel.Teams != null) && (serverMixTeams != null) && (clientMixTeams != null))
|
|
{
|
|
// Merging of project Teams
|
|
List<Guid> serverTeamsInMix = serverMixTeams.Select(t => new Guid(t.Id)).ToList();
|
|
List<Guid> clientNewTeamsInMix = clientMixTeams.Where(t => t.IsNew).Select(t => new Guid(t.Id)).ToList();
|
|
|
|
List<Guid> teamsForProject = new List<Guid>();
|
|
// Include all client model teams
|
|
teamsForProject.AddRange(clientProjectModel.Teams);
|
|
// Remove all teams, that are not new in Mix and does not exist in SQL database
|
|
teamsForProject.RemoveAll(t => !clientNewTeamsInMix.Contains(t) && !serverTeamsInMix.Contains(t));
|
|
serverProjectModel.Teams = teamsForProject;
|
|
}
|
|
}
|
|
|
|
protected void MergeTeamCollections(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel)
|
|
{
|
|
if (serverCalendarModel.Teams == null)
|
|
throw new ArgumentNullException("serverCalendarModel.Teams");
|
|
|
|
if (clientCalendarModel.Teams == null)
|
|
return;
|
|
|
|
var resourceManager = (new PeopleResourcesManager(dbContext));
|
|
var clientResources = clientCalendarModel.Teams.SelectMany(x => x.ExpCategories)
|
|
.SelectMany(x => x.Value.Resources)
|
|
.Select(x => Guid.Parse(x.Key));
|
|
var serverResources = resourceManager.GetPeopleResourceWithTeams4Resources(clientResources).Select(x => x.Id);
|
|
var deletedResources = clientResources.Except(serverResources);
|
|
|
|
// Merging of teams, that exist both in server and client models
|
|
// serverModel must have all new teams from clientModel (as a result of the MixController.GetCalendar method)
|
|
foreach (var clientTeam in clientCalendarModel.Teams)
|
|
{
|
|
var serverTeam = serverCalendarModel.Teams.FirstOrDefault(t => t.Id.Equals(clientTeam.Id));
|
|
if (serverTeam != null && !string.IsNullOrWhiteSpace(serverTeam.Id))
|
|
MergeSingleTeamModels(serverTeam, clientTeam, serverCalendarModel, deletedResources);
|
|
}
|
|
|
|
// Check, if some new teams in client Model doesn't exist in server Model.
|
|
// If so, write here code for adding absent teams
|
|
}
|
|
|
|
protected void MergeSingleTeamModels(MixTeamModel serverTeamModel, MixTeamModel clientTeamModel, MixCalendarModel serverCalendarModel, IEnumerable<Guid> deletedResources)
|
|
{
|
|
if (serverTeamModel == null)
|
|
throw new ArgumentNullException("serverTeamModel");
|
|
|
|
if (clientTeamModel == null)
|
|
throw new ArgumentNullException("clientTeamModel");
|
|
|
|
serverTeamModel.CompanyId = clientTeamModel.CompanyId ?? serverTeamModel.CompanyId;
|
|
serverTeamModel.CostCenterId = clientTeamModel.CostCenterId;
|
|
serverTeamModel.Name = clientTeamModel.Name;
|
|
serverTeamModel.UserId = clientTeamModel.UserId;
|
|
|
|
var serverExpCatsBackup = serverTeamModel.ExpCategories;
|
|
|
|
// planned capacity should be rewritten from Mongo only for new teams that do not have capacity saved in the live database
|
|
if (clientTeamModel.IsNew)
|
|
serverTeamModel.PlannedCapacity = clientTeamModel.PlannedCapacity != null ? clientTeamModel.PlannedCapacity.Clone() : null;
|
|
|
|
var categories = new Dictionary<string, ExpCategorySummaryInfoModel>();
|
|
if (clientTeamModel.ExpCategories != null)
|
|
{
|
|
foreach (var category in clientTeamModel.ExpCategories.Values)
|
|
{
|
|
var categoryKey = category.Id.ToString();
|
|
var backupCategory = serverExpCatsBackup.ContainsKey(categoryKey) ? serverExpCatsBackup[categoryKey] : null;
|
|
|
|
var serverCategory = new ExpCategorySummaryInfoModel()
|
|
{
|
|
Id = category.Id,
|
|
Name = category.Name,
|
|
UomValue = category.UomValue,
|
|
AllowResourceAssignment = category.AllowResourceAssignment,
|
|
ECScenario = serverTeamModel.ExpCategories.ContainsKey(categoryKey) ? serverTeamModel.ExpCategories[categoryKey].ECScenario : ExpCategorySummaryInfoModel.EC_Scenario.UNKNOWN,
|
|
|
|
AllocatedCapacity = (category.AllocatedCapacity != null) ?
|
|
category.AllocatedCapacity.Select(ac =>
|
|
new KeyValuePair<string, decimal>(ac.Key, ac.Value))
|
|
.ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary<string, decimal>(),
|
|
|
|
NeedCapacity = (category.NeedCapacity != null) ?
|
|
category.NeedCapacity.Select(ac =>
|
|
new KeyValuePair<string, decimal>(ac.Key, ac.Value))
|
|
.ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary<string, decimal>(),
|
|
|
|
ActualCapacityValues = new Dictionary<string, decimal>(),
|
|
PlannedCapacityValues = new Dictionary<string, decimal>(),
|
|
Resources = new Dictionary<string, ResourceSummaryInfoModel>()
|
|
};
|
|
if (category.Resources != null)
|
|
{
|
|
foreach (var resource in category.Resources.Values)
|
|
{
|
|
var deletedResource = deletedResources?.FirstOrDefault(t => t == resource.Id);
|
|
if (deletedResource != null && !Guid.Empty.Equals(deletedResource))
|
|
{
|
|
if (!serverCalendarModel.ModifiedObjects.DeletedResources.ContainsKey(resource.Id.ToString()))
|
|
serverCalendarModel.ModifiedObjects.DeletedResources.Add(resource.Id.ToString(), string.Empty);
|
|
|
|
if ((serverCategory.AllocatedCapacity != null) && (resource.AllocatedCapacity != null))
|
|
{
|
|
// Decrease server category Allocated Capacity with deleted Resource allocation values
|
|
foreach (var resourceWe in resource.AllocatedCapacity.Keys)
|
|
{
|
|
if (serverCategory.AllocatedCapacity.ContainsKey(resourceWe))
|
|
{
|
|
var valueToDecrease = resource.AllocatedCapacity[resourceWe];
|
|
var catSourceAllocationValue = serverCategory.AllocatedCapacity[resourceWe];
|
|
serverCategory.AllocatedCapacity[resourceWe] = (catSourceAllocationValue >= valueToDecrease) ?
|
|
catSourceAllocationValue - valueToDecrease : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
var resourceKey = resource.Id.ToString();
|
|
var serverResource = new ResourceSummaryInfoModel()
|
|
{
|
|
Id = resource.Id,
|
|
AllocatedCapacity = (resource.AllocatedCapacity != null) ?
|
|
resource.AllocatedCapacity.Select(r =>
|
|
new KeyValuePair<string, decimal>(r.Key, r.Value))
|
|
.ToDictionary(r => r.Key, r => r.Value) : new Dictionary<string, decimal>(),
|
|
|
|
TotalCapacity = new Dictionary<string, decimal>(),
|
|
NonProjectTime = new Dictionary<string, ResourceNptModel>()
|
|
};
|
|
// fill resource model with actual data from the live database
|
|
if (backupCategory != null)
|
|
{
|
|
if (backupCategory.Resources != null &&
|
|
backupCategory.Resources.ContainsKey(resourceKey))
|
|
{
|
|
var backupResource = backupCategory.Resources[resourceKey];
|
|
|
|
serverResource.Teams = (backupResource.Teams != null) ?
|
|
backupResource.Teams.Clone() : new List<ResourceSummaryInfoModel.TeamMembershipModel>();
|
|
|
|
if (backupResource.TotalCapacity != null)
|
|
serverResource.TotalCapacity = backupResource.TotalCapacity.Clone();
|
|
|
|
if (backupResource.NonProjectTime != null)
|
|
serverResource.NonProjectTime = backupResource.NonProjectTime.Clone();
|
|
if (backupResource.NonProjectTime != null)
|
|
serverResource.NonProjectTime = backupResource.NonProjectTime.Clone();
|
|
}
|
|
}
|
|
serverCategory.Resources.Add(resourceKey, serverResource);
|
|
}
|
|
}
|
|
// actual capacity should be calculated according to resource capacity
|
|
serverCategory.ActualCapacityValues = serverCategory.Resources
|
|
.SelectMany(x => x.Value.TotalCapacity)
|
|
.GroupBy(x => x.Key)
|
|
.ToDictionary(x => x.Key, g => g.Sum(s => s.Value));
|
|
|
|
if (backupCategory != null && backupCategory.PlannedCapacityValues != null)
|
|
serverCategory.PlannedCapacityValues = backupCategory.PlannedCapacityValues.Clone();
|
|
|
|
categories.Add(categoryKey, serverCategory);
|
|
}
|
|
}
|
|
serverTeamModel.ExpCategories = categories;
|
|
}
|
|
|
|
protected void MergeExpendituresNeedModel(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel)
|
|
{
|
|
if ((clientCalendarModel == null) || (clientCalendarModel.Projects == null) || (clientCalendarModel.Projects.Keys.Count < 1))
|
|
// Client model has no projects data
|
|
return;
|
|
|
|
if ((serverCalendarModel.NeedAllocations == null) || (serverCalendarModel.NeedAllocations.Count < 1))
|
|
{
|
|
serverCalendarModel.NeedAllocations = clientCalendarModel.NeedAllocations;
|
|
return;
|
|
}
|
|
|
|
// Merge need data. When mix goes to mongo, scenarios internal data is force loaded to model.
|
|
// If mix was not ever saved, client model contains data for the only scenarios, whick were edited by user
|
|
foreach (var scenarioId in clientCalendarModel.NeedAllocations.Keys)
|
|
{
|
|
var clientScenarioData = clientCalendarModel.NeedAllocations[scenarioId];
|
|
if ((clientScenarioData != null) && (clientScenarioData.Expenditures != null) && (clientScenarioData.Expenditures.Count > 0))
|
|
{
|
|
if (!serverCalendarModel.NeedAllocations.ContainsKey(scenarioId))
|
|
serverCalendarModel.NeedAllocations.Add(scenarioId, clientScenarioData);
|
|
else
|
|
serverCalendarModel.NeedAllocations[scenarioId] = clientScenarioData;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void SortProjects(MixCalendarModel model, long startDateUnix, long endDateUnix)
|
|
{
|
|
model.ManagedProjects = new List<Guid>();
|
|
model.UnscheduledProjects = new List<Guid>();
|
|
model.QueuedProjects = new List<Guid>();
|
|
model.UnassignedExpendituresProjects = new List<CategoryExpenditureInProject>();
|
|
|
|
if ((model.Projects == null) || (model.Projects.Count < 1))
|
|
return;
|
|
|
|
foreach (string projectIdText in model.Projects.Keys)
|
|
{
|
|
Guid projectId = new Guid(projectIdText);
|
|
MixProjectModel projectModel = model.Projects[projectIdText];
|
|
|
|
if (projectModel.Scenario == null)
|
|
{
|
|
// Send project to Unscheduled list
|
|
model.UnscheduledProjects.Add(projectId);
|
|
continue;
|
|
}
|
|
|
|
if ((projectModel.Scenario.StartDate > endDateUnix) ||
|
|
(projectModel.Scenario.EndDate < startDateUnix))
|
|
{
|
|
// Send project to Queued list
|
|
model.QueuedProjects.Add(projectId);
|
|
continue;
|
|
}
|
|
|
|
model.ManagedProjects.Add(projectId);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Merges collections of projects
|
|
/// </summary>
|
|
/// <param name="serverCalendarModel">Actual data taken from alive database</param>
|
|
/// <param name="clientCalendarModel">Mix data taken from Mongo</param>
|
|
protected void MergeProjectLists(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel)
|
|
{
|
|
if (serverCalendarModel == null)
|
|
throw new ArgumentException("serverCalendarModel");
|
|
|
|
if (serverCalendarModel.Projects == null)
|
|
throw new ArgumentException("serverCalendarModel.Projects");
|
|
|
|
if (serverCalendarModel.Teams == null)
|
|
throw new ArgumentException("serverCalendarModel.Teams");
|
|
|
|
if ((clientCalendarModel == null) || (clientCalendarModel.Projects == null))
|
|
return;
|
|
|
|
if (((clientCalendarModel.Projects == null) || (clientCalendarModel.Projects.Count < 1)) &&
|
|
(clientCalendarModel.ManagedProjects == null || (clientCalendarModel.ManagedProjects.Count < 1)) &&
|
|
((clientCalendarModel.UnscheduledProjects == null) || (clientCalendarModel.UnscheduledProjects.Count < 1)))
|
|
// Client model is empty
|
|
return;
|
|
|
|
foreach (var project in serverCalendarModel.Projects)
|
|
{
|
|
var mixProject = clientCalendarModel.Projects.FirstOrDefault(x => x.Value.Id == project.Value.Id);
|
|
if (mixProject.Value != null)
|
|
project.Value.Pinned = mixProject.Value.Pinned;
|
|
}
|
|
|
|
// All projects, found in live DB
|
|
var allLiveDbProjects = serverCalendarModel.Projects.Keys.Select(x => new Guid(x)).ToList();
|
|
|
|
// Merge Managed projects lists
|
|
List<Guid> existingManagedProjects = clientCalendarModel.ManagedProjects.Where(p =>
|
|
serverCalendarModel.ManagedProjects.Contains(p)).ToList();
|
|
|
|
List<Guid> newManagedProjectsFromServer = serverCalendarModel.ManagedProjects.Where(p =>
|
|
!existingManagedProjects.Contains(p) && !clientCalendarModel.UnscheduledProjects.Contains(p)).ToList();
|
|
|
|
serverCalendarModel.ManagedProjects.RemoveAll(p => !existingManagedProjects.Contains(p));
|
|
serverCalendarModel.ManagedProjects.AddRange(newManagedProjectsFromServer);
|
|
|
|
// Merge Unscheduled projects lists
|
|
List<Guid> existingUnscheduledProjects = clientCalendarModel.UnscheduledProjects.Intersect(serverCalendarModel.UnscheduledProjects).ToList();
|
|
List<Guid> clientOnlyUnscheduledProjects = clientCalendarModel.UnscheduledProjects.Except(serverCalendarModel.UnscheduledProjects)
|
|
.Where(x => allLiveDbProjects.Contains(x)).ToList();
|
|
|
|
List<Guid> newUnscheduledProjectsFromServer = serverCalendarModel.UnscheduledProjects.Where(p =>
|
|
!existingUnscheduledProjects.Contains(p) &&
|
|
!serverCalendarModel.ManagedProjects.Contains(p)).ToList();
|
|
|
|
serverCalendarModel.UnscheduledProjects.RemoveAll(p => !existingUnscheduledProjects.Contains(p));
|
|
serverCalendarModel.UnscheduledProjects.AddRange(newUnscheduledProjectsFromServer); // Add recently added to live DB projects
|
|
serverCalendarModel.UnscheduledProjects.AddRange(clientOnlyUnscheduledProjects); // Add client only unscheduled projects (in live DB have teams and scenarios)
|
|
|
|
serverCalendarModel.QueuedProjects.RemoveAll(p => serverCalendarModel.ManagedProjects.Contains(p) ||
|
|
serverCalendarModel.UnscheduledProjects.Contains(p));
|
|
|
|
// Merge Unassigned Expenditures Projects
|
|
List<CategoryExpenditureInProject> existingUnassignedExpProjects = clientCalendarModel.UnassignedExpendituresProjects.Where(p =>
|
|
serverCalendarModel.ManagedProjects.Contains(p.ProjectId)).ToList();
|
|
|
|
serverCalendarModel.UnassignedExpendituresProjects.Clear();
|
|
serverCalendarModel.UnassignedExpendituresProjects.AddRange(existingUnassignedExpProjects);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates list of projects, which attached to the Mix, but were deleted from Live DB
|
|
/// </summary>
|
|
/// <param name="serverCalendarModel">Server model (receives projects deleted list)</param>
|
|
/// <param name="clientCalendarModel">Client model to compare with</param>
|
|
/// <param name="filterStartDate"></param>
|
|
/// <param name="filterEndDate"></param>
|
|
public void SetDeletedFromLiveDbProjects(MixSaveModel serverCalendarModel,
|
|
MixCalendarModel clientCalendarModel, DateTime filterStartDate, DateTime filterEndDate)
|
|
{
|
|
if ((serverCalendarModel == null) || (serverCalendarModel.Calendar == null) ||
|
|
(serverCalendarModel.Calendar.Projects == null) || (clientCalendarModel == null) ||
|
|
(clientCalendarModel.Projects == null))
|
|
return;
|
|
|
|
serverCalendarModel.Calendar.ModifiedObjects.DeletedProjects = null;
|
|
|
|
// SA. ENV-1246. Get list of projects, which exist in Mongo Mix, but no longer exist on server
|
|
List<MixProjectModel> projectModelsToCheck = clientCalendarModel.Projects.Where(p =>
|
|
!clientCalendarModel.QueuedProjects.Contains(new Guid(p.Key)) &&
|
|
!serverCalendarModel.Calendar.Projects.Keys.Contains(p.Key))
|
|
.Select(x => x.Value).ToList();
|
|
|
|
if (projectModelsToCheck.Count > 0)
|
|
{
|
|
List<Guid> modelTeams = serverCalendarModel.Calendar.Teams.Select(t => new Guid(t.Id)).ToList();
|
|
projectModelsToCheck.RemoveAll(x => !ProjectPassFilter(x, filterStartDate, filterEndDate, modelTeams));
|
|
}
|
|
|
|
if (projectModelsToCheck.Count > 0)
|
|
{
|
|
List<Guid> projectsToCheck = projectModelsToCheck.Select(p => p.Id).ToList();
|
|
List<Guid> existingProjectsInLiveDb = dbContext.Projects.Where(p => projectsToCheck.Contains(p.Id))
|
|
.Select(p => p.Id).ToList();
|
|
List<Guid> notFoundInLiveDbProjects = projectsToCheck.Where(x => !existingProjectsInLiveDb.Contains(x)).ToList();
|
|
|
|
if (notFoundInLiveDbProjects.Count > 0)
|
|
{
|
|
serverCalendarModel.Calendar.ModifiedObjects.DeletedProjects = clientCalendarModel.Projects.Where(p =>
|
|
notFoundInLiveDbProjects.Contains(new Guid(p.Key))).Select(p => p.Value.Name).ToList();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates live DB scenario versions for scenarios in mix model according to given version info data
|
|
/// </summary>
|
|
/// <param name="model">Mix model to update scenarios in</param>
|
|
/// <param name="versionInfo">New scenarios version info</param>
|
|
public static void SetScenarioVersions(MixSaveModel model, List<MixScenarioTimestampModel> versionInfo)
|
|
{
|
|
if ((model == null) || (model.Calendar == null) || (model.Calendar.Projects == null))
|
|
return;
|
|
|
|
if (versionInfo == null)
|
|
return;
|
|
|
|
var projectsToUpdate = versionInfo.Where(x => model.Calendar.Projects.ContainsKey(x.ProjectId.ToString()))
|
|
.Select(x => x.ProjectId.ToString()).ToList();
|
|
var versionInfoIndexed = versionInfo.ToDictionary(k => k.ProjectId.ToString(), v => v);
|
|
|
|
foreach (var projectIdAsText in projectsToUpdate)
|
|
{
|
|
var projectModel = model.Calendar.Projects[projectIdAsText];
|
|
var versionInfoForProject = versionInfoIndexed[projectIdAsText];
|
|
|
|
if ((projectModel != null) && (projectModel.Scenario != null) && (versionInfoForProject != null))
|
|
{
|
|
projectModel.Scenario.Id = versionInfoForProject.ScenarioId;
|
|
|
|
if (projectModel.Scenario.VersionInfo == null)
|
|
{
|
|
projectModel.Scenario.VersionInfo = new ItemVersionInfo();
|
|
}
|
|
projectModel.Scenario.VersionInfo.SourceVersion = versionInfoForProject.Timestamp;
|
|
projectModel.Scenario.VersionInfo.RmoVersion = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void MergeLayouts(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel)
|
|
{
|
|
if (serverCalendarModel == null)
|
|
throw new ArgumentException("serverCalendarModel");
|
|
|
|
if (serverCalendarModel.Projects == null)
|
|
throw new ArgumentException("serverCalendarModel.Projects");
|
|
|
|
if (serverCalendarModel.Teams == null)
|
|
throw new ArgumentException("serverCalendarModel.Teams");
|
|
|
|
if ((clientCalendarModel == null) || (clientCalendarModel.Projects == null) ||
|
|
(clientCalendarModel.Layout == null) || (clientCalendarModel.Layout.Count < 1))
|
|
return;
|
|
|
|
List<Guid> layoutTeams = serverCalendarModel.Teams.Select(t => new Guid(t.Id)).ToList();
|
|
serverCalendarModel.Layout = new List<MixTeamLayoutRowItem>();
|
|
|
|
foreach (Guid teamId in layoutTeams)
|
|
{
|
|
List<Guid> existingForTeam = serverCalendarModel.ManagedProjects.Where(p =>
|
|
(serverCalendarModel.Projects[p.ToString()].Teams != null) &&
|
|
(serverCalendarModel.Projects[p.ToString()].Teams.Contains(teamId)) &&
|
|
(clientCalendarModel.Layout != null) &&
|
|
clientCalendarModel.Layout.Any(l => (l.TeamId.Equals(teamId) && l.ProjectId.Equals(p)))
|
|
).ToList();
|
|
|
|
List<Guid> newForTeam = serverCalendarModel.ManagedProjects.Where(p =>
|
|
(serverCalendarModel.Projects[p.ToString()].Teams != null) &&
|
|
(serverCalendarModel.Projects[p.ToString()].Teams.Contains(teamId)) &&
|
|
!existingForTeam.Contains(p)
|
|
).ToList();
|
|
|
|
List<MixTeamLayoutRowItem> teamLayoutRowsForExisingProjects =
|
|
clientCalendarModel.Layout.Where(l => l.TeamId.Equals(teamId) && existingForTeam.Contains(l.ProjectId))
|
|
.Select(r => new MixTeamLayoutRowItem()
|
|
{
|
|
TeamId = teamId,
|
|
Row = r.Row,
|
|
ProjectId = r.ProjectId,
|
|
Index = r.Index
|
|
}).OrderBy(o1 => o1.Row).ThenBy(o2 => o2.Index).ToList();
|
|
|
|
List<MixTeamLayoutRowItem> teamLayoutRowsForNewProjects =
|
|
newForTeam.Select(pId => new MixTeamLayoutRowItem()
|
|
{
|
|
TeamId = teamId,
|
|
Row = -1,
|
|
ProjectId = pId,
|
|
Index = 0
|
|
}).ToList();
|
|
|
|
// Renum row numbers for result layout rows
|
|
int lastOldRowNum = -1;
|
|
int newRowNum = -1;
|
|
int newColNum = 0;
|
|
|
|
foreach (MixTeamLayoutRowItem currentLayoutRow in teamLayoutRowsForExisingProjects)
|
|
{
|
|
if (lastOldRowNum != currentLayoutRow.Row)
|
|
{
|
|
// Project is located at new line
|
|
lastOldRowNum = currentLayoutRow.Row;
|
|
|
|
newRowNum++;
|
|
newColNum = 0;
|
|
}
|
|
else
|
|
{
|
|
// Projects is located at the same line with the previous one
|
|
newColNum++;
|
|
}
|
|
|
|
currentLayoutRow.Row = newRowNum;
|
|
currentLayoutRow.Index = newColNum;
|
|
}
|
|
|
|
// Set row numbers for new project layout rows
|
|
foreach (MixTeamLayoutRowItem currentLayoutRow in teamLayoutRowsForNewProjects)
|
|
{
|
|
newRowNum++;
|
|
currentLayoutRow.Row = newRowNum;
|
|
currentLayoutRow.Index = 0;
|
|
}
|
|
|
|
serverCalendarModel.Layout.AddRange(teamLayoutRowsForExisingProjects);
|
|
serverCalendarModel.Layout.AddRange(teamLayoutRowsForNewProjects);
|
|
}
|
|
}
|
|
|
|
protected void MergeProjectVersions(MixProjectModel serverProject, MixProjectModel clientProject)
|
|
{
|
|
ItemVersionInfo versionInfo = new ItemVersionInfo
|
|
{
|
|
ChangedInMain = false,
|
|
ChangedInRmo = false,
|
|
RmoVersion = 1,
|
|
SourceVersion = null
|
|
};
|
|
|
|
if ((serverProject.Scenario != null) && (clientProject.Scenario == null))
|
|
{
|
|
// Recently added to the Mix project
|
|
if (serverProject.Scenario.VersionInfo != null)
|
|
{
|
|
versionInfo.SourceVersion = serverProject.Scenario.VersionInfo.SourceVersion;
|
|
versionInfo.ChangedInMain = true;
|
|
}
|
|
|
|
serverProject.Scenario.VersionInfo = versionInfo;
|
|
}
|
|
|
|
if ((serverProject.Scenario != null) && (clientProject.Scenario != null))
|
|
{
|
|
// Project with active scenarios exist in both databases
|
|
if (clientProject.Scenario.VersionInfo != null)
|
|
{
|
|
versionInfo.RmoVersion = clientProject.Scenario.VersionInfo.RmoVersion;
|
|
versionInfo.SourceVersion = clientProject.Scenario.VersionInfo.SourceVersion;
|
|
versionInfo.ChangedInRmo = versionInfo.RmoVersion > 1;
|
|
versionInfo.ChangedInMain =
|
|
!versionInfo.ChangedInRmo &&
|
|
((serverProject.Scenario.VersionInfo != null) &&
|
|
(
|
|
serverProject.Scenario.VersionInfo.SourceVersion.HasValue &&
|
|
clientProject.Scenario.VersionInfo.SourceVersion.HasValue &&
|
|
(serverProject.Scenario.VersionInfo.SourceVersion.Value !=
|
|
clientProject.Scenario.VersionInfo.SourceVersion.Value)
|
|
) ||
|
|
(serverProject.Scenario.VersionInfo.SourceVersion.HasValue &&
|
|
!clientProject.Scenario.VersionInfo.SourceVersion.HasValue
|
|
) ||
|
|
(!serverProject.Scenario.VersionInfo.SourceVersion.HasValue &&
|
|
clientProject.Scenario.VersionInfo.SourceVersion.HasValue
|
|
));
|
|
}
|
|
|
|
serverProject.Scenario = clientProject.Scenario.Clone();
|
|
serverProject.Scenario.VersionInfo = versionInfo;
|
|
}
|
|
|
|
if ((serverProject.Scenario == null) && (clientProject.Scenario != null))
|
|
{
|
|
// Project's active scenario was deleted from LiveDB or deactivated, while in the Mix
|
|
// this project still has scenario
|
|
if (clientProject.Scenario.VersionInfo != null)
|
|
{
|
|
versionInfo.RmoVersion = clientProject.Scenario.VersionInfo.RmoVersion;
|
|
versionInfo.SourceVersion = clientProject.Scenario.VersionInfo.SourceVersion;
|
|
versionInfo.ChangedInRmo = versionInfo.RmoVersion > 1;
|
|
versionInfo.ChangedInMain = !versionInfo.ChangedInRmo;
|
|
}
|
|
|
|
serverProject.Scenario = clientProject.Scenario.Clone();
|
|
serverProject.Scenario.VersionInfo = versionInfo;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs merging of info about scenario versions in server and cleint models
|
|
/// </summary>
|
|
/// <param name="serverModel"></param>
|
|
/// <param name="clientModel"></param>
|
|
/// <returns>ItemVersionInfo struct for destination model ready-to-use</returns>
|
|
/// <remarks>SA. ENV-1085</remarks>
|
|
protected ItemVersionInfo MergeScenarioVersionData(ItemVersionInfo serverModel, ItemVersionInfo clientModel)
|
|
{
|
|
ItemVersionInfo result = new ItemVersionInfo();
|
|
|
|
if ((serverModel != null) && (clientModel != null))
|
|
{
|
|
result.SourceVersion = clientModel.SourceVersion.HasValue ?
|
|
clientModel.SourceVersion.Value : serverModel.SourceVersion;
|
|
result.RmoVersion = clientModel.RmoVersion;
|
|
result.ChangedInMain = serverModel.SourceVersion.HasValue && clientModel.SourceVersion.HasValue &&
|
|
(serverModel.SourceVersion != clientModel.SourceVersion);
|
|
result.ChangedInRmo = clientModel.RmoVersion > 1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns TRUE, if project passes through Mix filter
|
|
/// </summary>
|
|
/// <param name="projectModel">Project to check</param>
|
|
/// <param name="startDate">Filter start date</param>
|
|
/// <param name="endDate">Filter end date</param>
|
|
/// <param name="teams">Filter teams</param>
|
|
/// <returns></returns>
|
|
protected bool ProjectPassFilter(MixProjectModel projectModel, DateTime startDate, DateTime endDate,
|
|
List<Guid> teams)
|
|
{
|
|
bool result = false;
|
|
|
|
if ((projectModel != null) && (projectModel.Teams != null) && (teams != null))
|
|
{
|
|
// We don't check dates, because, a project is included in a Mix, if it suits Mix filter teams.
|
|
// Dates only affect on projects sorting: Managed collection or Queued Projects
|
|
List<Guid> commonTeams = projectModel.Teams.Intersect(teams).ToList();
|
|
return (commonTeams.Count > 0);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
protected long GetUnixDate(DateTime? date)
|
|
{
|
|
return date.HasValue ? Utils.ConvertToUnixDate(date.Value) : 0;
|
|
}
|
|
}
|
|
} |