using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.Entity; using System.Linq; using System.Net; using System.Web; using System.Web.Mvc; using EnVisage.Code; using EnVisage.Code.Cache; using jQuery.DataTables.Mvc; using EnVisage.Models; using EnVisage.Code.BLL; using EnVisage.App_Start; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using System.Data.Entity.Infrastructure; namespace EnVisage.Controllers { public class TeamController : BaseController { /// /// An UI representation of Team to be displayed as list items /// public class ListTeam { public Guid Id { get; set; } public string Name { get; set; } public string Users { get; set; } public string Comany { get; set; } public string CostCenter { get; set; } public string CostCenterNumber { get; set; } public string GLAccount { get; set; } public string ReportTo { get; set; } public bool IsResourcesAttached { get; set; } } /// /// GET: /Teams/ /// /// Empty view [HttpGet] [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Read)] public ActionResult Index() { return View(); } /// /// Returns JSON teams list with filters and sort for jQuery DataTables /// [HttpPost] [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Read)] public JsonResult Index(JQueryDataTablesModel jQueryDataTablesModel) { int totalRecordCount; int searchRecordCount; var teams = GetTeams(startIndex: jQueryDataTablesModel.iDisplayStart, pageSize: jQueryDataTablesModel.iDisplayLength, sortedColumns: jQueryDataTablesModel.GetSortedColumns(), totalRecordCount: out totalRecordCount, searchRecordCount: out searchRecordCount, searchString: jQueryDataTablesModel.sSearch); return this.DataTablesJson(items: teams, totalRecords: totalRecordCount, totalDisplayRecords: searchRecordCount, sEcho: jQueryDataTablesModel.sEcho); } [HttpPost] public ActionResult GetExpCatDropdown(string teamId) { var expCats = Utils.GetTeamExpenditureCategories(Guid.Parse(teamId)); return Json(new { Result = true, data = expCats }, JsonRequestBehavior.AllowGet); } private string GetUserName(string Id) { var ac = new ApplicationDbContext(); var usermanager = new UserManager(new UserStore(ac)); return usermanager.FindById(Id).UserName; } private IList GetTeams(int startIndex, int pageSize, ReadOnlyCollection sortedColumns, out int totalRecordCount, out int searchRecordCount, string searchString) { var query = from c in DbContext.Teams select new ListTeam() { Id = c.Id, Name = c.Name, Comany = c.Company.Name, CostCenter = c.CreditDepartment.Name, CostCenterNumber = c.CreditDepartment.CreditNumber, ReportTo = c.Contact.FirstName + " " + c.Contact.LastName, IsResourcesAttached = c.PeopleResources.Any() }; //filter if (!string.IsNullOrWhiteSpace(searchString)) { query = query.Where(c => c.Name.ToLower().Contains(searchString.ToLower())); } //sort foreach (var sortedColumn in sortedColumns) { switch (sortedColumn.PropertyName) { case "Id": if (sortedColumn.Direction == SortingDirection.Ascending) query = query.OrderBy(c => c.Id); else query = query.OrderByDescending(c => c.Id); break; case "Company": if (sortedColumn.Direction == SortingDirection.Ascending) query = query.OrderBy(c => c.Comany); else query = query.OrderByDescending(c => c.Comany); break; case "CostCenter": if (sortedColumn.Direction == SortingDirection.Ascending) query = query.OrderBy(c => c.CostCenter); else query = query.OrderByDescending(c => c.CostCenter); break; case "View": if (sortedColumn.Direction == SortingDirection.Ascending) query = query.OrderBy(c => c.GLAccount); else query = query.OrderByDescending(c => c.GLAccount); break; case "ReportTo": if (sortedColumn.Direction == SortingDirection.Ascending) query = query.OrderBy(c => c.ReportTo); else query = query.OrderByDescending(c => c.ReportTo); break; default: if (sortedColumn.Direction == SortingDirection.Ascending) query = query.OrderBy(c => c.Name); else query = query.OrderByDescending(c => c.Name); break; } } totalRecordCount = DbContext.ExpenditureCategory.Count(); searchRecordCount = query.Count(); var list = query.Skip(startIndex).Take(pageSize).ToList(); foreach (var q in list) { var users = DbContext.User2Team.Where(x => x.TeamId == q.Id).ToList(); foreach (var user in users) { q.Users += GetUserName(user.UserId); } } return list; } // GET: /Team/Details/5 [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Read)] public ActionResult Board() { var model = new TeamboardModel { Teams = new TeamManager(DbContext).GetTeamsByUser(Guid.Parse(User.Identity.GetUserId())).ToList() }; var user = new UsersCache().Value.FirstOrDefault(x => x.Id == new Guid(HttpContext.User.Identity.GetUserId())); if (user != null) ViewBag.IsUOMHours = !user.PreferredResourceAllocation; return View(model); } // GET: /Team/Edit/5 [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Write)] public ActionResult Edit(Guid? id, Guid? viewId) { ViewBag.TeamId = id.ToString(); var model = new TeamModel(); try { var manager = new TeamManager(DbContext); model = (TeamModel)manager.Load(id) ?? new TeamModel(); if (Guid.Empty.Equals(model.Id)) { model.UserId = new List(); model.ViewId = new List(); if (viewId.HasValue && !model.ViewId.Contains(viewId.Value)) model.ViewId.Add(viewId.Value); } else { model.UserId = DbContext.User2Team.Where(x => x.TeamId == model.Id).ToList().Select(x => Guid.Parse(x.UserId)).ToList(); model.ViewId = DbContext.Team2View.Where(x => x.TeamId == model.Id).Select(tv => tv.ViewId).ToList(); } } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } return View(model); } [HttpPost] [ValidateAntiForgeryToken] [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Write)] public ActionResult Edit(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(); ContentLocker.RemoveLock("Team", model.Id.ToString(), User.Identity.Name); return RedirectToAction("Index", "View"); } 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 empty model with validation messages (if any) return View(model); } // GET: /Team/Delete/5 [HttpGet] [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Write)] public ActionResult Delete(Guid? id) { if (id == null || id == Guid.Empty) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var model = new TeamModel(); try { var manager = new TeamManager(DbContext); model = (TeamModel)manager.Load(id); if (model == null) return HttpNotFound(); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } return View(model); } // POST: /CreditDepartment/Delete/5 [HttpPost] [ValidateAntiForgeryToken] [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Write)] public ActionResult Delete(TeamModel model) { if (ContentLocker.IsLock("Team", model.Id.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var manager = new TeamManager(DbContext); var dbObj = manager.Load(model.Id, false); if (dbObj == null) return HttpNotFound(); if (!dbObj.PeopleResources.Any()) { var capacityScenarioId = dbObj.PlannedCapacityScenarioId; DbContext.User2Team.RemoveRange(DbContext.User2Team.Where(c2s => c2s.TeamId == dbObj.Id)); DbContext.Team2View.RemoveRange(DbContext.Team2View.Where(tv => tv.TeamId == dbObj.Id)); DbContext.Teams.Remove(dbObj); DbContext.SaveChanges(); if (capacityScenarioId != null) (DbContext as IObjectContextAdapter).ObjectContext.ExecuteStoreCommand(string.Format("exec sp_DeleteScenario '{0}'", capacityScenarioId)); ContentLocker.RemoveLock("Team", dbObj.Id.ToString(), User.Identity.Name); return RedirectToAction("Index", "View"); } //ModelState.AddModelError("error", "This team can't be deleted, because it's has some attached people resources."); SetErrorScript(message: "This team cannot be deleted, because it has some attached people resources."); return View(model); } /// /// /// /// /// /// /// /// /// A value indicating whether graph data is in hours or in resources. If null or true - Hours, false - Resources. /// [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Write)] public JsonResult ChangeCapacity(DateTime? startDate, DateTime? endDate, string expCat, string capacityValue, Guid teamId) { if (string.IsNullOrEmpty(capacityValue) || capacityValue == "undefined" || capacityValue == "0") return null; var rateManager = new RateManager(DbContext); var expenditureCategoryId = new Guid(expCat); var val = decimal.Parse(capacityValue); var expCats = DbContext.ExpenditureCategory.Where(x => x.Id == expenditureCategoryId).ToList(); var uomIds = expCats.Select(t => t.UOMId); var uoms = DbContext.UOMs.Where(x => uomIds.Contains(x.Id)).ToList(); var uomMultiplier = Utils.GetUOMMultiplier(expCats, uoms, expenditureCategoryId, false); val = val / uomMultiplier; var teamManager = new TeamManager(DbContext); var team = teamManager.Load(teamId, false); var scenarioManager = new ScenarioManager(DbContext); Scenario scen = null; if (team.PlannedCapacityScenarioId == null || team.PlannedCapacityScenarioId == Guid.Empty) { scen = new Scenario { Name = team.Name.Trim() + " Planned Capacity", Type = (int) ScenarioType.TeamPlannedCapacity, Id = Guid.NewGuid() }; team.PlannedCapacityScenarioId = scen.Id; DbContext.Scenarios.Add(scen); DbContext.SaveChanges(); } else scen = scenarioManager.Load(team.PlannedCapacityScenarioId); var weekendings = (from c in DbContext.FiscalCalendars where c.Type == 0 && c.StartDate >= startDate && c.EndDate <= endDate orderby c.StartDate select c.EndDate).ToArray(); var sds = (from sd in DbContext.ScenarioDetail where sd.ParentID == team.PlannedCapacityScenarioId && sd.ExpenditureCategoryId == expenditureCategoryId && weekendings.Contains(sd.WeekEndingDate.Value) select sd).ToList(); foreach (var week in weekendings) { var sd = (from s in sds where s.WeekEndingDate == week select s).FirstOrDefault(); if (sd != null) { sd.Quantity += val; if (sd.Quantity < 0) sd.Quantity = 0; sd.Cost = sd.Quantity * rateManager.GetRateValue(expenditureCategoryId, week); } else { if (val < 0) continue; var newSD = new ScenarioDetail {Id = Guid.NewGuid(), ParentID = scen.Id, Quantity = val}; newSD.Cost = newSD.Quantity * rateManager.GetRateValue(expenditureCategoryId, week); newSD.ExpenditureCategoryId = expenditureCategoryId; newSD.WeekEndingDate = week; newSD.WeekOrdinal = 0; DbContext.ScenarioDetail.Add(newSD); } } DbContext.SaveChanges(); return Json(new { Result = true, data = weekendings }, JsonRequestBehavior.AllowGet); } [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Write)] public JsonResult ResetCapacity(DateTime? startDate, DateTime? endDate, string expCat, Guid teamId, bool? fullTime) { var rateManager = new RateManager(DbContext); var expenditureCategoryId = new Guid(expCat); var expCategory = DbContext.ExpenditureCategory.Where(x => x.Id == expenditureCategoryId).FirstOrDefault(); var uomVal = expCategory.UOM.UOMValue; var teamManager = new TeamManager(DbContext); var team = teamManager.Load(teamId, false); var peopleresouces = team.PeopleResources.Where(x => x.ExpenditureCategoryId == expenditureCategoryId && x.IsActiveEmployee).ToArray(); var scenarioManager = new ScenarioManager(DbContext); Scenario scen = null; if (team.PlannedCapacityScenarioId == null || team.PlannedCapacityScenarioId == Guid.Empty) { scen = new Scenario { Name = team.Name.Trim() + " Planned Capacity", Type = (int)ScenarioType.TeamPlannedCapacity, Id = Guid.NewGuid() }; team.PlannedCapacityScenarioId = scen.Id; DbContext.Scenarios.Add(scen); DbContext.SaveChanges(); } else scen = scenarioManager.Load(team.PlannedCapacityScenarioId); List weekendings = null; if (fullTime != null && (bool)fullTime) weekendings = (from c in DbContext.FiscalCalendars where c.Type == 0 && c.StartDate >= startDate orderby c.StartDate select c.EndDate).ToList(); else weekendings = (from c in DbContext.FiscalCalendars where c.Type == 0 && c.StartDate >= startDate && c.EndDate <= endDate orderby c.StartDate select c.EndDate).ToList(); var sds = (from sd in DbContext.ScenarioDetail where sd.ParentID == team.PlannedCapacityScenarioId && sd.ExpenditureCategoryId == expenditureCategoryId && weekendings.Contains(sd.WeekEndingDate.Value) select sd).ToList(); DbContext.ScenarioDetail.RemoveRange(sds); var rates = DbContext.Rates.Where(x => x.ExpenditureCategoryId == expenditureCategoryId && x.Type == (int)RateModel.RateType.Global).ToList(); List sdToAdd = new List(); foreach (var week in weekendings) { decimal vc = uomVal * peopleresouces.Count(); if (vc <= 0) continue; var newSD = new ScenarioDetail { Id = Guid.NewGuid(), ParentID = scen.Id, Quantity = vc }; var currrate = rates.FirstOrDefault(x => week >= x.StartDate && week <= x.EndDate); newSD.Cost = newSD.Quantity * ((currrate != null) ? currrate.Rate1 : 0); newSD.ExpenditureCategoryId = expenditureCategoryId; newSD.WeekEndingDate = week; newSD.WeekOrdinal = 0; sdToAdd.Add(newSD); } DbContext.ScenarioDetail.AddRange(sdToAdd); DbContext.SaveChanges(); return Json(new { Result = true, data = weekendings }, JsonRequestBehavior.AllowGet); } [HttpPost] [AreaSecurityAttribute(area = Areas.Views, level = AccessLevel.Read)] public ActionResult GetTeamResourcesInfo(Guid? teamId) { var model = new TeamManager(DbContext).Load(teamId); return PartialView("~/Views/PeopleResource/_resourcesList.cshtml", model); } private List FillMissingWeeends(List list, IEnumerable weekEnds) { if (list.Count < weekEnds.Count()) { var result = weekEnds.Except(list.Select(x => x[0])); list.AddRange(result.Select(x => new long[] { x, 0 })); } return list.OrderBy(x => x[0]).ToList(); } } }