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(); } } }
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(); } } }