703 lines
28 KiB
C#
703 lines
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Web.Mvc;
|
|
using EnVisage.Code;
|
|
using System.Data.Entity;
|
|
using System.Linq;
|
|
using EnVisage.Models.ValidationAttributes.Scenarios;
|
|
using EnVisage.Code.Cache;
|
|
using Microsoft.AspNet.Identity;
|
|
using EnVisage.Models.Cache;
|
|
|
|
namespace EnVisage.Models
|
|
{
|
|
public class ScenarioDetailModel : IBaseModel<Scenario>
|
|
{
|
|
#region Enums and subclasses
|
|
public enum ScenarioProbability
|
|
{
|
|
Low = 1,
|
|
Expected = 2,
|
|
High = 3
|
|
}
|
|
|
|
public enum SavingsType
|
|
{
|
|
HardSavings,
|
|
SoftSavings
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
public Guid Id { get; set; }
|
|
|
|
[Required]
|
|
[AllowHtml]
|
|
[MaxLength(100)]
|
|
public string Name { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets an Id of the template.
|
|
/// </summary>
|
|
[Display(Name = "Template")]
|
|
public Guid TemplateId { get; set; }
|
|
|
|
[Display(Name = "Template Name")]
|
|
public string TemplateName { get; set; }
|
|
|
|
[Display(Name = "Project Name")]
|
|
public string ProjectName { get; set; }
|
|
|
|
[Display(Name = "Project Deadline")]
|
|
[DataType(DataType.Date)]
|
|
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
|
|
public DateTime? ProjectDeadline { get; set; }
|
|
|
|
[Display(Name = "Part Name")]
|
|
public string PartName { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets an Id of the project.
|
|
/// </summary>
|
|
public Guid ParentId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets a color that will be used for scenario in reports.
|
|
/// </summary>
|
|
[MaxLength(8)]
|
|
public string Color { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a type of scenario.
|
|
/// </summary>
|
|
[Required]
|
|
[Display(Name = "Scenario Type")]
|
|
public ScenarioType? Type { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a scenario of scenario.
|
|
/// </summary>
|
|
[Display(Name = "Scenario Status")]
|
|
public ScenarioStatus? Status { get; set; }
|
|
|
|
[Display(Name = "Active Scenario")]
|
|
public bool IsActiveScenario { get; set; }
|
|
|
|
[Display(Name = "Freeze Resources")]
|
|
public bool FreezeResources { get; set; }
|
|
|
|
[Display(Name = "Use this project's ACTUALS data for weekending dates that apply?")]
|
|
public bool UseActuals { get; set; }
|
|
|
|
[Display(Name = "Child Scenarios #")]
|
|
public int ChildScenarios { get; set; }
|
|
|
|
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yy}", ApplyFormatInEditMode = true)]
|
|
[Display(Name = "Scenario Start Date")]
|
|
[Required]
|
|
[ScenarioStartDateValidator]
|
|
public DateTime? StartDate { get; set; }
|
|
|
|
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yy}", ApplyFormatInEditMode = true)]
|
|
[Display(Name = "Scenario End Date")]
|
|
[Required]
|
|
[ScenarioEndDateValidator]
|
|
public DateTime? EndDate { get; set; }
|
|
|
|
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yy}", ApplyFormatInEditMode = true)]
|
|
[Display(Name = "Milestone Start Date")]
|
|
public DateTime? MilestoneStartDate { get; set; }
|
|
|
|
[Display(Name = "Growth Scenario?")]
|
|
public bool GrowthScenario { get; set; }
|
|
|
|
[Display(Name = "Revenue Generating")]
|
|
public bool IsRevenueGenerating { get; set; }
|
|
|
|
[Display(Name = "Projected Revenue")]
|
|
[DataType(DataType.Currency), DisplayFormat(DataFormatString = "{0:G29}", ApplyFormatInEditMode = true)]
|
|
public decimal ProjectedRevenue { get; set; }
|
|
|
|
[Display(Name = "Use L&M Margin?")]
|
|
public bool UseLMMargin { get; set; }
|
|
|
|
[Display(Name = "Projected Margin")]
|
|
[Range(1, 100)]
|
|
public int? GrossMargin { get; set; }
|
|
|
|
[Display(Name = "L&M Margin")]
|
|
[Range(1, 100)]
|
|
public int? LMMargin { get; set; }
|
|
|
|
[Display(Name = "Calculated Gross Margin (Forecast)")]
|
|
[Range(1, 100)]
|
|
public int CalculatedGrossMargin { get; set; }
|
|
|
|
[Display(Name = "Calculated Gross Margin LM (Forecast)")]
|
|
public int CalculatedGrossMarginLM { get; set; }
|
|
|
|
[Display(Name = "Calculated Gross Margin (Actuals)")]
|
|
public int? CalculatedGrossMarginActuals { get; set; }
|
|
|
|
[Display(Name = "Calculated Gross Margin LM (Actuals)")]
|
|
[Range(1, 100)]
|
|
public int? CalculatedGrossMarginLMActuals { get; set; }
|
|
|
|
[Display(Name = "Top-Down Expense")]
|
|
[TDDirectCostValidator]
|
|
public decimal TDDirectCosts { get; set; }
|
|
|
|
[Display(Name = "Top-Down Direct Costs LM")]
|
|
public decimal TDDirectCostsLM { get; set; }
|
|
|
|
[Display(Name = "Top-Down Revenue Per Milestone")]
|
|
public decimal TDRevenuePerShot { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Expense")]
|
|
public decimal BUDirectCosts { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Direct Costs LM (Forecast)")]
|
|
public decimal BUDirectCostsLM { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Direct Costs (Actuals)")]
|
|
public decimal BUDirectCostsActuals { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Direct Costs LM (Actuals)")]
|
|
public decimal BUDirectCostsLMActuals { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Costs/Milestones (Forecast)")]
|
|
public decimal BUCostsShots { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Costs/Milestones LM (Forecast)")]
|
|
public decimal BUCostsShotsLM { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Costs/Milestones (Actuals)")]
|
|
public decimal BUCostsShotsActuals { get; set; }
|
|
|
|
[Display(Name = "Bottom-Up Costs/Milestones LM (Actuals)")]
|
|
public decimal BUCostsShotsLMActuals { get; set; }
|
|
|
|
[Display(Name = "Total Milestones")]
|
|
// not editable
|
|
//[Range(1, 2147483647)]
|
|
public int TotalMilestones { get; set; }
|
|
public string UserPageSettings { get; set; }
|
|
|
|
[Display(Name = "Labor Split Percentage")]
|
|
// not editable
|
|
//[Range(0, 100)]
|
|
[UIHint("Slider")]
|
|
public short LaborSplitPercentage { get; set; }
|
|
|
|
[Display(Name = "Labor/Materials Split")]
|
|
public string LaborMaterialsSplit { get; set; }
|
|
|
|
[Display(Name = "Actual Labor")]
|
|
public decimal? ActualLabor { get; set; }
|
|
|
|
[Display(Name = "Actual Materials")]
|
|
public decimal? ActualMaterials { get; set; }
|
|
|
|
[Display(Name = "Actual Labor/Materials Split")]
|
|
public string ActualLaborMaterialsSplit { get; set; }
|
|
|
|
[Display(Name = "Calculated Duration (weeks)")]
|
|
public int? Duration { get; set; }
|
|
|
|
[Display(Name = "Cost Savings")]
|
|
public decimal? CostSavings { get; set; }
|
|
|
|
[Display(Name = "Cost Savings Duration")]
|
|
public int? CostSavingsDuration { get; set; }
|
|
|
|
[Display(Name = "Cost Savings Description")]
|
|
public string CostSavingsDescription { get; set; }
|
|
|
|
[Display(Name = "ROI Date")]
|
|
public DateTime? ROIDate { get; set; }
|
|
|
|
[Display(Name = "ROI Date")]
|
|
public string ROIDateStr { get { return ROIDate.HasValue ? ROIDate.Value.ToShortDateString() : ""; } set { } }
|
|
|
|
[Display(Name = "Hard/Soft Savings")]
|
|
public string HardSoftSavings { get; set; }
|
|
|
|
[Display(Name = "Savings After Cost")]
|
|
public decimal? SavingsAfterCost { get; set; }
|
|
|
|
[Display(Name = "Calculated Revenue After Cost")]
|
|
public decimal RevenueAfterCost { get; set; }
|
|
|
|
[Display(Name = "Actual Revenue After Cost")]
|
|
public decimal? ActualRevenueAfterCost { get; set; }
|
|
|
|
public decimal EFXSplit { get; set; }
|
|
|
|
public IList<ScenarioModel.ExpenditureItem> Expenditures { get; set; }
|
|
|
|
public IList<ScenarioModel.ExpenditureItem> ScenarioExpenditures { get; set; }
|
|
|
|
public RatesModel RatesModel { get; set; }
|
|
|
|
public string BackUrl { get; set; }
|
|
public string BackName { get; set; }
|
|
public string ActiveTab { get; set; }
|
|
|
|
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
|
|
[Display(Name = "Date for start of change")]
|
|
[DateForStartOfChangeValidator]
|
|
public DateTime? DateForStartOfChanges { get; set; }
|
|
public CostSavingModel CostSaving { get; set; }
|
|
public string ValidationGroup
|
|
{
|
|
get
|
|
{
|
|
return "Step2";
|
|
}
|
|
}
|
|
public bool HasActuals { get; set; }
|
|
public long ActualsStartDate { get; set; }
|
|
public long ActualsEndDate { get; set; }
|
|
public decimal ActualsTotal { get; set; }
|
|
public bool NeedToRecalculateScenarioDetails { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
public ScenarioDetailModel()
|
|
{
|
|
Expenditures = new List<ScenarioModel.ExpenditureItem>();
|
|
RatesModel = new RatesModel();
|
|
CostSaving = new CostSavingModel();
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
/// <summary>
|
|
/// Casts a <see cref="Scenario"/> obect to the object of type <see cref="ScenarioModel"/>.
|
|
/// </summary>
|
|
/// <param name="obj">A <see cref="Scenario"/> object.</param>
|
|
/// <returns>A <see cref="ScenarioModel"/> object filled with data from db.</returns>
|
|
public static explicit operator ScenarioDetailModel(Scenario obj)
|
|
{
|
|
if (obj == null)
|
|
return null;
|
|
|
|
var model = new ScenarioDetailModel
|
|
{
|
|
Id = obj.Id,
|
|
Name = obj.Name,
|
|
ProjectName = (obj.Project.ParentProjectId.HasValue ? obj.Project.ParentProject.Name : obj.Project.Name),
|
|
ProjectDeadline = obj.Project.Deadline,
|
|
PartName = (obj.Project.ParentProjectId.HasValue ? obj.Project.Name : string.Empty),
|
|
TemplateName = obj.ParentScenario != null ? obj.ParentScenario.Name : string.Empty,
|
|
Color = obj.Color,
|
|
TemplateId = obj.TemplateId ?? Guid.Empty,
|
|
ParentId = obj.ParentId ?? Guid.Empty,
|
|
Type = (ScenarioType)obj.Type,
|
|
ChildScenarios = obj.ChildScenarios.Count,
|
|
EndDate = obj.EndDate,
|
|
StartDate = obj.StartDate,
|
|
Status = obj.Status == null ? (ScenarioStatus?)null : (ScenarioStatus)obj.Status,
|
|
|
|
GrossMargin = obj.ExpectedGrossMargin.HasValue ? Convert.ToInt32(obj.ExpectedGrossMargin * 100) : (int?)null,
|
|
GrowthScenario = obj.GrowthScenario,
|
|
IsActiveScenario = obj.Status == Code.ScenarioStatus.Active.GetHashCode(),
|
|
LMMargin = obj.ExpectedGrossMargin_LM.HasValue ? Convert.ToInt32(obj.ExpectedGrossMargin_LM * 100) : (int?)null,
|
|
UseLMMargin = obj.UseLMMargin == 1,
|
|
LaborSplitPercentage = Convert.ToInt16(obj.CGSplit * 100),
|
|
MilestoneStartDate = obj.ShotStartDate,
|
|
ProjectedRevenue = (obj.ProjectedRevenue ?? 0),
|
|
TotalMilestones = obj.Shots ?? 0,
|
|
Expenditures = new List<ScenarioModel.ExpenditureItem>(),
|
|
Duration = obj.Duration,
|
|
CalculatedGrossMargin = (int)((obj.CalculatedGrossMargin ?? 0) * 100),
|
|
CalculatedGrossMarginLM = (int)((obj.CalculatedGrossMargin_LM ?? 0) * 100),
|
|
|
|
// SA. ENV-698. There was found, that Calculated by Actuals margins are the same as Calculated by Forecast. Begin
|
|
CalculatedGrossMarginActuals =
|
|
(obj.Actuals_BUDirectCosts.HasValue && obj.ProjectedRevenue.HasValue && (obj.ProjectedRevenue.Value != 0)) ?
|
|
(int)((obj.ProjectedRevenue.Value - obj.Actuals_BUDirectCosts.Value) / obj.ProjectedRevenue.Value * 100) : 0,
|
|
CalculatedGrossMarginLMActuals =
|
|
(obj.Actuals_BUDirectCosts_LM.HasValue && obj.ProjectedRevenue.HasValue && (obj.ProjectedRevenue.Value != 0)) ?
|
|
(int)((obj.ProjectedRevenue.Value - obj.Actuals_BUDirectCosts_LM.Value) / obj.ProjectedRevenue.Value * 100) : 0,
|
|
// SA. ENV-698. End
|
|
|
|
TDDirectCosts = Math.Round(obj.TDDirectCosts ?? 0),
|
|
TDDirectCostsLM = Math.Round(obj.TDDirectCosts_LM ?? 0),
|
|
TDRevenuePerShot = Math.Round(obj.TDRevenueShot ?? 0),
|
|
BUDirectCosts = Math.Round(obj.BUDirectCosts ?? 0),
|
|
BUDirectCostsLM = Math.Round(obj.BUDirectCosts_LM ?? 0),
|
|
BUDirectCostsActuals = Math.Round(obj.Actuals_BUDirectCosts ?? 0),
|
|
BUDirectCostsLMActuals = Math.Round(obj.Actuals_BUDirectCosts_LM ?? 0),
|
|
BUCostsShots = Math.Round((((obj.Shots ?? 0) > 0) ? (obj.BUDirectCosts ?? 0) / (obj.Shots ?? 0) : (obj.BUDirectCosts ?? 0))),
|
|
BUCostsShotsLM = Math.Round((((obj.Shots ?? 0) > 0) ? (obj.BUDirectCosts_LM ?? 0) / (obj.Shots ?? 0) : (obj.BUDirectCosts_LM ?? 0))),
|
|
BUCostsShotsActuals = Math.Round((((obj.Shots ?? 0) > 0) ? (obj.Actuals_BUDirectCosts ?? 0) / (obj.Shots ?? 0) : (obj.Actuals_BUDirectCosts ?? 0))),
|
|
BUCostsShotsLMActuals = Math.Round((((obj.Shots ?? 0) > 0) ? (obj.Actuals_BUDirectCosts_LM ?? 0) / (obj.Shots ?? 0) : (obj.Actuals_BUDirectCosts_LM ?? 0))),
|
|
FreezeResources = Convert.ToBoolean(obj.FreezeRevenue),
|
|
IsRevenueGenerating = obj.Project.IsRevenueGenerating,
|
|
|
|
CostSavings = (obj.CostSavings.HasValue) ? obj.CostSavings.Value : (decimal?)null,
|
|
CostSavingsDuration = (obj.CostSavingsEndDate.HasValue && obj.CostSavingsStartDate.HasValue) ? (obj.CostSavingsEndDate.Value.Month - obj.CostSavingsStartDate.Value.Month) + 12 * (obj.CostSavingsEndDate.Value.Year - obj.CostSavingsStartDate.Value.Year) + 1 : (int?)null,
|
|
CostSavingsDescription = obj.CostSavingsDescription,
|
|
//TODO: replace with loading of cost savings for all scenarios by single request. See ENV-590.
|
|
ROIDate = obj.ROIDate, // GetROIDate(obj),
|
|
HardSoftSavings = (obj.CostSavingsType.HasValue) ? (obj.CostSavingsType.Value == 1 ? "Hard" : "Soft") : string.Empty,
|
|
|
|
SavingsAfterCost = (decimal?)null,
|
|
RevenueAfterCost = 0,
|
|
EFXSplit = obj.EFXSplit ?? 0
|
|
};
|
|
model.RatesModel = new RatesModel()
|
|
{
|
|
ScenarioId = model.Id
|
|
};
|
|
if (obj.CostSavingsStartDate.HasValue && obj.CostSavingsEndDate.HasValue)
|
|
{
|
|
model.CostSaving = new CostSavingModel()
|
|
{
|
|
CostSavings = (decimal?)obj.CostSavings,
|
|
CostSavingStartDate = obj.CostSavingsStartDate,
|
|
CostSavingEndDate = obj.CostSavingsEndDate,
|
|
CostSavingType = obj.CostSavingsType == 1,
|
|
CostSavingsPanelExpanded = true,
|
|
ScenarioStartDate = obj.StartDate,
|
|
CostSavingItems = Newtonsoft.Json.JsonConvert.SerializeObject(GetCostSavingItems(obj)),
|
|
ROIDate = obj.ROIDate // GetROIDate(obj)
|
|
};
|
|
if (obj.CostSavings.HasValue && obj.BUDirectCosts.HasValue && obj.CostSavings.Value >= obj.BUDirectCosts.Value)
|
|
{
|
|
model.SavingsAfterCost = (decimal?)(obj.CostSavings.Value - obj.BUDirectCosts.Value);
|
|
}
|
|
|
|
if (obj.CostSavings.HasValue && model.IsRevenueGenerating)
|
|
{
|
|
model.RevenueAfterCost = model.ProjectedRevenue;
|
|
model.ActualRevenueAfterCost = model.ProjectedRevenue;
|
|
|
|
if (obj.BUDirectCosts.HasValue && obj.CostSavings.Value < obj.BUDirectCosts.Value)
|
|
model.RevenueAfterCost += (decimal)(obj.CostSavings.Value - obj.BUDirectCosts.Value);
|
|
|
|
if (obj.Actuals_BUDirectCosts.HasValue && obj.CostSavings.Value < obj.Actuals_BUDirectCosts.Value)
|
|
model.ActualRevenueAfterCost += (decimal)(obj.CostSavings.Value - obj.Actuals_BUDirectCosts.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (model.IsRevenueGenerating)
|
|
{
|
|
model.RevenueAfterCost = model.ProjectedRevenue;
|
|
model.ActualRevenueAfterCost = model.ProjectedRevenue;
|
|
|
|
if (obj.BUDirectCosts.HasValue)
|
|
model.RevenueAfterCost -= obj.BUDirectCosts.Value;
|
|
|
|
if (obj.Actuals_BUDirectCosts.HasValue)
|
|
model.ActualRevenueAfterCost -= obj.Actuals_BUDirectCosts.Value;
|
|
}
|
|
}
|
|
|
|
model.TrimStringProperties();
|
|
return model;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies data from model to DAL object.
|
|
/// </summary>
|
|
/// <param name="dbObj">A target DAL object.</param>
|
|
public void CopyTo(Scenario dbObj)
|
|
{
|
|
if (dbObj == null)
|
|
throw new ArgumentNullException();
|
|
dbObj.Name = Name;
|
|
|
|
// SA. Fixed bug ENV-707. Begin fix
|
|
if (!String.IsNullOrEmpty(Color))
|
|
dbObj.Color = Color.Replace("#", "");
|
|
else
|
|
dbObj.Color = null;
|
|
// End fix ENV-707
|
|
|
|
dbObj.Type = Type.GetHashCode();
|
|
dbObj.Status = IsActiveScenario ? Code.ScenarioStatus.Active.GetHashCode() : Code.ScenarioStatus.Inactive.GetHashCode();
|
|
dbObj.ShotStartDate = MilestoneStartDate;
|
|
}
|
|
|
|
#endregion
|
|
|
|
//private static DateTime? GetROIDate(Scenario scenario)
|
|
//{
|
|
// if (!scenario.CostSavings.HasValue)
|
|
// return null;
|
|
// if (scenario.BUDirectCosts > scenario.CostSavings)
|
|
// return null;
|
|
// if (scenario.CostSavings1 == null || scenario.CostSavings1.Count == 0)
|
|
// return null;
|
|
// var costSavingsSum = 0.0M;
|
|
// foreach (var costSaving in scenario.CostSavings1.OrderBy(t => t.Year).ThenBy(t => t.Month))
|
|
// {
|
|
// costSavingsSum += costSaving.Cost ?? 0;
|
|
// if (costSavingsSum >= scenario.BUDirectCosts)
|
|
// {
|
|
// return new DateTime(costSaving.Year, costSaving.Month, 1);
|
|
// }
|
|
// }
|
|
// return null;
|
|
//}
|
|
|
|
public static List<ScenarioCostSavingModel> GetCostSavingItems(Scenario scenario)
|
|
{
|
|
var costSavingItems = new List<ScenarioCostSavingModel>();
|
|
|
|
if (scenario != null && scenario.CostSavings1 != null && scenario.CostSavings1.Count > 0)
|
|
{
|
|
foreach (var year in scenario.CostSavings1.OrderBy(x => x.Year).Select(x => x.Year).Distinct())
|
|
{
|
|
var yearSaving = new ScenarioCostSavingModel()
|
|
{
|
|
Year = year,
|
|
Costs = new decimal?[13]
|
|
};
|
|
|
|
foreach (var cost in scenario.CostSavings1.Where(x => x.Year == year))
|
|
yearSaving.Costs[cost.Month] = cost.Cost;
|
|
|
|
yearSaving.Costs[0] = yearSaving.Costs.Sum(x => x ?? 0);
|
|
costSavingItems.Add(yearSaving);
|
|
}
|
|
}
|
|
|
|
return costSavingItems;
|
|
}
|
|
}
|
|
|
|
public class LaborMaterialsCostInfo
|
|
{
|
|
public decimal Labor { get; set; }
|
|
public decimal Materials { get; set; }
|
|
public decimal Total { get; set; }
|
|
public string LaborAndMaterialSplit
|
|
{
|
|
get
|
|
{
|
|
if (Labor == 0 && Materials == 0)
|
|
return "0/0";
|
|
|
|
decimal laborPart = Math.Round((Labor / (Labor + Materials)) * 100, 2);
|
|
return string.Format("{0:G29}/{1:G29}", laborPart, 100 - laborPart);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ScenarioCopyModel
|
|
{
|
|
public Guid ScenarioId { get; set; }
|
|
[Required]
|
|
[Display(Name = "Target Project")]
|
|
public Guid TargetProjectId { get; set; }
|
|
public ScenarioStatus TargetStatus { get; set; }
|
|
public bool includeCostSavings { get; set; }
|
|
public bool hasCostSavings { get; set; }
|
|
}
|
|
|
|
public class ScenarioDetailsCalendarModel
|
|
{
|
|
#region Properties
|
|
|
|
public Guid Id { get; set; }
|
|
public string Name { get; set; }
|
|
public Guid ParentId { get; set; }
|
|
public Guid? TemplateId { get; set; }
|
|
public long StartDate { get; set; }
|
|
public long EndDate { get; set; }
|
|
public decimal ProjectedRevenue { get; set; }
|
|
public bool GrowthScenario { get; set; }
|
|
public ScenarioType Type { get; set; }
|
|
public bool UseLMMargin { get; set; }
|
|
public decimal? GrossMargin { get; set; }
|
|
public decimal? LMMargin { get; set; }
|
|
public int Duration { get; set; }
|
|
public decimal TDDirectCosts { get; set; }
|
|
public decimal CGSplit { get; set; }
|
|
public decimal EFXSplit { get; set; }
|
|
public bool Pinned { get; set; }
|
|
public int Shots { get; set; }
|
|
public bool IsActiveScenario { get; set; }
|
|
public bool ShowAvgTotals { get; set; }
|
|
public bool IsUOMHours { get; set; }
|
|
public bool ShowActuals { get; set; }
|
|
public bool IsTableModeQuantity { get; set; }
|
|
public bool IsViewModeMonth { get; set; }
|
|
public bool ShowFilters { get; set; }
|
|
public string DataSection
|
|
{
|
|
get { return "scenarioCalendar"; }
|
|
}
|
|
public List<ExpenditureModel> AvailableExpenditures { get; set; }
|
|
public List<TeamInScenarioModel> TeamsInScenario { get; set; }
|
|
public bool NeedToRecalculateScenarioDetails { get; set; }
|
|
public bool NeedToAdjustMargin { get; set; }
|
|
|
|
/// <summary>
|
|
/// Rebuild calendar only by request
|
|
/// </summary>
|
|
public bool InitOnDemand { get; set; }
|
|
public string PagePreferences { get; private set; }
|
|
public ScenarioCalendarOpener Opener { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
public ScenarioDetailsCalendarModel(User user, ScenarioCalendarOpener opener)
|
|
{
|
|
AvailableExpenditures = new List<ExpenditureModel>();
|
|
TeamsInScenario = new List<TeamInScenarioModel>();
|
|
|
|
Opener = opener;
|
|
|
|
if (user != null)
|
|
{
|
|
ShowAvgTotals = user.PreferredTotalsDisplaying;
|
|
IsUOMHours = !user.PreferredResourceAllocation;
|
|
PagePreferences = user.GetPreferences("/Scenarios/Details", DataSection);
|
|
}
|
|
}
|
|
|
|
public ScenarioDetailsCalendarModel(ScenarioDetailModel model, User user, ScenarioCalendarOpener opener)
|
|
: this(user, opener)
|
|
{
|
|
if (model != null)
|
|
{
|
|
Id = model.Id;
|
|
Name = model.Name;
|
|
ParentId = model.ParentId;
|
|
TemplateId = model.TemplateId;
|
|
StartDate = model.StartDate.HasValue ? Utils.ConvertToUnixDate(model.StartDate.Value) : 0;
|
|
EndDate = model.EndDate.HasValue ? Utils.ConvertToUnixDate(model.EndDate.Value) : 0;
|
|
ProjectedRevenue = model.ProjectedRevenue;
|
|
GrowthScenario = model.GrowthScenario;
|
|
Type = model.Type ?? ScenarioType.Portfolio;
|
|
UseLMMargin = model.UseLMMargin;
|
|
GrossMargin = model.GrossMargin;
|
|
LMMargin = model.LMMargin;
|
|
Duration = model.Duration ?? 0;
|
|
TDDirectCosts = model.TDDirectCosts;
|
|
CGSplit = model.LaborSplitPercentage / (decimal)100.0;
|
|
EFXSplit = model.EFXSplit;
|
|
Shots = model.TotalMilestones;
|
|
IsActiveScenario = model.IsActiveScenario;
|
|
ShowActuals = false;
|
|
IsTableModeQuantity = true;
|
|
IsViewModeMonth = true;
|
|
ShowFilters = false;
|
|
TeamsInScenario = null;
|
|
NeedToRecalculateScenarioDetails = Guid.Empty.Equals(model.Id);
|
|
NeedToAdjustMargin = Guid.Empty.Equals(model.Id);
|
|
|
|
if (model.ScenarioExpenditures != null)
|
|
{
|
|
AvailableExpenditures = model.ScenarioExpenditures.Select(t => new ExpenditureModel
|
|
{
|
|
Id = t.Id,
|
|
Name = t.Name
|
|
}).ToList();
|
|
}
|
|
}
|
|
}
|
|
|
|
public ScenarioDetailsCalendarModel(CreateScenarioModel.GeneralInfoModel model, User user, ScenarioCalendarOpener opener)
|
|
: this(user, opener)
|
|
{
|
|
Id = model.ScenarioId;
|
|
Name = model.ScenarioName;
|
|
ParentId = model.PartId ?? model.ProjectId;
|
|
TemplateId = model.TemplateId;
|
|
StartDate = model.StartDate.HasValue ? Utils.ConvertToUnixDate(model.StartDate.Value) : 0;
|
|
EndDate = model.EndDate.HasValue ? Utils.ConvertToUnixDate(model.EndDate.Value) : 0;
|
|
ProjectedRevenue = 0;
|
|
GrowthScenario = model.GrowthScenario;
|
|
Type = ScenarioType.Portfolio;
|
|
UseLMMargin = false;
|
|
GrossMargin = 0;
|
|
LMMargin = null;
|
|
Duration = 0;
|
|
TDDirectCosts = 0;
|
|
CGSplit = model.LaborSplitPercentage / (decimal)100.0;
|
|
EFXSplit = model.EFXSplit;
|
|
Shots = 0;
|
|
IsActiveScenario = model.CreateAsActive;
|
|
ShowActuals = false;
|
|
IsTableModeQuantity = true;
|
|
IsViewModeMonth = true;
|
|
ShowFilters = false;
|
|
NeedToRecalculateScenarioDetails = Guid.Empty.Equals(model.ScenarioId);
|
|
NeedToAdjustMargin = Guid.Empty.Equals(model.ScenarioId);
|
|
|
|
if (model.ScenarioExpenditures != null)
|
|
{
|
|
AvailableExpenditures = model.ScenarioExpenditures.Where(t => t.Checked).Select(t => new ExpenditureModel
|
|
{
|
|
Id = t.Id,
|
|
Name = t.Name
|
|
}).ToList();
|
|
}
|
|
|
|
if (model.Teams != null && model.Teams.Sliders != null && model.Teams.Sliders.Count > 0)
|
|
{
|
|
TeamsInScenario = model.Teams.Sliders.Select(x => new TeamInScenarioModel()
|
|
{
|
|
TeamId = x.EntityId,
|
|
Allocation = (short)Math.Round(x.AllocatePercentage, 0),
|
|
IsNew = x.IsExcludable
|
|
}).ToList();
|
|
}
|
|
}
|
|
|
|
public ScenarioDetailsCalendarModel(ScenarioCalendarMixModel model, User user)
|
|
: this(user, ScenarioCalendarOpener.RMO)
|
|
{
|
|
if (model != null)
|
|
{
|
|
Id = model.Id;
|
|
ParentId = model.ParentId ?? model.TemplateId;
|
|
TemplateId = model.TemplateId;
|
|
StartDate = model.StartDate;
|
|
EndDate = model.EndDate;
|
|
ProjectedRevenue = model.ProjectedRevenue ?? 0;
|
|
GrowthScenario = model.GrowthScenario;
|
|
Type = model.Type;
|
|
UseLMMargin = model.UseLMMargin;
|
|
GrossMargin = model.GrossMargin;
|
|
LMMargin = model.LMMargin;
|
|
Duration = model.Duration;
|
|
TDDirectCosts = model.TDDirectCosts ?? 0;
|
|
CGSplit = model.CGSplit;
|
|
EFXSplit = model.EFXSplit;
|
|
Pinned = model.Pinned;
|
|
Shots = 0;
|
|
IsActiveScenario = true;
|
|
ShowActuals = false;
|
|
IsTableModeQuantity = true;
|
|
IsViewModeMonth = true;
|
|
ShowFilters = false;
|
|
TeamsInScenario = null;
|
|
NeedToRecalculateScenarioDetails = false;
|
|
NeedToAdjustMargin = false;
|
|
InitOnDemand = true; // calendar will be populated with data by client-side request
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Enums
|
|
|
|
public enum ScenarioCalendarOpener
|
|
{
|
|
CreateScenarioWizard = 0,
|
|
Details = 1,
|
|
RMO = 2
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |