private IEnumerable <(DateTime Date, double Value)> GetItems(CashAccount account, IEntitiesSerializer serializer, DateTime until)
        {
            var user = $"U{account.User.AsUser()}";
            var curr = $"@{account.Currency}";

            if (account.Reimburse != null)
            {
                var rb  = new Composite.Composite(Accountant);
                var tmp = Composite.Composite.GetTemplate(account.Reimburse);
                var rng = Composite.Composite.DateRange(tmp.Day);
                rb.DoInquiry(rng, tmp, out var rbVal, BaseCurrency.Now, serializer);
                // ReSharper disable once PossibleInvalidOperationException
                var rbF = rng.EndDate.Value;
                yield return(rbF, rbVal);
            }

            foreach (var debt in account.Items)
            {
                switch (debt)
                {
                case OnceItem oi:
                    yield return(oi.Date, oi.Fund);

                    break;

                case OnceQueryItem oqi:
                    yield return(oqi.Date, Accountant.RunGroupedQuery($"{user} {curr}*({oqi.Query})``v").Fund);

                    break;

                case MonthlyItem mn:
                    for (var d = NextDate(mn.Day); d <= until; d = NextDate(mn.Day, d))
                    {
                        if (mn.Since != default(DateTime) && d < mn.Since)
                        {
                            continue;
                        }
                        if (mn.Till != default(DateTime) && d > mn.Till)
                        {
                            continue;
                        }

                        yield return(d, mn.Fund);
                    }

                    break;

                case SimpleCreditCard cc:
                    var rng = $"[{ClientDateTime.Today.AddMonths(-3).AsDate()}~]";
                    var mv  = $"{{({user}*{cc.Query})+{user} T3999+{user} T6603 A {rng}}}";
                    var mos = new Dictionary <DateTime, double>();
                    foreach (var grpC in Accountant.RunGroupedQuery($"{{{user}*({cc.Query})*({user} <+(-{user} {curr})) {rng}}}+{mv}:{user}*({cc.Query})`Cd")
                             .Items
                             .Cast <ISubtotalCurrency>())
                    {
                        foreach (var b in grpC.Items.Cast <ISubtotalDate>())
                        {
                            var mo  = NextDate(cc.RepaymentDay, NextDate(cc.BillDay, b.Date.Value), true);
                            var cob = Accountant.From(mo, grpC.Currency)
                                      * Accountant.To(mo, account.Currency)
                                      * b.Fund;
                            if (mos.ContainsKey(mo))
                            {
                                mos[mo] += cob;
                            }
                            else
                            {
                                mos[mo] = cob;
                            }
                        }
                    }

                    foreach (var b in Accountant.RunGroupedQuery($"{{{user}*({cc.Query})*({user} {curr}>) {rng}}}-{mv}:{user}*({cc.Query})`d")
                             .Items
                             .Cast <ISubtotalDate>())
                    {
                        var mo = NextDate(cc.RepaymentDay, b.Date.Value, true);
                        if (mos.ContainsKey(mo))
                        {
                            mos[mo] += b.Fund;
                        }
                        else
                        {
                            mos[mo] = b.Fund;
                        }
                    }

                    for (var d = ClientDateTime.Today; d <= until; d = NextDate(cc.BillDay, d))
                    {
                        var mo  = NextDate(cc.RepaymentDay, NextDate(cc.BillDay, d), true);
                        var cob = -(NextDate(cc.BillDay, d) - d).TotalDays * cc.MonthlyFee / (365.2425 / 12);
                        if (mos.ContainsKey(mo))
                        {
                            mos[mo] += cob;
                        }
                        else
                        {
                            mos[mo] = cob;
                        }
                    }

                    foreach (var kvp in mos)
                    {
                        yield return(kvp.Key, kvp.Value);
                    }

                    break;

                case ComplexCreditCard cc:
                    var stmt = -Accountant.RunGroupedQuery($"({cc.Query})*({user} {curr})-{user} \"\"``v").Fund;
                    var pmt  = Accountant.RunGroupedQuery($"({cc.Query})*({user} {curr} \"\" >)``v").Fund;
                    var nxt  = -Accountant.RunGroupedQuery($"({cc.Query})*({user} {curr} \"\" <)``v").Fund;
                    if (pmt < stmt)
                    {
                        if (NextDate(cc.BillDay, NextDate(cc.RepaymentDay)) == NextDate(cc.BillDay))
                        {
                            yield return(NextDate(cc.RepaymentDay), pmt - stmt);
                        }
                        else
                        {
                            nxt += stmt - pmt;     // Not paid in full
                        }
                    }
                    else
                    {
                        nxt -= pmt - stmt;     // Paid too much
                    }
                    for (var d = ClientDateTime.Today; d <= until; d = NextDate(cc.BillDay, d))
                    {
                        nxt += (NextDate(cc.BillDay, d) - d).TotalDays * cc.MonthlyFee / (365.2425 / 12);
                        if (cc.MaximumUtility >= 0 && cc.MaximumUtility < nxt)
                        {
                            yield return(NextDate(cc.BillDay, d), cc.MaximumUtility - nxt);

                            nxt = cc.MaximumUtility;
                        }

                        yield return(NextDate(cc.RepaymentDay, d).AddMonths(1), -nxt);

                        nxt = 0;
                    }

                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
        }
Beispiel #2
0
        private IEnumerable <(DateTime Date, double Value)> GetItems(CashAccount account, IEntitiesSerializer serializer)
        {
            var curr = $"@{account.Currency}";
            var init = Accountant.RunGroupedQuery($"{curr}*({account.QuickAsset}) [~.]``v").Fund;

            yield return(ClientDateTime.Today, init);

            if (account.Reimburse != null)
            {
                var rb  = new Composite.Composite(Accountant);
                var tmp = Composite.Composite.GetTemplate(account.Reimburse);
                var rng = Composite.Composite.DateRange(tmp.Day);
                rb.DoInquiry(rng, tmp, out var rbVal, BaseCurrency.Now, serializer);
                // ReSharper disable once PossibleInvalidOperationException
                var rbF = rng.EndDate.Value;
                yield return(rbF, rbVal);
            }

            foreach (var debt in account.Items)
            {
                switch (debt)
                {
                case FixedItem fi:
                    yield return(fi.Day, fi.Fund);

                    break;

                case SimpleItem sd:
                    yield return(sd.Day, Accountant.RunGroupedQuery($"{curr}*({sd.Query})``v").Fund);

                    break;

                case CreditCard cd:
                    foreach (var grpC in Accountant.RunGroupedQuery(
                                 $"{{{{({cd.Query})*(<+(-{curr}))}}+{{({cd.Query})+T3999+T6603 A}}}}*{{[{ClientDateTime.Today.AddMonths(-3).AsDate()}~]}}:{cd.Query}`Cd")
                             .Items
                             .Cast <ISubtotalCurrency>())
                    {
                        foreach (var b in grpC.Items.Cast <ISubtotalDate>())
                        {
                            // ReSharper disable once PossibleInvalidOperationException
                            var d  = b.Date.Value;
                            var mo = new DateTime(d.Year, d.Month, 1, 0, 0, 0, DateTimeKind.Utc);
                            if (d.Day >= cd.BillDay)
                            {
                                mo = mo.AddMonths(1);
                            }
                            if (cd.RepaymentDay <= cd.BillDay)
                            {
                                mo = mo.AddMonths(1);
                            }
                            mo = mo.AddDays(cd.RepaymentDay - 1);
                            if (mo <= ClientDateTime.Today)
                            {
                                continue;
                            }

                            var cob = ExchangeFactory.Instance.From(mo, grpC.Currency)
                                      * ExchangeFactory.Instance.To(mo, account.Currency)
                                      * b.Fund;
                            yield return(mo, cob);
                        }
                    }

                    foreach (var b in Accountant.RunGroupedQuery(
                                 $"{{({cd.Query})*({curr}>) [{ClientDateTime.Today.AddMonths(-3).AsDate()}~]}}-{{({cd.Query})+T3999+T6603 A}}:{cd.Query}`d")
                             .Items
                             .Cast <ISubtotalDate>())
                    {
                        // ReSharper disable once PossibleInvalidOperationException
                        var d  = b.Date.Value;
                        var mo = new DateTime(d.Year, d.Month, 1, 0, 0, 0, DateTimeKind.Utc);
                        if (d.Day > cd.RepaymentDay)
                        {
                            mo = mo.AddMonths(1);
                        }
                        mo = mo.AddDays(cd.RepaymentDay - 1);
                        if (mo <= ClientDateTime.Today)
                        {
                            continue;
                        }

                        yield return(mo, b.Fund);
                    }

                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
        }