623 lines
23 KiB
C#
623 lines
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Linq;
|
|
using System.Web;
|
|
using EnVisage.Models;
|
|
using System.Data.Entity.Infrastructure;
|
|
using jQuery.DataTables.Mvc;
|
|
using System.Data.SqlClient;
|
|
using System.Data.Entity.Core.Objects;
|
|
using System.Data;
|
|
|
|
namespace EnVisage.Code.BLL
|
|
{
|
|
public class SkillsMatrixManager
|
|
{
|
|
public class MatrixFilterInternal
|
|
{
|
|
public List<Guid> Teams = new List<Guid>();
|
|
public List<Guid> Resources = new List<Guid>();
|
|
public List<Guid> Skills = new List<Guid>();
|
|
public List<Guid> SkillGroups = new List<Guid>();
|
|
public List<int> Levels = new List<int>();
|
|
public bool? IncludeInterested;
|
|
public bool SkillWithDataOnly = false;
|
|
}
|
|
|
|
public SkillsMatrixManager(EnVisageEntities dbContext)
|
|
{
|
|
this.dbContext = dbContext;
|
|
}
|
|
|
|
protected EnVisageEntities dbContext = null;
|
|
|
|
public void Save(SkillsMatrixSaveModel model)
|
|
{
|
|
if (model == null)
|
|
throw new ArgumentNullException("model");
|
|
|
|
if (model.DatePoint < Utils.ConvertToUnixDate(Constants.UnixEpochDate))
|
|
throw new ArgumentException("model.DatePoint");
|
|
|
|
if (model.Values != null)
|
|
{
|
|
#region Saving levels
|
|
|
|
DateTime datePointUtc = Utils.ConvertFromUnixDate(model.DatePoint);
|
|
datePointUtc = datePointUtc.ToUniversalTime();
|
|
datePointUtc = new DateTime(datePointUtc.Year, datePointUtc.Month, datePointUtc.Day);
|
|
|
|
List<SkillsMatrixSaveModel.DataItem> levelsToSave =
|
|
model.Values.Where(k => (k.Value != null) && k.Value.LevelChanged).Select(x => x.Value).ToList();
|
|
|
|
foreach (SkillsMatrixSaveModel.DataItem item in levelsToSave)
|
|
{
|
|
Guid newId = Guid.NewGuid();
|
|
Skill2Resource rec = new Skill2Resource()
|
|
{
|
|
Id = newId,
|
|
Type = (short)model.DataType,
|
|
EffectiveDate = datePointUtc,
|
|
ResourceId = item.ResourceId,
|
|
SkillId = item.SkillId,
|
|
Level = (short?)item.Level,
|
|
Interested = item.Interested,
|
|
DateCreated = DateTime.UtcNow
|
|
};
|
|
dbContext.Skill2Resource.Add(rec);
|
|
}
|
|
|
|
#endregion
|
|
#region Saving Skill Interests
|
|
|
|
List<SkillsMatrixSaveModel.DataItem> interestsToSave =
|
|
model.Values.Where(k => (k.Value != null) && k.Value.InterestChanged).Select(x => x.Value).ToList();
|
|
|
|
foreach (SkillsMatrixSaveModel.DataItem item in interestsToSave)
|
|
{
|
|
var recsToUpdate = dbContext.Skill2Resource.Where(x =>
|
|
x.SkillId.Equals(item.SkillId) && x.ResourceId.Equals(item.ResourceId)).ToList();
|
|
recsToUpdate.ForEach(x => x.Interested = item.Interested);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
protected List<VW_Skill2Resource> GetPieChartData(SkillMatrixTimeLayer timeLayer, Skill2ResourceType dt, MatrixFilterInternal innerFilter)
|
|
{
|
|
var qry = GetSkillMatrixBaseDataQuery(timeLayer, dt);
|
|
qry = ApplyFilter(qry, innerFilter);
|
|
if (innerFilter.Levels.Count > 0)
|
|
qry = qry.Where(x => innerFilter.Levels.Contains((int)x.Level));
|
|
if (innerFilter.IncludeInterested.HasValue)
|
|
qry = qry.Where(x => x.Interested == innerFilter.IncludeInterested.Value);
|
|
if (innerFilter.Skills.Count > 0)
|
|
qry = qry.Where(x => innerFilter.Skills.Contains(x.SkillId));
|
|
if (innerFilter.SkillGroups.Count > 0)
|
|
qry = qry.Where(x => innerFilter.SkillGroups.Contains(x.SkillGroupId));
|
|
|
|
return qry.ToList();
|
|
}
|
|
|
|
public SkillsMatrixSaveModel LoadSkillMatrix(SkillMatrixTimeLayer timeLayer, Skill2ResourceType DataType,
|
|
DateTime DatePoint, Guid userId, bool withChartData, SkillsMaxtrixFilterModel filter = null)
|
|
{
|
|
DateTime datePoint = DatePoint.ToUniversalTime().Date;
|
|
SkillsMatrixSaveModel result = new SkillsMatrixSaveModel()
|
|
{
|
|
DataType = DataType,
|
|
DatePoint = Utils.ConvertToUnixDate(datePoint)
|
|
};
|
|
|
|
// Process incoming filter. Convert it to business-level filtering rules
|
|
MatrixFilterInternal innerFilter = this.ProcessFilter(filter, userId);
|
|
|
|
var prManager = new PeopleResourcesManager(dbContext);
|
|
var teamResourceModels = prManager.LoadPeopleResourcesNonStrict(innerFilter.Teams, innerFilter.Resources, datePoint);
|
|
var resourcesInMatrix = (teamResourceModels != null) ? teamResourceModels.Select(x => x.Id).ToList() : null;
|
|
|
|
var qry = GetSkillMatrixBaseDataQuery(timeLayer, DataType);
|
|
qry = ApplyFilter(qry, innerFilter);
|
|
|
|
if (resourcesInMatrix != null)
|
|
qry = qry.Where(x => resourcesInMatrix.Contains(x.ResourceId));
|
|
|
|
List<VW_Skill2Resource> skillsData = qry.ToList();
|
|
|
|
#region Fill Model with skills and skill groups
|
|
|
|
List<Skill> allSkills = null;
|
|
|
|
if (innerFilter.SkillWithDataOnly)
|
|
{
|
|
// Retrive only skills with data
|
|
var skillsWithData = skillsData.Select(x => x.SkillId).Distinct();
|
|
var skillGroupsWithData = skillsData.Select(x => x.SkillGroupId).Distinct();
|
|
allSkills = dbContext.Skills.AsNoTracking()
|
|
.Where(x => skillsWithData.Contains(x.Id) || skillGroupsWithData.Contains(x.Id))
|
|
.Distinct().ToList();
|
|
}
|
|
else
|
|
{
|
|
// Retrive all skills
|
|
allSkills = dbContext.Skills.AsNoTracking().ToList();
|
|
}
|
|
|
|
IEnumerable<Guid> matrixSkillGroups = allSkills.Where(x => !x.ParentId.HasValue &&
|
|
((innerFilter.SkillGroups.Count < 1) || innerFilter.SkillGroups.Contains(x.Id))).Select(x => x.Id);
|
|
IEnumerable<Guid> matrixSkills = allSkills.Where(x =>
|
|
(x.ParentId.HasValue || (!x.ParentId.HasValue && !x.HasChildren)) &&
|
|
((innerFilter.Skills.Count < 1) || innerFilter.Skills.Contains(x.Id)))
|
|
.Select(x => x.Id);
|
|
|
|
result.SkillGroups =
|
|
allSkills.Where(x => matrixSkillGroups.Contains(x.Id))
|
|
.Select(g =>
|
|
new SkillsMatrixSaveModel.SkillGroupDisplayModel()
|
|
{
|
|
Id = g.Id,
|
|
Name = g.Name,
|
|
Skills = allSkills.Where(s =>
|
|
((s.ParentId.HasValue && s.ParentId.Value.Equals(g.Id)) || (s.Id.Equals(g.Id))) &&
|
|
matrixSkills.Contains(s.Id)).OrderBy(s => s.Name)
|
|
.Select(s => new SkillsMatrixSaveModel.SkillDisplayModel()
|
|
{
|
|
// SA. If values assigned directly to Skill Group, the virtual Skill is created.
|
|
// Its Id is the same, as its parent group has. Virtual skill doesn't has name, and has
|
|
// attribute IsVirtual=true
|
|
Id = s.Id,
|
|
Name = (s.Id != g.Id) ? s.Name : String.Empty,
|
|
SkillGroupId = g.Id,
|
|
IsVirtual = (s.Id == g.Id)
|
|
}).OrderBy(s => s.Name).ToList()
|
|
}).OrderBy(g => g.Name).ToList();
|
|
|
|
#endregion
|
|
|
|
if (withChartData)
|
|
{
|
|
const int RecordCount = 10;
|
|
#region Bar Chart Data
|
|
var BarData = new SkillsMatrixBarChartModel();
|
|
bool IncludeInterested = filter.IncludeInterested.HasValue && filter.IncludeInterested.Value;
|
|
List<VW_Skill2Resource> GraphData = skillsData;
|
|
if (innerFilter.Levels.Count > 0)
|
|
{
|
|
IEnumerable<int?> nullableLevels = innerFilter.Levels.Select(v => new int?(v));
|
|
GraphData = GraphData.Where(x => nullableLevels.Contains(x.Level)).ToList();
|
|
}
|
|
if (innerFilter.IncludeInterested.HasValue)
|
|
GraphData = GraphData.Where(x => x.Interested == innerFilter.IncludeInterested.Value).ToList();
|
|
if (innerFilter.Skills.Count > 0)
|
|
GraphData = GraphData.Where(x => innerFilter.Skills.Contains(x.SkillId)).ToList();
|
|
if (innerFilter.SkillGroups.Count > 0)
|
|
GraphData = GraphData.Where(x => innerFilter.SkillGroups.Contains(x.SkillGroupId)).ToList();
|
|
|
|
|
|
BarData.Colors = new string[] { "#eeeeee", "#deebf7", "#bdd7ee", "#9bc2e6", "#2f75b5" };
|
|
var skillTitles = new string[] { "Cannot Perform", "Knows All Elements", "Can Complete the Basics", "Proficient", "Exceptional" };
|
|
var sortedGroups = GraphData.GroupBy(r => r.SkillGroupId)
|
|
.Select(g => new
|
|
{
|
|
id = g.Key,
|
|
count = g.Count(),
|
|
level0 = g.Where(p => p.Level == 0).Count(),
|
|
level1 = g.Where(p => p.Level == 1).Count(),
|
|
level2 = g.Where(p => p.Level == 2).Count(),
|
|
level3 = g.Where(p => p.Level == 3).Count(),
|
|
level4 = g.Where(p => p.Level == 4).Count()
|
|
})
|
|
.OrderByDescending(l => l.count).Take(RecordCount).ToArray();
|
|
|
|
// Prepare data for graphs and diagramms
|
|
var _GData = new List<int[]>[5];
|
|
BarData.GTitles = new List<List<object>>();
|
|
if (sortedGroups.Count() > 0)
|
|
BarData.GMaxVal = sortedGroups[0].count;
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
_GData[i] = new List<int[]>();
|
|
}
|
|
var j = 1;
|
|
foreach (var item in sortedGroups)
|
|
{
|
|
var title = new List<object>();
|
|
title.Add(j + 0.25);//label width fix
|
|
title.Add(result.SkillGroups.Where(x => x.Id == item.id).FirstOrDefault().Name);
|
|
BarData.GTitles.Add(title);
|
|
_GData[0].Add(new int[] { j, item.level0 });
|
|
_GData[1].Add(new int[] { j, item.level1 });
|
|
_GData[2].Add(new int[] { j, item.level2 });
|
|
_GData[3].Add(new int[] { j, item.level3 });
|
|
_GData[4].Add(new int[] { j, item.level4 });
|
|
j++;
|
|
}
|
|
|
|
var sortedTop = GraphData.GroupBy(r => r.SkillId).Select(g => new
|
|
{
|
|
id = g.Key,
|
|
count = g.Count(),
|
|
level0 = g.Where(p => p.Level == 0).Count(),
|
|
level1 = g.Where(p => p.Level == 1).Count(),
|
|
level2 = g.Where(p => p.Level == 2).Count(),
|
|
level3 = g.Where(p => p.Level == 3).Count(),
|
|
level4 = g.Where(p => p.Level == 4).Count()
|
|
})
|
|
.OrderByDescending(l => l.count).Take(RecordCount).ToArray();
|
|
var _Data = new List<int[]>[5];
|
|
if (sortedTop.Length > 0)
|
|
BarData.MaxVal = sortedTop[0].count;
|
|
BarData.Data = new List<object>();
|
|
BarData.GroupData = new List<object>();
|
|
BarData.Titles = new List<List<object>>();
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
_Data[i] = new List<int[]>();
|
|
}
|
|
j = 1;
|
|
foreach (var item in sortedTop)
|
|
{
|
|
var title = new List<object>();
|
|
title.Add(j + 0.25);//label width fix
|
|
title.Add(allSkills.Where(x => x.Id == item.id).FirstOrDefault().Name);
|
|
BarData.Titles.Add(title);
|
|
_Data[0].Add(new int[] { j, item.level0 });
|
|
_Data[1].Add(new int[] { j, item.level1 });
|
|
_Data[2].Add(new int[] { j, item.level2 });
|
|
_Data[3].Add(new int[] { j, item.level3 });
|
|
_Data[4].Add(new int[] { j, item.level4 });
|
|
j++;
|
|
}
|
|
var z = _Data.Length;
|
|
foreach (var item in _Data.Reverse())
|
|
{
|
|
BarData.Data.Add(new
|
|
{
|
|
label = skillTitles[z - 1],
|
|
data = item,
|
|
color = BarData.Colors[z - 1],
|
|
stack = true,
|
|
bars = new { show = true, fill = 1, barWidth = 0.5, align = "center", lineWidth = 0 }
|
|
});
|
|
z--;
|
|
}
|
|
z = _GData.Length;
|
|
foreach (var item in _GData.Reverse())
|
|
{
|
|
BarData.GroupData.Add(new
|
|
{
|
|
label = skillTitles[z - 1],
|
|
data = item,
|
|
color = BarData.Colors[z - 1],
|
|
stack = true,
|
|
bars = new { show = true, fill = 1, barWidth = 0.5, align = "center", lineWidth = 0 }
|
|
});
|
|
z--;
|
|
}
|
|
result.BarGraphData = BarData;
|
|
|
|
#endregion
|
|
#region Pie Chart Data;
|
|
|
|
var PieData = new SkillsMatrixPieChartModel();
|
|
List<VW_Skill2Resource> pastData = (timeLayer == SkillMatrixTimeLayer.Past) ? GraphData : GetPieChartData(SkillMatrixTimeLayer.Past, Skill2ResourceType.Actual, innerFilter);
|
|
List<VW_Skill2Resource> presData = (timeLayer == SkillMatrixTimeLayer.Present) ? GraphData : GetPieChartData(SkillMatrixTimeLayer.Present, Skill2ResourceType.Actual, innerFilter);
|
|
List<VW_Skill2Resource> futureData = (timeLayer == SkillMatrixTimeLayer.Future) ? GraphData : GetPieChartData(SkillMatrixTimeLayer.Future, Skill2ResourceType.Planned, innerFilter);
|
|
|
|
PieData.PastData = GetMainToOtherDistribution(pastData, allSkills, false);
|
|
PieData.PresentData = GetMainToOtherDistribution(presData, allSkills, false);
|
|
PieData.FutureData = GetMainToOtherDistribution(futureData, allSkills, false);
|
|
|
|
PieData.PastGroupedData = GetMainToOtherDistribution(pastData, allSkills, true);
|
|
PieData.PresentGroupedData = GetMainToOtherDistribution(presData, allSkills, true);
|
|
PieData.FutureGroupedData = GetMainToOtherDistribution(futureData, allSkills, true);
|
|
|
|
result.PieGraphData = PieData;
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Fill Model with Resources and Teams;
|
|
|
|
// load all PeopleResource2Team relations, which were up to date at 'datePoint' date
|
|
var allResources = new HashSet<Guid>();
|
|
var allTeams = new HashSet<Guid>();
|
|
// prepare model.Teams and model.Resources collections
|
|
if (teamResourceModels != null)
|
|
{
|
|
foreach (var item in teamResourceModels)
|
|
{
|
|
// add resource to model.Resources collection if it does not exist there yet
|
|
if (!allResources.Contains(item.Id))
|
|
{
|
|
allResources.Add(item.Id);
|
|
result.Resources.Add(new SkillsMatrixSaveModel.Resource
|
|
{
|
|
Id = item.Id,
|
|
FirstName = item.FirstName,
|
|
LastName = item.LastName,
|
|
Teams = new List<Guid>()
|
|
});
|
|
}
|
|
// add Team to model.Teams collection if it does not exist there yet
|
|
if (!allTeams.Contains(item.Team.Id))
|
|
{
|
|
allTeams.Add(item.Team.Id);
|
|
result.Teams.Add(new SkillsMatrixSaveModel.Team
|
|
{
|
|
Id = item.Team.Id,
|
|
Name = item.Team.Name,
|
|
Resources = new List<Guid> {
|
|
item.Id
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// add resource to existing team record in model.Teams
|
|
var teamItem = result.Teams.FirstOrDefault(t => t.Id == item.Team.Id);
|
|
if (teamItem != null && teamItem.Resources.All(x => x != item.Id))
|
|
teamItem.Resources.Add(item.Id);
|
|
}
|
|
// add current team to all model.Resources records
|
|
foreach (var resItem in result.Resources)
|
|
{
|
|
if (resItem.Id == item.Id)
|
|
{
|
|
resItem.Teams.Add(item.TeamId.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result.Teams = result.Teams.OrderBy(x => x.Name).ToList();
|
|
|
|
#endregion
|
|
#region Get data items
|
|
|
|
List<SkillsMatrixSaveModel.DataItem> dataValues =
|
|
skillsData.Select(v => new SkillsMatrixSaveModel.DataItem()
|
|
{
|
|
ResourceId = v.ResourceId,
|
|
SkillId = v.SkillId,
|
|
Level = (int?)v.Level,
|
|
Interested = v.Interested
|
|
}).ToList();
|
|
|
|
#endregion
|
|
#region Post-filtering result by Skill Levels and Interests
|
|
|
|
bool filterByLevels = (innerFilter.Levels.Count > 0);
|
|
bool filterByInterest = innerFilter.IncludeInterested.HasValue;
|
|
|
|
if (filterByLevels || filterByInterest)
|
|
{
|
|
// Get resources and skills, suitable to SkillLevels and Interest filters
|
|
List<Guid> resourcesToDisplay = new List<Guid>();
|
|
List<Guid> skillsToDisplay = new List<Guid>();
|
|
|
|
resourcesToDisplay = dataValues.Where(x =>
|
|
(!filterByLevels || (filterByLevels && x.Level.HasValue && innerFilter.Levels.Contains(x.Level.Value))) &&
|
|
(!filterByInterest || (filterByInterest && (x.Interested == innerFilter.IncludeInterested.Value))))
|
|
.Select(x => x.ResourceId).ToList();
|
|
|
|
skillsToDisplay = dataValues.Where(x =>
|
|
(!filterByLevels || (filterByLevels && x.Level.HasValue && innerFilter.Levels.Contains(x.Level.Value))) &&
|
|
(!filterByInterest || (filterByInterest && (x.Interested == innerFilter.IncludeInterested.Value))))
|
|
.Select(x => x.SkillId).ToList();
|
|
|
|
// Clear matrix data values, resource- and skill-lists
|
|
dataValues.RemoveAll(x => !resourcesToDisplay.Contains(x.ResourceId) ||
|
|
!skillsToDisplay.Contains(x.SkillId));
|
|
|
|
result.SkillGroups.ForEach(sg =>
|
|
sg.Skills.RemoveAll(sk => !skillsToDisplay.Contains(sk.Id)));
|
|
result.SkillGroups.RemoveAll(s => s.Skills.Count < 1);
|
|
|
|
result.Resources.RemoveAll(r => !resourcesToDisplay.Contains(r.Id));
|
|
result.Teams.ForEach(t =>
|
|
t.Resources.RemoveAll(rId => !resourcesToDisplay.Contains(rId)));
|
|
result.Teams.RemoveAll(t => t.Resources.Count < 1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
result.Values = dataValues
|
|
.ToDictionary(k => k.ResourceId.ToString() + "#" + k.SkillId.ToString(), v => v);
|
|
|
|
return result;
|
|
}
|
|
|
|
protected List<SkillsMatrixPieChartPartModel> GetMainToOtherDistribution(List<VW_Skill2Resource> GraphData, List<Skill> skills, bool useSkillgroups)
|
|
{
|
|
var retData = new List<SkillsMatrixPieChartPartModel>();
|
|
var other = new List<SkillsMatrixPieChartPartModel>();
|
|
var total = 1.0M;
|
|
var data = GraphData.GroupBy(r => (useSkillgroups ? r.SkillGroupId : r.SkillId))
|
|
.Select(g => new
|
|
{
|
|
id = g.Key,
|
|
count = g.Sum(x=> x.Level + 1 ?? 0)
|
|
})
|
|
.OrderByDescending(l => l.count).ToList();
|
|
var dataTotal = data.Select(x => x.count).Sum();
|
|
if (dataTotal > 0)
|
|
foreach (var item in data)
|
|
{
|
|
var percentage = (decimal)item.count / dataTotal;
|
|
if (total > .3M)
|
|
{
|
|
retData.Add(new SkillsMatrixPieChartPartModel()
|
|
{
|
|
TypeId = new List<Guid>() { item.id },
|
|
Label = skills.Where(x => x.Id == item.id).FirstOrDefault().Name,
|
|
Value = item.count
|
|
});
|
|
total -= percentage;
|
|
}
|
|
else
|
|
{
|
|
other.Add(new SkillsMatrixPieChartPartModel()
|
|
{
|
|
TypeId = new List<Guid>() { item.id },
|
|
Label = skills.Where(x => x.Id == item.id).FirstOrDefault().Name,
|
|
Value = item.count
|
|
});
|
|
}
|
|
}
|
|
if (other.Count() > 2)
|
|
{
|
|
retData.Add(new SkillsMatrixPieChartPartModel()
|
|
{
|
|
Label = "Other",
|
|
TypeId = other.SelectMany(x => x.TypeId).ToList(),
|
|
Value = other.Sum(x => x.Value)
|
|
});
|
|
}
|
|
else
|
|
retData.AddRange(other);
|
|
return retData;
|
|
}
|
|
|
|
protected IQueryable<VW_Skill2Resource> GetSkillMatrixBaseDataQuery(SkillMatrixTimeLayer timeLayer,
|
|
Skill2ResourceType Type)
|
|
{
|
|
IQueryable<VW_Skill2Resource> qry = null;
|
|
|
|
switch (timeLayer)
|
|
{
|
|
case SkillMatrixTimeLayer.Present:
|
|
qry = dbContext.VW_Skill2Resource.AsNoTracking()
|
|
.Where(x => (x.Type == (short)Skill2ResourceType.Actual) && (x.EffectiveDate <= DateTime.UtcNow))
|
|
.GroupBy(x => new { x.Type, x.ResourceId, x.SkillId })
|
|
.Select(x => x.OrderByDescending(a => a.EffectiveDate).ThenByDescending(b => b.DateCreated).Take(1))
|
|
.SelectMany(x => x);
|
|
break;
|
|
|
|
case SkillMatrixTimeLayer.Past:
|
|
IQueryable<Guid> presentRecords = dbContext.VW_Skill2Resource.AsNoTracking()
|
|
.Where(x => (x.Type == (short)Skill2ResourceType.Actual) && (x.EffectiveDate <= DateTime.UtcNow))
|
|
.GroupBy(x => new { x.Type, x.ResourceId, x.SkillId })
|
|
.Select(x => x.OrderByDescending(a => a.EffectiveDate).ThenByDescending(b => b.DateCreated).Take(1))
|
|
.SelectMany(x => x)
|
|
.Select(x => x.Id);
|
|
|
|
qry = dbContext.VW_Skill2Resource.AsNoTracking()
|
|
.Where(x => (x.Type == (short)Skill2ResourceType.Actual) && !presentRecords.Contains(x.Id))
|
|
.GroupBy(x => new { x.Type, x.ResourceId, x.SkillId })
|
|
.Select(x => x.OrderBy(a => a.PastYearDateOffset).Take(1))
|
|
.SelectMany(x => x);
|
|
break;
|
|
case SkillMatrixTimeLayer.Future:
|
|
qry = dbContext.VW_Skill2Resource.AsNoTracking()
|
|
.Where(x => (x.Type == (short)Skill2ResourceType.Planned))
|
|
.GroupBy(x => new { x.Type, x.ResourceId, x.SkillId })
|
|
.Select(x => x.OrderBy(a => a.FutureYearDateOffset).Take(1))
|
|
.SelectMany(x => x);
|
|
break;
|
|
}
|
|
|
|
return qry;
|
|
}
|
|
|
|
protected IQueryable<VW_Skill2Resource> ApplyFilter(IQueryable<VW_Skill2Resource> baseQuery,
|
|
MatrixFilterInternal filter)
|
|
{
|
|
if (baseQuery == null)
|
|
throw new ArgumentNullException("baseQuery");
|
|
|
|
var qry = baseQuery;
|
|
|
|
if (filter != null)
|
|
{
|
|
// Filtering by Resources
|
|
if ((filter.Resources != null) && (filter.Resources.Count > 0))
|
|
qry = qry.Where(x => filter.Resources.Contains(x.ResourceId));
|
|
|
|
// Filtering by SkillGroups
|
|
if ((filter.SkillGroups != null) && (filter.SkillGroups.Count > 0))
|
|
qry = qry.Where(x => filter.SkillGroups.Contains(x.SkillGroupId));
|
|
|
|
// Filtering by Skills (data may be assigned to Skill item and directly to Skill Group item)
|
|
// In the las case, SkillId and SkillGroupId in the qry are equal
|
|
if ((filter.Skills != null) && (filter.Skills.Count > 0))
|
|
qry = qry.Where(x => filter.Skills.Contains(x.SkillId) || filter.SkillGroups.Contains(x.SkillId));
|
|
}
|
|
|
|
return qry;
|
|
}
|
|
|
|
protected MatrixFilterInternal ProcessFilter(SkillsMaxtrixFilterModel filter, Guid userId)
|
|
{
|
|
MatrixFilterInternal result = new MatrixFilterInternal();
|
|
|
|
if (filter != null)
|
|
{
|
|
#region Filter by Teams
|
|
|
|
var teamMngr = new TeamManager(dbContext);
|
|
|
|
List<Guid> teamsFilterReviewd = (filter.Teams != null) && (filter.Teams.Count > 0) ?
|
|
filter.Teams : null;
|
|
List<Guid> viewsFilterReviewd = (filter.Views != null) && (filter.Views.Count > 0) ?
|
|
filter.Views : null;
|
|
List<Guid> companiesFilterReviewd = (filter.Companies != null) && (filter.Companies.Count > 0) ?
|
|
filter.Companies : null;
|
|
|
|
result.Teams =
|
|
teamMngr.GetTeamsByUserFiltered(userId.ToString(), teamsFilterReviewd, viewsFilterReviewd, companiesFilterReviewd).Select(t=>t.TeamId).ToList();
|
|
|
|
#endregion
|
|
#region Filter by Skills and Skill Groups
|
|
|
|
List<Guid> resultSkillGroups = new List<Guid>();
|
|
List<Guid> resultSkills = new List<Guid>();
|
|
|
|
if ((filter.Skills != null) && (filter.Skills.Count > 0))
|
|
{
|
|
// Add parent SkillGroups for Skills, listed in the incoming filter
|
|
resultSkillGroups.AddRange(dbContext.Skills.AsNoTracking()
|
|
.Where(x => x.ParentId.HasValue && filter.Skills.Contains(x.Id))
|
|
.Select(x => x.ParentId.Value));
|
|
// Add SkillGroups, which listed in the incoming Skill filter list
|
|
resultSkillGroups.AddRange(dbContext.Skills.AsNoTracking()
|
|
.Where(x => !x.ParentId.HasValue && filter.Skills.Contains(x.Id))
|
|
.Select(x => x.Id));
|
|
|
|
// Add child skills for selected Skill Groups
|
|
resultSkills.AddRange(dbContext.Skills.AsNoTracking()
|
|
.Where(x => x.ParentId.HasValue && filter.Skills.Contains(x.ParentId.Value))
|
|
.Select(x => x.Id));
|
|
|
|
// Include the only skills form filter.Skills (ignore groups here)
|
|
resultSkills.AddRange(dbContext.Skills.AsNoTracking()
|
|
.Where(x => x.ParentId.HasValue && filter.Skills.Contains(x.Id))
|
|
.Select(x => x.Id));
|
|
// Include Skills Groups with no child skills. Include as skills
|
|
resultSkills.AddRange(dbContext.Skills.AsNoTracking()
|
|
.Where(x => !x.ParentId.HasValue && filter.Skills.Contains(x.Id) && !x.HasChildren)
|
|
.Select(x => x.Id));
|
|
}
|
|
|
|
result.SkillGroups = resultSkillGroups.Distinct().ToList();
|
|
result.Skills = resultSkills.Distinct().ToList();
|
|
|
|
#endregion
|
|
|
|
if (filter.Resources != null)
|
|
result.Resources.AddRange(filter.Resources.Distinct());
|
|
|
|
if (filter.SkillLevels != null)
|
|
result.Levels.AddRange(filter.SkillLevels.Distinct());
|
|
|
|
result.IncludeInterested = filter.IncludeInterested;
|
|
result.Teams = result.Teams.Distinct().ToList();
|
|
result.SkillWithDataOnly = filter.SkillsWithDataOnly;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
} |