示例#1
0
        /// <summary>
        /// Ported from posts_as_equity::report_subtotal
        /// </summary>
        public void ReportSubtotal()
        {
            Date finish = default(Date);

            foreach (Post post in ComponentPosts)
            {
                Date date = post.GetDate();
                if (!finish.IsValid() || date > finish)
                {
                    finish = date;
                }
            }

            Xact xact = Temps.CreateXact();

            xact.Payee = "Opening Balances";
            xact.Date  = finish;

            Value total = Value.Get(0);

            foreach (KeyValuePair <string, AcctValue> pair in Values)
            {
                Value value = pair.Value.Value.StripAnnotations(Report.WhatToKeep());
                if (!Value.IsNullOrEmpty(value))
                {
                    if (value.Type == ValueTypeEnum.Balance)
                    {
                        foreach (KeyValuePair <Commodity, Amount> amountPair in value.AsBalance.Amounts)
                        {
                            if (!amountPair.Value.IsZero)
                            {
                                FiltersCommon.HandleValue(
                                    /* value=      */ Value.Get(amountPair.Value),
                                    /* account=    */ pair.Value.Account,
                                    /* xact=       */ xact,
                                    /* temps=      */ Temps,
                                    /* handler=    */ (PostHandler)Handler,
                                    /* date=       */ finish,
                                    /* act_date_p= */ false);
                            }
                        }
                    }
                    else
                    {
                        FiltersCommon.HandleValue(
                            /* value=      */ Value.Get(value.AsAmount),
                            /* account=    */ pair.Value.Account,
                            /* xact=       */ xact,
                            /* temps=      */ Temps,
                            /* handler=    */ (PostHandler)Handler,
                            /* date=       */ finish,
                            /* act_date_p= */ false);
                    }
                }

                if (!pair.Value.IsVirtual || pair.Value.MustBalance)
                {
                    total.InPlaceAdd(value);
                }
            }
            Values.Clear();

            // This last part isn't really needed, since an Equity:Opening
            // Balances posting with a null amount will automatically balance with
            // all the other postings generated.  But it does make the full
            // balancing amount clearer to the user.
            if (!total.IsZero)
            {
                Action <Amount> postCreator = amt =>
                {
                    Post balancePost = Temps.CreatePost(xact, BalanceAccount);
                    balancePost.Amount = amt.Negated();
                    Handler.Handle(balancePost);
                };

                if (total.Type == ValueTypeEnum.Balance)
                {
                    total.AsBalance.MapSortedAmounts(postCreator);
                }
                else
                {
                    postCreator(total.AsAmount);
                }
            }
        }
示例#2
0
        public override void Flush()
        {
            if (Interval.Duration == null)
            {
                base.Flush();
                return;
            }

            // Sort all the postings we saw by date ascending
            // [DM] Enumerable.OrderBy is a stable sort that preserve original positions for equal items
            AllPosts = AllPosts.OrderBy(p => p, new IntervalPostCompare()).ToList();

            // only if the interval has no start use the earliest post
            if (!(Interval.Begin.HasValue && Interval.FindPeriod(Interval.Begin.Value)))
            {
                // Determine the beginning interval by using the earliest post
                if (AllPosts.Any() && !Interval.FindPeriod(AllPosts.First().GetDate()))
                {
                    throw new LogicError(LogicError.ErrorMessageFailedToFindPeriodForIntervalReport);
                }
            }

            // Walk the interval forward reporting all posts within each one
            // before moving on, until we reach the end of all_posts
            bool sawPosts = false;

            for (int i = 0; i < AllPosts.Count;)
            {
                Post post = AllPosts[i];

                Logger.Current.Debug("filters.interval", () => String.Format("Considering post {0} = {1}", post.GetDate(), post.Amount));
                Logger.Current.Debug("filters.interval", () => String.Format("interval is:{0}", DebugInterval(Interval)));

                if (Interval.Finish.HasValue && post.GetDate() >= Interval.Finish.Value)
                {
                    throw new InvalidOperationException("assert(! interval.finish || post->date() < *interval.finish)");
                }

                if (Interval.WithinPeriod(post.GetDate()))
                {
                    Logger.Current.Debug("filters.interval", () => "Calling subtotal_posts::operator()");
                    base.Handle(post);
                    ++i;
                    sawPosts = true;
                }
                else
                {
                    if (sawPosts)
                    {
                        Logger.Current.Debug("filters.interval", () => "Calling subtotal_posts::report_subtotal()");
                        ReportSubtotal(Interval);
                        sawPosts = false;
                    }
                    else if (GenerateEmptyPosts)
                    {
                        // Generate a null posting, so the intervening periods can be
                        // seen when -E is used, or if the calculated amount ends up
                        // being non-zero
                        Xact nullXact = Temps.CreateXact();
                        nullXact.Date = Interval.InclusiveEnd.Value;

                        Post nullPost = Temps.CreatePost(nullXact, EmptytAccount);
                        nullPost.Flags |= SupportsFlagsEnum.POST_CALCULATED;
                        nullPost.Amount = new Amount(0);

                        base.Handle(nullPost);
                        ReportSubtotal(Interval);
                    }

                    Logger.Current.Debug("filters.interval", () => "Advancing interval");
                    ++Interval;
                }
            }

            // If the last postings weren't reported, do so now.
            if (sawPosts)
            {
                Logger.Current.Debug("filters.interval", () => "Calling subtotal_posts::report_subtotal() at end");
                ReportSubtotal(Interval);
            }

            // Tell our parent class to flush
            base.Flush();
        }