EnVisageOnline/Beta/Source/EnVisage/Models/ScenarioDetailModel.cs

369 lines
15 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;
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; }
/// <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; }
// not editable[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yy}", ApplyFormatInEditMode = true)]
[Display(Name = "Scenario Start Date")]
public DateTime? StartDate { get; set; }
// not editable[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yy}", ApplyFormatInEditMode = true)]
[Display(Name = "Scenario End Date")]
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 = "Scenario End Date")]
public string EndDateStr { get; set; }
[Display(Name = "Scenario Start Date")]
public string StartDateStr { get; set; }
[Display(Name = "Growth Scenario?")]
public bool GrowthScenario { get; set; }
[Display(Name = "Revenue Generating")]
public bool IsRevenueGenerating { get; set; }
[Display(Name = "Projected Revenue")]
public int ProjectedRevenue { get; set; }
[Display(Name = "Use L&M Margin?")]
public bool UseLMMargin { get; set; }
[Display(Name = "Expected Gross Margin")]
// not editable[Range(1, 100)]
public int? GrossMargin { get; set; }
[Display(Name = "L&M Margin")]
// not editable
//[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 Direct Costs")]
public int TDDirectCosts { get; set; }
[Display(Name = "Top-Down Direct Costs LM")]
public int TDDirectCostsLM { get; set; }
[Display(Name = "Top-Down Revenue Per Milestone")]
public int TDRevenuePerShot { get; set; }
[Display(Name = "Bottom-Up Direct Costs (Forecast)")]
public int BUDirectCosts { get; set; }
[Display(Name = "Bottom-Up Direct Costs LM (Forecast)")]
public int BUDirectCostsLM { get; set; }
[Display(Name = "Bottom-Up Direct Costs (Actuals)")]
public int BUDirectCostsActuals { get; set; }
[Display(Name = "Bottom-Up Direct Costs LM (Actuals)")]
public int BUDirectCostsLMActuals { get; set; }
[Display(Name = "Bottom-Up Costs/Milestones (Forecast)")]
public int BUCostsShots { get; set; }
[Display(Name = "Bottom-Up Costs/Milestones LM (Forecast)")]
public int BUCostsShotsLM { get; set; }
[Display(Name = "Bottom-Up Costs/Milestones (Actuals)")]
public int BUCostsShotsActuals { get; set; }
[Display(Name = "Bottom-Up Costs/Milestones LM (Actuals)")]
public int BUCostsShotsLMActuals { get; set; }
[Display(Name = "Total Milestones")]
// not editable
//[Range(1, 2147483647)]
public int TotalMilestones { 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 = "Duration")]
public Nullable<int> Duration { get; set; }
[Display(Name = "Cost Savings")]
public int? CostSavings { get; set; }
[Display(Name = "Cost Savings Duration")]
public int? CostSavingsDuration { 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 int? SavingsAfterCost { get; set; }
[Display(Name = "Revenue After Cost")]
public int? RevenueAfterCost { get; set; }
public ScenarioStatus CopyStatus { get; set; }
public int CopyProgectId { get; set; }
public IList<ScenarioModel.ExpenditureItem> Expenditures { get; set; }
public IList<ScenarioModel.ProjectItem> Projects { 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 List<Team2Scenario> TeamAllocations { get; set; }
public string TeamAllocationsJson { get; set; }
public List<NoteModel> Notes { get {
List<NoteModel> result = new List<NoteModel>();
EnVisageEntities DbContext = new EnVisageEntities();
var notes = (from c in DbContext.Notes where c.ParentId == Id select c).ToList();
foreach (var note in notes)
result.Add((NoteModel)note);
return result;
} set{} }
public string ActiveTab { get; set; }
#endregion
#region Constructors
public ScenarioDetailModel()
{
Expenditures = new List<ScenarioModel.ExpenditureItem>();
RatesModel = new RatesModel();
}
#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.Name,
TemplateName = obj.ParentScenario != null ? obj.ParentScenario.Name : string.Empty,
Color = obj.Color,
TemplateId = obj.TemplateId ?? Guid.Empty,
ParentId = obj.ParentId ?? Guid.Empty,
Type = obj.Type == null ? (ScenarioType?) null : (ScenarioType) obj.Type,
ChildScenarios = obj.ChildScenarios.Count,
EndDate = obj.EndDate,
StartDate = obj.StartDate,
EndDateStr = (obj.EndDate ?? DateTime.Today).ToString("d"),
StartDateStr = (obj.StartDate ?? DateTime.Today).ToString("d"),
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 = (int)Math.Round(obj.ProjectedRevenue ?? 0),
TotalMilestones = obj.Shots ?? 0,
Expenditures = new List<ScenarioModel.ExpenditureItem>(),
Duration = obj.Duration,
CalculatedGrossMargin = obj.CalculatedGrossMargin.HasValue ? Convert.ToInt32(obj.CalculatedGrossMargin * 100) : (int?)null,
CalculatedGrossMarginLM = obj.CalculatedGrossMargin_LM.HasValue ? Convert.ToInt32(obj.CalculatedGrossMargin_LM * 100) : (int?)null,
CalculatedGrossMarginActuals = obj.CalculatedGrossMargin.HasValue ? Convert.ToInt32(obj.CalculatedGrossMargin * 100) : (int?)null,
CalculatedGrossMarginLMActuals = obj.CalculatedGrossMargin_LM.HasValue ? Convert.ToInt32(obj.CalculatedGrossMargin_LM * 100) : (int?)null,
TDDirectCosts = (int)Math.Round(obj.TDDirectCosts ?? 0),
TDDirectCostsLM = (int)Math.Round(obj.TDDirectCosts_LM ?? 0),
TDRevenuePerShot = (int)Math.Round(obj.TDRevenueShot ?? 0),
BUDirectCosts = (int)Math.Round(obj.BUDirectCosts ?? 0),
BUDirectCostsLM = (int)Math.Round(obj.BUDirectCosts_LM ?? 0),
BUDirectCostsActuals = (int)Math.Round(obj.Actuals_BUDirectCosts ?? 0),
BUDirectCostsLMActuals = (int)Math.Round(obj.Actuals_BUDirectCosts_LM ?? 0),
BUCostsShots = (int)Math.Round((((obj.Shots ?? 0) > 0) ? (obj.BUDirectCosts ?? 0) / (obj.Shots ?? 0) : (obj.BUDirectCosts ?? 0))),
BUCostsShotsLM = (int)Math.Round((((obj.Shots ?? 0) > 0) ? (obj.BUDirectCosts_LM ?? 0) / (obj.Shots ?? 0) : (obj.BUDirectCosts_LM ?? 0))),
BUCostsShotsActuals = (int)Math.Round((((obj.Shots ?? 0) > 0) ? (obj.Actuals_BUDirectCosts ?? 0) / (obj.Shots ?? 0) : (obj.Actuals_BUDirectCosts ?? 0))),
BUCostsShotsLMActuals = (int)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) ? (int?)obj.CostSavings.Value : (int?)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,
//TODO: replace with loading of cost savings for all scenarios by single request. See ENV-590.
ROIDate = GetROIDate(obj),
HardSoftSavings = (obj.CostSavingsType.HasValue) ? (obj.CostSavingsType.Value == 1 ? "Hard" : "Soft") : string.Empty,
SavingsAfterCost = (int?)null,
RevenueAfterCost = (int?)null,
TeamAllocations = obj.Team2Scenario.OrderBy(x => x.Team.Name).ToList(),
TeamAllocationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(obj.Team2Scenario.ToDictionary(c => c.TeamId, c => c.Allocation))
};
model.RatesModel = new RatesModel()
{
ScenarioId = model.Id
};
if (obj.CostSavings.HasValue && obj.CostSavingsStartDate.HasValue && obj.CostSavingsEndDate.HasValue)
{
if (obj.BUDirectCosts.HasValue && obj.CostSavings.Value >= obj.BUDirectCosts.Value)
{
model.SavingsAfterCost = (int?)(obj.CostSavings.Value - obj.BUDirectCosts.Value);
}
if (model.IsRevenueGenerating)
{
model.RevenueAfterCost = model.ProjectedRevenue;
if (obj.BUDirectCosts.HasValue && obj.CostSavings.Value < obj.BUDirectCosts.Value)
{
model.RevenueAfterCost += (int)(obj.CostSavings.Value - obj.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;
dbObj.Color = Color.Replace("#", "");
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;
if (costSavingsSum >= scenario.BUDirectCosts)
{
return new DateTime(costSaving.Year, costSaving.Month, 1);
}
}
return null;
}
}
}