EnVisageOnline/Main-RMO/Source/EnVisage/Controllers/MixController.cs

942 lines
37 KiB
C#

using EnVisage.App_Start;
using EnVisage.Code;
using EnVisage.Code.BLL;
using EnVisage.Models;
using System;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using System.Collections.Generic;
using MongoDB.Bson;
using EnVisage.Code.DAL.Mongo;
using MongoDB.Bson.Serialization;
using EnVisage.Code.Cache;
namespace EnVisage.Controllers
{
[Authorize]
public class MixController : BaseController
{
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
public ActionResult Index(string id)
{
return View("Index", null, id);
}
public ActionResult ExportToPDF(string id)
{
PDFExporter exporter = new PDFExporter();
exporter.BrowserWidth = 2560;
byte[] pdfBuffer = exporter.ExportPage(Url.Action("Index", "Mix", new { @id = id }, this.Request.Url.Scheme), 20, true, Request.Cookies);
// send the PDF file to browser
FileResult fileResult = new FileContentResult(pdfBuffer, "application/pdf");
fileResult.FileDownloadName = "Prevu-RMO-" + DateTime.Today.Month + "-" + DateTime.Today.Day + ".pdf";
return fileResult;
}
private void LoadMixFilterValues(MixFilterVariantsModel model, string userId)
{
if (model == null)
throw new ArgumentNullException("Model must be not null");
if (string.IsNullOrWhiteSpace(userId))
throw new ArgumentNullException("userId");
model.AvailableTeamsAndViews = Utils.GetViewsAndTeams(userId);
model.AvailableUsers = Utils.GetUsers().ToList();
model.AvailableMixes = Utils.GetMixesAvailable4User(userId);
model.AvailableExpenditures = Utils.GetExpenditures();
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
public JsonResult GetPageFilter()
{
var userId = User.Identity.GetID();
var model = new MixSaveModel()
{
Users = new List<Guid>() { Guid.Parse(userId) }
};
LoadMixFilterValues(model.Filter.Variants, userId);
return Json(model);
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
public JsonResult LoadMix(string model)
{
string mixId = model;
MixSaveModel serverModel = new MixSaveModel();
MixSaveModel mongoModel = new MixSaveModel();
LoadMixFilterValues(serverModel.Filter.Variants, User.Identity.GetID());
if (!string.IsNullOrWhiteSpace(mixId))
{
// Get mix data from Mongo
var mixManager = ResolveMixManager(DbProvider.MongoDb);
mongoModel = mixManager.RetrieveModel(mixId);
if (mongoModel != null)
{
var startDate = Utils.ConvertFromUnixDate(mongoModel.StartDate);
var endDate = Utils.ConvertFromUnixDate(mongoModel.EndDate);
var endDateCorrected = endDate.AddDays(6);
// Create server Mix model from SQL
GetCalendar(serverModel.Calendar, startDate, endDateCorrected,
mongoModel.Filter.Selection.TeamsViews.Where(t => t.Group.Name == "Teams").Select(x => new Guid(x.Id)).ToList(),
mongoModel.Filter.Selection.TeamsViews.Where(t => t.Group.Name == "Views").Select(x => new Guid(x.Id)).ToList(),
mongoModel.Filter.Selection.TeamsViews.Where(x => x.IsNew).Select(t => (MixTeamViewModel)t).ToList());
MixModelsMergeManager mergeMngr = new MixModelsMergeManager();
mergeMngr.MergeHeaders(serverModel, mongoModel);
mergeMngr.MergeFilters(serverModel.Filter, mongoModel.Filter);
mergeMngr.MergeCalendars(serverModel, mongoModel, startDate, endDate);
}
}
return Json(serverModel);
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
public ActionResult DeleteMix(string model)
{
try
{
Guid userId = new Guid(User.Identity.GetID());
if (!string.IsNullOrWhiteSpace(model))
{
var mixManager = ResolveMixManager(DbProvider.MongoDb);
mixManager.Delete(model);
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Write)]
public ActionResult SaveMix(MixSaveModel model)
{
if (!string.IsNullOrWhiteSpace(model.Id) && ContentLocker.IsLock("Mix", model.Id, User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
model.TrimStringProperties();
if (ModelState.IsValid)
{
try
{
var mixManager = ResolveMixManager(DbProvider.MongoDb);
model.CreatedBy = User.Identity.GetID();
var mix = mixManager.SaveWithChildren(model);
DbContext.SaveChanges();
return Json(new
{
Id = mix.Id.ToString()
});
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
}
// SA. For model errors debug:
var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0).ToList();
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Write)]
public ActionResult ActivateMix(string model)
{
if (string.IsNullOrWhiteSpace(model) || ContentLocker.IsLock("Mix", model.ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
try
{
var mixManager = ResolveMixManager(DbProvider.MongoDb);
mixManager.ActivateMix(model);
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
public ActionResult LoadCalendar(MixSaveModel model)
{
MixSaveModel clientModel = model;
if ((clientModel == null) || (clientModel.Filter == null) || (clientModel.Filter.Selection == null))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if ((clientModel.Filter.Selection.StartDate < 1) || (clientModel.Filter.Selection.EndDate < 1))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
try
{
var startDate = Utils.ConvertFromUnixDate(clientModel.Filter.Selection.StartDate);
var endDate = Utils.ConvertFromUnixDate(clientModel.Filter.Selection.EndDate);
var endDateCorrected = endDate.AddDays(6);
var teams = clientModel.Filter.Selection.TeamsViews.Where(t => !t.IsNew && t.Group.Name == "Teams")
.Select(t => new Guid(t.Id)).Distinct().ToList();
var views = clientModel.Filter.Selection.TeamsViews.Where(t => t.Group.Name == "Views")
.Select(t => new Guid(t.Id)).Distinct().ToList();
var newTeams = clientModel.Filter.Selection.TeamsViews.Where(x => x.IsNew).ToList();
MixSaveModel serverModel = new MixSaveModel();
GetCalendar(serverModel.Calendar, startDate, endDateCorrected, teams, views, newTeams);
MixModelsMergeManager mergeMngr = new MixModelsMergeManager();
mergeMngr.MergeFilters(serverModel.Filter, clientModel.Filter);
mergeMngr.MergeCalendars(serverModel, clientModel, startDate, endDate);
return new JsonResult()
{
Data = serverModel,
MaxJsonLength = int.MaxValue
};
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
#region Private Methods
private void GetCalendar(MixCalendarModel model, DateTime startDate, DateTime endDate, List<Guid> teamsIds,
List<Guid> viewsIds, List<MixTeamViewModel> NewTeams)
{
// SA. ENV-1218
UOMManager uomMngr = new UOMManager(DbContext);
Dictionary<Guid, UOM> uoms = uomMngr.GetAsDictionary();
var fiscalCalendarManager = (new FiscalCalendarManager(DbContext));
var teamManager = (new TeamManager(DbContext));
var mixManager = ResolveMixManager(DbProvider.MongoDb);
var scenarioManager = (new ScenarioManager(DbContext));
var prManager = (new PeopleResourcesManager(DbContext));
var fiscalCalendar = fiscalCalendarManager.GetFiscalCalendar(FiscalCalendarModel.FiscalYearType.Week, null, null, true, null);
var weekEndings = fiscalCalendar.FindAll(x => x.EndDate >= startDate && x.EndDate <= endDate).Select(x => x.EndDate).OrderBy(x => x).ToList();
var teams = teamManager.FindTeams(teamsIds, viewsIds, User.Identity.GetID());
var teams2Scenarios = teamManager.GetRelationsWithScenariosTree(teams.Select(x => x.Id).ToList(),
ScenarioType.Portfolio, ScenarioStatus.Active);
var activeScenarios = teams2Scenarios.SelectMany(x => x.Value.Select(s => s.ScenarioId)).Distinct().ToList();
var allTeamsProjects = teams.SelectMany(x => x.Team2Project.Select(p => p.ProjectId)).Distinct().ToList();
var plannedCapacityScenarios =
teams.Where(x => x.PlannedCapacityScenarioId.HasValue).Select(x => x.PlannedCapacityScenarioId.Value).ToList();
var actualCapacityScenarios =
teams.Where(x => x.ActualCapacityScenarioId.HasValue).Select(x => x.ActualCapacityScenarioId.Value).ToList();
var capacityScenarios = plannedCapacityScenarios.Union(actualCapacityScenarios).ToList();
var expCatsInTeams = scenarioManager.GetCategoriesInScenarios(capacityScenarios);
// for reducing number of retrieving scenario details rows we should to retrieve only by ECs which exists in teams
var scenarioDetails = scenarioManager.GetScenarioDetailsTree(capacityScenarios.Union(activeScenarios).ToList(),
expCatsInTeams.Keys.ToList());
// for reducing number of retrieving teams allocations rows we should to retrieve only by active scenarios and ECs which exists in teams
var teamsAllocations = teamManager.GetTeamsAllocationTree(teams.Select(x => x.Id).ToList(), activeScenarios,
expCatsInTeams.Keys.ToList());
var resources = prManager.FindResourcesTree(teams.Select(x => x.Id), true);
var resourcesIds = resources.SelectMany(x => x.Value.SelectMany(r => r.Value.Select(rv => rv.Id)));
model.FiscalCalendarWeekEndings = fiscalCalendar.Select(x => Utils.ConvertToUnixDate(x.EndDate)).OrderBy(x => x).ToList();
model.WeekEndings = CastWeekEndingsToTree(weekEndings);
model.Projects = mixManager.GetProjectModel(allTeamsProjects).ToDictionary(x => x.Id.ToString());
model.Vacations = prManager.GetTotalVacaitons(resourcesIds)
.ToDictionary(x => x.Key.ToString(), g => g.Value.ToDictionary(v => Utils.ConvertToUnixDate(v.Key).ToString(), gv => gv.Value));
model.Trainings = prManager.GetTotalTrainings(resourcesIds)
.ToDictionary(x => x.Key.ToString(), g => g.Value.ToDictionary(v => Utils.ConvertToUnixDate(v.Key).ToString(), gv => gv.Value));
#region Existence Teams Filling
foreach (var team in teams)
{
var teamAllocations = teamsAllocations.ContainsKey(team.Id) ? teamsAllocations[team.Id] : null;
var teamResources = resources.ContainsKey(team.Id) ? resources[team.Id] : null;
var mixTeam = new MixTeamModel()
{
Id = team.Id.ToString(),
Name = team.Name
};
var plannedCapacityScenario = (team.PlannedCapacityScenarioId.HasValue &&
scenarioDetails.ContainsKey(team.PlannedCapacityScenarioId.Value))
? scenarioDetails[team.PlannedCapacityScenarioId.Value]
: null;
var actualCapacityScenario = (team.ActualCapacityScenarioId.HasValue &&
scenarioDetails.ContainsKey(team.ActualCapacityScenarioId.Value))
? scenarioDetails[team.ActualCapacityScenarioId.Value]
: null;
var expCatsInTeam = new List<Guid>();
if (plannedCapacityScenario != null && plannedCapacityScenario.Keys.Count > 0)
expCatsInTeam.AddRange(plannedCapacityScenario.Keys);
if (actualCapacityScenario != null && actualCapacityScenario.Keys.Count > 0)
expCatsInTeam.AddRange(actualCapacityScenario.Keys);
foreach (var expCatId in expCatsInTeam.Distinct())
{
Guid uomId = expCatsInTeams[expCatId].UOMId; // SA. ENV-1218
var activityCategory = new ActivityExpCategoryFooterModel()
{
Id = expCatId,
Name = expCatsInTeams[expCatId].ExpCategoryWithCcName, // Name, SA. ENV-1218
UomValue = uoms[uomId].UOMValue // SA. ENV-1218
};
if (plannedCapacityScenario != null && plannedCapacityScenario.ContainsKey(expCatId))
{
activityCategory.PlannedCapacityValues = plannedCapacityScenario[expCatId]
.Where(x => x.WeekEndingDate.HasValue)
.OrderBy(x => x.WeekEndingDate)
.ToDictionary(x => Utils.ConvertToUnixDate(x.WeekEndingDate.Value).ToString(), g => g.Quantity ?? 0);
}
if (actualCapacityScenario != null && actualCapacityScenario.ContainsKey(expCatId))
{
activityCategory.ActualCapacityValues = actualCapacityScenario[expCatId]
.Where(x => x.WeekEndingDate.HasValue)
.OrderBy(x => x.WeekEndingDate)
.ToDictionary(x => Utils.ConvertToUnixDate(x.WeekEndingDate.Value).ToString(), g => g.Quantity ?? 0);
}
if (teams2Scenarios.ContainsKey(team.Id))
{
foreach (var team2scenario in teams2Scenarios[team.Id])
{
var teamAllocationsInScenarioAndEC = (teamAllocations != null &&
teamAllocations.ContainsKey(team2scenario.ScenarioId) &&
teamAllocations[team2scenario.ScenarioId].ContainsKey(expCatId))
? teamAllocations[team2scenario.ScenarioId][expCatId]
: new Dictionary<DateTime, TeamAllocation>();
if (!scenarioDetails.ContainsKey(team2scenario.ScenarioId))
continue;
if (!scenarioDetails[team2scenario.ScenarioId].ContainsKey(expCatId))
continue;
foreach (var detail in scenarioDetails[team2scenario.ScenarioId][expCatId])
{
decimal quantity = 0;
if (teamAllocationsInScenarioAndEC.ContainsKey(detail.WeekEndingDate.Value))
quantity = teamAllocationsInScenarioAndEC[detail.WeekEndingDate.Value].Quantity;
else
quantity = (team2scenario.Allocation * (detail.Quantity ?? 0)) / (decimal)100.0;
var sdKey = Utils.ConvertToUnixDate(detail.WeekEndingDate.Value).ToString();
if (!activityCategory.NeedCapacity.ContainsKey(sdKey))
activityCategory.NeedCapacity.Add(sdKey, 0);
activityCategory.NeedCapacity[sdKey] += quantity;
}
}
}
if (teamResources != null && teamResources.ContainsKey(expCatId))
{
foreach (var resource in teamResources[expCatId])
{
var resourceModel = new ActivityResourceFooterModel()
{
Id = resource.Id,
Name = string.Format("{0} {1}", resource.FirstName, resource.LastName)
};
var fiscalCalendarWeeks4Resource = fiscalCalendar.Where(x => x.StartDate >= resource.StartDate && x.EndDate <= resource.EndDate).Select(x => x.EndDate).ToList();
// TODO: take into consideration trainings and vacations for current resource
foreach (var weekEnding in fiscalCalendarWeeks4Resource)
{
var rKey = Utils.ConvertToUnixDate(weekEnding).ToString();
if (!resourceModel.TotalCapacity.ContainsKey(rKey))
resourceModel.TotalCapacity.Add(rKey, activityCategory.UomValue);
}
foreach (var rAllocation in resource.PeopleResourceAllocations)
{
if (!rAllocation.WeekEndingDate.HasValue)
continue;
var rKey = Utils.ConvertToUnixDate(rAllocation.WeekEndingDate.Value).ToString();
if (!resourceModel.AllocatedCapacity.ContainsKey(rKey))
resourceModel.AllocatedCapacity.Add(rKey, 0);
if (!activityCategory.AllocatedCapacity.ContainsKey(rKey))
activityCategory.AllocatedCapacity.Add(rKey, 0);
resourceModel.AllocatedCapacity[rKey] += rAllocation.Quantity ?? 0;
activityCategory.AllocatedCapacity[rKey] += rAllocation.Quantity ?? 0;
}
activityCategory.Resources.Add(resourceModel.Id.ToString(), resourceModel);
}
}
mixTeam.ExpCategories.Add(activityCategory.Id.ToString(), activityCategory);
}
model.Teams.Add(mixTeam);
}
#endregion
#region New Teams Filling
if (NewTeams != null)
{
foreach (var team in NewTeams.Where(x => !teams.Any(t => t.Id.ToString() == x.Id)))
{
var mixTeam = new MixTeamModel()
{
Id = team.Id.ToString(),
Name = team.TVName,
CompanyId = team.CompanyId,
UserId = team.UserId,
CostCenterId = team.CostCenterId,
Group = team.Group,
IsNew = true
};
var expCatsInTeam = new List<Guid>();
if (null != team.Data)
{
if (team.Data != null)
expCatsInTeam = team.Data.Where(t => t != null).Select(x => x.Id).ToList();
var expCats = DbContext.ExpenditureCategory.Where(x => expCatsInTeam.Contains(x.Id))
.ToDictionary(x => x.Id, x => x);
foreach (var expCat in team.Data.Where(t => t != null))
{
if (expCat.Positions != null)
foreach (var pos in expCat.Positions)
{
pos.SDate = Utils.ConvertFromUnixDate(long.Parse(pos.StartDate.Substring(6, 13)));
pos.EDate = (!string.IsNullOrEmpty(pos.EndDate))
? Utils.ConvertFromUnixDate(long.Parse(pos.EndDate.Substring(6, 13)))
: (DateTime?)null;
}
var activityCategory = new ActivityExpCategoryFooterModel()
{
Id = expCat.Id,
Name = expCats.ContainsKey(expCat.Id) ? expCats[expCat.Id].Name : string.Empty,
UomValue = expCats.ContainsKey(expCat.Id)
? expCats[expCat.Id].UOM != null ? expCats[expCat.Id].UOM.UOMValue : 0
: 0
};
foreach (var week in weekEndings)
{
activityCategory.PlannedCapacityValues.Add(Utils.ConvertToUnixDate(week).ToString(),
expCat.Positions == null
? 0
: expCat.Positions.Count(
x => x.SDate <= week && (!x.EDate.HasValue || x.EDate >= week)) * activityCategory.UomValue);
}
mixTeam.ExpCategories.Add(activityCategory.Id.ToString(), activityCategory);
// SA. ENV-1025. We need to reset attributes, because the values cause model deserialization problems
// on saving Mix operation
if (expCat.Positions != null)
foreach (var pos in expCat.Positions)
{
pos.SDate = null;
pos.EDate = null;
}
}
}
model.Teams.Add(mixTeam);
}
}
#endregion
model.Teams = model.Teams.OrderBy(x => x.Name).ToList();
}
private Dictionary<string, Dictionary<string, List<int>>> CastWeekEndingsToTree(List<DateTime> weekEndings)
{
var weekEndingsHierarchy = weekEndings.Select(x => new
{
x.Year,
x.Month,
x.Day
})
.GroupBy(x => x.Year)
.OrderBy(x => x.Key)
.ToDictionary(year => year.Key.ToString(),
months => months.GroupBy(month => month.Month)
.OrderBy(month => month.Key)
.ToDictionary(month => month.Key.ToString(),
days => days.Select(day => day.Day).OrderBy(day => day).ToList()));
return weekEndingsHierarchy;
}
private IMixManager<Code.DAL.Mongo.Mix> ResolveMixManager(DbProvider dbProvider)
{
switch (dbProvider)
{
//case DbProvider.SqlServer:
// return new MixManager(DbContext);
case DbProvider.MongoDb:
return new MongoMixManager(DbContext, User.Identity.GetID());
default:
throw new InvalidOperationException(string.Format("DbProvider with value = {0} not defined", dbProvider.GetHashCode()));
}
}
#endregion
// GET: /Team/Edit/5
[AreaSecurityAttribute(area = Areas.Teams, level = AccessLevel.Write)]
public ActionResult EditTeam(Guid? id)
{
bool isNewTeam = !id.HasValue || (id.Value == Guid.Empty);
ViewBag.IsNewTeam = isNewTeam;
var model = new TeamModel();
try
{
if (!isNewTeam)
{
var manager = new TeamManager(DbContext);
model = (TeamModel)manager.Load(id) ?? new TeamModel();
}
else
{
model.Id = Guid.NewGuid();
}
if (isNewTeam)
{
model.UserId = new List<Guid>();
model.UserId.Add(new Guid(User.Identity.GetUserId()));
}
else
{
model.UserId = DbContext.User2Team.Where(x => x.TeamId == model.Id).ToList().Select(x => Guid.Parse(x.UserId)).ToList();
}
return PartialView("_mixTeams", model);
}
catch (BLLException blEx)
{
if (blEx.DisplayError)
{
//SetErrorScript(message: blEx.Message);
ModelState.AddModelError(string.Empty, "Cannot save view. Try again later.");
}
else
{
LogException(blEx);
//SetErrorScript();
ModelState.AddModelError(string.Empty, "Cannot save view. Try again later.");
}
}
catch (Exception exception)
{
LogException(exception);
SetErrorScript();
}
HttpContext.Response.StatusCode = 500;
HttpContext.Response.Clear();
return PartialView("_mixTeams", model);
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
[AreaSecurityAttribute(area = Areas.Teams, level = AccessLevel.Write)]
public ActionResult EditTeam(TeamModel model)
{
if (model == null || ContentLocker.IsLock("Team", model.Id.ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
model.TrimStringProperties();
if (model.ReportToId.HasValue && model.ReportToId == Guid.Empty)
model.ReportToId = null;
if (ModelState.IsValid)
{
try
{
var context = new EnVisageEntities();
var manager = new TeamManager(context);
manager.Save(model);
context.SaveChanges();
//(new ProjectAccessCache()).Invalidate();
ContentLocker.RemoveLock("Team", model.Id.ToString(), User.Identity.Name);
return PartialView("_mixTeams", model);
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
//SetErrorScript();
ModelState.AddModelError(string.Empty, "Cannot save team. Try again later.");
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
//SetErrorScript();
ModelState.AddModelError(string.Empty, "Cannot save team. Try again later.");
}
}
// return empty model with validation messages (if any)
HttpContext.Response.StatusCode = 500;
HttpContext.Response.Clear();
return PartialView("_mixTeams", model);
}
/// <summary>
/// Get Scenario details for the Project in da mix
/// </summary>
[HttpPost]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
[ValidateJsonAntiForgeryToken]
public ActionResult GetScenarioDetails(MixScenarioDetailsLoadModel model)
{
if (model == null || model.ScenarioId == Guid.Empty)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var errorMessage = string.Empty;
try
{
var mixManager = ResolveMixManager(DbProvider.MongoDb);
var allocations = mixManager.GetFullAllocationInfoByScenario(model.MixId, model.ScenarioId);
return Json(allocations);
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
errorMessage = blEx.Message;
else // if display not requried then display modal form with general error message
{
LogException(blEx);
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
}
// return empty model with validation messages (if any)
HttpContext.Response.StatusCode = 500;
HttpContext.Response.Clear();
return Json(errorMessage);
}
[HttpPost]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Write)]
[ValidateJsonAntiForgeryToken]
public ActionResult EditScenarioDetails(ScenarioCalendarMixModel model)
{
if (model == null || model.Id == Guid.Empty)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var errorMessage = string.Empty;
try
{
var user = (new UsersCache()).Value.FirstOrDefault(x => x.Id == new Guid(User.Identity.GetID()));
var detailsModel = (new ScenarioDetailsCalendarModel(model, user));
return PartialView("~/Views/Scenarios/_scenarioCalendar.cshtml", detailsModel);
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
errorMessage = blEx.Message;
else // if display not requried then display modal form with general error message
{
LogException(blEx);
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
}
// return empty model with validation messages (if any)
HttpContext.Response.StatusCode = 500;
HttpContext.Response.Clear();
return Json(errorMessage);
}
// SA. ENV-1254
[HttpPost]
[AreaSecurity(area = Areas.Mixes, level = AccessLevel.Read)]
[ValidateJsonAntiForgeryToken]
public ActionResult GetTeamsById(Guid[] ids, long startDateMs, long endDateMs)
{
var teamModels = new List<MixTeamModel>();
DateTime startDate = Utils.ConvertFromUnixDate(startDateMs);
DateTime endDate = Utils.ConvertFromUnixDate(endDateMs);
var teams = DbContext.Teams.AsNoTracking().Where(x => ids.Contains(x.Id)).ToList();
// SA. ENV-1218
UOMManager uomMngr = new UOMManager(DbContext);
Dictionary<Guid, UOM> uoms = uomMngr.GetAsDictionary();
var fiscalCalendarManager = (new FiscalCalendarManager(DbContext));
var teamManager = (new TeamManager(DbContext));
var scenarioManager = (new ScenarioManager(DbContext));
var prManager = (new PeopleResourcesManager(DbContext));
var fiscalCalendar = fiscalCalendarManager.GetFiscalCalendar(FiscalCalendarModel.FiscalYearType.Week, null, null, true, null);
var weekEndings = fiscalCalendar.FindAll(x => x.EndDate >= startDate && x.EndDate <= endDate).Select(x => x.EndDate).OrderBy(x => x).ToList();
var teams2Scenarios = teamManager.GetRelationsWithScenariosTree(teams.Select(x => x.Id).ToList(),
ScenarioType.Portfolio, ScenarioStatus.Active);
var activeScenarios = teams2Scenarios.SelectMany(x => x.Value.Select(s => s.ScenarioId)).Distinct().ToList();
var allTeamsProjects = teams.SelectMany(x => x.Team2Project.Select(p => p.ProjectId)).Distinct().ToList();
var plannedCapacityScenarios =
teams.Where(x => x.PlannedCapacityScenarioId.HasValue).Select(x => x.PlannedCapacityScenarioId.Value).ToList();
var actualCapacityScenarios =
teams.Where(x => x.ActualCapacityScenarioId.HasValue).Select(x => x.ActualCapacityScenarioId.Value).ToList();
var capacityScenarios = plannedCapacityScenarios.Union(actualCapacityScenarios).ToList();
var expCatsInTeams = scenarioManager.GetCategoriesInScenarios(capacityScenarios);
// for reducing number of retrieving scenario details rows we should to retrieve only by ECs which exists in teams
var scenarioDetails = scenarioManager.GetScenarioDetailsTree(capacityScenarios.Union(activeScenarios).ToList(),
expCatsInTeams.Keys.ToList());
// for reducing number of retrieving teams allocations rows we should to retrieve only by active scenarios and ECs which exists in teams
var teamsAllocations = teamManager.GetTeamsAllocationTree(teams.Select(x => x.Id).ToList(), activeScenarios,
expCatsInTeams.Keys.ToList());
var resources = prManager.FindResourcesTree(teams.Select(x => x.Id), true);
var resourcesIds = resources.SelectMany(x => x.Value.SelectMany(r => r.Value.Select(rv => rv.Id)));
foreach(var team in teams)
{
MixTeamModel mixTeam = new MixTeamModel()
{
Id = team.Id.ToString(),
Name = team.Name
};
var teamAllocations = teamsAllocations.ContainsKey(team.Id) ? teamsAllocations[team.Id] : null;
var teamResources = resources.ContainsKey(team.Id) ? resources[team.Id] : null;
var plannedCapacityScenario = (team.PlannedCapacityScenarioId.HasValue &&
scenarioDetails.ContainsKey(team.PlannedCapacityScenarioId.Value))
? scenarioDetails[team.PlannedCapacityScenarioId.Value]
: null;
var actualCapacityScenario = (team.ActualCapacityScenarioId.HasValue &&
scenarioDetails.ContainsKey(team.ActualCapacityScenarioId.Value))
? scenarioDetails[team.ActualCapacityScenarioId.Value]
: null;
var expCatsInTeam = new List<Guid>();
if (plannedCapacityScenario != null && plannedCapacityScenario.Keys.Count > 0)
expCatsInTeam.AddRange(plannedCapacityScenario.Keys);
if (actualCapacityScenario != null && actualCapacityScenario.Keys.Count > 0)
expCatsInTeam.AddRange(actualCapacityScenario.Keys);
foreach (var expCatId in expCatsInTeam.Distinct())
{
Guid uomId = expCatsInTeams[expCatId].UOMId; // SA. ENV-1218
var activityCategory = new ActivityExpCategoryFooterModel()
{
Id = expCatId,
Name = expCatsInTeams[expCatId].ExpCategoryWithCcName, // Name, SA. ENV-1218
UomValue = uoms[uomId].UOMValue // SA. ENV-1218
};
if (plannedCapacityScenario != null && plannedCapacityScenario.ContainsKey(expCatId))
{
activityCategory.PlannedCapacityValues = plannedCapacityScenario[expCatId]
.Where(x => x.WeekEndingDate.HasValue)
.OrderBy(x => x.WeekEndingDate)
.ToDictionary(x => Utils.ConvertToUnixDate(x.WeekEndingDate.Value).ToString(), g => g.Quantity ?? 0);
}
if (actualCapacityScenario != null && actualCapacityScenario.ContainsKey(expCatId))
{
activityCategory.ActualCapacityValues = actualCapacityScenario[expCatId]
.Where(x => x.WeekEndingDate.HasValue)
.OrderBy(x => x.WeekEndingDate)
.ToDictionary(x => Utils.ConvertToUnixDate(x.WeekEndingDate.Value).ToString(), g => g.Quantity ?? 0);
}
if (teams2Scenarios.ContainsKey(team.Id))
{
foreach (var team2scenario in teams2Scenarios[team.Id])
{
var teamAllocationsInScenarioAndEC = (teamAllocations != null &&
teamAllocations.ContainsKey(team2scenario.ScenarioId) &&
teamAllocations[team2scenario.ScenarioId].ContainsKey(expCatId))
? teamAllocations[team2scenario.ScenarioId][expCatId]
: new Dictionary<DateTime, TeamAllocation>();
if (!scenarioDetails.ContainsKey(team2scenario.ScenarioId))
continue;
if (!scenarioDetails[team2scenario.ScenarioId].ContainsKey(expCatId))
continue;
foreach (var detail in scenarioDetails[team2scenario.ScenarioId][expCatId])
{
decimal quantity = 0;
if (teamAllocationsInScenarioAndEC.ContainsKey(detail.WeekEndingDate.Value))
quantity = teamAllocationsInScenarioAndEC[detail.WeekEndingDate.Value].Quantity;
else
quantity = (team2scenario.Allocation * (detail.Quantity ?? 0)) / (decimal)100.0;
var sdKey = Utils.ConvertToUnixDate(detail.WeekEndingDate.Value).ToString();
if (!activityCategory.NeedCapacity.ContainsKey(sdKey))
activityCategory.NeedCapacity.Add(sdKey, 0);
activityCategory.NeedCapacity[sdKey] += quantity;
}
}
}
if (teamResources != null && teamResources.ContainsKey(expCatId))
{
foreach (var resource in teamResources[expCatId])
{
var resourceModel = new ActivityResourceFooterModel()
{
Id = resource.Id,
Name = string.Format("{0} {1}", resource.FirstName, resource.LastName)
};
var fiscalCalendarWeeks4Resource = fiscalCalendar.Where(x => x.StartDate >= resource.StartDate && x.EndDate <= resource.EndDate).Select(x => x.EndDate).ToList();
// TODO: take into consideration trainings and vacations for current resource
foreach (var weekEnding in fiscalCalendarWeeks4Resource)
{
var rKey = Utils.ConvertToUnixDate(weekEnding).ToString();
if (!resourceModel.TotalCapacity.ContainsKey(rKey))
resourceModel.TotalCapacity.Add(rKey, activityCategory.UomValue);
}
foreach (var rAllocation in resource.PeopleResourceAllocations)
{
if (!rAllocation.WeekEndingDate.HasValue)
continue;
var rKey = Utils.ConvertToUnixDate(rAllocation.WeekEndingDate.Value).ToString();
if (!resourceModel.AllocatedCapacity.ContainsKey(rKey))
resourceModel.AllocatedCapacity.Add(rKey, 0);
if (!activityCategory.AllocatedCapacity.ContainsKey(rKey))
activityCategory.AllocatedCapacity.Add(rKey, 0);
resourceModel.AllocatedCapacity[rKey] += rAllocation.Quantity ?? 0;
activityCategory.AllocatedCapacity[rKey] += rAllocation.Quantity ?? 0;
}
activityCategory.Resources.Add(resourceModel.Id.ToString(), resourceModel);
}
}
mixTeam.ExpCategories.Add(activityCategory.Id.ToString(), activityCategory);
}
teamModels.Add(mixTeam);
}
return Json(teamModels);
}
}
}