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 { /// /// Does merging of client changes model to server model /// 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(); List usersToAppend = clientModel.Users.Where(u => !serverModel.Users.Contains(u)).ToList(); serverModel.Users.AddRange(usersToAppend); } } /// /// Merges two collections of data /// /// Actual data taken from alive database /// Mix data taken from Mongo /// /// 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(); if (clientCalendarModel?.Projects == null) return; // Get project list to update (exist in both models) List 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); } } /// /// ??? /// /// ? /// ? /// A list of Teams from Mix filter which exist in SQL database. /// A list of Teams from Mix filter which exist in Mongo database. protected void MergeSingleProjectModels(MixProjectModel serverProjectModel, MixProjectModel clientProjectModel, List serverMixTeams, List clientMixTeams) { MergeProjectVersions(serverProjectModel, clientProjectModel); if ((clientProjectModel.Teams != null) && (serverMixTeams != null) && (clientMixTeams != null)) { // Merging of project Teams List serverTeamsInMix = serverMixTeams.Select(t => new Guid(t.Id)).ToList(); List clientNewTeamsInMix = clientMixTeams.Where(t => t.IsNew).Select(t => new Guid(t.Id)).ToList(); List teamsForProject = new List(); // 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 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(); 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(ac.Key, ac.Value)) .ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary(), NeedCapacity = (category.NeedCapacity != null) ? category.NeedCapacity.Select(ac => new KeyValuePair(ac.Key, ac.Value)) .ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary(), ActualCapacityValues = new Dictionary(), PlannedCapacityValues = new Dictionary(), Resources = new Dictionary() }; 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(r.Key, r.Value)) .ToDictionary(r => r.Key, r => r.Value) : new Dictionary(), TotalCapacity = new Dictionary(), NonProjectTime = new Dictionary() }; // 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(); 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(); model.UnscheduledProjects = new List(); model.QueuedProjects = new List(); model.UnassignedExpendituresProjects = new List(); 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); } } /// /// Merges collections of projects /// /// Actual data taken from alive database /// Mix data taken from Mongo 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 existingManagedProjects = clientCalendarModel.ManagedProjects.Where(p => serverCalendarModel.ManagedProjects.Contains(p)).ToList(); List 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 existingUnscheduledProjects = clientCalendarModel.UnscheduledProjects.Intersect(serverCalendarModel.UnscheduledProjects).ToList(); List clientOnlyUnscheduledProjects = clientCalendarModel.UnscheduledProjects.Except(serverCalendarModel.UnscheduledProjects) .Where(x => allLiveDbProjects.Contains(x)).ToList(); List 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 existingUnassignedExpProjects = clientCalendarModel.UnassignedExpendituresProjects.Where(p => serverCalendarModel.ManagedProjects.Contains(p.ProjectId)).ToList(); serverCalendarModel.UnassignedExpendituresProjects.Clear(); serverCalendarModel.UnassignedExpendituresProjects.AddRange(existingUnassignedExpProjects); } /// /// Creates list of projects, which attached to the Mix, but were deleted from Live DB /// /// Server model (receives projects deleted list) /// Client model to compare with /// /// 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 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 modelTeams = serverCalendarModel.Calendar.Teams.Select(t => new Guid(t.Id)).ToList(); projectModelsToCheck.RemoveAll(x => !ProjectPassFilter(x, filterStartDate, filterEndDate, modelTeams)); } if (projectModelsToCheck.Count > 0) { List projectsToCheck = projectModelsToCheck.Select(p => p.Id).ToList(); List existingProjectsInLiveDb = dbContext.Projects.Where(p => projectsToCheck.Contains(p.Id)) .Select(p => p.Id).ToList(); List 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(); } } } /// /// Updates live DB scenario versions for scenarios in mix model according to given version info data /// /// Mix model to update scenarios in /// New scenarios version info public static void SetScenarioVersions(MixSaveModel model, List 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 layoutTeams = serverCalendarModel.Teams.Select(t => new Guid(t.Id)).ToList(); serverCalendarModel.Layout = new List(); foreach (Guid teamId in layoutTeams) { List 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 newForTeam = serverCalendarModel.ManagedProjects.Where(p => (serverCalendarModel.Projects[p.ToString()].Teams != null) && (serverCalendarModel.Projects[p.ToString()].Teams.Contains(teamId)) && !existingForTeam.Contains(p) ).ToList(); List 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 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; } } /// /// Performs merging of info about scenario versions in server and cleint models /// /// /// /// ItemVersionInfo struct for destination model ready-to-use /// SA. ENV-1085 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; } /// /// Returns TRUE, if project passes through Mix filter /// /// Project to check /// Filter start date /// Filter end date /// Filter teams /// protected bool ProjectPassFilter(MixProjectModel projectModel, DateTime startDate, DateTime endDate, List 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 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; } } }