EnVisageOnline/Main-RMO/Source/EnVisage/Models/ScenarioDetailSnapshotModel.cs

662 lines
28 KiB
C#

using EnVisage.Code;
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Linq;
using EnVisage.Code.DAL.Mongo;
using EnVisage.Code.BLL;
namespace EnVisage.Models
{
public class ScenarioDetailSnapshotModelBase
{
public ScenarioInfoModel Scenario { get; set; }
public ScenarioCalendarFilterModel CalendarFilter { get; set; }
public List<ExpenditureModel> AvailableExpenditures { get; set; }
public List<ScenarioCalendarRateModel> Rates { get; set; }
public List<TeamInScenarioModel> TeamsInScenario { get; set; }
public bool NeedToRebind { get; set; }
public bool NeedToRecalculateScenarioDetails { get; set; }
public bool NeedToRefreshAllTeams { get; set; }
public bool LocalRatesLoaded { get; set; }
public ScenarioDetailSnapshotModelBase()
{
AvailableExpenditures = new List<ExpenditureModel>();
Rates = new List<ScenarioCalendarRateModel>();
TeamsInScenario = new List<TeamInScenarioModel>();
}
}
public class ScenarioDetailSnapshotModel : ScenarioDetailSnapshotModelBase
{
public List<SelectListItem> CategoryTypes { get; set; }
public List<SelectListItem> CGEFX { get; set; }
public List<SelectListItem> IncomeTypes { get; set; }
public List<SelectListItem> GLAccounts { get; set; }
public List<SelectListItem> CreditDepartments { get; set; }
public List<Utils.SelectListItemExt> Teams { get; set; }
public List<ScenarioExpenditureModel> Expenditures2Add { get; set; } // SA. ENV-840
public ScenarioCalendarModel Calendar { get; set; }
public ScenarioDetailSnapshotModel()
: base()
{
CategoryTypes = new List<SelectListItem>();
CGEFX = new List<SelectListItem>();
IncomeTypes = new List<SelectListItem>();
GLAccounts = new List<SelectListItem>();
CreditDepartments = new List<SelectListItem>();
Teams = new List<Utils.SelectListItemExt>();
}
}
public class ScenarioDetailSnapshotRecalculationModel : ScenarioDetailSnapshotModelBase
{
public ScenarioCalendarModelBase Calendar { get; set; }
}
public class ScenarioDetailsSnapshotSaveModel
{
public ScenarioInfoModel Scenario { get; set; }
public ScenarioCalendarModelBase Calendar { get; set; }
public List<ExpenditureModel> AvailableExpenditures { get; set; }
public List<TeamInScenarioModel> TeamsInScenario { get; set; }
public ScenarioDetailsSnapshotSaveModel()
{
AvailableExpenditures = new List<ExpenditureModel>();
TeamsInScenario = new List<TeamInScenarioModel>();
}
public static explicit operator ScenarioDetailsSnapshotSaveModel(ScenarioCalendarMixModel model)
{
if (model == null)
return null;
return new ScenarioDetailsSnapshotSaveModel()
{
Scenario = (ScenarioInfoModel)model,
Calendar = new ScenarioCalendarModelBase()
{
Expenditures = model.Expenditures
},
AvailableExpenditures = model.Expenditures.Select(x => new ExpenditureModel()
{
Id = x.Value.ExpenditureCategoryId,
Name = x.Value.ExpenditureCategoryName
}).Distinct().ToList()
};
}
}
#region Model Classes
public class ScenarioInfoModel
{
public Guid? Id { get; set; }
public string Name { get; set; }
public Guid? ParentId { get; set; }
public long? ProjectDeadline { get; set; }
public Guid? OldTemplateId { get; set; }
public Guid TemplateId { get; set; }
public long StartDate { get; set; }
public long EndDate { get; set; }
public decimal? ProjectedRevenue { get; set; }
public long ActualStartDate { get; set; }
public long ActualEndDate { 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 decimal? GreenIndicator { get; set; }
public decimal? YellowIndicator { get; set; }
public decimal? RedIndicator { get; set; }
public int Duration { get; set; }
public decimal? TDDirectCosts { get; set; }
public decimal CGSplit { get; set; }
public decimal EFXSplit { get; set; }
public bool FreezeRevenue { get; set; }
public int Shots { get; set; }
public bool IsActiveScenario { get; set; }
public long? DateForStartOfChanges { get; set; }
public CostSavingSnapshotModel CostSavings { get; set; }
public SaveAsScenario SaveAs { get; set; }
public bool SaveAsDraft { get; set; }
public bool NeedToAdjustMargin { get; set; }
public AdjustScenarioDetailsDistribution.DistributionType DistributionType { get; set; }
public static explicit operator ScenarioInfoModel(ScenarioCalendarMixModel model)
{
if (model == null)
return null;
return new ScenarioInfoModel()
{
ParentId = model.ParentId,
TemplateId = model.TemplateId,
StartDate = model.StartDate,
EndDate = model.EndDate,
ProjectedRevenue = model.ProjectedRevenue,
GrowthScenario = model.GrowthScenario,
Type = model.Type,
UseLMMargin = model.UseLMMargin,
GrossMargin = model.GrossMargin,
LMMargin = model.LMMargin,
Duration = model.Duration,
CGSplit = model.CGSplit,
EFXSplit = model.EFXSplit,
TDDirectCosts = model.TDDirectCosts,
CostSavings = model.CostSavings,
IsActiveScenario = true,
SaveAs = SaveAsScenario.New,
SaveAsDraft = false,
NeedToAdjustMargin = false
};
}
}
public class ScenarioCalendarFilterModel
{
/// <summary>String representation for <see cref="ExpenditureCategoryModel.CategoryTypes"/></summary>
public string CategoryType { get; set; }
/// <summary>String representation for <see cref="ExpenditureCategoryModel.CgEfx"/></summary>
public string LaborMaterials { get; set; }
public Guid? IncomeType { get; set; }
public Guid? GLAccount { get; set; }
public Guid? CreditDepartment { get; set; }
public IEnumerable<Guid> SelectedExpCats { get; set; }
public bool IsTableModeQuantity { get; set; }
public bool IsViewModeMonth { get; set; }
public bool ShowActuals { get; set; }
public bool IsUOMHours { get; set; }
public bool ShowAvgTotals { get; set; }
}
public class ScenarioCalendarRateModel
{
public Guid expCatId { get; set; }
public List<RateValueModel> rateValues { get; set; }
}
public class RateValueModel
{
public long weekStartDate { get; set; }
public long weekEndDate { get; set; }
public decimal rateValue { get; set; }
}
public class CollapsableModelBase
{
public bool Collapsed { get; set; }
public string CollapsedClass { get; set; }
public CollapsableModelBase()
{
Collapsed = true;
CollapsedClass = "fa-plus-square";
}
}
public class ScenarioDetailsItem
{
public Guid? ForecastId { get; set; }
public Guid? ActualsId { get; set; }
public decimal? ForecastQuantity { get; set; }
public decimal? ActualsQuantity { get; set; }
public decimal? ForecastCost { get; set; }
public decimal? ActualsCost { get; set; }
public int WeekOrdinal { get; set; }
public bool Changed { get; set; }
}
public class ExpenditureDetail : CollapsableModelBase
{
public Guid ExpenditureCategoryId { get; set; }
public string ExpenditureCategoryName { get; set; }
public int Type { get; set; }
public int UseType { get; set; } //default is 1
public string CGEFX { get; set; }
public Guid GLId { get; set; }
public Guid UOMId { get; set; }
public Guid CreditId { get; set; }
public Guid? SystemAttributeOne { get; set; }
public Guid? SystemAttributeTwo { get; set; }
public int? SortOrder { get; set; }
public decimal UOMValue { get; set; }
public Dictionary<string, ScenarioDetailsItem> Details { get; set; }
public Dictionary<string, ExpenditureDetailsTeam> Teams { get; set; }
/// <summary>
/// SA. ENV-1254. Added for RMO to store EC unassigned to any team values
/// </summary>
public Dictionary<string, decimal> UnassignedAllocations { get; set; }
public ExpenditureDetail()
: base()
{
Details = new Dictionary<string, ScenarioDetailsItem>();
Teams = new Dictionary<string, ExpenditureDetailsTeam>();
UnassignedAllocations = new Dictionary<string, decimal>();
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (!(obj is ExpenditureDetail))
return false;
return ExpenditureCategoryId == (obj as ExpenditureDetail).ExpenditureCategoryId;
}
public override int GetHashCode()
{
return ExpenditureCategoryId.GetHashCode();
}
public static explicit operator ExpenditureDetail(MixExpenditureAllocation obj)
{
var model = new ExpenditureDetail
{
CGEFX = obj.CGEFX,
CreditId = obj.CreditId,
ExpenditureCategoryId = obj.ExpCatId,
ExpenditureCategoryName = obj.ExpenditureCategoryName,
GLId = obj.GLId,
SortOrder = obj.SortOrder,
SystemAttributeOne = obj.SysAttrOne,
SystemAttributeTwo = obj.SysAttrTwo,
Teams = new Dictionary<string, ExpenditureDetailsTeam>(),
Type = obj.Type,
UOMId = obj.UOMId,
UOMValue = obj.UOMValue,
UseType = obj.UseType,
Details = obj.Allocations.Where(x => x.Value != null).Select((pair, i) => new { pair.Key, pair.Value, index = i }).ToDictionary(key => key.Key, value => new ScenarioDetailsItem
{
ForecastId = Guid.NewGuid(),
ForecastQuantity = value.Value.Quantity,
ForecastCost = value.Value.Cost,
WeekOrdinal = value.index + 1
})
};
// SA. ENV-1254
if ((obj.UnassignedAllocations != null) && (obj.UnassignedAllocations.Keys.Count > 0))
{
model.UnassignedAllocations = obj.UnassignedAllocations.Select(item =>
new KeyValuePair<string, decimal>(item.Key, item.Value))
.ToDictionary(i1 => i1.Key, i2 => i2.Value);
}
return model;
}
public void CopyTo(MixExpenditureAllocation expenditureAllocation)
{
expenditureAllocation.Allocations =
Details.Select(pair => new { pair.Key, pair.Value.ForecastQuantity, pair.Value.ForecastCost })
.ToDictionary(key => key.Key, value => new QuantityItem()
{
Quantity = value.ForecastQuantity ?? 0,
Cost = value.ForecastCost ?? 0
});
expenditureAllocation.CGEFX = CGEFX;
expenditureAllocation.CreditId = CreditId;
expenditureAllocation.ExpCatId = ExpenditureCategoryId;
expenditureAllocation.ExpenditureCategoryName = ExpenditureCategoryName;
expenditureAllocation.GLId = GLId;
expenditureAllocation.SortOrder = SortOrder;
expenditureAllocation.SysAttrOne = SystemAttributeOne;
expenditureAllocation.SysAttrTwo = SystemAttributeTwo;
expenditureAllocation.Type = Type;
expenditureAllocation.UOMId = UOMId;
expenditureAllocation.UOMValue = UOMValue;
expenditureAllocation.UseType = UseType;
// SA. ENV-1254
if ((UnassignedAllocations != null) && (UnassignedAllocations.Keys.Count > 0))
{
expenditureAllocation.UnassignedAllocations = UnassignedAllocations.Select(item =>
new KeyValuePair<string, decimal>(item.Key, item.Value))
.ToDictionary(i1 => i1.Key, i2 => i2.Value);
}
}
}
public class ExpenditureDetailsTeam : CollapsableModelBase
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsAccessible { get; set; }
/// <summary>Current allocation for scenario in certain EC</summary>
public Dictionary<string, decimal> QuantityValues { get; set; }
/// <summary>Quantity available for allocation in certain EC</summary>
public Dictionary<string, decimal> RestQuantityValues { get; set; }
/// <summary>All team capacity in certain EC</summary>
public Dictionary<string, decimal> CapacityQuantityValues { get; set; }
/// <summary>All resources from current team allocated in certain EC</summary>
public Dictionary<string, TeamResource> Resources { get; set; }
/// <summary>All resources from current team available for allocation in certain EC</summary>
public Dictionary<string, TeamResource> AllResources { get; set; }
public bool Changed { get; set; }
public bool CanBeDeleted { get; set; }
public ExpenditureDetailsTeam()
: base()
{
AllResources = new Dictionary<string, TeamResource>();
Resources = new Dictionary<string, TeamResource>();
QuantityValues = new Dictionary<string, decimal>();
RestQuantityValues = new Dictionary<string, decimal>();
CapacityQuantityValues = new Dictionary<string, decimal>();
}
public static explicit operator ExpenditureDetailsTeam(MixTeamAllocation obj)
{
var model = new ExpenditureDetailsTeam
{
Id = Guid.Parse(obj.TeamId),
Name = obj.Name,
QuantityValues = obj.Allocations,
AllResources = (obj.AllResources ?? new Dictionary<string, MixResourceAllocation>()).Select(t => (TeamResource)t.Value).ToDictionary(key => key.Id.ToString())
};
return model;
}
public void CopyTo(MixTeamAllocation teamAllocation)
{
teamAllocation.Name = Name;
teamAllocation.TeamId = Id.ToString();
teamAllocation.Allocations = QuantityValues;
teamAllocation.AllResources = (AllResources ?? new Dictionary<string, TeamResource>()).Select(t =>
{
var alloc = new MixResourceAllocation();
t.Value.CopyTo(alloc);
return alloc;
}).ToDictionary(key => key.ResourceId);
}
}
public class TeamResource
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsActiveEmployee { get; set; }
public Dictionary<string, decimal> CapacityQuantityValues { get; set; }
public Dictionary<string, decimal> QuantityValues { get; set; }
public Dictionary<string, decimal> RestQuantityValues { get; set; }
public Dictionary<string, bool> ReadOnly { get; set; }
public bool Changed { get; set; }
public bool Deleted { get; set; }
public TeamResource()
{
CapacityQuantityValues = new Dictionary<string, decimal>();
QuantityValues = new Dictionary<string, decimal>();
RestQuantityValues = new Dictionary<string, decimal>();
ReadOnly = new Dictionary<string, bool>();
}
public static explicit operator TeamResource(MixResourceAllocation obj)
{
var model = new TeamResource
{
Id = Guid.Parse(obj.ResourceId),
Name = obj.Name,
QuantityValues = obj.Allocations
};
return model;
}
public void CopyTo(MixResourceAllocation allocation)
{
allocation.Name = Name;
allocation.ResourceId = Id.ToString();
allocation.Allocations = QuantityValues;
}
}
public class TeamResourceSortable : TeamResource
{
public string LastName { get; set; }
}
public class ScenarioCalendarModelBase
{
public Dictionary<string, ExpenditureDetail> Expenditures { get; set; }
public List<VW_ScenarioAndProxyDetails> GetScenarioDetails(bool needForecast)
{
var scenarioDetails = new List<VW_ScenarioAndProxyDetails>();
if (Expenditures != null && Expenditures.Count > 0)
{
// we have to create new items only for those dates where scenario has forecast data
// e.g.:
// actuals: 11.09.2015, 18.09.2015
// forecast: 25.09.2015, 02.10.2015, 09.10.2015
// so we have to create new forecast items for categories which exist only in actuals only for 3 dates which correspond to forecast data
var forecastDates = Expenditures.SelectMany(x => x.Value.Details)
.Where(x => x.Value != null && x.Value.ForecastId.HasValue && x.Value.ForecastId != Guid.Empty)
.Select(x => x.Key).Distinct().ToList();
foreach (var ec in Expenditures)
{
foreach (var detail in ec.Value.Details)
{
if (needForecast && (!detail.Value.ForecastId.HasValue || Guid.Empty.Equals(detail.Value.ForecastId)))
{
// this condition must be here because if current week corresponds to left or right side of actuals (befor or after forecast)
// we do not need to create forecast items for these dates
if (forecastDates.Contains(detail.Key))
{
// SA. ENV-667. Create new dataitem
scenarioDetails.Add(new VW_ScenarioAndProxyDetails()
{
Id = Guid.NewGuid(),
ExpenditureCategoryId = ec.Value.ExpenditureCategoryId,
ExpenditureCategoryName = String.Empty, // SA. ENV-839
ExpCategoryWithCcName = ec.Value.ExpenditureCategoryName, // SA. ENV-839
WeekEndingDate = Constants.UnixEpochDate.AddMilliseconds(long.Parse(detail.Key)),
LastUpdate = DateTime.UtcNow,
WeekOrdinal = detail.Value.WeekOrdinal,
Quantity = detail.Value.ForecastQuantity ?? 0,
Cost = detail.Value.ForecastCost ?? 0,
Type = ec.Value.Type,
UseType = ec.Value.UseType,
CGEFX = ec.Value.CGEFX,
GLId = ec.Value.GLId,
UOMId = ec.Value.UOMId,
CreditId = ec.Value.CreditId,
SystemAttributeOne = ec.Value.SystemAttributeOne,
SystemAttributeTwo = ec.Value.SystemAttributeTwo,
SortOrder = ec.Value.SortOrder
});
}
continue;
}
if (!needForecast && !detail.Value.ActualsId.HasValue)
continue;
scenarioDetails.Add(new VW_ScenarioAndProxyDetails()
{
Id = needForecast ? detail.Value.ForecastId.Value : detail.Value.ActualsId.Value,
ExpenditureCategoryId = ec.Value.ExpenditureCategoryId,
ExpenditureCategoryName = String.Empty, // SA. ENV-839
ExpCategoryWithCcName = ec.Value.ExpenditureCategoryName, // SA. ENV-839
WeekEndingDate = Constants.UnixEpochDate.AddMilliseconds(long.Parse(detail.Key)),
LastUpdate = DateTime.UtcNow,
WeekOrdinal = detail.Value.WeekOrdinal,
Quantity = needForecast ? detail.Value.ForecastQuantity : detail.Value.ActualsQuantity,
Cost = needForecast ? detail.Value.ForecastCost : detail.Value.ActualsCost,
Type = ec.Value.Type,
UseType = ec.Value.UseType,
CGEFX = ec.Value.CGEFX,
GLId = ec.Value.GLId,
UOMId = ec.Value.UOMId,
CreditId = ec.Value.CreditId,
SystemAttributeOne = ec.Value.SystemAttributeOne,
SystemAttributeTwo = ec.Value.SystemAttributeTwo,
SortOrder = ec.Value.SortOrder
});
}
}
}
return scenarioDetails;
}
public Dictionary<string, Dictionary<string, ExpenditureDetailsTeam>> GetTeams()
{
if (Expenditures == null || Expenditures.Count <= 0)
return new Dictionary<string, Dictionary<string, ExpenditureDetailsTeam>>();
return Expenditures.Select(x => new
{
ExpenditureId = x.Key,
Teams = x.Value.Teams
}).ToDictionary(x => x.ExpenditureId, g => g.Teams);
}
public ScenarioCalendarModelBase()
{
Expenditures = new Dictionary<string, ExpenditureDetail>();
}
}
public class ScenarioCalendarModel : ScenarioCalendarModelBase
{
public Dictionary<string, List<ScenarioDetailsModel.HeaderBase>> Headers { get; set; }
public ScenarioCalendarModel()
: base()
{
Headers = new Dictionary<string, List<ScenarioDetailsModel.HeaderBase>>();
}
}
public class ScenarioCalendarMixModel : ScenarioCalendarModelBase
{
public Guid Id { get; set; }
public Guid? ParentId { get; set; }
public long StartDate { get; set; }
public long EndDate { get; set; }
public Guid TemplateId { 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 decimal? TDDirectCosts { get; set; }
public int Duration { get; set; }
public decimal CGSplit { get; set; }
public decimal EFXSplit { get; set; }
public CostSavingSnapshotModel CostSavings { get; set; }
public bool IsNew { get; set; }
public string Name { get; set; }
public bool Pinned { get; set; }
public List<ScenarioCalendarRateModel> Rates { get; set; }
public ScenarioCalendarMixModel() : base()
{
Rates = new List<ScenarioCalendarRateModel>();
}
public static explicit operator ScenarioCalendarMixModel(Scenario scenario)
{
if (scenario == null)
return null;
return new ScenarioCalendarMixModel()
{
Id = scenario.Id,
StartDate = scenario.StartDate.HasValue ? Utils.ConvertToUnixDate(scenario.StartDate.Value) : 0,
EndDate = scenario.EndDate.HasValue ? Utils.ConvertToUnixDate(scenario.EndDate.Value) : 0,
TemplateId = scenario.TemplateId ?? Guid.Empty,
ParentId = scenario.ParentId,
ProjectedRevenue = scenario.ProjectedRevenue,
GrowthScenario = scenario.GrowthScenario,
Type = (ScenarioType)scenario.Type,
UseLMMargin = scenario.UseLMMargin == 1,
GrossMargin = (scenario.ExpectedGrossMargin ?? 0) * 100,
LMMargin = (scenario.ExpectedGrossMargin_LM ?? 0) * 100,
TDDirectCosts = scenario.TDDirectCosts,
Duration = scenario.Duration ?? 0,
CGSplit = scenario.CGSplit ?? 0,
EFXSplit = scenario.EFXSplit ?? 0,
CostSavings = (CostSavingSnapshotModel)scenario,
Name = scenario.Name
};
}
public static explicit operator ScenarioCalendarMixModel(MixScenario scenario)
{
if (scenario == null)
return null;
return new ScenarioCalendarMixModel()
{
Id = scenario.Id,
StartDate = scenario.StartDate,
EndDate = scenario.EndDate,
TemplateId = scenario.TemplateId,
ParentId = scenario.ParentId,
ProjectedRevenue = scenario.ProjectedRevenue,
GrowthScenario = scenario.GrowthScenario,
Type = scenario.Type,
UseLMMargin = scenario.UseLMMargin,
GrossMargin = scenario.GrossMargin,
LMMargin = scenario.LMMargin,
TDDirectCosts = scenario.TDDirectCosts,
Duration = scenario.Duration,
CGSplit = scenario.CGSplit,
EFXSplit = scenario.EFXSplit,
CostSavings = scenario.CostSavings,
Rates = scenario.Rates,
IsNew = scenario.IsNew // SA. ENV-1159
};
}
}
public class CostSavingSnapshotModel
{
public decimal? CostSavings { get; set; }
public long? CostSavingStartDate { get; set; }
public long? CostSavingEndDate { get; set; }
public List<ScenarioCostSavingModel> CostSavingItems { get; set; }
public bool CostSavingType { get; set; }
public string CostSavingDescription { get; set; }
public static explicit operator CostSavingSnapshotModel(Scenario scenario)
{
if (scenario == null)
return null;
return new CostSavingSnapshotModel()
{
CostSavings = scenario.CostSavings,
CostSavingStartDate = scenario.CostSavingsStartDate.HasValue ? Utils.ConvertToUnixDate(scenario.CostSavingsStartDate.Value) : (long?)null,
CostSavingEndDate = scenario.CostSavingsEndDate.HasValue ? Utils.ConvertToUnixDate(scenario.CostSavingsEndDate.Value) : (long?)null,
CostSavingType = (scenario.CostSavingsType ?? 0) == 1,
CostSavingDescription = scenario.CostSavingsDescription,
CostSavingItems = ScenarioDetailModel.GetCostSavingItems(scenario)
};
}
}
public class TeamInScenarioModel
{
public Guid TeamId { get; set; }
public short Allocation { get; set; }
public bool IsNew { get; set; }
public bool IsAccessible { get; set; }
}
#endregion
}