/// <summary> /// Resource price /// </summary> public ResourcePricing Price(PurchaseOrSalePricingStyleType priceType) { // find pricing that is ok; ResourcePricing price = Apsim.Children(this, typeof(ResourcePricing)).Where(a => a.Enabled & ((a as ResourcePricing).PurchaseOrSale == PurchaseOrSalePricingStyleType.Both | (a as ResourcePricing).PurchaseOrSale == priceType) && (a as ResourcePricing).TimingOK).FirstOrDefault() as ResourcePricing; // does simulation have finance ResourcesHolder resources = Apsim.Parent(this, typeof(ResourcesHolder)) as ResourcesHolder; bool financesPresent = (resources.FinanceResource() != null); if (price == null) { if (financesPresent) { string warn = "No pricing is available for [r=" + this.Parent.Name + "." + this.Name + "]"; if (Clock != null & Apsim.Children(this, typeof(ResourcePricing)).Count > 0) { warn += " in month [" + Clock.Today.ToString("MM yyyy") + "]"; } warn += "\nAdd [r=ResourcePricing] component to [r=" + this.Parent.Name + "." + this.Name + "] to include financial transactions for purchases and sales."; if (!Warnings.Exists(warn) & Summary != null) { Summary.WriteWarning(this, warn); Warnings.Add(warn); } } return(new ResourcePricing() { PricePerPacket = 0, PacketSize = 1, UseWholePackets = true }); } return(price); }
/// <summary> /// Get value of a specific individual /// </summary> /// <returns>value</returns> public double ValueofIndividual(Ruminant ind, PurchaseOrSalePricingStyleType purchaseStyle) { if (PricingAvailable()) { List <Ruminant> animalList = new List <Ruminant>() { ind }; // search through RuminantPriceGroups for first match with desired purchase or sale flag foreach (AnimalPriceGroup item in priceGroups.Where(a => a.PurchaseOrSale == purchaseStyle || a.PurchaseOrSale == PurchaseOrSalePricingStyleType.Both)) { if (animalList.Filter(item).Count() == 1) { return(item.Value * ((item.PricingStyle == PricingStyleType.perKg) ? ind.Weight : 1.0)); } } // no price match found. string warningString = $"No [{purchaseStyle.ToString()}] price entry was found for [r={ind.Breed}] meeting the required criteria [f=age: {ind.Age}] [f=gender: {ind.GenderAsString}] [f=weight: {ind.Weight.ToString("##0")}]"; if (!Warnings.Exists(warningString)) { Warnings.Add(warningString); Summary.WriteWarning(this, warningString); } } return(0); }
/// <summary> /// Get value of a specific individual /// </summary> /// <returns>value</returns> public AnimalPriceGroup ValueofIndividual(Ruminant ind, PurchaseOrSalePricingStyleType purchaseStyle, string warningMessage = "") { if (PricingAvailable()) { if (ind.CurrentPrice == null || !ind.CurrentPrice.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)) { ind.CurrentPrice = 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); } return(ind.CurrentPrice); } return(null); }
/// <summary> /// Get value of a specific individual /// </summary> /// <returns>value</returns> public double ValueofIndividual(Ruminant ind, PurchaseOrSalePricingStyleType purchaseStyle) { if (PricingAvailable()) { List <Ruminant> animalList = new List <Ruminant>() { ind }; // search through RuminantPriceGroups for first match with desired purchase or sale flag foreach (AnimalPriceGroup item in Apsim.Children(PriceList, typeof(AnimalPriceGroup)).Cast <AnimalPriceGroup>().Where(a => a.PurchaseOrSale == purchaseStyle || a.PurchaseOrSale == PurchaseOrSalePricingStyleType.Both)) { if (animalList.Filter(item).Count() == 1) { return(item.Value * ((item.PricingStyle == PricingStyleType.perKg) ? ind.Weight : 1.0)); } } // no price match found. string warning = "No " + purchaseStyle.ToString() + " price entry was found for an indiviudal with details ([f=age: " + ind.Age + "] [f=herd: " + ind.HerdName + "] [f=gender: " + ind.GenderAsString + "] [f=weight: " + ind.Weight.ToString("##0") + "])"; if (!Warnings.Exists(warning)) { Warnings.Add(warning); Summary.WriteWarning(this, warning); } } return(0); }
/// <summary> /// Resource price /// </summary> public ResourcePricing Price(PurchaseOrSalePricingStyleType priceType) { // find pricing that is ok; ResourcePricing price = null; // if market exists look for market pricing to override local pricing as all transactions will be through the market if (!((this.Parent.Parent as ResourcesHolder).FoundMarket is null) && this.MarketStoreExists) { price = EquivalentMarketStore.FindAllChildren <ResourcePricing>().FirstOrDefault(a => a.Enabled && ((a as ResourcePricing).PurchaseOrSale == PurchaseOrSalePricingStyleType.Both || (a as ResourcePricing).PurchaseOrSale == priceType) && (a as ResourcePricing).TimingOK); }
/// <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> /// Does pricing exist for this type /// </summary> public bool PricingExists(PurchaseOrSalePricingStyleType priceType) { // find pricing that is ok; return(this.FindAllChildren <ResourcePricing>().Where(a => a.Enabled & ((a as ResourcePricing).PurchaseOrSale == PurchaseOrSalePricingStyleType.Both | (a as ResourcePricing).PurchaseOrSale == priceType) && (a as ResourcePricing).TimingOK).FirstOrDefault() != null); }
/// <summary> /// pricing /// </summary> public ResourcePricing Price(PurchaseOrSalePricingStyleType priceStyle) { 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 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); }
/// <summary> /// Get the value to use for the transaction style requested /// </summary> /// <param name="transactionStyle">Style of transaction grouping</param> /// <param name="pricingStyle">Style of pricing if necessary</param> /// <returns>Label to group by</returns> public string GetTransactionCategory(RuminantTransactionsGroupingStyle transactionStyle, PurchaseOrSalePricingStyleType pricingStyle = PurchaseOrSalePricingStyleType.Both) { string result = "N/A"; switch (transactionStyle) { case RuminantTransactionsGroupingStyle.Combined: return("All"); case RuminantTransactionsGroupingStyle.ByPriceGroup: return(BreedParams.GetPriceGroupOfIndividual(this, pricingStyle)?.Name ?? $"{pricingStyle}NotSet"); case RuminantTransactionsGroupingStyle.ByClass: return(this.Class); case RuminantTransactionsGroupingStyle.BySexAndClass: return(this.FullCategory); default: break; } return(result); }
/// <summary> /// Group and summarize individuals by transaction style for reporting /// </summary> /// <param name="individuals">Individuals to summarize</param> /// <param name="priceStyle">Price style to use</param> /// <param name="warningMessage">A custom warning message used if prices cannot be found otherwise the standard messge will be reported for each unique missing price</param> /// <returns>A grouped summary of individuals</returns> public IEnumerable <RuminantReportTypeDetails> SummarizeIndividualsByGroups(IEnumerable <Ruminant> individuals, PurchaseOrSalePricingStyleType priceStyle, string warningMessage = "") { var groupedInd = from ind in individuals group ind by ind.BreedParams.Name into breedGroup select new RuminantReportTypeDetails() { RuminantTypeName = breedGroup.Key, RuminantTypeGroup = from gind in breedGroup group gind by gind.GetTransactionCategory(TransactionStyle, priceStyle) into catind select new RuminantReportGroupDetails() { GroupName = catind.Key, Count = catind.Count(), TotalAdultEquivalent = catind.Sum(a => a.AdultEquivalent), TotalWeight = catind.Sum(a => a.Weight), TotalPrice = catind.Sum(a => a.BreedParams.GetPriceGroupOfIndividual(a, priceStyle, warningMessage)?.CalculateValue(a)) } }; return(groupedInd); }