EnVisageOnline/Main-RMO/Source/EnVisage/Code/Charts/DashboardChartManager.cs

1085 lines
55 KiB
C#

using EnVisage.Code.BLL;
using EnVisage.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EnVisage.Code.Charts
{
public class DashboardCharthManager
{
private class Data
{
public decimal? cost { get; set; }
public decimal? quantity { get; set; }
public DateTime? weekend { get; set; }
public string projectStatus { get; set; }
public int? type { get; set; }
public string Name { get; set; }
public Guid? ExpCatId { get; set; }
public Guid ProjectId { get; set; }
public Guid ProjectType { get; set; }
public decimal? ScenarioBUCost { get; set; }
public int ScenarioDuration { get; set; }
}
public class PieData
{
public List<Guid> TypeId { get; set; }
public string Label { get; set; }
public decimal Value { get; set; }
public string PresetColor { get; set; }
}
EnVisageEntities db = new EnVisageEntities();
/// <summary>
///
/// </summary>
/// <param name="StartDate"></param>
/// <param name="EndDate"></param>
/// <param name="principals"></param>
/// <param name="type"></param>
/// <param name="status"></param>
/// <param name="classification"></param>
/// <param name="mode"></param>
/// <param name="teamId"></param>
/// <param name="viewId"></param>
/// <param name="isUOMHours">Indicates whether UOM (unit of measure) is hours or resources.</param>
/// <returns></returns>
public Dictionary<string, List<long[]>> GetData(DateTime StartDate, DateTime EndDate, Guid userId, string type, List<Guid> projectStatuses, List<Guid> projectTypes, ForecastDashboardMode mode, List<Guid> teams, List<Guid> views, bool? isUOMHours, bool isLaborMode, List<Guid> filterGroups, List<Guid> strategicGoals)
{
var result = new Dictionary<string, List<long[]>>();
var projects = GetFilteredProjectList(userId, teams, views);
if (strategicGoals != null && strategicGoals.Count > 0)
{
var sgs = db.StrategicGoal2Project.Where(x => strategicGoals.Contains(x.StrategicGoalId)).Select(x => x.ProjectId).ToList();
projects = projects.Where(x => sgs.Contains(x.Id));
}
int typeInt = 0;
if (!string.IsNullOrWhiteSpace(type) && type != "null")
typeInt = (int)Enum.Parse(typeof(ScenarioType), type);
Dictionary<Guid, ExpenditureCategory> expCats = new Dictionary<Guid, ExpenditureCategory>();
if (isLaborMode)
expCats = (from e in db.ExpenditureCategory where e.Type == (int)ExpenditureCategoryModel.CategoryTypes.Labor select e).ToDictionary(e => e.Id);
else
expCats = (from e in db.ExpenditureCategory where e.Type != (int)ExpenditureCategoryModel.CategoryTypes.Labor select e).ToDictionary(e => e.Id);
List<Guid> expCatGuids = expCats.Keys.ToList();
var uoms = db.UOMs.AsNoTracking().ToDictionary(u => u.Id);
IQueryable<Data> data = null;
long[] fiscalCalendarChartPoints = null;
List<DateTime> fiscalCalendarWeekendings = new List<DateTime>();
DateTime firstWeekEnding = DateTime.MinValue;
DateTime lastWeekEnding = DateTime.MinValue;
if (EndDate.Subtract(StartDate).TotalDays <= 400)
{
fiscalCalendarChartPoints = (from c in db.FiscalCalendars
where c.Type == (int)FiscalCalendarModel.FiscalYearType.Week &&
c.EndDate >= StartDate && c.EndDate <= EndDate && c.AdjustingPeriod == false && c.NonWorking == 0
orderby c.StartDate
select c.EndDate).ToArray().Select(t => (long)t.Subtract(Constants.UnixEpochDate).TotalMilliseconds).ToArray();
if (fiscalCalendarChartPoints.Length > 0)
{
firstWeekEnding = Constants.UnixEpochDate.AddMilliseconds(fiscalCalendarChartPoints[0]);
lastWeekEnding = Constants.UnixEpochDate.AddMilliseconds(fiscalCalendarChartPoints[fiscalCalendarChartPoints.Length - 1]);
}
fiscalCalendarWeekendings.AddRange(fiscalCalendarChartPoints.Select(i => Constants.UnixEpochDate.AddMilliseconds(i)));
data = GetWeeksData(firstWeekEnding, lastWeekEnding, projects, projectStatuses, projectTypes, typeInt, mode != ForecastDashboardMode.MainDashboard, isLaborMode, filterGroups);
}
else
{
//ENV-848. As our StartDate's month END will be the very first X point on the graph, it looks like graph is starting with next month, so let's gather date for month before the start date
StartDate = StartDate.AddMonths(-1);
fiscalCalendarChartPoints = (from f0 in db.FiscalCalendars
from f1 in db.FiscalCalendars
where f0.Type == (int)FiscalCalendarModel.FiscalYearType.Week && f1.Type == (int)FiscalCalendarModel.FiscalYearType.Month &&
f1.YearInt == f0.YearInt && f0.StartDate <= f1.EndDate && f0.EndDate >= f1.EndDate &&
f0.EndDate >= StartDate && f0.EndDate <= EndDate && f0.AdjustingPeriod == false && f0.NonWorking == 0
select f0.EndDate).ToArray().Select(t => (long)t.Subtract(Constants.UnixEpochDate).TotalMilliseconds).ToArray();
if (fiscalCalendarChartPoints.Length > 0)
{
firstWeekEnding = Constants.UnixEpochDate.AddMilliseconds(fiscalCalendarChartPoints[0]);
lastWeekEnding = Constants.UnixEpochDate.AddMilliseconds(fiscalCalendarChartPoints[fiscalCalendarChartPoints.Length - 1]);
}
fiscalCalendarWeekendings.AddRange(fiscalCalendarChartPoints.Select(i => Constants.UnixEpochDate.AddMilliseconds(i)));
data = GetMonthData(projects, projectStatuses, projectTypes, typeInt, mode != ForecastDashboardMode.MainDashboard, isLaborMode, filterGroups, fiscalCalendarWeekendings);
}
var projectIds = projects.Select(t => t.Id).ToArray();
var allVacations = (from vacWeek in db.PeopleResourceVacations
join vac in db.Vacations on vacWeek.VacationId equals vac.Id
join p in db.PeopleResources on vac.PeopleResourceId equals p.Id
join t in db.Team2Project on p.TeamId equals t.TeamId
where (teams.Count == 0 || (p.TeamId.HasValue && teams.Contains(p.TeamId.Value))) && projectIds.Contains(t.ProjectId) && expCatGuids.Contains(p.ExpenditureCategoryId)
select new
{
vacWeek.Id,
vacWeek.WeekEndingDate,
vacWeek.HoursOff,
Rate = db.Rates.FirstOrDefault(r => r.ExpenditureCategoryId == p.ExpenditureCategoryId && r.StartDate <= vacWeek.WeekEndingDate && r.EndDate >= vacWeek.WeekEndingDate)
}).Distinct().ToArray();
var allTrainings = (from traningWeek in db.PeopleResourceTrainings
join training in db.Trainings on traningWeek.TrainingId equals training.Id
join p in db.PeopleResources on traningWeek.PeopleResourceId equals p.Id
join t in db.Team2Project on p.TeamId equals t.TeamId
where (teams.Count == 0 || (p.TeamId.HasValue && teams.Contains(p.TeamId.Value))) && projectIds.Contains(t.ProjectId) && expCatGuids.Contains(p.ExpenditureCategoryId)
select new
{
traningWeek.Id,
traningWeek.WeekEndingDate,
traningWeek.HoursOff,
Rate = db.Rates.FirstOrDefault(r => r.ExpenditureCategoryId == p.ExpenditureCategoryId && r.StartDate <= traningWeek.WeekEndingDate && r.EndDate >= traningWeek.WeekEndingDate)
}).Distinct().ToArray();
//init result dictionary
if (mode == ForecastDashboardMode.MainDashboard)
{
result.Add("plannedCapacity", new List<long[]>());
result.Add("plannedCapacityQ", new List<long[]>());
}
result.Add("training", new List<long[]>());
result.Add("trainingQ", new List<long[]>());
result.Add("vacation", new List<long[]>());
result.Add("vacationQ", new List<long[]>());
result.Add("totalPlannedCapacity", new List<long[]>());
result.Add("totalPlannedCapacityQ", new List<long[]>());
result.Add("resourceCapacity", new List<long[]>());
result.Add("resourceCapacityQ", new List<long[]>());
//capacity and project status data remains uninitialized as we do not know what capacity scenarios and project statuses we have
List<Data> dataList = data.ToList();
long wkending = dataList.Count > 0 ? (long)dataList[0].weekend.Value.Subtract(Constants.UnixEpochDate).TotalMilliseconds : 0;
Dictionary<string, decimal> tmpProjectStatus = new Dictionary<string, decimal>();
Dictionary<string, decimal> tmpCapacity = new Dictionary<string, decimal>();
Dictionary<DateTime, PeopleResourceModel.CapacityValues> totalActualCapacity = new Dictionary<DateTime,PeopleResourceModel.CapacityValues>();
//if (mode == ForecastDashboardMode.MainDashboard)
// totalActualCapacity = GetWeeklyTeamCapacity(teams, expCats, uoms, isUOMHours, false, fiscalCalendarWeekendings);
//else if (mode == ForecastDashboardMode.TeamForecast)
// totalActualCapacity = GetWeeklyTeamCapacity(teams, expCats, uoms, isUOMHours, false, fiscalCalendarWeekendings);
//else if (mode == ForecastDashboardMode.ViewForecast)
// totalActualCapacity = GetWeeklyViewCapacity(views, expCats, uoms, isUOMHours, false, fiscalCalendarWeekendings);
Dictionary<DateTime, PeopleResourceModel.CapacityValues> totalPlannedCapacity = new Dictionary<DateTime, PeopleResourceModel.CapacityValues>();
//if (mode == ForecastDashboardMode.MainDashboard)
// totalPlannedCapacity = GetWeeklyTeamCapacity(teams, expCats, uoms, isUOMHours, true, fiscalCalendarWeekendings);
//else if (mode == ForecastDashboardMode.TeamForecast)
// totalPlannedCapacity = GetWeeklyTeamCapacity(teams, expCats, uoms, isUOMHours, true, fiscalCalendarWeekendings);
//else if (mode == ForecastDashboardMode.ViewForecast)
// totalPlannedCapacity = GetWeeklyViewCapacity(views, expCats, uoms, isUOMHours, true, fiscalCalendarWeekendings);
Guid[] plannedScenarios = new Guid[0];
Guid[] actualScenarios = new Guid[0];
if (mode == ForecastDashboardMode.MainDashboard || mode == ForecastDashboardMode.TeamForecast)
{
plannedScenarios = (from s in db.Teams where teams.Contains(s.Id) && s.PlannedCapacityScenarioId != null select s.PlannedCapacityScenarioId.Value).ToArray();
actualScenarios = (from s in db.Teams where teams.Contains(s.Id) && s.ActualCapacityScenarioId != null select s.ActualCapacityScenarioId.Value).ToArray();
}
else if (mode == ForecastDashboardMode.ViewForecast)
{
plannedScenarios = (from s in db.Teams
join tv in db.Team2View on s.Id equals tv.TeamId
where views.Contains(tv.ViewId) && s.PlannedCapacityScenarioId != null
select s.PlannedCapacityScenarioId.Value).ToArray();
actualScenarios = (from s in db.Teams
join tv in db.Team2View on s.Id equals tv.TeamId
where views.Contains(tv.ViewId) && s.ActualCapacityScenarioId != null
select s.ActualCapacityScenarioId.Value).ToArray();
}
Guid[] expCatIds = expCats.Keys.ToArray();
//var sdsP = (from sd in db.ScenarioDetail where plannedScenarios.Contains(sd.ParentID.Value) && fiscalCalendarWeekendings.Contains(sd.WeekEndingDate.Value) && expCatIds.Contains(sd.ExpenditureCategoryId.Value) select sd).ToDictionary( x=> x.WeekEndingDate, x => Sum(x.Cost));
//var sdsA = (from sd in db.ScenarioDetail where actualScenarios.Contains(sd.ParentID.Value) && fiscalCalendarWeekendings.Contains(sd.WeekEndingDate.Value) && expCatIds.Contains(sd.ExpenditureCategoryId.Value) select sd).ToDictionary(x => x.WeekEndingDate, x => x);
Dictionary<DateTime?, Dictionary<Guid?, List<ScenarioDetail>>> plannedCapacityDetails =
(from sdPlan in db.ScenarioDetail
where plannedScenarios.Contains(sdPlan.ParentID.Value) && fiscalCalendarWeekendings.Contains(sdPlan.WeekEndingDate.Value) && expCatIds.Contains(sdPlan.ExpenditureCategoryId.Value)
select sdPlan).GroupBy(sd => sd.WeekEndingDate).ToDictionary(k1 => k1.Key, g1 => g1.GroupBy(sd2 => sd2.ExpenditureCategoryId).ToDictionary(k2 => k2.Key, g2 => g2.ToList()));
Dictionary<DateTime?, Dictionary<Guid?, List<ScenarioDetail>>> actualCapacityDetails =
(from sdAct in db.ScenarioDetail
where actualScenarios.Contains(sdAct.ParentID.Value) && fiscalCalendarWeekendings.Contains(sdAct.WeekEndingDate.Value) && expCatIds.Contains(sdAct.ExpenditureCategoryId.Value)
select sdAct).GroupBy(sd => sd.WeekEndingDate).ToDictionary(k1 => k1.Key, g1 => g1.GroupBy(sd2 => sd2.ExpenditureCategoryId).ToDictionary(k2 => k2.Key, g2 => g2.ToList()));
for (int i = 0; i < dataList.Count; i++)
{
var week = dataList[i].weekend.Value;
if (!totalPlannedCapacity.ContainsKey(week))
{
var quantity = 0M;
var cost = 0M;
if (plannedCapacityDetails.ContainsKey(week))
{
var sdP = plannedCapacityDetails[week];// (from s in sdsP where s.WeekEndingDate == week select s).ToList();
foreach (var s in sdP)
{
quantity += s.Value.Sum(x => x.Quantity.Value) * Utils.GetUOMMultiplier(expCats, uoms, s.Key ?? Guid.Empty, isUOMHours);
cost += s.Value.Sum(x => x.Cost.Value);
}
}
totalPlannedCapacity.Add(week, new PeopleResourceModel.CapacityValues()
{
Quantity = quantity,
Cost = cost,
WeekEnding = week
});
}
if (!totalActualCapacity.ContainsKey(week))
{
var quantity = 0M;
var cost = 0M;
if (actualCapacityDetails.ContainsKey(week))
{
var sdA = actualCapacityDetails[week];//(from s in sdsA where s.WeekEndingDate == week select s).ToList();
foreach (var s in sdA)
{
quantity += s.Value.Sum(x => x.Quantity.Value) * Utils.GetUOMMultiplier(expCats, uoms, s.Key ?? Guid.Empty, isUOMHours);
cost += s.Value.Sum(x => x.Cost.Value);
}
}
totalActualCapacity.Add(week, new PeopleResourceModel.CapacityValues()
{
Quantity = quantity,
Cost = cost,
WeekEnding = week
});
}
Data sd = dataList[i];
//fill data into tmps
if (!sd.type.HasValue)
continue;
if ((int)ScenarioType.Portfolio == sd.type.Value || (int)ScenarioType.Scheduling == sd.type.Value)
{
//the dataset is already filtered by correct scenario type so we're just summarizing the numbers here
if (!tmpProjectStatus.ContainsKey(sd.projectStatus))
{
tmpProjectStatus.Add(sd.projectStatus, 0.0M);
tmpProjectStatus.Add(sd.projectStatus + "Q", 0.0M);
}
tmpProjectStatus[sd.projectStatus] += sd.cost ?? 0;
tmpProjectStatus[sd.projectStatus + "Q"] += (sd.quantity ?? 0) * Utils.GetUOMMultiplier(expCats, uoms, sd.ExpCatId ?? Guid.Empty, isUOMHours);
}
else if ((int)ScenarioType.Capacity == sd.type.Value)
{
if (!tmpCapacity.ContainsKey(sd.Name))
{
tmpCapacity.Add(sd.Name, 0.0M);
tmpCapacity.Add(sd.Name + "Q", 0.0M);
}
tmpCapacity[sd.Name] += sd.cost ?? 0;
tmpCapacity[sd.Name + "Q"] += (sd.quantity ?? 0) * Utils.GetUOMMultiplier(expCats, uoms, sd.ExpCatId ?? Guid.Empty, isUOMHours);
}
else
{
throw new InvalidOperationException("Incorrect scenario type found");
}
if (i == dataList.Count - 1 || (i < dataList.Count - 1 && (long)dataList[i+1].weekend.Value.Subtract(Constants.UnixEpochDate).TotalMilliseconds != wkending))
{
//new week, push result data and reinit temps
if (0 != wkending)
{
if (mode == ForecastDashboardMode.MainDashboard)
{
foreach (string cn in tmpCapacity.Keys)
{
if (!result.ContainsKey(cn))
{
result.Add(cn, new List<long[]>());
}
result[cn].Add(new long[] { wkending, (long)(Math.Round(tmpCapacity[cn])) });
}
}
//TRAININGS
var ed = Constants.UnixEpochDate.AddMilliseconds(wkending);
var startd = ed.AddDays(-6);
decimal tmpTrainingQ = allTrainings.Where(t => t.WeekEndingDate <= ed && t.WeekEndingDate >= startd).Sum(t => t.HoursOff);
result["trainingQ"].Add(new long[] { wkending, (long)(tmpTrainingQ * Utils.GetUOMMultiplier(expCats, uoms, sd.ExpCatId ?? Guid.Empty, isUOMHours)) });
decimal tmpTraining = allTrainings.Where(t => t.WeekEndingDate <= ed && t.WeekEndingDate >= startd).Sum(t => t.HoursOff * (t.Rate != null ? t.Rate.Rate1 : 0));
result["training"].Add(new long[] { wkending, (long)tmpTraining });
//VACATIONS
ed = Constants.UnixEpochDate.AddMilliseconds(wkending);
startd = ed.AddDays(-6);
decimal tmpVacationQ = allVacations.Where(t => t.WeekEndingDate <= ed && t.WeekEndingDate >= startd).Sum(t => t.HoursOff);
result["vacationQ"].Add(new long[] { wkending, (long)(tmpVacationQ * Utils.GetUOMMultiplier(expCats, uoms, sd.ExpCatId ?? Guid.Empty, isUOMHours)) });
decimal tmpVacation = allVacations.Where(t => t.WeekEndingDate <= ed && t.WeekEndingDate >= startd).Sum(t => t.HoursOff * (t.Rate != null ? t.Rate.Rate1 : 0));
result["vacation"].Add(new long[] { wkending, (long)tmpVacation });
foreach (string sn in tmpProjectStatus.Keys)
{
if (!result.ContainsKey(sn))
{
result.Add(sn, new List<long[]>());
}
result[sn].Add(new long[] { wkending, (long)(Math.Round(tmpProjectStatus[sn])) });
}
}
if (i < dataList.Count - 1)
wkending = (long)dataList[i + 1].weekend.Value.Subtract(Constants.UnixEpochDate).TotalMilliseconds;
tmpProjectStatus = new Dictionary<string, decimal>();
tmpCapacity = new Dictionary<string, decimal>();
}
}
result["resourceCapacity"].AddRange(totalActualCapacity.Select(x => new long[]
{
(long)x.Key.Subtract(Constants.UnixEpochDate).TotalMilliseconds,
(long)(Math.Round(x.Value.Cost))
}));
result["resourceCapacityQ"].AddRange(totalActualCapacity.Select(x => new long[]
{
(long)x.Key.Subtract(Constants.UnixEpochDate).TotalMilliseconds,
(long)(Math.Round(x.Value.Quantity))
}));
result["totalPlannedCapacity"].AddRange(totalPlannedCapacity.Select(x => new long[]
{
(long)x.Key.Subtract(Constants.UnixEpochDate).TotalMilliseconds,
(long)(Math.Round(x.Value.Cost))
}));
result["totalPlannedCapacityQ"].AddRange(totalPlannedCapacity.Select(x => new long[]
{
(long)x.Key.Subtract(Constants.UnixEpochDate).TotalMilliseconds,
(long)(Math.Round(x.Value.Quantity))
}));
//Fill missing weekends for all items in dictionary
foreach (string key in result.Keys)
{
List<long[]> lst = FillMissingWeeends(result[key], fiscalCalendarChartPoints);
result[key].Clear();
result[key].AddRange(lst);
}
return result;
}
/// <summary>
/// Get projects, filtered by user access permissions and given filter view or team (depends on page mode)
/// </summary>
/// <param name="mode">Forecast page display mode</param>
/// <param name="userId">User id</param>
/// <param name="filterItemId">Id of view or team to filter projects (depends on page mode)</param>
/// <param name="teams">Returning list of teams, discovered during filtration (e.g. for the filtering by given view Id)</param>
/// <returns>Available for given user and team (view teams) projects</returns>
/// <remarks>SA. ENV-608</remarks>
private IQueryable<Project> GetFilteredProjectList(Guid userId, List<Guid> teams, List<Guid> views)
{
var filteredTeams = (new TeamManager(db)).GetTeamsByUser(userId.ToString(), teams, views);
teams.AddRange(filteredTeams.Where(x => !teams.Any(t => t == x.Id)).Select(x => x.Id));
// Get list of project, that are available to given user, filtered for given team or view
IQueryable<Project> projects =
(from c in db.Projects.AsNoTracking()
join o in db.VW_ProjectAccessByUser on c.Id equals o.Id
where o.UserId.Equals(userId) && c.Team2Project.Any(x => teams.Contains(x.TeamId))
select c);
return projects;
}
/// <summary>
/// Returns current, next and previous fiscal periods of given type for the datepoint
/// </summary>
/// <param name="datePoint"></param>
/// <param name="periodType"></param>
/// <returns>Returns periods, if exist (-1 = prev, 0 = current, 1 = next)</returns>
/// <remarks>SA. ENV-608</remarks>
private Dictionary<int, Guid> GetClosedToDateFiscalPeriods(DateTime datePoint,
FiscalCalendarModel.FiscalYearType periodType)
{
Dictionary<int, Guid> result = new Dictionary<int, Guid>();
DateTime viewRangeStartDate = datePoint.AddYears(-2);
DateTime viewRangeEndDate = datePoint.AddYears(2);
List<FiscalCalendar> periods =
(from FiscalCalendar period in db.FiscalCalendars.AsNoTracking()
orderby period.StartDate
where (period.Type == (int)periodType) && (period.StartDate >= viewRangeStartDate) &&
(period.EndDate <= viewRangeEndDate)
select period).ToList();
int periodCount = periods.Count;
FiscalCalendar periodItem;
for (int index = 0; index < periodCount; index++)
{
periodItem = periods[index];
if ((periodItem.StartDate <= datePoint) && (periodItem.EndDate >= datePoint))
{
result.Add(0, periodItem.Id);
if (index > 0)
result.Add(-1, periods[index - 1].Id);
if ((index + 1) < periodCount)
result.Add(1, periods[index + 1].Id);
break;
}
}
return result;
}
/// <summary>
/// Returns top 5 projects performance data by cost
/// </summary>
/// <param name="mode">Page display mode (general dashboard, team or view dashboard)</param>
/// <param name="userId"></param>
/// <param name="datePoint"></param>
/// <param name="filterItemId">Team or View id to filter projects</param>
/// <returns></returns>
/// <remarks>SA. ENV-608</remarks>
public Dictionary<string, StackGraphDataBlock> GetPerformanceGraphDataByProjects(ForecastDashboardMode mode, Guid userId, DateTime datePoint, List<Guid> filterGroups, List<Guid> projectTypes, List<Guid> teams, List<Guid> views)
{
var result = new Dictionary<string, StackGraphDataBlock>();
StackGraphDataBlock singleGraphDataBlock;
StackGraphSerie forecastDataSerie;
StackGraphSerie variationsPosDataSerie;
StackGraphSerie variationsNegDataSerie;
StackGraphSerie actualsDataSerie;
StackGraphBarOptions barTitles;
// Get list of project, that are available to given user, filtered for given team or view
IQueryable<Project> projects = GetFilteredProjectList(userId, teams, views);
List<Guid> projectFilter = projects.Select(x => x.Id).ToList();
// Get current, prev and following fiscal periods
Dictionary<int, Guid> fiscalPeriods =
GetClosedToDateFiscalPeriods(datePoint, FiscalCalendarModel.FiscalYearType.Quarter);
Dictionary<int, string> resultKeys = new Dictionary<int, string>();
resultKeys.Add(-1, "PrevPeriod");
resultKeys.Add(0, "CurrentPeriod");
resultKeys.Add(1, "NextPeriod");
for (int index = -1; index <= 1; index++)
{
if (fiscalPeriods.ContainsKey(index))
{
Guid currentPeriodId = fiscalPeriods[index];
var query = db.VW_ProjectPerformance.AsNoTracking().OrderByDescending(row => row.ProjectWeight).Where(row => currentPeriodId.Equals(row.FiscalPeriodId) &&
projectFilter.Contains(row.ProjectId) && row.BUDirectCosts.HasValue);
if (filterGroups != null && filterGroups.Count > 0)
query = query.Where(row => row.ScenarioGroupId.HasValue && filterGroups.Contains(row.ScenarioGroupId.Value));
if (projectTypes != null && projectTypes.Count > 0)
query = query.Where(row => projectTypes.Contains(row.ProjectTypeId));
var projectRows =
(from VW_ProjectPerformance row in query
select row).Take(5);
int rowIndex = 1;
singleGraphDataBlock = new StackGraphDataBlock();
forecastDataSerie = new StackGraphSerie();
variationsPosDataSerie = new StackGraphSerie();
variationsNegDataSerie = new StackGraphSerie();
barTitles = new StackGraphBarOptions();
actualsDataSerie = new StackGraphSerie();
foreach (VW_ProjectPerformance row in projectRows)
{
long graphPoint = rowIndex;
if (row.ActualsCostVariation.HasValue)
{
if (row.ActualsCostVariation.Value > 0)
{
// Actual costs lager Forecast costs
forecastDataSerie.data.AddValue(graphPoint, row.BUDirectCosts.Value);
variationsPosDataSerie.data.AddValue(graphPoint, row.ActualsCostVariation.Value);
variationsNegDataSerie.data.AddValue(graphPoint, 0);
}
else
{
// Actual costs less Forecast costs
forecastDataSerie.data.AddValue(graphPoint, row.BUDirectCosts.Value + row.ActualsCostVariation.Value); // ActualsCostVariation is negative value
variationsPosDataSerie.data.AddValue(graphPoint, 0);
variationsNegDataSerie.data.AddValue(graphPoint, -row.ActualsCostVariation.Value);
}
}
else
{
// No actauls
forecastDataSerie.data.AddValue(graphPoint, row.BUDirectCosts.Value);
variationsPosDataSerie.data.AddValue(graphPoint, 0);
variationsNegDataSerie.data.AddValue(graphPoint, 0);
}
// Store actuals data to virtual serie
if (row.ActualsTotalCost.HasValue)
actualsDataSerie.data.AddValue(graphPoint, row.ActualsTotalCost.Value);
else
actualsDataSerie.data.AddValue(graphPoint, 0);
// Store project name
barTitles.AddValue(graphPoint, row.ProjectName);
rowIndex++;
}
singleGraphDataBlock.series.Add(forecastDataSerie);
singleGraphDataBlock.series.Add(variationsPosDataSerie);
singleGraphDataBlock.series.Add(variationsNegDataSerie);
singleGraphDataBlock.series.Add(actualsDataSerie);
singleGraphDataBlock.barOptions = barTitles;
string dataKey = resultKeys[index];
result.Add(dataKey, singleGraphDataBlock);
}
}
return result;
}
/// <summary>
/// Returns top 5 projects performance data by cost
/// </summary>
/// <param name="mode">Page display mode (general dashboard, team or view dashboard)</param>
/// <param name="userId"></param>
/// <param name="datePoint"></param>
/// <param name="filterItemId">Team or View id to filter projects</param>
/// <returns></returns>
/// <remarks>SA. ENV-608</remarks>
public Dictionary<string, StackGraphDataBlock>
GetPerformanceGraphDataByProjectClass(ForecastDashboardMode mode, Guid userId, DateTime datePoint,
List<Guid> filterGroups, List<Guid> projectTypes, List<Guid> teams, List<Guid> views)
{
var result = new Dictionary<string, StackGraphDataBlock>();
StackGraphDataBlock singleGraphDataBlock;
StackGraphSerie forecastDataSerie;
StackGraphSerie variationsPosDataSerie;
StackGraphSerie variationsNegDataSerie;
StackGraphSerie actualsDataSerie;
StackGraphBarOptions barTitles;
// Get list of project, that are available to given user, filtered for given team or view
IQueryable<Project> projects = GetFilteredProjectList(userId, teams, views);
List<Guid> projectFilter = projects.Select(x => x.Id).ToList();
// Get current, prev and following fiscal periods
Dictionary<int, Guid> fiscalPeriods =
GetClosedToDateFiscalPeriods(datePoint, FiscalCalendarModel.FiscalYearType.Quarter);
Dictionary<int, string> resultKeys = new Dictionary<int, string>();
resultKeys.Add(-1, "PrevPeriod");
resultKeys.Add(0, "CurrentPeriod");
resultKeys.Add(1, "NextPeriod");
for (int index = -1; index <= 1; index++)
{
if (fiscalPeriods.ContainsKey(index))
{
Guid currentPeriodId = fiscalPeriods[index];
var query = db.VW_ProjectPerformance.AsNoTracking().Where(x => currentPeriodId.Equals(x.FiscalPeriodId) && projectFilter.Contains(x.ProjectId) && x.BUDirectCosts.HasValue);
if (filterGroups != null && filterGroups.Count > 0)
query = query.Where(x => x.ScenarioGroupId.HasValue && filterGroups.Contains(x.ScenarioGroupId.Value));
if (projectTypes != null && projectTypes.Count > 0)
query = query.Where(row => projectTypes.Contains(row.ProjectTypeId));
var projectClassRows =
(from VW_ProjectPerformance row in query
group row by new { row.ProjectTypeName }
into grp
select new
{
grp.Key.ProjectTypeName,
BUDirectCosts = grp.Sum(x => x.BUDirectCosts),
ActualsCostVariation = grp.Sum(x => x.ActualsCostVariation.HasValue ? x.ActualsCostVariation : 0),
ActualsTotalCosts = grp.Sum(x => x.ActualsTotalCost.HasValue ? x.ActualsTotalCost : 0),
ProjectsCount = grp.Count()
}).OrderByDescending(x => x.BUDirectCosts).Take(5).ToList();
int rowIndex = 1;
singleGraphDataBlock = new StackGraphDataBlock();
forecastDataSerie = new StackGraphSerie();
variationsPosDataSerie = new StackGraphSerie();
variationsNegDataSerie = new StackGraphSerie();
barTitles = new StackGraphBarOptions();
actualsDataSerie = new StackGraphSerie();
foreach (var row in projectClassRows)
{
long graphPoint = rowIndex;
if (row.ActualsCostVariation.HasValue)
{
if (row.ActualsCostVariation.Value > 0)
{
// Actual costs lager Forecast costs
forecastDataSerie.data.AddValue(graphPoint, row.BUDirectCosts.Value);
variationsPosDataSerie.data.AddValue(graphPoint, row.ActualsCostVariation.Value);
variationsNegDataSerie.data.AddValue(graphPoint, 0);
}
else
{
// Actual costs less Forecast costs
forecastDataSerie.data.AddValue(graphPoint, row.BUDirectCosts.Value + row.ActualsCostVariation.Value); // ActualsCostVariation is negative value
variationsPosDataSerie.data.AddValue(graphPoint, 0);
variationsNegDataSerie.data.AddValue(graphPoint, -row.ActualsCostVariation.Value);
}
}
else
{
// No actauls
forecastDataSerie.data.AddValue(graphPoint, row.BUDirectCosts.Value);
variationsPosDataSerie.data.AddValue(graphPoint, 0);
variationsNegDataSerie.data.AddValue(graphPoint, 0);
}
// Store actuals data to virtual serie
if (row.ActualsTotalCosts.HasValue)
actualsDataSerie.data.AddValue(graphPoint, row.ActualsTotalCosts.Value);
else
actualsDataSerie.data.AddValue(graphPoint, 0);
// Store project name
barTitles.AddValue(graphPoint, row.ProjectTypeName);
rowIndex++;
}
singleGraphDataBlock.series.Add(forecastDataSerie);
singleGraphDataBlock.series.Add(variationsPosDataSerie);
singleGraphDataBlock.series.Add(variationsNegDataSerie);
singleGraphDataBlock.series.Add(actualsDataSerie);
singleGraphDataBlock.barOptions = barTitles;
string dataKey = resultKeys[index];
result.Add(dataKey, singleGraphDataBlock);
}
}
return result;
}
/// <summary>
/// Fill absent weekends and normalize arrays
/// </summary>
private List<long[]> FillMissingWeeends(List<long[]> list, IEnumerable<long> weekEnds)
{
if (list.Count < weekEnds.Count())
{
var result = weekEnds.Except(list.Select(x => x[0]));
list.AddRange(result.Select(x => new long[] { x, 0 }));
list.RemoveAll(x => !weekEnds.Contains(x[0]));
}
return list.OrderBy(x => x[0]).ToList();
}
/// <summary>
///
/// </summary>
/// <param name="StartDate"></param>
/// <param name="EndDate"></param>
/// <param name="projects"></param>
/// <param name="status"></param>
/// <param name="classification"></param>
/// <param name="scenarioType"></param>
/// <param name="noOldCapacities"></param>
/// <returns></returns>
private IQueryable<Data> GetWeeksData(DateTime firstWeekEnding, DateTime lastWeekEnding, IQueryable<Project> projects, List<Guid> projectStatuses, List<Guid> projectTypes, int scenarioType, bool noOldCapacities, bool isLaborMode, List<Guid> filterGroups)
{
if (projectStatuses != null && projectStatuses.Count > 0)
projects = projects.Where(x => projectStatuses.Contains(x.StatusId));
if (projectTypes != null && projectTypes.Count > 0)
projects = projects.Where(x => projectTypes.Contains(x.TypeId));
Guid[] projectIds = (from p in projects select p.Id).ToArray();
Guid[] expCatIds = null;
if (isLaborMode) expCatIds = (from e in db.ExpenditureCategory where e.Type == (int)ExpenditureCategoryModel.CategoryTypes.Labor select e.Id).ToArray();
else expCatIds = (from e in db.ExpenditureCategory where e.Type != (int)ExpenditureCategoryModel.CategoryTypes.Labor select e.Id).ToArray();
List<int> scTypes = new List<int>();
if (!noOldCapacities)
scTypes.AddRange(new int[] { (int)ScenarioType.Capacity, (int)ScenarioType.Vacation, (int)ScenarioType.Training });
if (scenarioType != 0)
scTypes.Add(scenarioType);
else
scTypes.Add((int)ScenarioType.Portfolio);
IQueryable<Data> data = null;
if (filterGroups != null && filterGroups.Count > 0)
{
data = (from sd in db.ScenarioDetail.AsNoTracking()
join s in db.Scenarios on sd.ParentID equals s.Id
join p in db.Projects on s.ParentId equals p.Id
where sd.WeekEndingDate >= firstWeekEnding && sd.WeekEndingDate <= lastWeekEnding
&& projectIds.Contains(s.ParentId.Value) && s.Status == (int?)ScenarioStatus.Active
&& scTypes.Contains(s.Type) && expCatIds.Contains(sd.ExpenditureCategoryId.Value) && s.Scenario2Group.Any(g => filterGroups.Contains(g.GroupId))
orderby sd.WeekEndingDate
select new Data
{
cost = sd.Cost,
quantity = sd.Quantity,
weekend = sd.WeekEndingDate,
projectStatus = projects.FirstOrDefault(x => x.Id == s.ParentId).Status.Name,
type = s.Type,
Name = s.Name,
ScenarioBUCost = (s.UseLMMargin ?? 0) == 1 ? s.BUDirectCosts_LM : s.BUDirectCosts,
ScenarioDuration = s.Duration ?? 0,
ExpCatId = sd.ExpenditureCategoryId,
ProjectId = s.ParentId.Value,
ProjectType = p.TypeId
});
}
else
{
data = (from sd in db.ScenarioDetail.AsNoTracking()
join s in db.Scenarios on sd.ParentID equals s.Id
join p in db.Projects on s.ParentId equals p.Id
where sd.WeekEndingDate >= firstWeekEnding && sd.WeekEndingDate <= lastWeekEnding
&& projectIds.Contains(s.ParentId.Value) && s.Status == (int?)ScenarioStatus.Active
&& scTypes.Contains(s.Type) && expCatIds.Contains(sd.ExpenditureCategoryId.Value)
orderby sd.WeekEndingDate
select new Data
{
cost = sd.Cost,
quantity = sd.Quantity,
weekend = sd.WeekEndingDate,
projectStatus = projects.FirstOrDefault(x => x.Id == s.ParentId).Status.Name,
type = s.Type,
Name = s.Name,
ScenarioBUCost = (s.UseLMMargin ?? 0) == 1 ? s.BUDirectCosts_LM : s.BUDirectCosts,
ScenarioDuration = s.Duration ?? 0,
ExpCatId = sd.ExpenditureCategoryId,
ProjectType = p.TypeId
});
}
return data;
}
/// <summary>
///
/// </summary>
/// <param name="StartDate"></param>
/// <param name="EndDate"></param>
/// <param name="projects"></param>
/// <param name="status"></param>
/// <param name="classification"></param>
/// <param name="scenarioType"></param>
/// <param name="noOldCapacities"></param>
/// <param name="uomMultiplier">A value of resource capacity multiplier. E.g. if user wants to see data in hours, then <paramref name="uomMultiplier"/>
/// equals to 1. If user wants to see data in resources then <paramref name="uomMultiplier"/> equals to 1/40 = 0.025.</param>
/// <returns></returns>
private IQueryable<Data> GetMonthData(IQueryable<Project> projects, List<Guid> projectStatuses, List<Guid> projectTypes, int scenarioType, bool noOldCapacities, bool isLaborMode, List<Guid> filterGroups, List<DateTime> fiscalCalendarWeekendings)
{
if (projectStatuses != null && projectStatuses.Count > 0)
projects = projects.Where(x => projectStatuses.Contains(x.StatusId));
if (projectTypes != null && projectTypes.Count > 0)
projects = projects.Where(x => projectTypes.Contains(x.TypeId));
Guid[] projectIds = (from p in projects select p.Id).ToArray();
Guid[] expCatIds = null;
if (isLaborMode) expCatIds = (from e in db.ExpenditureCategory where e.Type == (int)ExpenditureCategoryModel.CategoryTypes.Labor select e.Id).ToArray();
else expCatIds = (from e in db.ExpenditureCategory where e.Type != (int)ExpenditureCategoryModel.CategoryTypes.Labor select e.Id).ToArray();
List<int> scTypes = new List<int>();
if (!noOldCapacities)
scTypes.AddRange(new int[] { (int)ScenarioType.Capacity, (int)ScenarioType.Vacation, (int)ScenarioType.Training });
if (scenarioType != 0)
scTypes.Add(scenarioType);
else
scTypes.Add((int)ScenarioType.Portfolio);
IQueryable<Data> data = null;
if (filterGroups != null && filterGroups.Count > 0)
{
data = (from sd in db.ScenarioDetail.AsNoTracking()
join s in db.Scenarios on sd.ParentID equals s.Id
join p in db.Projects on s.ParentId equals p.Id
where fiscalCalendarWeekendings.Contains(sd.WeekEndingDate.Value)
&& projectIds.Contains(s.ParentId.Value) && s.Status == (int?)ScenarioStatus.Active
&& scTypes.Contains(s.Type) && expCatIds.Contains(sd.ExpenditureCategoryId.Value) && s.Scenario2Group.Any(g => filterGroups.Contains(g.GroupId))
orderby sd.WeekEndingDate
select new Data
{
cost = sd.Cost,
quantity = sd.Quantity,
weekend = sd.WeekEndingDate,
projectStatus = projects.FirstOrDefault(x => x.Id == s.ParentId).Status.Name,
type = s.Type,
Name = s.Name,
ScenarioBUCost = (s.UseLMMargin ?? 0) == 1 ? s.BUDirectCosts_LM : s.BUDirectCosts,
ScenarioDuration = s.Duration ?? 0,
ExpCatId = sd.ExpenditureCategoryId,
ProjectId = s.ParentId.Value,
ProjectType = p.TypeId
});
}
else
{
data = (from sd in db.ScenarioDetail.AsNoTracking()
join s in db.Scenarios on sd.ParentID equals s.Id
join p in db.Projects on s.ParentId equals p.Id
where fiscalCalendarWeekendings.Contains(sd.WeekEndingDate.Value)
&& projectIds.Contains(s.ParentId.Value) && s.Status == (int?)ScenarioStatus.Active
&& scTypes.Contains(s.Type) && expCatIds.Contains(sd.ExpenditureCategoryId.Value)
orderby sd.WeekEndingDate
select new Data
{
cost = sd.Cost,
quantity = sd.Quantity,
weekend = sd.WeekEndingDate,
projectStatus = projects.FirstOrDefault(x => x.Id == s.ParentId).Status.Name,
type = s.Type,
Name = s.Name,
ScenarioBUCost = (s.UseLMMargin ?? 0) == 1 ? s.BUDirectCosts_LM : s.BUDirectCosts,
ScenarioDuration = s.Duration ?? 0,
ExpCatId = sd.ExpenditureCategoryId,
ProjectId = s.ParentId.Value,
ProjectType = p.TypeId
});
}
return data;
}
public List<PieData> GetPieData(DateTime startDate, DateTime endDate, Guid userId, ForecastDashboardMode mode, List<Guid> teams, List<Guid> views, bool isLaborMode, List<Guid> filterGroups, List<Guid> projectTypes, List<Guid> projectStatuses, List<Guid> strategicGoals, string presetColor, bool chartModeCost)
{
var query = db.Projects.AsNoTracking().Where(x => !x.HasChildren);
if (projectStatuses != null && projectStatuses.Count > 0)
query = query.Where(x => projectStatuses.Contains(x.StatusId));
if (projectTypes != null && projectTypes.Count > 0)
query = query.Where(x => projectTypes.Contains(x.TypeId));
if (strategicGoals != null && strategicGoals.Count > 0)
{
var sgs = db.StrategicGoal2Project.Where(x => strategicGoals.Contains(x.StrategicGoalId)).Select(x => x.ProjectId).ToList();
query = query.Where(x => sgs.Contains(x.Id));
}
var filteredTeams = (new TeamManager(db)).GetTeamsByUser(userId.ToString(), teams, views);
teams.AddRange(filteredTeams.Where(x => !teams.Any(t => t == x.Id)).Select(x=> x.Id));
IQueryable<Project> projects = (from c in query
join o in db.VW_ProjectAccessByUser on c.Id equals o.Id
where o.UserId.Equals(userId) && c.Team2Project.Any(x => teams.Contains(x.TeamId))
select c);
var data = GetPieChartData(startDate, endDate.AddDays(7), projects, isLaborMode, filterGroups, chartModeCost).OrderByDescending(x => x.Value);
var retData = new List<PieData>();
var other = new List<PieData>();
var totalTime = data.Sum(x=>x.Value);
var total = 1.0M;
if (data.Count() == 1)
data.First().PresetColor = presetColor;
if (projectTypes.Count == 0 && totalTime > 0)
{
foreach (var item in data)
{
var percentage = item.Value / totalTime;
if (total > .15M)
{
retData.Add(item);
total -= percentage;
}
else{
other.Add(item);
}
}
//var perPrecent = data.Max(x => x.Time) / 100;
//retData = data.Where(x => x.Time >= perPrecent * 80).Take(2).ToList<PieData>();
//var existedTypeIds = retData.SelectMany(ex => ex.TypeId).ToList();
//var other = data.Where(x => !existedTypeIds.Contains(x.TypeId.FirstOrDefault()));
if (other.Count() > 2)
{
retData.Add(new PieData()
{
Label = "Other",
TypeId = other.SelectMany(x => x.TypeId).ToList(),
Value = other.Sum(x => x.Value)
});
}else{
retData = data.ToList<PieData>();
}
}
else
{
retData = data.ToList<PieData>();
}
return retData;
}
/// <summary>
///
/// </summary>
/// <param name="startDate">Start of reporting period.</param>
/// <param name="endDate">End of reporting period.</param>
/// <param name="projects">A queryable collection of projects to filter by.</param>
/// <param name="isLaborMode">Indicates whether to load data for labor or for materials expenditure categories.</param>
/// <returns>A list of data for each classification.</returns>
private List<PieData> GetPieChartData(DateTime startDate, DateTime endDate, IQueryable<Project> projects, bool isLaborMode, List<Guid> filterGroups, bool chartModeCost)
{
var projectIds = (from p in projects select p.Id).ToArray();
var expCatIds = isLaborMode
? (from e in db.ExpenditureCategory
where e.Type == (int)ExpenditureCategoryModel.CategoryTypes.Labor
select e.Id).ToArray()
: (from e in db.ExpenditureCategory
where e.Type != (int)ExpenditureCategoryModel.CategoryTypes.Labor
select e.Id).ToArray();
var scTypes = new List<int> { (int)ScenarioType.Portfolio, (int)ScenarioType.Scheduling };
var types = db.Types.AsNoTracking().ToDictionary(key => key.Id, elem => elem.Name);
var query = db.Scenarios.AsNoTracking().Where(x => x.Status == (int?)ScenarioStatus.Active);
if (filterGroups != null && filterGroups.Count > 0)
query = query.Where(x => filterGroups.Contains(x.Scenario2Group.FirstOrDefault().GroupId));
var data = (from sd in db.ScenarioDetail
join s in query on sd.ParentID equals s.Id
join p in db.Projects on s.ParentId equals p.Id
//where !(s.StartDate <= StartDate || s.EndDate >= EndDate)
where sd.WeekEndingDate >= startDate && sd.WeekEndingDate <= endDate
&& projectIds.Contains(s.ParentId.Value)
&& scTypes.Contains(s.Type) && expCatIds.Contains(sd.ExpenditureCategoryId.Value)
select new
{
s.Id,
s.UseLMMargin,
s.BUDirectCosts_LM,
s.BUDirectCosts,
s.Duration,
p.TypeId,
}).Distinct().ToArray().GroupBy(group => group.TypeId).Select(grouping => new PieData
{
TypeId = new List<Guid>(){grouping.Key},
Value = (chartModeCost) ? grouping.Sum(x => (x.UseLMMargin ?? 0) == 1 ? x.BUDirectCosts_LM ?? 0 : x.BUDirectCosts ?? 0) : grouping.Sum(x => x.Duration ?? 0),
Label = types.ContainsKey(grouping.Key) ? types[grouping.Key] : string.Empty
}).ToList();
return data;
}
private Dictionary<DateTime, PeopleResourceModel.CapacityValues> GetWeeklyViewCapacity(List<Guid> views, Dictionary<Guid, ExpenditureCategory> expCats, Dictionary<Guid, UOM> uoms, bool? isUOMMode, bool isPlanned, List<DateTime> fiscalCalendarWeekendings)
{
if (views == null || views.Count <= 0)
return new Dictionary<DateTime, PeopleResourceModel.CapacityValues>();
var context = new EnVisageEntities();
Guid[] scenarios;
if (isPlanned) scenarios = (from s in context.Teams
join tv in context.Team2View on s.Id equals tv.TeamId
where views.Contains(tv.ViewId) && s.PlannedCapacityScenarioId != null
select s.PlannedCapacityScenarioId.Value).ToArray();
else scenarios = (from s in context.Teams
join tv in context.Team2View on s.Id equals tv.TeamId
where views.Contains(tv.ViewId) && s.ActualCapacityScenarioId != null
select s.ActualCapacityScenarioId.Value).ToArray();
return GetWeeklyCapacity(scenarios, expCats, uoms, isUOMMode, fiscalCalendarWeekendings);
}
private Dictionary<DateTime, PeopleResourceModel.CapacityValues> GetWeeklyTeamCapacity(List<Guid> TeamIds, Dictionary<Guid, ExpenditureCategory> expCats, Dictionary<Guid, UOM> uoms, bool? isUOMMode, bool isPlanned, List<DateTime> fiscalCalendarWeekendings)
{
if (TeamIds == null || TeamIds.Count <= 0)
return new Dictionary<DateTime, PeopleResourceModel.CapacityValues>();
var context = new EnVisageEntities();
Guid[] scenarios;
if (isPlanned) scenarios = (from s in context.Teams where TeamIds.Contains(s.Id) && s.PlannedCapacityScenarioId != null select s.PlannedCapacityScenarioId.Value).ToArray();
else scenarios = (from s in context.Teams where TeamIds.Contains(s.Id) && s.ActualCapacityScenarioId != null select s.ActualCapacityScenarioId.Value).ToArray();
return GetWeeklyCapacity(scenarios, expCats, uoms, isUOMMode, fiscalCalendarWeekendings);
}
private Dictionary<DateTime, PeopleResourceModel.CapacityValues> GetWeeklyCapacity(Guid[] SccenarioIds, Dictionary<Guid, ExpenditureCategory> expCats, Dictionary<Guid, UOM> uoms, bool? isUOMMode, List<DateTime> fiscalCalendarWeekendings)
{
var dict = new Dictionary<DateTime, PeopleResourceModel.CapacityValues>();
var context = new EnVisageEntities();
Guid[] expCatIds = expCats.Keys.ToArray();
var sds = (from sd in context.ScenarioDetail where SccenarioIds.Contains(sd.ParentID.Value) && fiscalCalendarWeekendings.Contains(sd.WeekEndingDate.Value) && expCatIds.Contains(sd.ExpenditureCategoryId.Value) select sd).ToList();
// fill dictionary with weekly capacity for each week
foreach (var week in fiscalCalendarWeekendings)
{
if (!dict.ContainsKey(week))
{
var quantity = 0M;
var cost = 0M;
var sd = (from s in sds where s.WeekEndingDate == week select s).ToList();
foreach (var s in sd)
{
quantity += s.Quantity.Value * Utils.GetUOMMultiplier(expCats, uoms, s.ExpenditureCategoryId ?? Guid.Empty, isUOMMode);
cost += s.Cost.Value;
}
dict.Add(week, new PeopleResourceModel.CapacityValues()
{
Quantity = quantity,
Cost = cost,
WeekEnding = week
});
}
}
return dict;
}
}
#region SA. ENV-608. Dashboard performance graph
public class StackGraphSerieData : List<List<object>>
{
public void AddValue(long tickValue, decimal dataValue)
{
List<object> point = new List<object>();
point.Add(tickValue);
point.Add(dataValue);
this.Add(point);
}
}
public class StackGraphSerie
{
public StackGraphSerieData data;
public StackGraphSerie()
{
data = new StackGraphSerieData();
}
}
public class StackGraphBarOptions : List<List<object>>
{
public void AddValue(long tickValue, string barTitle)
{
List<object> option = new List<object>();
option.Add(tickValue);
option.Add(barTitle);
this.Add(option);
}
}
public class StackGraphDataBlock
{
public List<StackGraphSerie> series;
public StackGraphBarOptions barOptions;
public StackGraphDataBlock()
{
series = new List<StackGraphSerie>();
}
}
#endregion
}