Files
BusinessMgr-2019/SaBusMgrStandardBase/Base/Bus/SbmCostEstimate.cs
T
2021-08-04 21:32:35 +01:00

757 lines
26 KiB
C#

using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.CodeTypes;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
namespace Sarand.BusinessMgr.Net.Standard.Base.Bus
{
//=======================================================================
public class SbmCostEstimate : SbmHierarchyItem
{
//-------------------------------------------------------------------
// Columns.
public enum Column
{
Hidden,
Pos,
Id,
// CostEstimate.
// Common properties.
Notes,
Status,
Status_Ind,
Status_Desc,
CreateOn_Date,
UpdateOn_Date,
}
//-------------------------------------------------------------------
/// <summary>Properties other than common.</summary>
public class DataProperties
{
public Sbm.CostEstimateCategory CostEstimateCategory { get; set; } = Sbm.CostEstimateCategory.Unknown;
public String Type { get; set; } = "";
public decimal Time { get; set; } = 0.0m;
public decimal Rate { get; set; } = 0.0m;
public decimal Cost { get; set; } = 0.0m;
public ushort Markup { get; set; } = 0;
public ushort MinQuantity { get; set; } = 0;
public ushort CodeSeq { get; set; } = 0;
}
//-------------------------------------------------------------------
// Data.
public new class Data : SacsHierarchyItem.Data
{
// Data members.
private readonly DataProperties data = new DataProperties();
// Construction.
public Data()
{
Status = DefaultStatus;
}
public Sbm.CostEstimateCategory CostEstimateCategory
{
get { return data.CostEstimateCategory; }
set { CheckChanged((int)data.CostEstimateCategory, (int)value); data.CostEstimateCategory = value; }
}
public String Type
{
get { return data.Type; }
set { CheckChanged(data.Type, value); data.Type = value; }
}
public decimal Time
{
get { return data.Time; }
set { CheckChanged(data.Time, value); data.Time = value; }
}
public decimal Rate
{
get { return data.Rate; }
set { CheckChanged(data.Rate, value); data.Rate = value; }
}
public decimal Cost
{
get { return data.Cost; }
set { CheckChanged(data.Cost, value); data.Time = value; }
}
public ushort Markup
{
get { return data.Markup; }
set { CheckChanged(data.Markup, value); data.Markup = value; }
}
public ushort MinQuantity
{
get { return data.MinQuantity; }
set { CheckChanged(data.MinQuantity, value); data.MinQuantity = value; }
}
public ushort CodeSeq
{
get { return data.CodeSeq; }
set { CheckChanged(data.CodeSeq, value); data.CodeSeq = value; }
}
internal void PopulateFrom(Data data)
{
CostEstimateCategory = data.CostEstimateCategory;
Type = data.Type;
Time = data.Time;
Rate = data.Rate;
Cost = data.Cost;
Markup = data.Markup;
MinQuantity = data.MinQuantity;
CodeSeq = data.CodeSeq;
base.PopulateFrom(data);
}
public Data Clone()
{
Data data = new Data();
data.PopulateFrom(this);
return data;
}
}
//-------------------------------------------------------------------
// Data members.
private readonly Data data = new Data();
private readonly Sbm.CostEstimateCategory costEstimateCategory;
private readonly String type;
private readonly decimal time = 0.0m;
private readonly decimal rate = 0.0m;
private readonly decimal cost = 0.0m;
private readonly ushort markup = 0;
private readonly ushort minQuantity = 0;
private readonly ushort codeSeq = 0;
// Static Definition.
private static String costEstimate = "CostEstimate";
private static String delimArchiveOld = "#~#";
private static String delimArchive = "#~#";
//-------------------------------------------------------------------
// Construction.
public SbmCostEstimate(ISbmUserContext userContext, Sbm.CostEstimateCategory costEstimateCategory) : base(userContext)
{
CostEstimateCategory = costEstimateCategory;
Status = DefaultStatus;
}
// Conversion from ItemLink.
public SbmCostEstimate(ISbmUserContext userContext, String archive) : base(userContext)
{
String[] data = archive.Split(new String[] { delimArchive }, StringSplitOptions.None);
costEstimateCategory = (Sbm.CostEstimateCategory)(data.Length > 0 ? StringUtil.ToShort(data[0]) : 0);
type = (data.Length > 1 ? data[1] : "");
time = (data.Length > 2 ? StringUtil.ToDecimal(data[2]) : 0.0m);
rate = (data.Length > 3 ? StringUtil.ToDecimal(data[3]) : 0.0m);
cost = (data.Length > 4 ? StringUtil.ToDecimal(data[4]) : 0.0m);
markup = (ushort)(data.Length > 5 ? StringUtil.ToInt(data[5]) : 0);
minQuantity = (ushort)(data.Length > 6 ? StringUtil.ToInt(data[6]) : 0);
}
//-------------------------------------------------------------------
// CostEstimate status.
private static readonly List<SaStatus> containerItemStatuses = new List<SaStatus>()
{
SaStatus.Active,
SaStatus.Disabled,
};
public static SaStatus DefaultStatus { get { return SaStatus.Current; } }
public static List<SaStatus> CostEstimateStatuses { get { return new List<SaStatus>(containerItemStatuses); } }
public static DataValue.TriStateType GetStatusTriState(SaStatus status)
{
switch (status)
{
case SaStatus.Active:
return DataValue.TriStateType.Green;
case SaStatus.OnHold:
return DataValue.TriStateType.Amber;
case SaStatus.Disabled:
return DataValue.TriStateType.Red;
case SaStatus.Deleted:
return DataValue.TriStateType.Purple;
}
return DataValue.TriStateType.Unknown;
}
//-------------------------------------------------------------------
// Utilities.
public List<TypeCodeDesc> GetCategories(Sbm.CostEstimateCategoryType costEstimateCategoryType, bool includeCommodityCode)
{
List<TypeCodeDesc> categories = new List<TypeCodeDesc>();
if (includeCommodityCode)
categories.Add(Sbm.CostEstimateCategory.CommodityCost, "CCU", "Material per unit");
categories.Add(Sbm.CostEstimateCategory.CostPerUnit, "CPU", "Cost per unit");
categories.Add(Sbm.CostEstimateCategory.CostPerJob, "CPJ", "Cost per job");
categories.Add(Sbm.CostEstimateCategory.LabourPerUnit, "LPU", "Labour per unit");
categories.Add(Sbm.CostEstimateCategory.LabourPerJob, "LPJ", "Labour per job");
// Remove unneccessary categories from the list:
if (costEstimateCategoryType != Sbm.CostEstimateCategoryType.Any)
{
foreach (TypeCodeDesc category in categories)
{
if (costEstimateCategoryType == Sbm.CostEstimateCategoryType.Cost && IsLabour((Sbm.CostEstimateCategory)category.Type)) categories.Clear();
else if (costEstimateCategoryType == Sbm.CostEstimateCategoryType.Labour && !IsLabour((Sbm.CostEstimateCategory)category.Type)) categories.Clear();
}
}
return categories;
}
// Cost estimate types.
public Sbm.ApplCodeType GetCodeTypeForCategory(Sbm.CostEstimateCategory costEstimateCategory)
{
if (costEstimateCategory == Sbm.CostEstimateCategory.CostPerUnit) return Sbm.ApplCodeType.CostPerUnit;
if (costEstimateCategory == Sbm.CostEstimateCategory.CostPerJob) return Sbm.ApplCodeType.CostPerJob;
if (costEstimateCategory == Sbm.CostEstimateCategory.LabourPerUnit) return Sbm.ApplCodeType.LabourPerUnit;
if (costEstimateCategory == Sbm.CostEstimateCategory.LabourPerJob) return Sbm.ApplCodeType.LabourPerJob;
return Sbm.ApplCodeType.Unknown;
}
// Matching.
public bool MatchesByCategoryType(Sbm.CostEstimateCategory costEstimateCategory, String type)
{
if (CostEstimateCategory != costEstimateCategory) return false;
if (Type != type) return false;
return true;
}
// Cloning - make a copy of the item.
public SbmCostEstimate Clone()
{
SbmCostEstimate costEstimateCost = new SbmCostEstimate(UserContext, costEstimateCategory.ToString());
//costEstimateCost.CopyAttributesFrom(this);
costEstimateCost.Type = Type;
costEstimateCost.Time = Time;
costEstimateCost.Rate = Rate;
costEstimateCost.Cost = Cost;
costEstimateCost.Markup = Markup;
costEstimateCost.MinQuantity = MinQuantity;
costEstimateCost.Changed = false;
return costEstimateCost;
}
// Conversion.
public String Conversion()
{
String archive = "";
archive += CostEstimateCategory.ToString() + delimArchive;
archive += Type.ToString() + delimArchive;
archive += StringUtil.FormatNumeric(Time, 4) + delimArchive;
archive += Rate.ToString() + delimArchive;
archive += Cost.ToString() + delimArchive;
archive += Markup.ToString() + delimArchive;
archive += MinQuantity.ToString() + delimArchive;
return archive;
}
//-------------------------------------------------------------------
// Validation.
public bool IsValid()
{
if (!IsValidCategory(costEstimateCategory)) return false;
if (!IsValidType()) return false;
if (!IsValidTime()) return false;
if (!IsValidRate()) return false;
if (!IsValidCost()) return false;
return true;
}
public bool IsValidCategory(Sbm.CostEstimateCategory costEstimateCategory)
{
if (costEstimateCategory < Sbm.CostEstimateCategory.CommodityCost) return false;
if (costEstimateCategory > Sbm.CostEstimateCategory.LabourPerJob) return false;
return true;
}
public bool IsValidType()
{
return true;
}
public bool IsValidTime()
{
return true;
}
public bool IsValidRate()
{
return true;
}
public bool IsValidCost()
{
return true;
}
//-------------------------------------------------------------------
// Properties.
public Data GetData() { return data.Clone(); }
public void SetData(Data data)
{
String fn = GetType().Name + ".SetData";
// Properties that cannot be changed if previously specified.
if (SysId.IsValid(Id) && SysId.ToInt(Id) != SysId.ToInt(data.Id))
throw new NotSupportedException(fn + " Id cannot be changed");
// Populate individual properties to ensure that 'Changed' indicator is kept up to date.
this.data.PopulateFrom(data);
}
//-------------------------------------------------------------------
// Attributes.
public Sbm.CostEstimateCategory CostEstimateCategory
{
get { return data.CostEstimateCategory; }
set { data.CostEstimateCategory = value; }
}
public bool IsLabour()
{
return IsLabour(costEstimateCategory);
}
public bool IsLabour(Sbm.CostEstimateCategory costEstimateCategory)
{
switch (costEstimateCategory)
{
case Sbm.CostEstimateCategory.LabourPerJob:
case Sbm.CostEstimateCategory.LabourPerUnit:
return true;
}
return false;
}
public bool IsUnitCost()
{
return IsUnitCost(costEstimateCategory);
}
public bool IsUnitCost(Sbm.CostEstimateCategory costEstimateCategory)
{
switch (costEstimateCategory)
{
case Sbm.CostEstimateCategory.CommodityCost:
case Sbm.CostEstimateCategory.CostPerUnit:
case Sbm.CostEstimateCategory.LabourPerUnit:
return true;
}
return false;
}
public bool IsJobCost()
{
return IsJobCost(costEstimateCategory);
}
public bool IsJobCost(Sbm.CostEstimateCategory costEstimateCategory)
{
switch (costEstimateCategory)
{
case Sbm.CostEstimateCategory.CostPerJob:
case Sbm.CostEstimateCategory.LabourPerJob:
return true;
}
return false;
}
public String Type
{
get { return data.Type; }
set { data.Type = value; }
}
public decimal Time
{
get { return data.Time; }
set { data.Time = value; }
}
public decimal Rate
{
get { return data.Rate; }
set { data.Rate = value; }
}
public decimal Cost
{
get { return data.Cost; }
set { data.Time = value; }
}
public ushort Markup
{
get { return data.Markup; }
set { data.Markup = value; }
}
public ushort MinQuantity
{
get { return data.MinQuantity; }
set { data.MinQuantity = value; }
}
public ushort CodeSeq
{
get { return data.CodeSeq; }
set { data.CodeSeq = value; }
}
// Calculated costs.
public decimal GetCostPerUnit(decimal quantity)
{
decimal costPerUnit = cost;
if (IsLabour())
costPerUnit = time * rate;
if (IsJobCost())
{
if (quantity != 0.0m)
costPerUnit /= quantity;
else
costPerUnit = 0m;
}
// Apply the markup %
if (markup > 0)
costPerUnit *= 1 + (markup / 100.0m);
// Round to 2 decimals.
long costPerUnit100 = (long)((costPerUnit * 100.0m) + 0.5m);
costPerUnit = costPerUnit100 / 100.0m;
return costPerUnit;
}
public decimal GetCostPerJob(decimal quantity)
{
// Check for 'Cost per job' categories.
if (IsJobCost(costEstimateCategory))
{
if (IsLabour())
return time * rate;
return cost;
}
// Cost is 'per unit'.
decimal costPerJob = GetCostPerUnit(quantity) * quantity;
return costPerJob;
}
//-------------------------------------------------------------------
}
//=======================================================================
// C o s t E s t i m a t e D a t a L i s t
//=======================================================================
public static class SbmCostEstimateList
{
/// <summary>Check whether currency exists/locate in list with specified Id.</summary>
//-------------------------------------------------------------------
// Find in List.
public static bool Find(this List<SbmCostEstimate> values, SbmCostEstimate containerItem)
{
if (containerItem == null) return false;
return (values.Find(item => item == containerItem) != null);
}
public static bool FindByCategoryType(this List<SbmCostEstimate> values, Sbm.CostEstimateCategory costEstimateCategory, String type)
{
if (costEstimateCategory < 0 && StringUtil.IsEmpty(type)) return false;
return values.Exists(item => item.MatchesByCategoryType(costEstimateCategory, type));
}
//-------------------------------------------------------------------
public static void SetCommodityCosts(this List<SbmCostEstimate> values, ISbmUserContext userContext, SbmCommodity commodity, decimal quantity)
{
// Retrieve costs from commodity and remove unwanted costs (for other quantities).
List<SbmCostEstimate> costEstimatesCommodity = commodity.GetCostEstimates();
costEstimatesCommodity.ConsolidateByQuantity(quantity);
// If there are cost estimates remaining, replace the contents of this list.
if (costEstimatesCommodity != null && !StringUtil.IsEmpty(costEstimatesCommodity.ToString()))
{
// Make a note of the current list of estimates and replace with those from the commodity.
List<SbmCostEstimate> costEstimatesCostSave = costEstimatesCommodity;
costEstimatesCommodity.Clear();
// Copy associated details from previous list.
for (int est = 1; est <= values.Count; est++)
{
SbmCostEstimate costEstimate = values[est];
if (costEstimatesCostSave.FindByCategoryType(costEstimate.CostEstimateCategory, costEstimate.Type))
{
costEstimate.Markup = values[est].Markup;
if (costEstimate.IsLabour())
costEstimate.Rate = values[est].Rate;
costEstimate.Notes = values[est].Notes;
}
}
// Clean-up:
costEstimatesCostSave.Clear();
}
else
{
// Commodity has no costs - just use the cost price (if specified).
decimal cost = commodity.CostPrice;
if (cost > 0)
{
bool bCommodityCostFound = false;
for (int i = 1; !bCommodityCostFound && i <= values.Count; i++)
{
SbmCostEstimate costEstimateCost = values[i];
if (costEstimateCost == null) continue;
if (costEstimateCost.CostEstimateCategory == Sbm.CostEstimateCategory.CommodityCost)
{
costEstimateCost.Cost = cost;
bCommodityCostFound = true;
}
}
if (!bCommodityCostFound)
{
// Create a new entry for the commodity cost.
SbmCostEstimate costEstimateCost = new SbmCostEstimate(userContext, Sbm.CostEstimateCategory.CommodityCost.ToString());
costEstimateCost.Cost = cost;
costEstimatesCommodity.Add(costEstimateCost);
costEstimatesCommodity.Sort();
costEstimateCost = null; // Now owned by the list.
}
}
}
// Clean-up:
if (costEstimatesCommodity != null)
{
costEstimatesCommodity.Clear();
}
}
public static void ConsolidateByQuantity(this List<SbmCostEstimate> values, decimal quantity)
{
//if (!this || IsEmpty()) return.
if (quantity < 1) quantity = 1.0m;
ushort iQuantity = (ushort)(quantity + 0.5m);
// Repeat for each cost in the list.
for (int est = 1; est <= values.Count; est++)
{
// Check if this cost estimate's min qty is higher than the specified quantity.
SbmCostEstimate costEstimateCost = values[est];
Sbm.CostEstimateCategory costEstimateCategoryCost = costEstimateCost.CostEstimateCategory;
ushort iMinQty = costEstimateCost.MinQuantity;
if (iMinQty > iQuantity)
{
// Never use a cost estimate where the min qty is higher than the required qty.
costEstimateCost = null;
est--;
continue;
}
// Compare to each of the other costs in the list:
for (int costCmd = 1; costEstimateCost != null && costCmd <= values.Count; costCmd++)
{
// Ignore the same commodity.
SbmCostEstimate costEstimateCommodity = values[costCmd];
if (costEstimateCommodity == costEstimateCost) continue;
// Only interested if the category and type are the same:
if (costEstimateCategoryCost == costEstimateCommodity.CostEstimateCategory && costEstimateCost.Type == costEstimateCommodity.Type)
{
ushort iMinQtyCmp = costEstimateCommodity.MinQuantity;
// Commodity costs are banded by minimum quantity.
// Costs are retained where their minimum quantity is the
// highest value less than or equal to the specified quantity:
// eg. Min qty: 1,10,20, Qty = 15, retain min qty 10.
if (iMinQty < iMinQtyCmp)
{
if (iQuantity < iMinQtyCmp)
{
costEstimateCommodity = null;
costCmd--;
continue;
}
else if (iQuantity >= iMinQtyCmp)
{
costEstimateCost = null;
est--;
continue;
}
}
}
}
}
}
//-------------------------------------------------------------------
// Seq/Compare.
public static void SetTypeCodeSequence(this List<SbmCostEstimate> values, List<SaCodeDfn> costPerUnits, List<SaCodeDfn> costPerJobs, List<SaCodeDfn> labourPerUnits, List<SaCodeDfn> labourPerJobs)
{
foreach (SbmCostEstimate costEstimate in values)
{
// Identify the corresponding list of code definitions.
List<SaCodeDfn> codes = null;
switch (costEstimate.CostEstimateCategory)
{
case Sbm.CostEstimateCategory.CostPerUnit: codes = costPerUnits; break;
case Sbm.CostEstimateCategory.CostPerJob: codes = costPerJobs; break;
case Sbm.CostEstimateCategory.LabourPerUnit: codes = labourPerUnits; break;
case Sbm.CostEstimateCategory.LabourPerJob: codes = labourPerJobs; break;
}
if (codes != null && codes.Exists(item => item.Code.Equals(costEstimate.Type)))
costEstimate.CodeSeq = codes.Find(item => item.Code.Equals(costEstimate.CodeSeq)).Sequence;
}
}
public static int CompareCatType(this List<SbmCostEstimate> values, SbmCostEstimate costEstimate1, SbmCostEstimate costEstimate2)
{
if (costEstimate1 == null || costEstimate2 == null) return 0;
if (costEstimate1 == costEstimate2) return 0;
// Commodity costs always appear at the top of the list:
if (costEstimate1.CostEstimateCategory != Sbm.CostEstimateCategory.CommodityCost && costEstimate1.CostEstimateCategory == Sbm.CostEstimateCategory.CommodityCost) return 1;
if (costEstimate1.CostEstimateCategory == Sbm.CostEstimateCategory.CommodityCost && costEstimate1.CostEstimateCategory != Sbm.CostEstimateCategory.CommodityCost) return -1;
if (costEstimate1.CostEstimateCategory == Sbm.CostEstimateCategory.CommodityCost && costEstimate1.CostEstimateCategory == Sbm.CostEstimateCategory.CommodityCost)
{
return costEstimate1.Type.CompareTo(costEstimate2.Type);
}
// Labour estimates always appear below cost estimates.
if (costEstimate1.IsLabour() && !costEstimate2.IsLabour()) return 1;
if (!costEstimate1.IsLabour() && costEstimate2.IsLabour()) return -1;
// Estimates are the same type (cost or labour).
// Compare the sequence derived from the typed code.
if (costEstimate1.CodeSeq > costEstimate2.CodeSeq) return 1;
if (costEstimate1.CodeSeq < costEstimate2.CodeSeq) return -1;
// Code sequences are the same - compare the type code.
if (costEstimate1.Type != costEstimate2.Type)
return costEstimate1.Type.CompareTo(costEstimate2.Type);
// Everything else being equal, sort per unit before per job.
if (costEstimate1.IsJobCost() && !costEstimate2.IsJobCost()) return 1;
if (!costEstimate1.IsJobCost() && costEstimate2.IsJobCost()) return -1;
if (costEstimate1.CostEstimateCategory > costEstimate2.CostEstimateCategory) return 1;
if (costEstimate1.CostEstimateCategory < costEstimate2.CostEstimateCategory) return -1;
int costEstimateCompare = costEstimate1.Type.CompareTo(costEstimate2.Type);
if (costEstimateCompare != 0) return costEstimateCompare;
if (costEstimate1.GetCostPerUnit(1.0m) > costEstimate2.GetCostPerUnit(1.0m)) return 1;
if (costEstimate1.CostEstimateCategory == costEstimate2.CostEstimateCategory && costEstimate1.Type == costEstimate2.Type) return 0;
return -1;
}
//-------------------------------------------------------------------
// Sort - by category and type.
public static void Sort(this List<SbmCostEstimate> values)
{
values.Sort
(
delegate (SbmCostEstimate costEstimate1, SbmCostEstimate costEstimate2)
{
return CompareCatType(values, costEstimate1, costEstimate2);
}
);
}
// Costs by category.
public static bool HasCostsByCategory(this List<SbmCostEstimate> values, Sbm.CostEstimateCategory costEstimateCategory)
{
if (costEstimateCategory < 0) return false;
return values.Exists(item => item.CostEstimateCategory.Equals(costEstimateCategory));
}
public static List<String> GetCostCodesByCategory(this List<SbmCostEstimate> values, Sbm.CostEstimateCategory costEstimateCategory)
{
List<String> codes = new List<String>();
for (int i = 1; i <= values.Count; i++)
{
SbmCostEstimate costEstimateCost = values[i];
if (costEstimateCost.CostEstimateCategory == costEstimateCategory)
codes.Add(costEstimateCost.Clone().ToString());
}
return codes;
}
public static List<SbmCostEstimate> GetCostsByCategory(this List<SbmCostEstimate> values, Sbm.CostEstimateCategory costEstimateCategory)
{
List<SbmCostEstimate> costEstimateCosts = new List<SbmCostEstimate>();
for (int i = 1; i <= values.Count; i++)
{
SbmCostEstimate costEstimateCost = values[i];
if (costEstimateCost.CostEstimateCategory == costEstimateCategory)
costEstimateCosts.Add(costEstimateCost.Clone());
}
return costEstimateCosts;
}
// Utilities.
public static bool HasCostForMinQuantity(this List<SbmCostEstimate> values, ushort quantity, bool ignoreZeroAmount)
{
for (int est = 1; est <= values.Count; est++)
{
SbmCostEstimate costEstimateCost = values[est];
if (costEstimateCost.MinQuantity == quantity)
if (!ignoreZeroAmount || (costEstimateCost.IsLabour() && costEstimateCost.Time > 0.0m) || (!costEstimateCost.IsLabour() && costEstimateCost.Cost > 0.0m)) return true;
}
return false;
}
//-------------------------------------------------------------------
// Getting Calculate totals.
public static decimal GetCostPerUnit(this List<SbmCostEstimate> values, decimal quantity)
{
decimal total = 0.0m;
for (int est = 1; est <= values.Count; est++)
total += values[est].GetCostPerUnit(quantity);
return total;
}
public static decimal GetCostPerJob(this List<SbmCostEstimate> values, decimal quantity)
{
decimal total = 0.0m;
for (int est = 1; est <= values.Count; est++)
total += values[est].GetCostPerJob(quantity);
return total;
}
public static decimal GetLabourTimePerUnit(this List<SbmCostEstimate> values)
{
// Total of times for 'per unit' labour estimates.
decimal time = 0.0m;
for (int est = 1; est <= values.Count; est++)
{
SbmCostEstimate costEstimateEst = values[est];
if (costEstimateEst != null && costEstimateEst.IsLabour() && costEstimateEst.IsUnitCost())
time += costEstimateEst.Time;
}
return time;
}
public static decimal GetLabourTimePerJob(this List<SbmCostEstimate> values)
{
// Total of times for 'per job' labour estimates.
decimal time = 0.0m;
for (int est = 1; est <= values.Count; est++)
{
SbmCostEstimate costEstimateEst = values[est];
if (costEstimateEst != null && costEstimateEst.IsLabour() && costEstimateEst.IsJobCost())
time += costEstimateEst.Time;
}
return time;
}
public static decimal GetLabourTimePerUnit(this List<SbmCostEstimate> values, decimal quantity)
{
// Estimated time per unit.
return (GetLabourTimePerJob(values, quantity) / quantity);
}
public static decimal GetLabourTimePerJob(this List<SbmCostEstimate> values, decimal quantity)
{
// Estimated total time for job.
decimal time = 0.0m;
for (int est = 1; est <= values.Count; est++)
{
SbmCostEstimate costEstimateEst = values[est];
if (costEstimateEst != null && costEstimateEst.IsLabour())
{
if (costEstimateEst.IsUnitCost())
time += costEstimateEst.Time * quantity;
else
time += costEstimateEst.Time;
}
}
return time;
}
//-------------------------------------------------------------------
public static List<SbmCostEstimate> Clone(this List<SbmCostEstimate> values)
{
// ToDo CostEstimate list clone: Should each value in the list be cloned?
return new List<SbmCostEstimate>(values);
}
//-------------------------------------------------------------------
}
//=======================================================================
}