using EnVisage.App_Start; using EnVisage.Code.BLL; using EnVisage.Code.HtmlHelpers; using EnVisage.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using EnVisage.Code; using System.Net; using jQuery.DataTables.Mvc; using Microsoft.AspNet.Identity; namespace EnVisage.Controllers { public class PeopleResourceController : BaseController { private PeopleResourcesManager _manager = null; public PeopleResourcesManager Manager { get { return _manager ?? (_manager = new PeopleResourcesManager(DbContext)); } } // GET: Resource [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Read)] public ActionResult Index() { return View(DbContext.Teams.AsNoTracking().ToList()); } [HttpPost] [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Read)] public JsonResult Index(JQueryDataTablesModel jQueryDataTablesModel) { var resources = Manager.GetResources(); return this.DataTablesJson(items: resources, totalRecords: resources.Count, totalDisplayRecords: resources.Count, sEcho: jQueryDataTablesModel.sEcho); } [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Read)] public ActionResult Details(Guid? resourceId) { if (!resourceId.HasValue) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var model = (PeopleResourceModel)Manager.Load(resourceId); if (SecurityManager.CheckSecurityObjectPermission(Areas.Vacations, AccessLevel.Read)) model.Vacations = VacationManager.GetVacations(model.Id); if (SecurityManager.CheckSecurityObjectPermission(Areas.Trainings, AccessLevel.Read)) model.Trainings = TrainingManager.GetTrainings(model.Id); model.Training.Resources = new List() { resourceId.Value }; var maxdate = (from c in DbContext.FiscalCalendars where c.Type == 0 orderby c.StartDate descending select c.EndDate).FirstOrDefault(); if (model.EndDate == maxdate) model.PermanentResource = true; return View(model); } [HttpGet] //[ValidateAntiForgeryToken] [AreaSecurityAttribute(area = Areas.Trainings, level = AccessLevel.Write)] public ActionResult LoadTraining(Guid? Id, Guid resourceId) { #region Week Ending Day system setting var weekEndingSetting = DbContext.SystemSettings.FirstOrDefault(t => t.Type == (int)SystemSettingType.FiscalCalendarWeekEnding); var weekEndingDay = weekEndingSetting != null ? (DayOfWeek)Convert.ToInt16(weekEndingSetting.Value) : DayOfWeek.Saturday; #endregion if (Id.HasValue) { var manager = new TrainingManager(DbContext); TrainingModel model = (TrainingModel)manager.Load(Id, false); model.WeekendingDay = (short)weekEndingDay; return PartialView("_scheduleTraining", model); } else { return PartialView("_scheduleTraining", new TrainingModel() { TrainingStartDate = DateTime.Now, TrainingEndDate = DateTime.Now.AddDays(14), Resources = new List() { resourceId }, TrainingCost = 0, TrainingTimeAllocated = 0, WeekendingDay = (short)weekEndingDay }); } } [HttpPost] [ValidateAntiForgeryToken] [AreaSecurityAttribute(area = Areas.Trainings, level = AccessLevel.Write)] public ActionResult DeleteTraining(Guid deleteTrainingId, Guid Id) { if (ContentLocker.IsLock("Trainings", deleteTrainingId.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var manager = new TrainingManager(DbContext); var dbObj = manager.Load(deleteTrainingId, false); if (dbObj == null) return HttpNotFound(); DbContext.PeopleResourceTrainings.RemoveRange(DbContext.PeopleResourceTrainings.Where(t => t.TrainingId == dbObj.Id)); DbContext.Trainings.Remove(dbObj); DbContext.SaveChanges(); ContentLocker.RemoveLock("Trainings", dbObj.Id.ToString(), User.Identity.Name); return RedirectToAction("Details", "PeopleResource", new { resourceId = Id }); } [HttpPost] [ValidateAntiForgeryToken] [AreaSecurityAttribute(area = Areas.Trainings, level = AccessLevel.Write)] public ActionResult ScheduleTraining(TrainingModel model) { if (model == null || ContentLocker.IsLock("Trainings", model.Id.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); model.TrimStringProperties(); if (ModelState.IsValid) { try { //var redirectId = model.Id; //model.Id = Guid.Empty; //model.PeopleResourceTrainings = model.Resources.Select(x => new PeopleResourceTrainingModel() { Id = x }).ToList(); var manager = new TrainingManager(DbContext); manager.Save(model); DbContext.SaveChanges(); ContentLocker.RemoveLock("Trainings", model.Id.ToString(), User.Identity.Name); //return RedirectToAction("Details", "PeopleResource", new { resourceId = redirectId }); //return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri); return PartialView("_scheduleTraining", 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 expedenture categories. Try again later."); } } catch (Exception exception) // handle any unexpected error { LogException(exception); //SetErrorScript(); ModelState.AddModelError(string.Empty, "Cannot save expedenture categories. Try again later."); } } HttpContext.Response.StatusCode = 500; HttpContext.Response.Clear(); //return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri); return PartialView("_scheduleTraining", model); } [HttpGet] [AreaSecurityAttribute(area = Areas.Vacations, level = AccessLevel.Write)] public ActionResult EditVacation(Guid? id, Guid? peopleResourceId) { if ((id == null || id == Guid.Empty) && (peopleResourceId == null || peopleResourceId == Guid.Empty)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var manager = new VacationManager(DbContext); var model = id == null || Guid.Empty.Equals(id) ? new VacationModel() : (VacationModel)manager.Load(id) ?? new VacationModel(); if (Guid.Empty.Equals(model.Id) && peopleResourceId != null) model.PeopleResourceId = peopleResourceId.Value; #region Load Unit of Measure Value var uomRecord = (from p in DbContext.PeopleResources join ec in DbContext.ExpenditureCategory on p.ExpenditureCategoryId equals ec.Id join uom in DbContext.UOMs on ec.UOMId equals uom.Id where p.Id == model.PeopleResourceId select new { uom.Id, uom.UOMValue }).FirstOrDefault(); if (uomRecord == null || uomRecord.UOMValue == 0) throw new UOMNotExistsException(); if (Guid.Empty.Equals(model.Id) && peopleResourceId != null) model.HoursOff = 100; model.UOMValue = uomRecord.UOMValue; #endregion #region Week Ending Day system setting var weekEndingSetting = DbContext.SystemSettings.FirstOrDefault(t => t.Type == (int)SystemSettingType.FiscalCalendarWeekEnding); var weekEndingDay = weekEndingSetting != null ? (DayOfWeek)Convert.ToInt16(weekEndingSetting.Value) : DayOfWeek.Saturday; model.WeekendingDay = (short)weekEndingDay; #endregion return View(model); } [HttpPost] [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public ActionResult EditVacation(VacationModel model) { if (model == null || ContentLocker.IsLock("Vacations", model.Id.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); model.TrimStringProperties(); if (ModelState.IsValid) { try { var manager = new VacationManager(DbContext); manager.Save(model); DbContext.SaveChanges(); ContentLocker.RemoveLock("Vacations", model.Id.ToString(), User.Identity.Name); return model.ParentViewId.HasValue ? RedirectToAction("Details", "PeopleResource", new { resourceId = model.PeopleResourceId, viewId = model.ParentViewId.Value }) : RedirectToAction("Details", "PeopleResource", new { resourceId = model.PeopleResourceId }); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } } return View(model); } [HttpPost] [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public ActionResult Details(PeopleResourceModel model) { model.TrimStringProperties(); if (ModelState.IsValid) { try { Manager.Save(model); DbContext.SaveChanges(); return RedirectToAction("Index"); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } } return View(model); } [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public ActionResult Edit(Guid? resourceId, Guid? teamId, Guid? categoryId, bool? noAdjust) { var model = new PeopleResourceModel(); if (resourceId.HasValue && (resourceId != Guid.Empty)) model = (PeopleResourceModel)Manager.Load(resourceId); else { if (teamId.HasValue && teamId.Value != Guid.Empty) model.TeamId = teamId.Value; if (categoryId.HasValue && categoryId.Value != Guid.Empty) model.ExpenditureCategoryId = categoryId.Value; if(noAdjust.HasValue && noAdjust.Value == true) model.ChangeCapacity = false; else model.ChangeCapacity = true; } var maxdate = (from c in DbContext.FiscalCalendars where c.Type == 0 orderby c.StartDate descending select c.EndDate).FirstOrDefault(); if (model.EndDate == maxdate) model.PermanentResource = true; ViewBag.TeamsList = Utils.GetTeamsAvailableForUser(Guid.Parse(User.Identity.GetID())); ViewBag.ExpendituresList = Utils.GetResourceExpendituresList(model.ExpenditureCategory != null ? model.ExpenditureCategory.Id : Guid.Empty); return View(model); } [HttpPost] [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public ActionResult Edit(PeopleResourceModel model, Guid[] expCatId, string[] expCatName, string[] expCatGroup, bool[] expCatChecked) { if (model == null || ContentLocker.IsLock("PeopleResource", model.Id.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); model.TrimStringProperties(); if (ModelState.IsValid) { try { if (model.PermanentResource) { var maxdate = (from c in DbContext.FiscalCalendars where c.Type == 0 orderby c.StartDate descending select c.EndDate).FirstOrDefault(); model.EndDate = maxdate; } //Actual capacity change cases: 1. New resource, 2. Resource status change (active/inactive), 3. Resource category change, 4. Resource team change, 5. Start/End date change //Planned capacity change cases: when actual capacity is changed AND [model.ChangeCapacity] is set bool newresource = model.Id == Guid.Empty; bool statuschanged = false; bool categorychanged = false; bool teamchanged = false; bool dateschanged = false; PeopleResourceModel oldModel = null; if (model.Id != Guid.Empty) { oldModel = (PeopleResourceModel)Manager.Load(model.Id); statuschanged = model.IsActiveEmployee != oldModel.IsActiveEmployee; categorychanged = model.ExpenditureCategoryId != oldModel.ExpenditureCategoryId; teamchanged = model.TeamId != oldModel.TeamId; dateschanged = model.StartDate != oldModel.StartDate || model.EndDate != oldModel.EndDate; } if (oldModel != null && oldModel.IsActiveEmployee) { if (teamchanged || categorychanged || dateschanged || statuschanged) { RemoveCapacity(oldModel, false); if(model.ChangeCapacity) RemoveCapacity(oldModel, true); } } Manager.Save(model); if (model.IsActiveEmployee) { if (newresource || statuschanged || categorychanged || teamchanged || dateschanged) { AddCapacity(model, false); if(model.ChangeCapacity) AddCapacity(model, true); } } if (statuschanged && !model.IsActiveEmployee && !model.ReassignOnDeactivation) { var allocations = DbContext.PeopleResourceAllocations.Where(x => x.PeopleResourceId == model.Id).ToList(); DbContext.PeopleResourceAllocations.RemoveRange(allocations); } DbContext.SaveChanges(); ContentLocker.RemoveLock("PeopleResource", model.Id.ToString(), User.Identity.Name); if (model.AddMore) return RedirectToAction("Edit", "PeopleResource", new { @resourceId = Guid.Empty.ToString(), @teamId = model.TeamId }); else return RedirectToAction("Board", "Team", new { @teamId = model.TeamId }); } catch (BLLException blEx) { if (blEx.DisplayError) SetErrorScript(message: blEx.Message); else { LogException(blEx); SetErrorScript(); } } catch (Exception exception) { LogException(exception); SetErrorScript(); } } ViewBag.TeamsList = Utils.GetTeamsAvailableForUser(Guid.Parse(User.Identity.GetID())); ViewBag.ExpendituresList = Utils.GetResourceExpendituresList(model.ExpenditureCategory != null ? model.ExpenditureCategory.Id : Guid.Empty); return View(model); } public void AddCapacity(PeopleResourceModel model, bool isPlanned) { var weekendings = (from c in DbContext.FiscalCalendars.AsNoTracking() where c.Type == 0 && c.StartDate >= model.StartDate && c.AdjustingPeriod == false && c.NonWorking == 0 orderby c.StartDate select c.EndDate).ToArray(); var teamManager = new TeamManager(DbContext); var team = teamManager.Load(model.TeamId); Guid? parentId = isPlanned ? team.PlannedCapacityScenarioId : team.ActualCapacityScenarioId; var capacityDetails = (from sd in DbContext.ScenarioDetail where sd.ParentID == parentId && sd.ExpenditureCategoryId == model.ExpenditureCategoryId && weekendings.Contains(sd.WeekEndingDate.Value) select sd).ToDictionary(x => x.WeekEndingDate, x => x); foreach (var week in weekendings) { PeopleResourceModel.CapacityValues vc; if (model.WeeklyCapacities.ContainsKey(week)) vc = model.WeeklyCapacities[week]; else continue; var capacityWeek = capacityDetails.ContainsKey(week) ? capacityDetails[week] : null; if (capacityWeek != null) { capacityWeek.Quantity += vc.Quantity; capacityWeek.Cost += vc.Cost; DbContext.Entry(capacityWeek).State = System.Data.Entity.EntityState.Modified; } else { var newSd = new ScenarioDetail { Id = Guid.NewGuid(), ParentID = (isPlanned) ? team.PlannedCapacityScenarioId : team.ActualCapacityScenarioId, Quantity = vc.Quantity, Cost = vc.Cost, ExpenditureCategoryId = model.ExpenditureCategoryId, WeekEndingDate = week, WeekOrdinal = 0 }; DbContext.ScenarioDetail.Add(newSd); } } DbContext.SaveChanges(); } public void RemoveCapacity(PeopleResourceModel model, bool IsPlanned) { var weekendings = (from c in DbContext.FiscalCalendars.AsNoTracking() where c.Type == 0 && c.StartDate >= model.StartDate && c.AdjustingPeriod == false && c.NonWorking == 0 orderby c.StartDate select c.EndDate).ToArray(); var teamManager = new TeamManager(DbContext); var team = teamManager.Load(model.TeamId); Guid? ParentId; if (IsPlanned) ParentId = team.PlannedCapacityScenarioId; else ParentId = team.ActualCapacityScenarioId; var sds = (from sd in DbContext.ScenarioDetail where sd.ParentID == ParentId && sd.ExpenditureCategoryId == model.ExpenditureCategoryId && weekendings.Contains(sd.WeekEndingDate.Value) select sd).ToDictionary(x => x.WeekEndingDate, x => x); foreach (var week in weekendings) { if (!sds.ContainsKey(week)) continue; var sd = sds[week]; PeopleResourceModel.CapacityValues vc = null; if (model.WeeklyCapacities.ContainsKey(week)) vc = model.WeeklyCapacities[week]; else continue; if (sd != null) { sd.Quantity -= vc.Quantity; if (sd.Quantity < 0) sd.Quantity = 0; sd.Cost -= vc.Cost; if (sd.Cost < 0) sd.Cost = 0; DbContext.Entry(sd).State = System.Data.Entity.EntityState.Modified; } } DbContext.SaveChanges(); } [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public JsonResult Reassign(PeopleResourceModel model) { var projectIds = Request.Form.AllKeys.Where(x => x.Length > 30).Select(x => new Guid(x)).ToArray(); foreach (var projId in projectIds) { var scenarioIds = DbContext.Scenarios.Where(x => x.ParentId == projId).Select(x => x.Id).ToList(); var allocations = DbContext.PeopleResourceAllocations.Where(x => scenarioIds.Contains(x.ScenarioId) && x.PeopleResourceId == model.Id).ToList(); if (string.IsNullOrEmpty(Request.Form[projId.ToString()])) continue; var newResourceId = new Guid(Request.Form[projId.ToString()]); foreach (var alloc in allocations) { alloc.PeopleResourceId = newResourceId; DbContext.Entry(alloc).State = System.Data.Entity.EntityState.Modified; } } DbContext.SaveChanges(); return Json(new { Result = true, data = "" }, JsonRequestBehavior.AllowGet); } [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public ActionResult Delete(Guid? resourceId) { var model = (PeopleResourceModel)Manager.Load(resourceId); model.ChangeCapacity = true; return View(model); } [HttpPost] [AreaSecurityAttribute(area = Areas.Resources, level = AccessLevel.Write)] public ActionResult Delete(PeopleResourceModel model, Guid? teamId) { if (ContentLocker.IsLock("PeopleResource", model.Id.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var resource = (PeopleResourceModel)Manager.Load(model.Id); var id = resource.Id; RemoveCapacity(resource, false); if (model.ChangeCapacity) RemoveCapacity(resource, true); Manager.DeleteResource(model.Id); ContentLocker.RemoveLock("PeopleResource", id.ToString(), User.Identity.Name); return RedirectToAction("Board", "Team", new { @teamId = teamId.Value }); } [HttpGet] [AreaSecurityAttribute(area = Areas.Vacations, level = AccessLevel.Write)] public ActionResult DeleteVacation(Guid? id) { if (id == null || id == Guid.Empty) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var model = new VacationModel(); try { var manager = new VacationManager(DbContext); model = (VacationModel)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); } [HttpPost] [ValidateAntiForgeryToken] [AreaSecurityAttribute(area = Areas.Vacations, level = AccessLevel.Write)] public ActionResult DeleteVacation(VacationModel model, string viewId) { if (ContentLocker.IsLock("Vacations", model.Id.ToString(), User.Identity.Name)) return new HttpStatusCodeResult(HttpStatusCode.BadRequest); var manager = new VacationManager(DbContext); var dbObj = manager.Load(model.Id, false); if (dbObj == null) return HttpNotFound(); DbContext.PeopleResourceVacations.RemoveRange(DbContext.PeopleResourceVacations.Where(t => t.VacationId == dbObj.Id)); DbContext.Vacations.Remove(dbObj); DbContext.SaveChanges(); ContentLocker.RemoveLock("Vacations", dbObj.Id.ToString(), User.Identity.Name); return !string.IsNullOrEmpty(viewId) ? RedirectToAction("Details", "PeopleResource", new { resourceId = model.PeopleResourceId, viewId = viewId }) : RedirectToAction("Details", "PeopleResource", new { resourceId = model.PeopleResourceId }); } } }