/// <summary> /// Model the price of each present cohort for a given breed /// </summary> /// <param name="parent"></param> /// <returns></returns> public IEnumerable <AnimalPriceGroup> GetAnimalPrices(AnimalPricing parent) { List <AnimalPriceGroup> prices = new List <AnimalPriceGroup>(); double sire_price = 0; int row = -1; foreach (string cohort in RumNumbers.RowNames) { row++; if (RumNumbers.GetData <double>(row, RumActiveID) != 0) { if (!cohort.ToLower().Contains("sire")) { sire_price = RumPrices.GetData <double>(row, RumActiveID); } var group = new AnimalPriceGroup(parent) { Name = cohort, Value = RumPrices.GetData <double>(row, RumActiveID) }; // Filter cohort based on gender group.Add(new RuminantFilter(group) { Name = "GenderFilter", Parameter = 2, Value = cohort.ToLower().Contains("f") ? "Female" : "Male" }); // Filter cohort based on age group.Add(new RuminantFilter(group) { Name = "AgeFilter", Parameter = 3, Operator = 5, Value = RumAges.GetData <string>(row, RumActiveID) }); prices.Add(group); } } parent.SirePrice = sire_price; return(prices); }
public IEnumerable <AnimalPriceGroup> GetAnimalPrices(AnimalPricing pricing) { List <AnimalPriceGroup> prices = new List <AnimalPriceGroup>(); int index = Breeds.IndexOf((pricing.Parent as RuminantType).Breed); // List of all the present cohorts var cohorts = pricing.Parent.Children.First().Children; foreach (var cohort in cohorts) { AnimalPriceGroup price = new AnimalPriceGroup(pricing) { Name = cohort.Name, PricingStyle = 1, Value = GetValue <double>(Prices.Element(cohort.Name), index) }; price.Add(new RuminantFilter(price) { Name = "GenderFilter", Parameter = 2, Value = (((RuminantTypeCohort)cohort).Gender == 0) ? "Male" : "Female" }); price.Add(new RuminantFilter(price) { Name = "AgeFilter", Parameter = 3, Operator = 5, Value = ((RuminantTypeCohort)cohort).Age.ToString() }); prices.Add(price); } return(prices.AsEnumerable()); }
/// <summary> /// Get value of a specific individual /// </summary> /// <returns>value</returns> public AnimalPriceGroup GetPriceGroupOfIndividual(Ruminant ind, PurchaseOrSalePricingStyleType purchaseStyle, string warningMessage = "") { if (PricingAvailable()) { AnimalPriceGroup animalPrice = (purchaseStyle == PurchaseOrSalePricingStyleType.Purchase) ? ind.CurrentPriceGroups.Buy : ind.CurrentPriceGroups.Sell; if (animalPrice == null || !animalPrice.Filter(ind)) { // search through RuminantPriceGroups for first match with desired purchase or sale flag foreach (AnimalPriceGroup priceGroup in priceGroups.Where(a => a.PurchaseOrSale == purchaseStyle || a.PurchaseOrSale == PurchaseOrSalePricingStyleType.Both)) { if (priceGroup.Filter(ind)) { if (purchaseStyle == PurchaseOrSalePricingStyleType.Purchase) { ind.CurrentPriceGroups = (priceGroup, ind.CurrentPriceGroups.Sell); return(priceGroup); } else { ind.CurrentPriceGroups = (ind.CurrentPriceGroups.Buy, priceGroup); return(priceGroup); } } } // no price match found. string warningString = warningMessage; if (warningString == "") { warningString = $"No [{purchaseStyle}] price entry was found for [r={ind.Breed}] meeting the required criteria [f=age: {ind.Age}] [f=sex: {ind.Sex}] [f=weight: {ind.Weight:##0}]"; } Warnings.CheckAndWrite(warningString, Summary, this, MessageType.Warning); } return(animalPrice); } return(null); }
/// <summary> /// Get value of a specific individual with special requirements check (e.g. breeding sire or draught purchase) /// </summary> /// <returns>value</returns> public double ValueofIndividual(Ruminant ind, PurchaseOrSalePricingStyleType purchaseStyle, RuminantFilterParameters property, string value) { double price = 0; if (PricingAvailable()) { string criteria = property.ToString().ToUpper() + ":" + value.ToUpper(); List <Ruminant> animalList = new List <Ruminant>() { ind }; //find first pricing entry matching specific criteria AnimalPriceGroup matchIndividual = null; AnimalPriceGroup matchCriteria = null; foreach (AnimalPriceGroup item in PriceList.FindAllChildren <AnimalPriceGroup>().Cast <AnimalPriceGroup>().Where(a => a.PurchaseOrSale == purchaseStyle || a.PurchaseOrSale == PurchaseOrSalePricingStyleType.Both)) { if (animalList.Filter(item).Count() == 1 && matchIndividual == null) { matchIndividual = item; } // check that pricing item meets the specified criteria. if (item.FindAllChildren <RuminantFilter>().Cast <RuminantFilter>().Where(a => (a.Parameter.ToString().ToUpper() == property.ToString().ToUpper() && a.Value.ToUpper() == value.ToUpper())).Count() > 0) { if (matchCriteria == null) { matchCriteria = item; } else { // multiple price entries were found. using first. value = xxx. if (!WarningsMultipleEntry.Contains(criteria)) { WarningsMultipleEntry.Add(criteria); Summary.WriteWarning(this, "Multiple specific [" + purchaseStyle.ToString() + "] price entries were found for [r=" + ind.Breed + "] where [" + property + "]" + (value.ToUpper() != "TRUE" ? " = [" + value + "]." : ".") + "\nOnly the first entry will be used. Price [" + matchCriteria.Value.ToString("#,##0.##") + "] [" + matchCriteria.PricingStyle.ToString() + "]."); } } } } if (matchCriteria == null) { // report specific criteria not found in price list string warningString = "No [" + purchaseStyle.ToString() + "] price entry was found for [r=" + ind.Breed + "] meeting the required criteria [" + property + "]" + (value.ToUpper() != "TRUE" ? " = [" + value + "]." : "."); if (matchIndividual != null) { // add using the best pricing available for [][] purchases of xx per head warningString += "\nThe best available price [" + matchIndividual.Value.ToString("#,##0.##") + "] [" + matchIndividual.PricingStyle.ToString() + "] will be used."; price = matchIndividual.Value * ((matchIndividual.PricingStyle == PricingStyleType.perKg) ? ind.Weight : 1.0); } else { warningString += "\nNo alternate price for individuals could be found for the individuals. Add a new [r=AnimalPriceGroup] entry in the [r=AnimalPricing] for [" + ind.Breed + "]"; } if (!WarningsNotFound.Contains(criteria)) { WarningsNotFound.Add(criteria); Summary.WriteWarning(this, warningString); } } else { price = matchCriteria.Value * ((matchCriteria.PricingStyle == PricingStyleType.perKg) ? ind.Weight : 1.0); } } return(price); }
/// <summary> /// Get value of a specific individual with special requirements check (e.g. breeding sire or draught purchase) /// </summary> /// <returns>value</returns> public AnimalPriceGroup GetPriceGroupOfIndividual(Ruminant ind, PurchaseOrSalePricingStyleType purchaseStyle, string property, string value, string warningMessage = "") { double price = 0; if (PricingAvailable()) { AnimalPriceGroup animalPrice = (purchaseStyle == PurchaseOrSalePricingStyleType.Purchase) ? ind.CurrentPriceGroups.Buy : ind.CurrentPriceGroups.Sell; if (animalPrice == null || !animalPrice.Filter(ind)) { string criteria = property.ToUpper() + ":" + value.ToUpper(); //find first pricing entry matching specific criteria AnimalPriceGroup matchIndividual = null; AnimalPriceGroup matchCriteria = null; var priceGroups = PriceList.FindAllChildren <AnimalPriceGroup>() .Where(a => a.PurchaseOrSale == purchaseStyle || a.PurchaseOrSale == PurchaseOrSalePricingStyleType.Both); foreach (AnimalPriceGroup priceGroup in priceGroups) { if (priceGroup.Filter(ind) && matchIndividual == null) { matchIndividual = priceGroup; } var suitableFilters = priceGroup.FindAllChildren <FilterByProperty>() .Where(a => (a.PropertyOfIndividual == property) & ( (a.Operator == System.Linq.Expressions.ExpressionType.Equal && a.Value.ToString().ToUpper() == value.ToUpper()) | (a.Operator == System.Linq.Expressions.ExpressionType.NotEqual && a.Value.ToString().ToUpper() != value.ToUpper()) | (a.Operator == System.Linq.Expressions.ExpressionType.IsTrue && value.ToUpper() == "TRUE") | (a.Operator == System.Linq.Expressions.ExpressionType.IsFalse && value.ToUpper() == "FALSE") ) ).Any(); // check that pricing item meets the specified criteria. if (suitableFilters) { if (matchCriteria == null) { matchCriteria = priceGroup; } else // multiple price entries were found. using first. value = xxx. if (!warningsMultipleEntry.Contains(criteria)) { warningsMultipleEntry.Add(criteria); Summary.WriteMessage(this, "Multiple specific [" + purchaseStyle.ToString() + "] price entries were found for [r=" + ind.Breed + "] where [" + property + "]" + (value.ToUpper() != "TRUE" ? " = [" + value + "]." : ".") + "\r\nOnly the first entry will be used. Price [" + matchCriteria.Value.ToString("#,##0.##") + "] [" + matchCriteria.PricingStyle.ToString() + "].", MessageType.Warning); } } } if (matchCriteria == null) { string warningString = warningMessage; if (warningString != "") { // no warning string passed to method so calculate one // report specific criteria not found in price list warningString = "No [" + purchaseStyle.ToString() + "] price entry was found for [r=" + ind.Breed + "] meeting the required criteria [" + property + "]" + (value.ToUpper() != "TRUE" ? " = [" + value + "]." : "."); if (matchIndividual != null) { // add using the best pricing available for [][] purchases of xx per head warningString += "\r\nThe best available price [" + matchIndividual.Value.ToString("#,##0.##") + "] [" + matchIndividual.PricingStyle.ToString() + "] will be used."; price = matchIndividual.Value * ((matchIndividual.PricingStyle == PricingStyleType.perKg) ? ind.Weight : 1.0); } else { warningString += "\r\nNo alternate price for individuals could be found for the individuals. Add a new [r=AnimalPriceGroup] entry in the [r=AnimalPricing] for [" + ind.Breed + "]"; } } if (!warningsNotFound.Contains(criteria)) { warningsNotFound.Add(criteria); Summary.WriteMessage(this, warningString, MessageType.Warning); } } if (purchaseStyle == PurchaseOrSalePricingStyleType.Purchase) { ind.CurrentPriceGroups = (matchCriteria, ind.CurrentPriceGroups.Sell); return(matchCriteria); } else { ind.CurrentPriceGroups = (ind.CurrentPriceGroups.Buy, matchCriteria); return(matchCriteria); } } } return(null); }
private void BuyWithTrucking() { // This activity will purchase animals based on available funds. int trucks = 0; int head = 0; double aESum = 0; double fundsAvailable = 0; if (bankAccount != null) { fundsAvailable = bankAccount.FundsAvailable; } double cost = 0; double shortfall = 0; bool fundsexceeded = false; // get current untrucked list of animal purchases List <Ruminant> herd = HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).OrderByDescending(a => a.Weight).ToList(); if (herd.Count == 0) { return; } List <Ruminant> boughtIndividuals = new List <Ruminant>(); // if purchase herd > min loads before allowing trucking if (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck >= trucking.MinimumTrucksBeforeBuying) { // while truck to fill while (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck > trucking.MinimumLoadBeforeBuying) { bool nonloaded = true; trucks++; double load450kgs = 0; // while truck below carrying capacity load individuals foreach (var ind in herd) { if (load450kgs + (ind.Weight / 450.0) <= trucking.Number450kgPerTruck) { nonloaded = false; head++; aESum += ind.AdultEquivalent; load450kgs += ind.Weight / 450.0; if (bankAccount != null) // perform with purchasing { double value = 0; AnimalPriceGroup pricing = null; if (ind.SaleFlag == HerdChangeReason.SirePurchase) { pricing = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Purchase, "IsSire", "true"); } else { pricing = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Purchase); } if (pricing != null) { value = pricing.CalculateValue(ind); } if (cost + value <= fundsAvailable && fundsexceeded == false) { ind.ID = HerdResource.NextUniqueID; boughtIndividuals.Add(ind); HerdResource.AddRuminant(ind, this); HerdResource.PurchaseIndividuals.Remove(ind); cost += value; } else { fundsexceeded = true; shortfall += value; } } else // no financial transactions { ind.ID = HerdResource.NextUniqueID; boughtIndividuals.Add(ind); HerdResource.AddRuminant(ind, this); HerdResource.PurchaseIndividuals.Remove(ind); } } } if (nonloaded) { Summary.WriteWarning(this, String.Format("There was a problem loading the purchase truck as purchase individuals did not meet the loading criteria for breed [r={0}]", this.PredictedHerdBreed)); break; } if (shortfall > 0) { break; } herd = HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).OrderByDescending(a => a.Weight).ToList(); } if (Status != ActivityStatus.Warning) { if (HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).Any() == false) { SetStatusSuccess(); } else { Status = ActivityStatus.Partial; } } // create trucking emissions if (trucking != null && trucks > 0) { trucking.ReportEmissions(trucks, false); } if (bankAccount != null && (trucks > 0 || trucking == null)) { ResourceRequest purchaseRequest = new ResourceRequest { ActivityModel = this, Required = cost, AllowTransmutation = false, Category = TransactionCategory, RelatesToResource = this.PredictedHerdName }; var groupedIndividuals = HerdResource.SummarizeIndividualsByGroups(boughtIndividuals, PurchaseOrSalePricingStyleType.Purchase); foreach (var item in groupedIndividuals) { foreach (var item2 in item.RuminantTypeGroup) { purchaseRequest.Required = item2.TotalPrice ?? 0; purchaseRequest.Category = $"{TransactionCategory}.{item2.GroupName}"; bankAccount.Remove(purchaseRequest); } } // report any financial shortfall in purchases if (shortfall > 0) { purchaseRequest.Available = bankAccount.Amount; purchaseRequest.Required = cost + shortfall; purchaseRequest.Provided = cost; purchaseRequest.ResourceType = typeof(Finance); purchaseRequest.ResourceTypeName = BankAccountName; ResourceRequestEventArgs rre = new ResourceRequestEventArgs() { Request = purchaseRequest }; OnShortfallOccurred(rre); } ResourceRequest expenseRequest = new ResourceRequest { Available = bankAccount.Amount, ActivityModel = this, AllowTransmutation = false }; // calculate transport costs if (trucking != null) { expenseRequest.Required = trucks * trucking.DistanceToMarket * trucking.CostPerKmTrucking; expenseRequest.Category = trucking.TransactionCategory; bankAccount.Remove(expenseRequest); if (expenseRequest.Required > expenseRequest.Available) { expenseRequest.Available = bankAccount.Amount; expenseRequest.ResourceType = typeof(Finance); expenseRequest.ResourceTypeName = BankAccountName; ResourceRequestEventArgs rre = new ResourceRequestEventArgs() { Request = expenseRequest }; OnShortfallOccurred(rre); } } } } else { this.Status = ActivityStatus.Warning; } }
private void BuyWithoutTrucking() { // This activity will purchase animals based on available funds. // get current untrucked list of animal purchases List <Ruminant> herd = HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).ToList(); if (herd.Count > 0) { if (this.Status != ActivityStatus.Warning) { this.Status = ActivityStatus.Success; } } else { return; } List <Ruminant> boughtIndividuals = new List <Ruminant>(); double fundsAvailable = 0; if (bankAccount != null) { fundsAvailable = bankAccount.FundsAvailable; } double cost = 0; double shortfall = 0; bool fundsexceeded = false; foreach (var newind in herd) { if (bankAccount != null) // perform with purchasing { double value = 0; AnimalPriceGroup pricing = null; if (newind.SaleFlag == HerdChangeReason.SirePurchase) { pricing = newind.BreedParams.ValueofIndividual(newind, PurchaseOrSalePricingStyleType.Purchase, "Male.IsSire", "true"); } else { pricing = newind.BreedParams.ValueofIndividual(newind, PurchaseOrSalePricingStyleType.Purchase); } if (pricing != null) { value = pricing.CalculateValue(newind); } if (cost + value <= fundsAvailable && fundsexceeded == false) { boughtIndividuals.Add(newind); HerdResource.PurchaseIndividuals.Remove(newind); newind.ID = HerdResource.NextUniqueID; HerdResource.AddRuminant(newind, this); cost += value; } else { fundsexceeded = true; shortfall += value; } } else // no financial transactions { boughtIndividuals.Add(newind); HerdResource.PurchaseIndividuals.Remove(newind); newind.ID = HerdResource.NextUniqueID; HerdResource.AddRuminant(newind, this); } } if (bankAccount != null) { ResourceRequest purchaseRequest = new ResourceRequest { ActivityModel = this, Required = cost, AllowTransmutation = false, Category = TransactionCategory, RelatesToResource = this.PredictedHerdName }; //bankAccount.Add(saleValue, this, this.PredictedHerdName, TransactionCategory); var groupedIndividuals = HerdResource.SummarizeIndividualsByGroups(boughtIndividuals, PurchaseOrSalePricingStyleType.Purchase); foreach (var item in groupedIndividuals) { foreach (var item2 in item.RuminantTypeGroup) { purchaseRequest.Required = item2.TotalPrice ?? 0; purchaseRequest.Category = $"{TransactionCategory}.{item2.GroupName}"; bankAccount.Remove(purchaseRequest); // bankAccount.Add(item2.TotalPrice, this, item.RuminantTypeName, $"{TransactionCategory}.{item2.GroupName}"); } } // report any financial shortfall in purchases if (shortfall > 0) { purchaseRequest.Available = bankAccount.Amount; purchaseRequest.Required = cost + shortfall; purchaseRequest.Provided = cost; purchaseRequest.ResourceType = typeof(Finance); purchaseRequest.ResourceTypeName = BankAccountName; ResourceRequestEventArgs rre = new ResourceRequestEventArgs() { Request = purchaseRequest }; OnShortfallOccurred(rre); } } }