EnVisageOnline/Main/Source/EnVisage/Models/TeamModel.cs

345 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using EnVisage.Code;
using System.Linq;
using EnVisage.Code.BLL;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Web.Mvc;
namespace EnVisage.Models
{
public class TeamModel : IBaseModel<Team>
{
public Guid Id { get; set; }
[Required]
[MaxLength(100, ErrorMessage = "Team name should not exceed 100 characters")]
[Display(Name = "Team Name")]
public string Name { get; set; }
[Required]
[Display(Name = "Business Unit")]
public Guid? CompanyId { get; set; }
[Required]
[Display(Name = "Cost Center")]
public Guid? CostCenterId { get; set; }
[Display(Name = "Report To")]
public Guid? ReportToId { get; set; }
public Guid? PlannedCapacityScenarioId { get; set; }
public Guid? ActualCapacityScenarioId { get; set; }
[UIHint("MultipleSelect")]
[Display(Name = "Contributors")]
public IList<Guid> UserId { get; set; }
[Display(Name = "Inherit Capacity From")]
public Guid? CapacityTeamId { get; set; }
[Display(Name = "Capacity Type")]
public bool CopyPlanned { get; set; }
[UIHint("MultipleSelect")]
[Display(Name = "Workflow Contacts")]
public IList<Guid> WorkFlowContacts { get; set; }
[UIHint("MultipleSelect")]
[Display(Name = "Notification List")]
public IList<Guid> NotificationContacts { get; set; }
[UIHint("MultipleSelect")]
[Display(Name = "Notification Workflow States")]
public IList<string> NotificationWorkFlowStates { get; set; }
[Display(Name = "Send in-app notification when team is added to a project")]
public bool ProjectAddNotification { get; set; }
public IEnumerable<AspNetUser> Users
{
get
{
EnVisageEntities DbContext = new EnVisageEntities();
return DbContext.AspNetUsers;
}
}
public static explicit operator TeamModel(MixTeamModel mixTeam)
{
if (mixTeam == null)
return null;
var team = new TeamModel()
{
Name = mixTeam.Name,
CompanyId = mixTeam.CompanyId,
CostCenterId = mixTeam.CostCenterId,
UserId = mixTeam.UserId
};
if (!string.IsNullOrWhiteSpace(mixTeam.Id))
{
Guid teamId;
if (Guid.TryParse(mixTeam.Id, out teamId) && !Guid.Empty.Equals(teamId))
team.Id = teamId;
}
return team;
}
/// <summary>
/// Copies data from model to DAL object.
/// </summary>
/// <param name="dbObj">A target DAL object.</param>
public void CopyTo(Team dbObj)
{
if (dbObj == null)
throw new ArgumentNullException();
dbObj.Name = Name;
dbObj.CostCenterId = CostCenterId;
dbObj.CompanyId = CompanyId;
dbObj.ReportsTo = ReportToId;
dbObj.PlannedCapacityScenarioId = PlannedCapacityScenarioId;
dbObj.ActualCapacityScenarioId = ActualCapacityScenarioId;
dbObj.ProjectAddNotification = ProjectAddNotification;
}
}
public class TeamInViewModel : TeamModel
{
public string CompanyName { get; set; }
public string CostCenterName { get; set; }
public string ReportToName { get; set; }
public List<string> TeamUsers { get; set; }
}
public class TeamWithResourcesModel : TeamModel
{
public List<PeopleResourceModel> PeopleResources { get; set; }
/// <summary>
/// Casts a <see cref="Team"/> obect to the object of type <see cref="TeamModel"/>.
/// </summary>
/// <param name="obj">A <see cref="Team"/> object.</param>
/// <returns>A <see cref="TeamModel"/> object filled with data from db.</returns>
public static explicit operator TeamWithResourcesModel(Team obj)
{
if (obj == null)
return null;
var model = new TeamWithResourcesModel
{
Id = obj.Id,
Name = obj.Name,
CompanyId = obj.CompanyId,
CostCenterId = obj.CostCenterId,
ReportToId = obj.ReportsTo,
PlannedCapacityScenarioId = obj.PlannedCapacityScenarioId,
ActualCapacityScenarioId = obj.ActualCapacityScenarioId
};
model.TrimStringProperties();
return model;
}
public TeamWithResourcesModel()
{
PeopleResources = new List<PeopleResourceModel>();
}
}
/// <summary>Aggregated information about specified Team</summary>
public class TeamSummaryInfoModel
{
public string Id { get; set; }
public Guid? CompanyId { get; set; }
public string Name { get; set; }
public AccessLevel AccessLevel { get; set; }
public Dictionary<string, ExpCategorySummaryInfoModel> ExpCategories { get; set; }
public TeamSummaryInfoModel()
{
ExpCategories = new Dictionary<string, ExpCategorySummaryInfoModel>();
}
}
/// <summary>Aggregated information about Expenditure Category in the specified Team</summary>
public class ExpCategorySummaryInfoModel
{
public enum EC_Scenario
{
UNKNOWN = 0,
ACTUALS = 1,
PLANNED = 2,
TEAM = 4
}
public Guid Id { get; set; }
public string Name { get; set; }
public decimal UomValue { get; set; }
public bool AllowResourceAssignment { get; set; }
public EC_Scenario ECScenario { get; set; }
/// <summary>Key - week ending date in milliseconds, value - capacity</summary>
public Dictionary<string, decimal> PlannedCapacityValues { get; set; }
/// <summary>Key - week ending date in milliseconds, value - capacity</summary>
public Dictionary<string, decimal> ActualCapacityValues { get; set; }
/// <summary>
/// Represents a weekly dictionary of sum of team allocations for the specified expenditure in the specified team.
/// </summary>
/// <remarks>Key - week ending date in milliseconds, value - sum of team allocations for all matched active scenarios
/// or sum of (Team2Scenario.Allocation * ScenarioDetail.Quantity / 100) if team allocation does not exist.</remarks>
public Dictionary<string, decimal> NeedCapacity { get; set; }
/// <summary>Sum of resource allocations for the specified Expenditure Category in the specified Team.</summary>
/// <remarks>Key - week ending date in milliseconds, value - capacity</remarks>
public Dictionary<string, decimal> AllocatedCapacity { get; set; }
/// <summary>Contains all resources related to current EC</summary>
public Dictionary<string, ResourceSummaryInfoModel> Resources { get; set; }
public ExpCategorySummaryInfoModel()
{
PlannedCapacityValues = new Dictionary<string, decimal>();
ActualCapacityValues = new Dictionary<string, decimal>();
NeedCapacity = new Dictionary<string, decimal>();
AllocatedCapacity = new Dictionary<string, decimal>();
Resources = new Dictionary<string, ResourceSummaryInfoModel>();
AllowResourceAssignment = true;
}
}
/// <summary>An item of the <see cref="ExpCategorySummaryInfoModel.Resources"/> collection. Represents an info about specified resource in the specified expenditure category and team.</summary>
public class ResourceSummaryInfoModel
{
public class TeamMembershipModel
{
public Guid TeamId { get; set; }
public long StartDate { get; set; }
public long? EndDate { get; set; }
}
public Guid Id { get; set; }
public List<ResourceSummaryInfoModel.TeamMembershipModel> Teams { get; set; }
/// <summary>
/// Contains total allocated resource capacity between active scenarios for certain week ending (key in milliseconds).
/// </summary>
public Dictionary<string, decimal> AllocatedCapacity { get; set; }
/// <summary>
/// Contains total available resource capacity for certain week ending (key in milliseconds). Gets from EC UoM value.
/// </summary>
public Dictionary<string, decimal> TotalCapacity { get; set; }
/// <summary>
/// Contains non-project time allocations for current resource splitted by non-project time categories
/// </summary>
public Dictionary<string, ResourceNptModel> NonProjectTime { get; set; }
public ResourceSummaryInfoModel()
{
AllocatedCapacity = new Dictionary<string, decimal>();
TotalCapacity = new Dictionary<string, decimal>();
NonProjectTime = new Dictionary<string, ResourceNptModel>();
Teams = new List<ResourceSummaryInfoModel.TeamMembershipModel>();
}
/// <summary>
/// Merges TeamInfo provided in the <paramref name="team"/> parameter into the <see cref="ResourceSummaryInfoModel.Teams"/> value.
/// If there are no existing record for the same team but for stacked period, then system, just adds entire <paramref name="team"/> into the <see cref="ResourceSummaryInfoModel.Teams"/> collection.
/// If there are existing record for the same team but for stacked period, then system updates existing record by merging date periods.
/// If <paramref name="team"/> is null or contains empty TeamId then system do nothing.
/// </summary>
/// <param name="team">An instance of <see cref="ResourceSummaryInfoModel.TeamMembershipModel"/> class with info to merge.</param>
/// <remarks>
/// IMPORTANT: use this method instead of build-in ICollection.Add method to avoid stacked periods.
/// </remarks>
public void MergeTeam(ResourceSummaryInfoModel.TeamMembershipModel team)
{
if (team == null || Guid.Empty.Equals(team.TeamId))
return;
var existingTeams = Teams.Where(t => t.TeamId == team.TeamId);
if (!existingTeams.Any())
Teams.Add(team);
else
{
var merged = false;
foreach (var existingTeam in existingTeams)
{
if (Utils.IsDateRangesStacked(Utils.ConvertFromUnixDate(existingTeam.StartDate), Utils.ConvertFromUnixDate(team.StartDate),
existingTeam.EndDate.HasValue ? Utils.ConvertFromUnixDate(existingTeam.EndDate.Value) : (DateTime?)null,
team.EndDate.HasValue ? Utils.ConvertFromUnixDate(team.EndDate.Value) : (DateTime?)null))
{
existingTeam.StartDate = Math.Min(existingTeam.StartDate, team.StartDate);
if (!existingTeam.EndDate.HasValue || !team.EndDate.HasValue)
existingTeam.EndDate = null;
else
existingTeam.EndDate = Math.Max(existingTeam.EndDate.Value, team.EndDate.Value);
merged = true;
break;
}
}
if (!merged)
Teams.Add(team);
}
}
}
/// <summary>
/// Represents information about NPT allocations specific for people resource and NPT.
/// </summary>
public class ResourceNptModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid CategoryId { get; set; }
public bool isTeamWide { get; set; }
public bool isReadOnly { get; set; }
/// <summary>
/// Gets or sets an Id of resource's own EC.
/// </summary>
public Guid ExpenditureCategoryId { get; set; }
public Dictionary<string, decimal> Allocations { get; set; }
public Dictionary<string, decimal> Costs { get; set; }
#region Constructors
public ResourceNptModel()
{
Allocations = new Dictionary<string, decimal>();
isReadOnly = false;
}
#endregion
}
public class TeamWithPermissionsModel
{
/// <summary>
/// Gets or sets a Team.Id value of the team which user has access to.
/// </summary>
public Guid TeamId { get; set; }
/// <summary>
/// Gets or sets a AspNetUser.Id value of the user who has access to the team with Id = <see cref="TeamWithPermissionsModel.TeamId"/>.
/// </summary>
public string UserId { get; set; }
/// <summary>
/// Gets or sets a team name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets a value indicating whether user has read access to the team or not.
/// </summary>
public bool Read { get; set; }
/// <summary>
/// Gets or sets a value indicating whether user has write access to the team or not.
/// </summary>
public bool Write { get; set; }
/// <summary>
/// Gets a value indicating level of a user's access to the specified Team.
/// </summary>
public AccessLevel AccessLevel
{
get
{
return Write ? AccessLevel.Write :
Read ? AccessLevel.Read : AccessLevel.None;
}
}
}
}