422 lines
16 KiB
C#
422 lines
16 KiB
C#
using EnVisage.Code.DAL.Mongo;
|
|
using EnVisage.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
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 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);
|
|
}
|
|
}
|
|
|
|
public void MergeCalendars(MixSaveModel serverModel, MixSaveModel clientModel,
|
|
DateTime periodStartWeekending, DateTime periodEndWeekending)
|
|
{
|
|
if ((serverModel == null) || (serverModel.Calendar == null))
|
|
return;
|
|
|
|
if ((clientModel == null) || (clientModel.Calendar == null))
|
|
return;
|
|
|
|
// Convert period bound dates to Unix
|
|
long startDateUnix = GetUnixDate(periodStartWeekending);
|
|
long endDateUnix = GetUnixDate(periodEndWeekending);
|
|
|
|
this.MergeTeamCollections(serverModel.Calendar, clientModel.Calendar);
|
|
this.MergeProjectCollections(serverModel.Calendar, clientModel.Calendar);
|
|
|
|
this.SortProjects(serverModel.Calendar, startDateUnix, endDateUnix);
|
|
this.MergeProjectLists(serverModel.Calendar, clientModel.Calendar);
|
|
this.MergeLayouts(serverModel.Calendar, clientModel.Calendar);
|
|
}
|
|
|
|
protected void MergeProjectCollections(MixCalendarModel serverCalendarModel,
|
|
MixCalendarModel clientCalendarModel)
|
|
{
|
|
if (serverCalendarModel == null)
|
|
throw new ArgumentNullException("serverCalendarModel");
|
|
|
|
if (serverCalendarModel.Projects == null)
|
|
serverCalendarModel.Projects = new Dictionary<string, MixProjectModel>();
|
|
|
|
if ((clientCalendarModel == null) || (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);
|
|
}
|
|
}
|
|
|
|
protected void MergeSingleProjectModels(MixProjectModel serverProjectModel, MixProjectModel clientProjectModel)
|
|
{
|
|
if (clientProjectModel.Scenario != null)
|
|
serverProjectModel.Scenario = clientProjectModel.Scenario.Clone();
|
|
else
|
|
serverProjectModel.Scenario = null;
|
|
|
|
if (clientProjectModel.Teams != null)
|
|
{
|
|
// Merging of project Teams
|
|
serverProjectModel.Teams = new List<Guid>();
|
|
serverProjectModel.Teams.AddRange(clientProjectModel.Teams);
|
|
}
|
|
}
|
|
|
|
protected void MergeTeamCollections(MixCalendarModel serverCalendarModel, MixCalendarModel clientCalendarModel)
|
|
{
|
|
if (serverCalendarModel.Teams == null)
|
|
throw new ArgumentNullException("serverCalendarModel.Teams");
|
|
|
|
if (clientCalendarModel.Teams == null)
|
|
return;
|
|
|
|
// 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 (MixTeamModel clientTeam in clientCalendarModel.Teams)
|
|
{
|
|
MixTeamModel serverTeam = serverCalendarModel.Teams.FirstOrDefault(t => t.Id.Equals(clientTeam.Id));
|
|
|
|
if ((serverTeam != null) && (serverTeam.Id.Length > 0))
|
|
{
|
|
MergeSingleTeamModels(serverTeam, clientTeam);
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
if (serverTeamModel == null)
|
|
throw new ArgumentNullException("serverTeamModel");
|
|
|
|
if (clientTeamModel == null)
|
|
throw new ArgumentNullException("clientTeamModel");
|
|
|
|
serverTeamModel.CompanyId = clientTeamModel.CompanyId;
|
|
serverTeamModel.CostCenterId = clientTeamModel.CostCenterId;
|
|
serverTeamModel.Name = clientTeamModel.Name;
|
|
serverTeamModel.UserId = clientTeamModel.UserId;
|
|
|
|
serverTeamModel.PlannedCapacity =
|
|
(clientTeamModel.PlannedCapacity != null) ?
|
|
clientTeamModel.PlannedCapacity.Select(pc => new MixTeamCapacity()
|
|
{
|
|
Id = pc.Id,
|
|
ExpCatId = pc.ExpCatId,
|
|
Values = (pc.Values != null) ? pc.Values.Select(k =>
|
|
new KeyValuePair<string, decimal>(k.Key, k.Value))
|
|
.ToDictionary(k => k.Key, v => v.Value) : new Dictionary<string, decimal>()
|
|
}).ToList() : null;
|
|
|
|
serverTeamModel.ExpCategories =
|
|
(clientTeamModel.ExpCategories != null) ?
|
|
clientTeamModel.ExpCategories.Select(k =>
|
|
new KeyValuePair<string, ActivityExpCategoryFooterModel>(k.Key, new ActivityExpCategoryFooterModel()
|
|
{
|
|
Id = k.Value.Id,
|
|
Name = k.Value.Name,
|
|
UomValue = k.Value.UomValue,
|
|
|
|
ActualCapacityValues = (k.Value.ActualCapacityValues != null) ?
|
|
k.Value.ActualCapacityValues.Select(ac =>
|
|
new KeyValuePair<string, decimal>(ac.Key, ac.Value))
|
|
.ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary<string, decimal>(),
|
|
|
|
AllocatedCapacity = (k.Value.AllocatedCapacity != null) ?
|
|
k.Value.AllocatedCapacity.Select(ac =>
|
|
new KeyValuePair<string, decimal>(ac.Key, ac.Value))
|
|
.ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary<string, decimal>(),
|
|
|
|
NeedCapacity = (k.Value.NeedCapacity != null) ?
|
|
k.Value.NeedCapacity.Select(ac =>
|
|
new KeyValuePair<string, decimal>(ac.Key, ac.Value))
|
|
.ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary<string, decimal>(),
|
|
|
|
PlannedCapacityValues = (k.Value.PlannedCapacityValues != null) ?
|
|
k.Value.PlannedCapacityValues.Select(ac =>
|
|
new KeyValuePair<string, decimal>(ac.Key, ac.Value))
|
|
.ToDictionary(ac => ac.Key, ac => ac.Value) : new Dictionary<string, decimal>(),
|
|
|
|
Resources = (k.Value.Resources != null) ?
|
|
k.Value.Resources.Select(ac =>
|
|
new KeyValuePair<string, ActivityResourceFooterModel>(ac.Key, new ActivityResourceFooterModel()
|
|
{
|
|
Id = ac.Value.Id,
|
|
Name = ac.Value.Name,
|
|
|
|
AllocatedCapacity = (ac.Value.AllocatedCapacity != null) ?
|
|
ac.Value.AllocatedCapacity.Select(r =>
|
|
new KeyValuePair<string, decimal>(r.Key, r.Value))
|
|
.ToDictionary(r => r.Key, r => r.Value) : new Dictionary<string, decimal>(),
|
|
|
|
TotalCapacity = (ac.Value.TotalCapacity != null) ?
|
|
ac.Value.TotalCapacity.Select(r =>
|
|
new KeyValuePair<string, decimal>(r.Key, r.Value))
|
|
.ToDictionary(r => r.Key, r => r.Value) : new Dictionary<string, decimal>()
|
|
})).ToDictionary(r => r.Key, r => r.Value) : new Dictionary<string, ActivityResourceFooterModel>()
|
|
})).ToDictionary(k => k.Key, v => v.Value) : null;
|
|
}
|
|
|
|
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>(); // SA. ENV-1210
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// 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.Where(p =>
|
|
serverCalendarModel.UnscheduledProjects.Contains(p)).ToList();
|
|
|
|
List<Guid> newUnscheduledProjectsFromServer = clientCalendarModel.UnscheduledProjects.Where(p =>
|
|
!existingUnscheduledProjects.Contains(p) &&
|
|
!serverCalendarModel.ManagedProjects.Contains(p)).ToList();
|
|
|
|
serverCalendarModel.UnscheduledProjects.RemoveAll(p => !existingUnscheduledProjects.Contains(p));
|
|
serverCalendarModel.UnscheduledProjects.AddRange(newUnscheduledProjectsFromServer);
|
|
|
|
serverCalendarModel.QueuedProjects.RemoveAll(p => serverCalendarModel.ManagedProjects.Contains(p) ||
|
|
serverCalendarModel.UnscheduledProjects.Contains(p));
|
|
|
|
// Merge Unassigned Expenditures Projects lists (ENV-1210)
|
|
List<CategoryExpenditureInProject> existingUnassignedExpProjects = clientCalendarModel.UnassignedExpendituresProjects.Where(p =>
|
|
serverCalendarModel.Projects.ContainsKey(p.ProjectId.ToString())).ToList();
|
|
|
|
serverCalendarModel.UnassignedExpendituresProjects.Clear();
|
|
serverCalendarModel.UnassignedExpendituresProjects.AddRange(existingUnassignedExpProjects);
|
|
}
|
|
|
|
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 long GetUnixDate(DateTime? date)
|
|
{
|
|
return date.HasValue ? Utils.ConvertToUnixDate(date.Value) : 0;
|
|
}
|
|
}
|
|
} |