public override void Flush() { if (Posts.Any()) { foreach (Post post in Posts) { if (post.Xact == null) { throw new InvalidOperationException("no xact"); } foreach (Post rPost in post.Xact.Posts) { PostXData xdata = rPost.XData; if (!xdata.Handled && (!xdata.Received ? !(rPost.Flags.HasFlag(SupportsFlagsEnum.ITEM_GENERATED) || rPost.Flags.HasFlag(SupportsFlagsEnum.POST_VIRTUAL)) : AlsoMatching)) { xdata.Handled = true; base.Handle(rPost); } } } } base.Flush(); }
/// <summary> /// Ported from void calc_posts::operator()(post_t& post) /// </summary> public override void Handle(Post post) { PostXData xdata = post.XData; if (LastPost != null) { if (!LastPost.HasXData) { throw new InvalidOperationException("no xdata"); } if (CalcRunningTotal) { xdata.Total = Value.Clone(LastPost.XData.Total); } xdata.Count = LastPost.XData.Count + 1; } else { xdata.Count = 1; } xdata.VisitedValue = post.AddToValue(xdata.VisitedValue, AmountExpr); xdata.Visited = true; Account acct = post.ReportedAccount; acct.XData.Visited = true; if (CalcRunningTotal) { xdata.Total = Value.AddOrSetValue(xdata.Total, xdata.VisitedValue); } base.Handle(post); LastPost = post; }
/// <summary> /// Ported from handle_value /// </summary> public static void HandleValue(Value value, Account account, Xact xact, Temporaries temps, PostHandler handler, Date date = default(Date), bool actDateP = true, Value total = null, bool directAmount = false, bool markVisited = false, bool bidirLink = true) { Post post = temps.CreatePost(xact, account, bidirLink); post.Flags |= SupportsFlagsEnum.ITEM_GENERATED; // If the account for this post is all virtual, then report the post as // such. This allows subtotal reports to show "(Account)" for accounts // that contain only virtual posts. if (account != null && account.HasXData && account.XData.AutoVirtualize) { if (!account.XData.HasNonVirtuals) { post.Flags |= SupportsFlagsEnum.POST_VIRTUAL; if (!account.XData.HasUnbVirtuals) { post.Flags |= SupportsFlagsEnum.POST_MUST_BALANCE; } } } PostXData xdata = post.XData; if (date.IsValid()) { if (actDateP) { xdata.Date = date; } else { xdata.ValueDate = date; } } Value temp = Value.Clone(value); switch (value.Type) { case ValueTypeEnum.Boolean: case ValueTypeEnum.Integer: temp.InPlaceCast(ValueTypeEnum.Amount); post.Amount = temp.AsAmount; break; case ValueTypeEnum.Amount: post.Amount = temp.AsAmount; break; case ValueTypeEnum.Balance: case ValueTypeEnum.Sequence: xdata.CompoundValue = temp; xdata.Compound = true; break; default: throw new InvalidOperationException(); } if (!Value.IsNullOrEmpty(total)) { xdata.Total = total; } if (directAmount) { xdata.DirectAmt = true; } Logger.Current.Debug("filters.changed_value.rounding", () => String.Format("post.amount = {0}", post.Amount)); handler.Handle(post); if (markVisited) { post.XData.Visited = true; post.Account.XData.Visited = true; } }
/// <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(); } }