using EnVisage.Code; using System; using System.Collections.Generic; using System.Linq; using EnVisage.Code.DAL.Mongo; using EnVisage.Code.BLL; using EnVisage.Models.ProjectDependencies; namespace EnVisage.Models { public class ScenarioDetailSnapshotModelBase { public ScenarioInfoModel Scenario { get; set; } public List AvailableExpenditures { get; set; } public List Rates { get; set; } public List TeamsInScenario { get; set; } public bool NeedToRebind { get; set; } //8.24.16 start tab public long filterStartDate { get; set; } public long filterEndDate { get; set; } //8.24.16 end public bool NeedToRecalculateScenarioDetails { get; set; } public bool LocalRatesLoaded { get; set; } public List WorkFlowActions { get; set; } public List WorkFlowStates { get; set; } public string WorkFlowSchema { get; set; } public ScenarioDetailSnapshotModelBase() { AvailableExpenditures = new List(); Rates = new List(); TeamsInScenario = new List(); WorkFlowActions = new List(); } } public class ScenarioDetailSnapshotModel : ScenarioDetailSnapshotModelBase { public List Expenditures2Add { get; set; } public ScenarioCalendarModel Calendar { get; set; } public List Notes { get; set; } public ScenarioDetailSnapshotModel() : base() { } } public class ScenarioDetailSnapshotRecalculationModel : ScenarioDetailSnapshotModelBase { public ScenarioCalendarModelBase Calendar { get; set; } } public class ScenarioDetailsSnapshotSaveModel { public ScenarioInfoModel Scenario { get; set; } public ScenarioCalendarModelBase Calendar { get; set; } public List AvailableExpenditures { get; set; } public List TeamsInScenario { get; set; } public List Notes { get; set; } public List NotesToDelete { get; set; } public List WorkFlowActions { get; set; } public List WorkFlowStates { get; set; } public string WorkFlowSchema { get; set; } public DependencyResolveModel Dependencies { get; set; } public ExpenditureCategoryChangesHistory Audit { get; set; } public ScenarioDetailsSnapshotSaveModel() { AvailableExpenditures = new List(); TeamsInScenario = new List(); WorkFlowActions = new List(); Audit = new ExpenditureCategoryChangesHistory(); } public ScenarioDetailsSnapshotSaveModel(ScenarioCalendarMixModel model) : this() { if (model == null) return; Scenario = new 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(); //todo: copy dependencies here } } #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 bool IsBottomUp { get; set; } public List UserDefinedFields { get; set; } public bool? AdjustMarginRased { get; set; } public long? DateForStartOfChangesOld { get; set; } #region Constructors public ScenarioInfoModel() { } public ScenarioInfoModel(ScenarioCalendarMixModel model) : this() { if (model == null) return; Id = model.Id; ParentId = model.ParentId; TemplateId = model.TemplateId; Name = model.Name; StartDate = model.StartDate; EndDate = model.EndDate; GrowthScenario = model.GrowthScenario; Type = model.Type; Duration = model.Duration; IsActiveScenario = true; SaveAs = SaveAsScenario.New; SaveAsDraft = false; NeedToAdjustMargin = false; IsBottomUp = model.IsBottomUp; if (model.FinInfo != null) { ProjectedRevenue = model.FinInfo.ProjectedRevenue; UseLMMargin = model.FinInfo.UseLMMargin; GrossMargin = model.FinInfo.GrossMargin; LMMargin = model.FinInfo.LMMargin; CGSplit = model.FinInfo.LaborSplitPercentage / (decimal)100.0; EFXSplit = model.FinInfo.EFXSplit; TDDirectCosts = model.FinInfo.TDDirectCosts; CostSavings = model.FinInfo.CostSaving; } } #endregion } public class ScenarioCalendarFilterModel { /// String representation for public string CategoryType { get; set; } /// String representation for public string LaborMaterials { get; set; } public Guid? IncomeType { get; set; } public Guid? GLAccount { get; set; } public Guid? CreditDepartment { get; set; } public IEnumerable 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 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 Details { get; set; } public Dictionary Teams { get; set; } public bool AllowResourceAssignment { get; set; } /// /// Added for RMO to store EC unassigned to any team values /// public Dictionary UnassignedAllocations { get; set; } public ExpenditureDetail() : base() { Details = new Dictionary(); Teams = new Dictionary(); UnassignedAllocations = new Dictionary(); } 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(), Type = obj.Type, UOMId = obj.UOMId, UOMValue = obj.UOMValue, UseType = obj.UseType, AllowResourceAssignment = obj.AllowResourceAssignment, 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 }) }; if ((obj.UnassignedAllocations != null) && (obj.UnassignedAllocations.Keys.Count > 0)) { model.UnassignedAllocations = obj.UnassignedAllocations.Select(item => new KeyValuePair(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; expenditureAllocation.AllowResourceAssignment = AllowResourceAssignment; if ((UnassignedAllocations != null) && (UnassignedAllocations.Keys.Count > 0)) { expenditureAllocation.UnassignedAllocations = UnassignedAllocations.Select(item => new KeyValuePair(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; } /// Current allocation for scenario in certain EC public Dictionary QuantityValues { get; set; } /// Quantity available for allocation in certain EC public Dictionary RestQuantityValues { get; set; } /// All team capacity in certain EC public Dictionary CapacityQuantityValues { get; set; } /// All resources from current team allocated in certain EC public Dictionary Resources { get; set; } /// All resources from current team available for allocation in certain EC public Dictionary AllResources { get; set; } public bool Changed { get; set; } public bool CanBeDeleted { get; set; } public ExpenditureDetailsTeam() : base() { AllResources = new Dictionary(); Resources = new Dictionary(); QuantityValues = new Dictionary(); RestQuantityValues = new Dictionary(); CapacityQuantityValues = new Dictionary(); } 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()).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()).Select(t => { var alloc = new MixResourceAllocation(); t.Value.CopyTo(alloc); return alloc; }).ToDictionary(key => key.ResourceId); } } /// /// Represents info about the resource within one of the teams. /// public class TeamResource { public Guid Id { get; set; } public Guid ExpenditureCategoryId { get; set; } public string Name { get; set; } public bool IsActiveEmployee { get; set; } public Dictionary CapacityQuantityValues { get; set; } public Dictionary QuantityValues { get; set; } public Dictionary RestQuantityValues { get; set; } public Dictionary ReadOnly { get; set; } public bool Changed { get; set; } public bool Deleted { get; set; } /// /// Gets or sets a value indicating start of work (milliseconds from Unix date) of the specified resource in the specified team. /// public long StartDate { get; set; } /// /// Gets or sets a value indicating end of work (milliseconds from Unix date) of the specified resource in the specified team. /// public long? EndDate { get; set; } /// /// Gets or sets a value indicating percent of involvment of the resource within the specified team. /// /// /// Min value = 0. Max value = 1. Value=0.75 means 75%. /// public decimal Allocation { get; set; } public TeamResource() { CapacityQuantityValues = new Dictionary(); QuantityValues = new Dictionary(); RestQuantityValues = new Dictionary(); ReadOnly = new Dictionary(); } public static explicit operator TeamResource(MixResourceAllocation obj) { var model = new TeamResource { Id = Guid.Parse(obj.ResourceId), ExpenditureCategoryId = obj.ExpCatId, 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 List Teams { get; set; } public TeamResourceSortable() : base() { Teams = new List(); } } public class ScenarioCalendarModelBase { public Dictionary Expenditures { get; set; } public List GetScenarioDetails(bool needForecast) { var scenarioDetails = new List(); 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?.ForecastId != null && 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 = Utils.ConvertFromUnixDate(long.Parse(detail.Key)), 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, AllowResourceAssignment = ec.Value.AllowResourceAssignment }); } 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 = Utils.ConvertFromUnixDate(long.Parse(detail.Key)), 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, AllowResourceAssignment = ec.Value.AllowResourceAssignment }); } } } return scenarioDetails; } public Dictionary> GetTeams() { if (Expenditures == null || Expenditures.Count <= 0) return new Dictionary>(); return Expenditures.Select(x => new { ExpenditureId = x.Key, x.Value.Teams }).ToDictionary(x => x.ExpenditureId, g => g.Teams); } public ScenarioCalendarModelBase() { Expenditures = new Dictionary(); } } public class ScenarioCalendarModel : ScenarioCalendarModelBase { public Dictionary> Headers { get; set; } public ScenarioCalendarModel() : base() { Headers = new Dictionary>(); } } public class CostSavingSnapshotModel { public decimal? CostSavings { get; set; } public long? CostSavingStartDate { get; set; } public long? CostSavingEndDate { get; set; } public bool CostSavingType { get; set; } public string CostSavingDescription { get; set; } public List CostSavingItems { get; set; } public CostSavingSnapshotModel() { CostSavingItems = new List(); } } public class TeamInScenarioModel { public Guid TeamId { get; set; } public short Allocation { get; set; } public bool IsNew { get; set; } public bool IsAdd { get; set; } public bool IsAccessible { get; set; } public bool CanBeDeleted { get; set; } } /// /// Information about versions of ralated item /// public class ItemVersionInfo { public ItemVersionInfo() { RmoVersion = 1; ChangedInMain = false; ChangedInRmo = false; } public ulong? SourceVersion { get; set; } public ulong RmoVersion { get; set; } public bool ChangedInMain { get; set; } public bool ChangedInRmo { get; set; } } public class ScenarioCalendarSelectItemTeamModel { public Guid Id { get; set; } public string Name { get; set; } public List Expenditures { get; set; } #region Constructors public ScenarioCalendarSelectItemTeamModel() { Expenditures = new List(); } #endregion } public class ExpenditureCategoryChangeCurveModel { public Guid FromExpenditureId { get; set; } public Guid ToExpenditureId { get; set; } } public class ExpenditureCategoryReallocateResourceModel { public Guid SourceExpCat { get; set; } public Guid TargetExpCat { get; set; } public long SourceWeekEnding { get; set; } public long TargetWeekEnding { get; set; } public short Percentage { get; set; } public string ReallocateBy { get; set; } public Guid UseCurveFromExpenditureId { get; set; } } public class ExpenditureCategoryRoundModel { public List ExpCats { get; set; } public long StartDate { get; set; } public long EndDate { get; set; } public string DecimalPlaces { get; set; } } public class ExpenditureCategoryChangesHistory { public Dictionary CurveChanges { get; set; } public Dictionary Reallocations { get; set; } public Dictionary Roundings { get; set; } public ExpenditureCategoryChangesHistory() { CurveChanges = new Dictionary(); Reallocations = new Dictionary(); Roundings = new Dictionary(); } } #endregion }