using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using EnVisage;
using EnVisage.Code;
using EnVisage.Code.BLL;
using EnVisage.Code.HtmlHelpers;
using EnVisage.Models;
using jQuery.DataTables.Mvc;
using EnVisage.App_Start;
using Microsoft.AspNet.Identity;
using System.Collections.ObjectModel;
using System.IO;
using FileHelpers;
using System.Web.Script.Serialization;
using EnVisage.Code.Cache;
namespace EnVisage.Controllers
{
[Authorize]
public class ProjectController : BaseController
{
internal class PreferenceItem
{
public string Key { get; set; }
public object Value { get; set; }
}
///
/// GET: /Project/
///
/// Empty view
[HttpGet]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Read)]
public ActionResult Index()
{
if (!SecurityManager.CheckSecurityObjectPermission(Areas.Projects, AccessLevel.Read))
return Redirect("/");
return View();
}
///
/// Returns JSON project list with filters and sort for jQuery DataTables
///
[HttpPost]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Read)]
public JsonResult Index(JQueryDataTablesModel jQueryDataTablesModel)
{
int totalRecordCount;
int searchRecordCount;
var clients = GetProjects(startIndex: jQueryDataTablesModel.iDisplayStart,
pageSize: jQueryDataTablesModel.iDisplayLength, sortedColumns: jQueryDataTablesModel.GetSortedColumns(),
totalRecordCount: out totalRecordCount, searchRecordCount: out searchRecordCount, searchString: jQueryDataTablesModel.sSearch);
return this.DataTablesJson(items: clients,
totalRecords: totalRecordCount,
totalDisplayRecords: searchRecordCount,
sEcho: jQueryDataTablesModel.sEcho);
}
private string GetJson(Scenario scenario)
{
return "";
}
private IList GetProjects(int startIndex,
int pageSize,
ReadOnlyCollection sortedColumns,
out int totalRecordCount,
out int searchRecordCount,
string searchString)
{
var userId = SecurityManager.GetUserPrincipal();
var user = new UsersCache().Value.FirstOrDefault(x => x.Id == userId);
string _ref = user.GetPreferences(this.Url.Action("Index", "Project"), "projectsTable");
var groupByTeam = false;
if (!string.IsNullOrEmpty( _ref))
{
var oprions = Newtonsoft.Json.JsonConvert.DeserializeObject>(_ref);
var option = oprions.FirstOrDefault(x => x.Key.Equals("groupByTeam"));
if (option != null)
{
groupByTeam = (bool)option.Value;
}
}
var projectsToDisplay = (new ProjectManager(DbContext)).GetProjects4User(userId, groupByTeam, sortedColumns[0], startIndex, pageSize, searchString, out totalRecordCount, out searchRecordCount);
var projectsIds = projectsToDisplay.Select(x => x.Id);
var partsIds = projectsToDisplay.Where(x => x.ProjectParts != null).SelectMany(x => x.ProjectParts).Where(x => x != null).Select(x => x.Id);
var projectsWithPartsIds = projectsIds.Union(partsIds).ToList();
var inactiveScenarios =
DbContext.Scenarios.Where(s => s.Type == (int)ScenarioType.Portfolio &&
s.Status == (int)ScenarioStatus.Inactive &&
s.ParentId.HasValue &&
projectsWithPartsIds.Contains(s.ParentId.Value))
.Select(x => new
{
ProjectId = x.ParentId.Value,
Scenario = new ScenarioInProjectModel()
{
Id = x.Id,
Name = x.Name
}
}).ToList().GroupBy(x => x.ProjectId).ToDictionary(x => x.Key, g => g.Select(x => x.Scenario).ToList());
foreach (var projItem in projectsToDisplay)
{
if (inactiveScenarios.ContainsKey(projItem.Id))
projItem.InactiveScenarios = inactiveScenarios[projItem.Id];
if ((projItem.ProjectParts != null) && projItem.ProjectParts.Count > 0)
{
foreach (var projPartItem in projItem.ProjectParts)
{
if (inactiveScenarios.ContainsKey(projPartItem.Id))
projPartItem.InactiveScenarios = inactiveScenarios[projPartItem.Id];
}
}
}
return projectsToDisplay;
}
// GET: /Project/Details/5
[HttpGet]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Read)]
public ActionResult Details(Guid? id)
{
if (id == null || id == Guid.Empty)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Read))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
var model = new ProjectModel();
try
{
var manager = new ProjectManager(DbContext);
model = (ProjectModel)manager.Load(id) ?? new ProjectModel();
if (model.Id == Guid.Empty)
return HttpNotFound();
}
catch (BLLException blEx)
{
if (blEx.DisplayError)
SetErrorScript(message: blEx.Message);
else
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception)
{
LogException(exception);
SetErrorScript();
}
return PartialView("_details", model);
}
[HttpGet]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult Copy(Guid? id)
{
if (id != null && id != Guid.Empty)
if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Write))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
var model = new ProjectModel();
try
{
var manager = new ProjectManager(DbContext);
model = (ProjectModel)manager.Load(id) ?? new ProjectModel();
var projectStatus = DbContext.Status.FirstOrDefault(x => x.Id == model.StatusId);
if (projectStatus != null)
{
if (projectStatus.Probability100)
model.Probability = 100;
ViewBag.IsProbability100 = projectStatus.Probability100;
}
else
{
ViewBag.IsProbability100 = false;
}
var statuses = DbContext.Status.Select(x => new { Id = x.Id, Probability100 = x.Probability100 }).ToList();
ViewBag.Statuses = new JavaScriptSerializer().Serialize(statuses);
}
catch (BLLException blEx)
{
if (blEx.DisplayError)
SetErrorScript(message: blEx.Message);
else
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception)
{
LogException(exception);
SetErrorScript();
}
model.SaveAsCopy = true;
return Edit(model);
}
// GET: /Project/Edit/5
[HttpGet]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult Edit(Guid? id, Guid? partId, string backUrl, string backName)
{
if (id != null && id != Guid.Empty)
if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Write))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
var model = new ProjectModel();
try
{
var manager = new ProjectManager(DbContext);
model = (ProjectModel)manager.Load(id) ?? new ProjectModel();
if (model.ParentProjectId != null && model.ParentProjectId != Guid.Empty)
{
model = (ProjectModel)manager.Load(model.ParentProjectId);
model.PartForScenarioId = id;
}
if (id == null || Guid.Empty.Equals(id))
{
model.ClientId = Guid.Empty;
model.Priority = 1;
}
else
model.ExpandedPartId = partId;
model.BackUrl = !string.IsNullOrEmpty(backUrl) ? backUrl : Url.Action("Index", "Project");
model.BackName = !string.IsNullOrEmpty(backName) ? backName : "projects";
var statuses = DbContext.Status.Select(x => new { Id = x.Id, Probability100 = x.Probability100 }).ToList();
ViewBag.Statuses = new JavaScriptSerializer().Serialize(statuses);
}
catch (BLLException blEx)
{
if (blEx.DisplayError)
SetErrorScript(message: blEx.Message);
else
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception)
{
LogException(exception);
SetErrorScript();
}
return View(model);
}
// POST: /Project/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult Edit(ProjectModel model)
{
if (model == null || ContentLocker.IsLock("Project", model.Id.ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (model.Id != Guid.Empty)
if (!SecurityManager.CheckProjectPermission(model.Id, AccessLevel.Write))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
#region trim model and remove incorrect values
model.TrimStringProperties();
//if user converted ordinary project to project with parts we need to convert old project to a "part" and create a parent project for it
//so basically we need to set project model's first part a successor of project that now became project with parts so all scenarios, permissions, etc. will be "reassigned" to the first part
//technically we just need to assign project ID to the first part and drop the ID of project + remove CompanyId, Projectnumber and Color from newly "added" part (done by ProjectPartModel itself)
if (model.Id != Guid.Empty && model.InitialHasChildrenState == false && model.HasChildren == true)
{
if (model.Parts.Count == 0)
throw new InvalidOperationException();
model.Parts[0].Id = model.Id;
model.Parts[0].OldId = model.Id;
model.Id = Guid.Empty;
model.InitialHasChildrenState = model.HasChildren;
//also need to drop ParentProjectId from all parts
foreach (ProjectPartModel pp in model.Parts)
pp.ParentProjectId = Guid.Empty;
}
// if user clicked "Generate Template" then save a project as new and mark it as IsTemplate=true
var isCreateCopy = model.SaveAsCopy;
var oldId = Guid.Empty;
var model2Save = (ProjectModel)model.Clone();
if (isCreateCopy)
{
oldId = model.Id;
model2Save.Parts = model.Parts.Select(p => p.Clone()).ToList();
model2Save.Id = Guid.Empty;
model2Save.Name += " - Copy";
model2Save.Parts.ToList().ForEach(p => p.Id = Guid.Empty);
model2Save.Parts.ToList().ForEach(p => p.ParentProjectId = Guid.Empty);
}
model2Save.ClientId = null;
var revalidationRequired = false;
for (var i = 0; i < model2Save.Parts.Count; i++)
{
if (model2Save.Parts[i].DeletedPart)
{
model.Parts.RemoveAt(i);
revalidationRequired = true;
}
}
foreach (var part in model2Save.Parts)
{
if (part.InternalContacts != null)
part.InternalContacts.RemoveAll(t => t == Guid.Empty);
if (part.ExternalContacts != null)
part.ExternalContacts.RemoveAll(t => t == Guid.Empty);
}
//TODO: temporary solution, we need to check for Guid.Empty.Equals(model2Save.Id). Should be replaced when fix the bug in BaseManager.Save method.
var isNew = Guid.Empty.Equals(model2Save.Id);
if (revalidationRequired)
{
ModelState.Clear();
TryValidateModel(model);
}
#endregion
#region Check all deleted teams can be removed from scenarios
// SA. ENV-754. Begin
ScenarioManager scenarioManager = new ScenarioManager(DbContext);
Dictionary> projectScenarios = new Dictionary>();
Dictionary> newProjectTeamList = new Dictionary>();
//TODO: check if we need to bypass this when project is being copied (!isCreateCopy) as we may get a copied project with incorrect permission set
if (!isNew && (model2Save.Parts.Count > 0) && !isCreateCopy)
{
for (int partIndex = 0; partIndex < model.Parts.Count; partIndex++)
{
ProjectPartModel part = model.Parts[partIndex];
Guid partId = part.Id;
if (!model.HasChildren && part.Id.Equals(Guid.Empty))
// If project has no parts, its virtual 0 part has no id. We must use model.id instead
partId = model.Id;
if (Guid.Empty.Equals(partId))
continue;
newProjectTeamList.Add(partId, new List());
if ((part.AssignedTeams != null) && part.AssignedTeams.Count > 0)
newProjectTeamList[partId].AddRange(part.AssignedTeams);
List partScenarios = scenarioManager.GetProjectNonActualsScenarios(partId);
projectScenarios.Add(partId, partScenarios);
/*
Dictionary> violdatedRecords =
scenarioManager.GetViolatedUpdateScenarioTeams(projectScenarios[partId],
newProjectTeamList[partId]);
foreach (Guid teamId in violdatedRecords.Keys)
{
// Some teams in scenarios can't be removed, because are allocated
string teamName = DbContext.Teams.AsNoTracking().SingleOrDefault(x => x.Id == teamId).Name;
string scenariosNames = "";
foreach (Guid scenarioId in violdatedRecords[teamId])
{
string scenarioName =
DbContext.Scenarios.AsNoTracking().SingleOrDefault(x => x.Id == scenarioId).Name;
scenariosNames += (", '" + scenarioName + "'");
}
if (scenariosNames.Length > 2)
scenariosNames = scenariosNames.Substring(2);
string errorText =
String.Format("The team '{0}' can't be removed from this project or part, because it is used in scenarios: {1}",
teamName, scenariosNames);
ModelState.AddModelError("", errorText);
ModelState.Remove(String.Format("Parts[{0}].AssignedTeams", partIndex));
// Restore original project teams
var originalProjectTeams = DbContext.Team2Project.Where(x => x.ProjectId.Equals(partId)).AsNoTracking()
.Select(t => t.TeamId);
model.Parts[partIndex].AssignedTeams = new List();
model.Parts[partIndex].AssignedTeams.AddRange(originalProjectTeams);
}
*/
}
}
// SA. ENV-754. End
#endregion
if (ModelState.IsValid)
{
using (DbContextTransaction trans = DbContext.Database.BeginTransaction())
try
{
var manager = new ProjectManager(DbContext);
var newProject = manager.Save(model2Save);
DbContext.SaveChanges();
var partIds = DbContext.Projects.Where(t => t.ParentProjectId.HasValue && t.ParentProjectId.Value == newProject.Id).Select(t => t.Id).ToArray();
//Give user Full Access permissions to the new project
var teamIds = new List();
foreach (var part in model2Save.Parts)
{
if (part.AssignedTeams != null)
teamIds.AddRange(part.AssignedTeams);
}
var existingUsersPermissions =
DbContext.ProjectAccesses.Where(t => partIds.Contains(t.ProjectId) || t.ProjectId == newProject.Id)
.Select(t => new { t.ProjectId, t.PrincipalId }).ToList();
var users = (from c in DbContext.User2Team where teamIds.Contains(c.TeamId) select c.UserId).Distinct().ToList();
if (!users.Contains(User.Identity.GetID(), StringComparer.OrdinalIgnoreCase))
users.Add(User.Identity.GetID());
foreach (var contributor in users)
{
if (!existingUsersPermissions.Any(t => t.PrincipalId == new Guid(contributor) && t.ProjectId == newProject.Id))
{
DbContext.ProjectAccesses.Add(new ProjectAccess()
{
PrincipalId = new Guid(contributor),
ProjectId = newProject.Id,
Read = 1,
Write = 1
});
}
foreach (var partId in partIds)
{
if (!existingUsersPermissions.Any(t => t.PrincipalId == new Guid(contributor) && t.ProjectId == partId))
{
DbContext.ProjectAccesses.Add(new ProjectAccess()
{
PrincipalId = new Guid(contributor),
ProjectId = partId,
Read = 1,
Write = 1
});
}
}
}
if (isNew)
{
#region Create Actuals scenario
if (!isCreateCopy)
{
var scenario = new Scenario
{
Id = Guid.NewGuid(),
Name = "ACTUALS",
ParentId = newProject.Id,
Type = ScenarioType.Actuals.GetHashCode(),
StartDate = DateTime.Now,
Color = "",
ProjectedRevenue = 0
};
DbContext.Scenarios.Add(scenario);
}
#endregion
#region Copy scenarios and referenced scenario details
//if (model2Save.TemplateId.HasValue && !Guid.Empty.Equals(model2Save.TemplateId))
//{
// oldId = model2Save.TemplateId.Value;
// var scenarios = DbContext.Scenarios.Where(t => t.ParentId == oldId).ToList();
// CopyScenarios(scenarios, newProject.Id);
//}
if (isCreateCopy)
{
FileManager fileMngr = new FileManager(DbContext);
if (!model2Save.HasChildren)
{
var scenarios = DbContext.Scenarios.Where(t => t.ParentId.HasValue && t.ParentId.Value == oldId).ToList();
CopyScenarios(scenarios, newProject.Id);
if ((model2Save.Parts.Count == 1) && (model2Save.Parts.First().Attachments != null) &&
(model2Save.Parts.First().Attachments.Count > 0))
{
IList copiedAttachments =
fileMngr.CopyPermanentFiles(model2Save.Parts.First().Attachments, newProject.Id, model2Save.GetType());
model2Save.Parts.First().Attachments = copiedAttachments;
}
}
else
{
foreach (var part in model2Save.Parts)
{
var scenarios = DbContext.Scenarios.Where(t => t.ParentId.HasValue && t.ParentId.Value == part.OldId).ToList();
CopyScenarios(scenarios, part.Id);
if ((part.Attachments != null) && (part.Attachments.Count > 0))
{
IList copiedAttachments =
fileMngr.CopyPermanentFiles(part.Attachments, part.Id, part.GetType());
part.Attachments = copiedAttachments;
}
}
}
}
#endregion
#region Move attachments to permanent storage (SA. ENV-502)
if (isNew && (model.Parts.Count > 0))
{
FileManager fileMngr = new FileManager(DbContext);
foreach (ProjectPartModel partModel in model.Parts)
{
Guid parentId = partModel.Id;
System.Type parentType = partModel.GetType();
if ((model.Parts.Count == 1) && partModel.Id.Equals(Guid.Empty))
{
parentId = newProject.Id;
parentType = model.GetType();
}
if ((partModel.Attachments != null) && (partModel.Attachments.Count > 0))
{
List newAttachments = partModel.Attachments.Where(x => x.IsNew).ToList();
List existingAttachments = partModel.Attachments.Where(x => !x.IsNew).ToList();
IList undeletedFiles = fileMngr.MoveToPermanentStorage(newAttachments, parentId, parentType);
if (undeletedFiles.Count > 0)
{
string errorMessage = "";
foreach (Guid fileId in undeletedFiles)
errorMessage += (", " + fileId.ToString());
errorMessage = errorMessage.Substring(2);
LogError(String.Format("Temp attachments copied to permanent storage, but some temp files were not deleted: {0}", errorMessage));
}
if (!isCreateCopy && (existingAttachments.Count > 0))
fileMngr.ChangeFilesParent(existingAttachments, parentId, parentType);
}
}
}
#endregion
}
// SA. Update project scenarios teams. ENV-754. Begin
if (!isNew && (model.Parts.Count > 0) && !isCreateCopy)
{
foreach (Guid partId in projectScenarios.Keys)
scenarioManager.UpdateScenarioTeams(projectScenarios[partId], newProjectTeamList[partId]);
#region Update project attachments (SA. ENV-502)
FileManager fileMngr = new FileManager(DbContext);
var partsIds = model.Parts.Select(x => x.Id).ToList();
if ((partsIds.Count() == 1) && partsIds.First().Equals(Guid.Empty))
{
partsIds.Clear();
partsIds.Add(model.Id);
}
List attachmentsToRemove = fileMngr.GetPermanentFilesByHolder(partsIds) as List;
List attachmentsToAdd;
foreach (ProjectPartModel partModel in model.Parts)
{
if ((partModel.Attachments != null) && (partModel.Attachments.Count > 0))
{
var foundAttachments = partModel.Attachments.Where(x => !x.IsNew).Select(y => y.Id);
attachmentsToRemove.RemoveAll(x => foundAttachments.Contains(x));
attachmentsToAdd = partModel.Attachments.Where(x => x.IsNew).ToList();
Guid holderId = partModel.Id;
System.Type holderType = partModel.GetType();
if (holderId.Equals(Guid.Empty) && (model.Parts.Count == 1) && !model.Id.Equals(Guid.Empty))
{
holderId = model.Id;
holderType = model.GetType();
}
if (attachmentsToAdd.Count > 0)
{
IList undeletedFiles = fileMngr.MoveToPermanentStorage(attachmentsToAdd, holderId, holderType);
if (undeletedFiles.Count > 0)
{
string errorMessage = "";
foreach (Guid fileId in undeletedFiles)
errorMessage += (", " + fileId.ToString());
errorMessage = errorMessage.Substring(2);
LogError(String.Format("Temp attachments copied to permanent storage, but some temp files were not deleted: {0}", errorMessage));
}
}
}
}
if (attachmentsToRemove.Count > 0)
fileMngr.DeletePermanentFiles(attachmentsToRemove, true);
#endregion
}
// SA. ENV-754. End
DbContext.SaveChanges();
trans.Commit();
new ProjectAccessCache().Invalidate();
ContentLocker.RemoveLock("Project", model.Id.ToString(), User.Identity.Name);
if (!isCreateCopy)
{
if (model2Save.ContinueToScenarios)
{
if (model.HasChildren)
return RedirectToAction("Edit", new { @id = newProject.Id, @ptab = "scenarios" });
else
return RedirectToAction("Edit", new { @id = newProject.Id, @ptab = "newscenario" });
}
else
{
return RedirectToAction("Edit", "Project", new { id = newProject.Id });//RedirectToAction("Index");
}
}
else
return RedirectToAction("Edit", "Project", new { id = newProject.Id });
}
catch (BLLException blEx) // handle any system specific error
{
trans.Rollback();
// 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
{
trans.Rollback();
LogException(exception);
SetErrorScript();
}
}
if (model.Id != null && model.Id != Guid.Empty)
{
model.Scenarios = new List();
var proj_db = DbContext.Projects.Where(x => x.Id == model.Id).FirstOrDefault();
foreach (var childProject in proj_db.ChildProjects.OrderBy(pp => pp.PartNum))
{
foreach (var scenario in childProject.Scenarios)
{
if (scenario.Type != ScenarioType.Actuals.GetHashCode())
model.ScenariosCount++;
model.Scenarios.Add((ScenarioTabModel)scenario);
}
}
}
// return empty model with validation messages (if any)
var statuses = DbContext.Status.Select(x => new { Id = x.Id, Probability100 = x.Probability100 }).ToList();
ViewBag.Statuses = new JavaScriptSerializer().Serialize(statuses);
return View(model);
}
private void CopyScenarios(IEnumerable scenarios, Guid newProjectId)
{
foreach (var currScenario in scenarios)
{
var currDetails = DbContext.ScenarioDetail.Where(
t => t.ParentID == currScenario.Id).AsNoTracking().ToList().OrderBy(t => t.ExpenditureCategoryId).ThenBy(t => t.WeekOrdinal);
var scenarioId = Guid.NewGuid();
var newScenario = new Scenario
{
Id = scenarioId,
ParentId = newProjectId,
Type = currScenario.Type,
Name = currScenario.Name,
ProjectedRevenue = currScenario.ProjectedRevenue,
ExpectedGrossMargin = currScenario.ExpectedGrossMargin,
CalculatedGrossMargin = currScenario.CalculatedGrossMargin,
CGSplit = currScenario.CGSplit,
EFXSplit = currScenario.EFXSplit,
Duration = currScenario.Duration,
TDDirectCosts = currScenario.TDDirectCosts,
BUDirectCosts = currScenario.BUDirectCosts,
Shots = currScenario.Shots,
TDRevenueShot = currScenario.TDRevenueShot,
BURevenueShot = currScenario.BURevenueShot,
LastUpdate = DateTime.Now,
Status = currScenario.Status,
UseLMMargin = currScenario.UseLMMargin,
ExpectedGrossMargin_LM = currScenario.ExpectedGrossMargin_LM,
CalculatedGrossMargin_LM = currScenario.CalculatedGrossMargin_LM,
TDDirectCosts_LM = currScenario.TDDirectCosts_LM,
BUDirectCosts_LM = currScenario.BUDirectCosts_LM,
BURevenueShot_LM = currScenario.BURevenueShot_LM,
EntryTimeStamp = DateTime.Now,
Actuals_BUDirectCosts = currScenario.Actuals_BUDirectCosts,
Actuals_BUDirectCosts_LM = currScenario.Actuals_BUDirectCosts_LM,
FreezeRevenue = currScenario.FreezeRevenue,
GrowthScenario = currScenario.GrowthScenario,
TemplateId = currScenario.TemplateId,
Color = currScenario.Color,
ProjectedExpense = currScenario.ProjectedExpense,
StartDate = currScenario.StartDate,
EndDate = currScenario.EndDate,
ShotStartDate = currScenario.ShotStartDate,
SystemAttributeObjectID = currScenario.SystemAttributeObjectID,
Team2Scenario = currScenario.Team2Scenario.Select(s => new Team2Scenario() { Id = Guid.NewGuid(), TeamId = s.TeamId, Allocation = s.Allocation, ScenarioId = scenarioId }).ToList()
};
DbContext.Scenarios.Add(newScenario);
foreach (var detail in currDetails)
{
var newDetailItem = new ScenarioDetail
{
Id = Guid.NewGuid(),
ExpenditureCategoryId = detail.ExpenditureCategoryId,
ParentID = newScenario.Id,
Quantity = detail.Quantity,
Cost = detail.Cost,
WeekOrdinal = detail.WeekOrdinal,
WeekEndingDate = detail.WeekEndingDate,
LastUpdate = DateTime.Now
};
DbContext.ScenarioDetail.Add(newDetailItem);
}
}
}
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult AddPart(ProjectPartModel model, int count)
{
try
{
if (ContentLocker.IsLock("Project", (model.ParentProjectId ?? Guid.Empty).ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (model.ParentProjectId.HasValue && model.ParentProjectId != Guid.Empty)
if (!SecurityManager.CheckProjectPermission(model.ParentProjectId.Value, AccessLevel.Write))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
//ENV-680. As we pass something to the action method, ModelState object is being generated and passed items being automatically validated
//The issue is - we pass ProjectPartModel instance with empty values and it is being validated and partial view being rendered with validation errors
//(for now ClientId and Priority are invalid). This it a standard MVC behavior and we cannot change that, so we have two options:
//1. reset the validation on the client side manipulating jQuery unobtrusive validation, but this will drop all the validation errors from the entire form
// and not just the part we've added
//2. clear errors in the ModelState manually - ModelState is not preserved during roundtrips so we're just dropping it now and validation
// still performs on the project save
//Option 2 seems to be much better choice here so here is the magic:
foreach (var key in ModelState.Keys)
{
ModelState[key].Errors.Clear();
}
return PartialView("~/Views/Shared/EditorTemplates/ProjectPartModel.cshtml", model);
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
SetErrorScript(message: 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 EmptyResult();
}
// GET: /Project/Delete/5
[HttpGet]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult Delete(Guid? id)
{
if (id == null || id == Guid.Empty)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (!SecurityManager.CheckProjectPermission(id.Value, AccessLevel.Write))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
var model = new ProjectModel();
try
{
var manager = new ProjectManager(DbContext);
model = (ProjectModel)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: /Project/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult Delete(ProjectModel model)
{
if (ContentLocker.IsLock("Project", model.Id.ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (!SecurityManager.CheckProjectPermission(model.Id, AccessLevel.Write))
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
var manager = new ProjectManager(DbContext);
var dbObj = manager.Load(model.Id, false);
if (dbObj == null)
return HttpNotFound();
// SA. ENV-502. Attachments. Get project files to delete
IList holders = manager.GetSubprojectsAndParts(dbObj);
FileManager fileMngr = new FileManager(DbContext);
fileMngr.QueuePermanentFilesToDelete(holders);
// SA. ENV-914. Project parts now are deleted inside SQL procedure
(DbContext as IObjectContextAdapter).ObjectContext.ExecuteStoreCommand(string.Format("exec sp_DeleteProject '{0}'", dbObj.Id));
DbContext.SaveChanges();
// SA. ENV-502. Delete attachments
fileMngr.DeleteQueuedFiles(true);
ContentLocker.RemoveLock("Project", dbObj.Id.ToString(), User.Identity.Name);
return RedirectToAction("Index");
}
[HttpGet]
[AreaSecurityAttribute(area = Areas.ImportActuals, level = AccessLevel.Read)]
public ActionResult ImportActuals(Guid? id)
{
ImportActualsModel model = null;
return View(model);
}
// POST: /Project/Import/5
[HttpPost, ActionName("ImportActuals")]
[AreaSecurityAttribute(area = Areas.ImportActuals, level = AccessLevel.Write)]
public ActionResult ImportActuals(ImportActualsModel model, HttpPostedFileBase fileUpload)
{
if (model == null || model.Id == Guid.Empty)
{
var file = fileUpload;
if (file == null || file.ContentLength < 1)
{
ModelState.AddModelError("", "File was not loaded");
return View();
}
using (var reader = new StreamReader(file.InputStream))
{
try
{
var engine = new FileHelperEngine();
ActualsImportRow[] dataRead = engine.ReadStream(reader);
var importer = new ImportActuals();
string log = string.Empty;
model = importer.ProcessImport(dataRead, Request["firstRowHeaders"] == "on", Request["zeroOut"] == "on", Request["uomHours"] == "on", User.Identity.Name, out log);
ViewBag.ImportResult = model.ImportSuccessful;
ViewBag.ImportLog = log;
return View(model);
}
catch (Exception c)
{
LogException(c);
ModelState.AddModelError("", c.Message);
return View(model);
}
}
}
else
{
string log = string.Empty;
var importer = new ImportActuals();
var result = importer.CommitImport(model, User.Identity.Name, out log);
//ViewBag.ImportResult = result;
ViewBag.ComletedImport = result;
ViewBag.ImportLog = log;
return View(model);
}
}
[HttpPost]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult AddNote(NoteModel model)
{
//if (model.ScenarioId != Guid.Empty && ContentLocker.IsLock("Scenarios", model.ScenarioId.ToString(), User.Identity.Name))
// return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
model.TrimStringProperties();
if (ModelState.IsValid)
{
try
{
model.Id = Guid.NewGuid();
var newnote = new Note();
model.CopyTo(newnote);
newnote.UserId = new Guid(User.Identity.GetID());
DbContext.Notes.Add(newnote);
DbContext.SaveChanges();
}
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();
}
}
UriBuilder builder = new UriBuilder(HttpContext.Request.UrlReferrer);
var query = HttpUtility.ParseQueryString(builder.Query);
query["ptab"] = "notes";
builder.Query = query.ToString();
return Redirect(builder.Uri.AbsoluteUri);
}
[HttpPost]
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult EditNote(NoteModel model)
{
//if (model.ScenarioId != Guid.Empty && ContentLocker.IsLock("Scenarios", model.ScenarioId.ToString(), User.Identity.Name))
// return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
model.TrimStringProperties();
if (ModelState.IsValid)
{
try
{
var note = (from c in DbContext.Notes where c.Id == model.Id select c).FirstOrDefault();
if (note == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
note.Title = model.Title;
note.NoteDetail = model.Details;
DbContext.SaveChanges();
}
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();
}
}
UriBuilder builder = new UriBuilder(HttpContext.Request.UrlReferrer);
var query = HttpUtility.ParseQueryString(builder.Query);
query["ptab"] = "notes";
builder.Query = query.ToString();
return Redirect(builder.Uri.AbsoluteUri);
}
// GET: /User/Edit/5
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult DeleteNote(string Id)
{
if (string.IsNullOrEmpty(Id) || Id == "JSVar")
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var NoteId = new Guid(Id);
var note = (from c in DbContext.Notes where c.Id == NoteId select c).FirstOrDefault();
if (note == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
else
{
DbContext.Notes.Remove(note);
DbContext.SaveChanges();
}
return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri);
}
// GET: /User/Edit/5
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult EditNote(string Id)
{
if (string.IsNullOrEmpty(Id) || Id == "JSVar")
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var NoteId = new Guid(Id);
var note = (from c in DbContext.Notes where c.Id == NoteId select c).FirstOrDefault();
if (note == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
else
{
return PartialView("_addNote", (NoteModel)note);
}
}
// GET: /User/Edit/5
[AreaSecurityAttribute(area = Areas.Projects, level = AccessLevel.Write)]
public ActionResult AddNote(string Id)
{
if (string.IsNullOrEmpty(Id))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var ParentId = new Guid(Id);
return PartialView("_addNote", new NoteModel(ParentId));
}
[HttpGet]
public JsonResult LoadExternalContacts(Guid? clientId, string selectControlId)
{
return Json(new
{
contacts = LoadContacts(clientId),
selectControlId = selectControlId
}
, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public JsonResult LoadInternalContacts(Guid? companyId, string selectControlId)
{
return Json(new
{
contacts = LoadContacts(companyId),
selectControlId = selectControlId
}
, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public JsonResult LoadCompanyGoals(Guid? companyId, string selectControlId)
{
return Json(new
{
goals = Utils.GetStrategicGoals(companyId, false),
selectControlId = selectControlId
}
, JsonRequestBehavior.AllowGet);
}
private List LoadContacts(Guid? parentId)
{
if (parentId == null || parentId == Guid.Empty)
return new List();
return DbContext.Contacts.Where(c => c.ParentId == parentId).OrderBy(c => c.LastName).Select(c => new ContactModel
{
Id = c.Id,
ParentId = c.ParentId ?? Guid.Empty,
FirstName = c.FirstName,
LastName = c.LastName,
Type = (ContactType)c.Type,
Email = c.Email,
}).ToList();
}
//function will do autocomplete for project number on the
//Edit Project page. It returns a list of unused project numbers from the supt_tbl_ProjectIds
[HttpGet]
public ActionResult ProjectNumberSearch(string term)
{
using (var dbContext = new EnVisageEntities())
{
var projectIDs = dbContext.supt_tbl_ProjectIds.AsNoTracking().Where(x => x.ProjectID.StartsWith(term)).OrderBy(p => p.ProjectID);
var projects = dbContext.Projects.AsNoTracking().OrderBy(p => p.ProjectNumber);
var list = (from pid in projectIDs
join d in projects
on pid.ProjectID equals d.ProjectNumber into output
from d in output.DefaultIfEmpty()
where d == null
select new { pid.ProjectID });
return this.Json(list.Select(x => x.ProjectID).ToList(),
JsonRequestBehavior.AllowGet);
}
return null;
}
}
}