/// <summary> /// Ported from changed_value_posts::output_intermediate_prices /// </summary> public void OutputIntermediatePrices(Post post, Date current) { // To fix BZ#199, examine the balance of last_post and determine whether the // price of that amount changed after its date and before the new post's // date. If so, generate an output_revaluation for that price change. // Mostly this is only going to occur if the user has a series of pricing // entries, since a posting-based revaluation would be seen here as a post. Value displayTotal = Value.Clone(LastTotal); if (displayTotal.Type == ValueTypeEnum.Sequence) { Xact xact = Temps.CreateXact(); xact.Payee = "Commodities revalued"; xact.Date = current.IsValid() ? current : post.ValueDate; Post temp = Temps.CopyPost(post, xact); temp.Flags |= SupportsFlagsEnum.ITEM_GENERATED; PostXData xdata = temp.XData; if (current.IsValid()) { xdata.Date = current; } Logger.Current.Debug("filters.revalued", () => String.Format("intermediate last_total = {0}", LastTotal)); switch (LastTotal.Type) { case ValueTypeEnum.Boolean: case ValueTypeEnum.Integer: LastTotal.InPlaceCast(ValueTypeEnum.Amount); temp.Amount = LastTotal.AsAmount; break; case ValueTypeEnum.Amount: temp.Amount = LastTotal.AsAmount; break; case ValueTypeEnum.Balance: case ValueTypeEnum.Sequence: xdata.CompoundValue = LastTotal; xdata.Compound = true; break; default: throw new InvalidOperationException(); } BindScope innerScope = new BindScope(Report, temp); displayTotal = DisplayTotalExpr.Calc(innerScope); Logger.Current.Debug("filters.revalued", () => String.Format("intermediate display_total = {0}", displayTotal)); } switch (displayTotal.Type) { case ValueTypeEnum.Void: case ValueTypeEnum.Integer: case ValueTypeEnum.Sequence: break; case ValueTypeEnum.Amount: case ValueTypeEnum.Balance: { if (displayTotal.Type == ValueTypeEnum.Amount) { displayTotal.InPlaceCast(ValueTypeEnum.Balance); } IDictionary <DateTime, Amount> allPrices = new SortedDictionary <DateTime, Amount>(); foreach (KeyValuePair <Commodity, Amount> amtComm in displayTotal.AsBalance.Amounts) { amtComm.Key.MapPrices((d, a) => allPrices[d] = a, current, post.ValueDate, true); } // Choose the last price from each day as the price to use IDictionary <Date, bool> pricingDates = new SortedDictionary <Date, bool>(); foreach (KeyValuePair <DateTime, Amount> price in allPrices.Reverse()) { // This insert will fail if a later price has already been inserted // for that date. var priceDate = (Date)price.Key.Date; Logger.Current.Debug("filters.revalued", () => String.Format("re-inserting {0} at {1}", price.Value, priceDate)); pricingDates[priceDate] = true; } // Go through the time-sorted prices list, outputting a revaluation for // each price difference. foreach (KeyValuePair <Date, bool> price in pricingDates) { OutputRevaluation(post, price.Key); LastTotal = RepricedTotal; } break; } default: throw new InvalidOperationException(); } }
public bool OutputRounding(Post post) { BindScope boundScope = new BindScope(Report, post); Value newDisplayTotal = new Value(); if (ShowRounding) { newDisplayTotal = DisplayTotalExpr.Calc(boundScope).StripAnnotations(Report.WhatToKeep()); Logger.Current.Debug("filters.changed_value.rounding", () => String.Format("rounding.new_display_total = {0}", newDisplayTotal)); } // Allow the posting to be displayed if: // 1. Its display_amount would display as non-zero, or // 2. The --empty option was specified, or // 3. a) The account of the posting is <Revalued>, and // b) the revalued option is specified, and // c) the --no-rounding option is not specified. if (post.Account == RevaluedAccount) { if (ShowRounding) { LastDisplayTotal = newDisplayTotal; } return(true); } Value repricedAmount = DisplayAmountExpr.Calc(boundScope).StripAnnotations(Report.WhatToKeep()); if (!Value.IsNullOrEmptyOrFalse(repricedAmount)) { if (!Value.IsNullOrEmpty(LastDisplayTotal)) { Logger.Current.Debug("filters.changed_value.rounding", () => String.Format("rounding.repriced_amount = {0}", repricedAmount)); Value preciseDisplayTotal = newDisplayTotal.Truncated() - repricedAmount.Truncated(); Logger.Current.Debug("filters.changed_value.rounding", () => String.Format("rounding.precise_display_total = {0}", preciseDisplayTotal)); Logger.Current.Debug("filters.changed_value.rounding", () => String.Format("rounding.last_display_total = {0}", LastDisplayTotal)); Value diff = preciseDisplayTotal - LastDisplayTotal; if (!Value.IsNullOrEmptyOrFalse(diff)) { Logger.Current.Debug("filters.changed_value.rounding", () => String.Format("rounding.diff = {0}", diff)); FiltersCommon.HandleValue( /* value= */ diff, /* account= */ RoundingAccount, /* xact= */ post.Xact, /* temps= */ Temps, /* handler= */ (PostHandler)Handler, /* date= */ default(Date), /* act_date_p= */ true, /* total= */ preciseDisplayTotal, /* direct_amount= */ true, /* mark_visited= */ false, /* bidir_link= */ false); } } if (ShowRounding) { LastDisplayTotal = newDisplayTotal; } return(true); } else { return(Report.EmptyHandler.Handled); } }