345 lines
13 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |