/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { FacadeF.ParsingF.Eof(expr); var result = Accountant.RunGroupedQuery("T1101+T611102+T1501+T611106 G``cd"); var resx = Accountant.RunGroupedQuery("T1101+T1501``c"); var sb = new StringBuilder(); foreach ( var(grp, rte) in result.Items.Cast <ISubtotalContent>() .Join( resx.Items.Cast <ISubtotalContent>(), grp => grp.Content, rsx => rsx.Content, (grp, bal) => (Group: grp, Rate: GetRate( grp.Items.Cast <ISubtotalDate>().OrderBy(b => b.Date, new DateComparer()).ToList(), bal.Fund))) .OrderByDescending(kvp => kvp.Rate)) { sb.AppendLine($"{grp.Content.CPadRight(30)} {$"{rte * 360:P2}".PadLeft(7)}"); } return(new PlainText(sb.ToString())); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { Template temp = null; if (ParsingF.Token(ref expr, true, t => (temp = GetTemplate(t)) != null) == null) { throw new ArgumentException("找不到模板", nameof(expr)); } var regex = new Regex(@"^[A-Za-z]{3}$"); var currency = Parsing.Token(ref expr, false, regex.IsMatch)?.ToUpperInvariant() ?? BaseCurrency.Now; DateFilter the; if (string.IsNullOrWhiteSpace(expr)) { the = DateRange(temp.Day); } else { the = ParsingF.Range(ref expr) ?? throw new ArgumentException("语法错误", nameof(expr)); ParsingF.Eof(expr); } return(DoInquiry(the, temp, out _, currency, serializer)); }
public InquiriesVisitor(Accountant accountant, DateFilter rng, string baseCurrency, IEntitiesSerializer serializer) { m_Accountant = accountant; m_BaseCurrency = baseCurrency; m_Serializer = serializer; m_Rng = rng; }
/// <summary> /// 执行检查表达式 /// </summary> /// <param name="distQuery">分期检索式</param> /// <param name="rng">日期过滤器</param> /// <param name="serializer">表示器</param> /// <returns>执行结果</returns> protected override IQueryResult ExecuteCheck(IQueryCompunded <IDistributedQueryAtom> distQuery, DateFilter rng, IEntitiesSerializer serializer) { var sb = new StringBuilder(); foreach (var a in Sort(Accountant.SelectAssets(distQuery))) { var sbi = new StringBuilder(); foreach (var item in Accountant.Update(a, rng, false, true)) { sbi.AppendLine(ListAssetItem(item)); } if (sbi.Length != 0) { sb.AppendLine(ListAsset(a, serializer, null, false)); sb.AppendLine(sbi.ToString()); } Accountant.Upsert(a); } if (sb.Length > 0) { return(new DirtyText(sb.ToString())); } return(new PlainSucceed()); }
/// <summary> /// 执行查询 /// </summary> /// <param name="rng">日期过滤器</param> /// <param name="inq">查询</param> /// <param name="val">金额</param> /// <param name="baseCurrency"></param> /// <param name="serializer"></param> /// <returns>执行结果</returns> public IQueryResult DoInquiry(DateFilter rng, BaseInquiry inq, out double val, string baseCurrency, IEntitiesSerializer serializer) { var visitor = new InquiriesVisitor(Accountant, rng, baseCurrency, serializer); val = inq.Accept(visitor); return(new PlainText(visitor.Result)); }
/// <inheritdoc /> protected override IQueryResult ExecuteList(IQueryCompunded <IDistributedQueryAtom> distQuery, DateTime?dt, bool showSchedule, IEntitiesSerializer serializer) { var sb = new StringBuilder(); foreach (var a in Sort(Accountant.SelectAssets(distQuery))) { sb.Append(ListAsset(a, serializer, dt, showSchedule)); } return(new PlainText(sb.ToString())); }
/// <inheritdoc /> public string PresentSubtotal(ISubtotalResult raw, ISubtotal par, IEntitiesSerializer serializer) { m_Par = par; Ga = par.GatherType; Cu = par.EquivalentCurrency; Serializer = serializer; Sb = new StringBuilder(); Depth = 0; Pre(); raw?.Accept(this); Post(); return(Sb.ToString()); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var rst = new Dictionary <DateTime, double[]>(); var n = Templates.Config.Accounts.Count; for (var i = 0; i < n; i++) { foreach (var(date, value) in GetItems(Templates.Config.Accounts[i], serializer)) { if (!rst.ContainsKey(date)) { rst.Add(date, new double[n]); } rst[date][i] += value; } } var aggs = new double[n]; var sb = new StringBuilder(); sb.Append("Date "); for (var i = 0; i < n; i++) { sb.Append($" {Templates.Config.Accounts[i].Currency.PadRight(15)} Sum "); } sb.AppendLine(" All"); foreach (var kvp in rst.OrderBy(kvp => kvp.Key)) { sb.Append($"{kvp.Key.AsDate()}"); var sum = 0D; for (var i = 0; i < n; i++) { aggs[i] += kvp.Value[i]; sum += aggs[i] * ExchangeFactory.Instance.From( kvp.Key, Templates.Config.Accounts[i].Currency); sb.Append(kvp.Value[i].AsCurrency(Templates.Config.Accounts[i].Currency).PadLeft(15)); sb.Append(aggs[i].AsCurrency(Templates.Config.Accounts[i].Currency).PadLeft(15)); } sb.AppendLine(sum.AsCurrency(BaseCurrency.Now).PadLeft(15)); } return(new PlainText(sb.ToString())); }
/// <inheritdoc /> protected override IQueryResult ExecuteRecal(IQueryCompunded <IDistributedQueryAtom> distQuery, IEntitiesSerializer serializer) { var lst = new List <Asset>(); foreach (var a in Sort(Accountant.SelectAssets(distQuery))) { Accountant.Depreciate(a); Accountant.Upsert(a); lst.Add(a); } return(new DirtyText(serializer.PresentAssets(lst))); }
public IQueryResult Execute(string expr, IEntitiesSerializer serializer) { expr = expr.Rest(); var rev = true; var val = Parsing.Double(ref expr); var curr = Parsing.Token(ref expr).ToUpperInvariant(); if (!val.HasValue) { rev = false; val = Parsing.DoubleF(ref expr); } var date = Parsing.UniqueTime(ref expr) ?? ClientDateTime.Today; Parsing.Eof(expr); var res = rev ? ExchangeFactory.Instance.To(date, curr) : ExchangeFactory.Instance.From(date, curr); return(new PlainText((res * val.Value).ToString("R"))); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var count = 0; while (!string.IsNullOrWhiteSpace(expr)) { var voucher = GenerateVoucher(ref expr); if (voucher == null) { continue; } if (Accountant.Upsert(voucher)) { count++; } } return(new NumberAffected(count)); }
/// <inheritdoc /> public async IAsyncEnumerable <string> PresentSubtotal(ISubtotalResult raw, ISubtotal par, IEntitiesSerializer serializer) { m_Par = par; Ga = par.GatherType; Cu = par.EquivalentCurrency; Serializer = serializer; Depth = 0; await foreach (var s in Pre()) { yield return(s); } if (raw != null) { await foreach (var s in raw.Accept(this)) { yield return(s); } } await foreach (var s in Post()) { yield return(s); } }
/// <inheritdoc /> protected override IQueryResult ExecuteUnregister(IQueryCompunded <IDistributedQueryAtom> distQuery, DateFilter rng, IQueryCompunded <IVoucherQueryAtom> query, IEntitiesSerializer serializer) { var sb = new StringBuilder(); foreach (var a in Sort(Accountant.SelectAssets(distQuery))) { foreach (var item in a.Schedule.Where(item => item.Date.Within(rng))) { if (query != null) { if (item.VoucherID == null) { continue; } var voucher = Accountant.SelectVoucher(item.VoucherID); if (voucher != null) { if (!MatchHelper.IsMatch(query, voucher.IsMatch)) { continue; } } } item.VoucherID = null; } sb.Append(ListAsset(a, serializer)); Accountant.Upsert(a); } if (sb.Length > 0) { return(new DirtyText(sb.ToString())); } return(new PlainSucceed()); }
/// <inheritdoc /> protected override IQueryResult ExecuteRegister(IQueryCompunded <IDistributedQueryAtom> distQuery, DateFilter rng, IQueryCompunded <IVoucherQueryAtom> query, IEntitiesSerializer serializer) { var sb = new StringBuilder(); foreach (var a in Sort(Accountant.SelectAssets(distQuery))) { sb.Append(serializer.PresentVouchers(Accountant.RegisterVouchers(a, rng, query))); Accountant.Upsert(a); } if (sb.Length > 0) { return(new DirtyText(sb.ToString())); } return(new PlainSucceed()); }
/// <inheritdoc /> protected override IQueryResult ExecuteQuery(IQueryCompunded <IDistributedQueryAtom> distQuery, IEntitiesSerializer serializer) => new PlainText(serializer.PresentAssets(Sort(Accountant.SelectAssets(distQuery))));
/// <summary> /// 执行检查表达式 /// </summary> /// <param name="distQuery">分期检索式</param> /// <param name="rng">日期过滤器</param> /// <param name="serializer">表示器</param> /// <returns>执行结果</returns> protected abstract IQueryResult ExecuteCheck(IQueryCompunded <IDistributedQueryAtom> distQuery, DateFilter rng, IEntitiesSerializer serializer);
/// <inheritdoc /> public IAsyncEnumerable <string> PresentSubtotal(ISubtotalResult raw, ISubtotal par, IEntitiesSerializer serializer) { m_Par = par; m_Depth = 0; return(AsyncEnumerable.Repeat((raw?.Accept(this)?.Value as JObject)?.ToString(), 1)); }
/// <inheritdoc /> public IQueryResult Execute(string expr, IEntitiesSerializer serializer) => m_Action(m_Initial == null ? expr : expr.Rest(), serializer);
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var csv = expr; expr = ParsingF.Line(ref csv); var parsed = new CsvParser(ParsingF.Optional(ref expr, "-")); var sb = new StringBuilder(); if (ParsingF.Optional(ref expr, "mark")) { var filt = Regularize(ParsingF.DetailQuery(ref expr)); ParsingF.Optional(ref expr, "as"); var marker = ParsingF.Token(ref expr); ParsingF.Eof(expr); if (string.IsNullOrWhiteSpace(marker)) { throw new FormatException("格式错误"); } parsed.Parse(csv); sb.AppendLine($"{parsed.Items.Count} parsed"); RunMark(filt, parsed, marker, sb); } else if (ParsingF.Optional(ref expr, "unmark")) { var filt = Regularize(ParsingF.DetailQuery(ref expr)); ParsingF.Eof(expr); RunUnmark(filt, sb); } else if (ParsingF.Optional(ref expr, "check")) { var filt = Regularize(ParsingF.DetailQuery(ref expr)); ParsingF.Eof(expr); parsed.Parse(csv); sb.AppendLine($"{parsed.Items.Count} parsed"); RunCheck(filt, parsed, sb); } else { ParsingF.Optional(ref expr, "auto"); var filt = Regularize(ParsingF.DetailQuery(ref expr)); ParsingF.Optional(ref expr, "as"); var marker = ParsingF.Token(ref expr); ParsingF.Eof(expr); if (string.IsNullOrWhiteSpace(marker)) { throw new FormatException("格式错误"); } parsed.Parse(csv); sb.AppendLine($"{parsed.Items.Count} parsed"); var markerFilt = new StmtVoucherDetailQuery( filt.VoucherQuery, new IntersectQueries <IDetailQueryAtom>( filt.DetailEmitFilter.DetailFilter, new StmtDetailQuery(marker))); var nullFilt = new StmtVoucherDetailQuery( filt.VoucherQuery, new IntersectQueries <IDetailQueryAtom>( filt.DetailEmitFilter.DetailFilter, new StmtDetailQuery(""))); var nmFilt = new StmtVoucherDetailQuery( filt.VoucherQuery, new IntersectQueries <IDetailQueryAtom>( filt.DetailEmitFilter.DetailFilter, new UnionQueries <IDetailQueryAtom>( new StmtDetailQuery(""), new StmtDetailQuery(marker)))); RunUnmark(markerFilt, sb); RunMark(nullFilt, parsed, marker, sb); RunCheck(nmFilt, parsed, sb); } return(new PlainText(sb.ToString())); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var content = Parsing.Token(ref expr); var avg = Parsing.DoubleF(ref expr); Parsing.Eof(expr); var tdy = ClientDateTime.Today; var ldom = AccountantHelper.LastDayOfMonth(tdy.Year, tdy.Month); var srng = new DateFilter(new DateTime(tdy.Year, tdy.Month, 1, 0, 0, 0, DateTimeKind.Utc), tdy); var balance = Accountant.RunGroupedQuery( $"T1002 {content.Quotation('\'')} [~{tdy.AsDate()}]`vD{srng.AsDateRange()}"); var bal = 0D; var btd = 0D; foreach (var b in balance.Items.Cast <ISubtotalDate>()) { if (b.Date == tdy) { btd += b.Fund; } else { bal += b.Fund; } } var targ = ldom.Day * avg; var sb = new StringBuilder(); sb.AppendLine($"Target: {targ.AsCurrency()}"); sb.AppendLine($"Balance until yesterday: {bal.AsCurrency()}"); if ((bal - targ).IsNonNegative()) { sb.AppendLine("Achieved."); sb.AppendLine(); sb.AppendLine( (btd - avg).IsNonNegative() ? $"Plan A: Credit {(btd - avg).AsCurrency()}, Balance {avg.AsCurrency()}" : $"Plan A: Debit {(avg - btd).AsCurrency()}, Balance {avg.AsCurrency()}"); sb.AppendLine("Plan B: No Action"); } else { var res = targ - bal; var rsd = ldom.Day - tdy.Day + 1; sb.AppendLine($"Deficiency: {res.AsCurrency()}"); var avx = res / rsd; if ((rsd * avg - res).IsNonNegative()) { sb.AppendLine($"Average deficiency: {avx.AsCurrency()} <= {avg.AsCurrency()}"); sb.AppendLine(); sb.AppendLine( (btd - avx).IsNonNegative() ? $"Plan A: Credit {(btd - avx).AsCurrency()}, Balance {avx.AsCurrency()}" : $"Plan A: Debit {(avx - btd).AsCurrency()}, Balance {avx.AsCurrency()}"); sb.AppendLine( (btd - avg).IsNonNegative() ? $"Plan B: Credit {(btd - avg).AsCurrency()}, Balance {avg.AsCurrency()}" : $"Plan B: Debit {(avg - btd).AsCurrency()}, Balance {avg.AsCurrency()}"); } else { sb.AppendLine($"Average deficiency: {avx.AsCurrency()} > {avg.AsCurrency()}"); sb.AppendLine(); sb.AppendLine( (btd - avx).IsNonNegative() ? $"Plan: Credit {(btd - avx).AsCurrency()}, Balance {avx.AsCurrency()}" : $"Plan: Debit {(avx - btd).AsCurrency()}, Balance {avx.AsCurrency()}"); } } return(new PlainText(sb.ToString())); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var remark = Parsing.Token(ref expr); var rate = Parsing.DoubleF(ref expr) / 10000D; var all = Parsing.Optional(ref expr, "all"); var endDate = !all ? Parsing.UniqueTime(ref expr) : null; Parsing.Eof(expr); var loans = Accountant.RunGroupedQuery($"({MajorFilter()})-\"\" ``rtcC").Items .Cast<ISubtotalRemark>() .ToList(); var rmkObj = loans.Single( b => b.Remark?.StartsWith(remark, StringComparison.InvariantCultureIgnoreCase) == true && !b.Remark.EndsWith("-利息", StringComparison.Ordinal)); var titleObj = rmkObj.Items.Cast<ISubtotalTitle>().Single(); var cntObj = titleObj.Items.Cast<ISubtotalContent>().Single(); // ReSharper disable once PossibleInvalidOperationException var title = titleObj.Title.Value; var content = cntObj.Content; var rmk = rmkObj.Remark; var currency = cntObj.Items.Cast<ISubtotalCurrency>().Single().Currency; var info = new LoanInfo { Currency = currency, Title = title, Content = content, Remark = rmk, Rate = rate }; if (!all && !endDate.HasValue || endDate.HasValue) { // ReSharper disable once PossibleInvalidOperationException var lastD = Accountant.RunVoucherQuery(info.QueryInterest(this)) .OrderByDescending(v => v.Date, new DateComparer()) .FirstOrDefault() ?.Date ?? Accountant.RunVoucherQuery(info.QueryCapital(this)) .OrderBy(v => v.Date, new DateComparer()) .First() .Date.Value; var capQuery = $"{info.QueryCapital(this)} [~{lastD.AsDate()}]``v"; var intQuery = $"{info.QueryInterest(this)} [~{lastD.AsDate()}]``v"; var capitalIntegral = Accountant.RunGroupedQuery(capQuery).Fund; var interestIntegral = Accountant.RunGroupedQuery(intQuery).Fund; Regularize( info, ref capitalIntegral, ref interestIntegral, lastD, endDate ?? ClientDateTime.Today); } else { var capitalIntegral = 0D; var interestIntegral = 0D; Regularize( info, ref capitalIntegral, ref interestIntegral, null, ClientDateTime.Today); } return new DirtySucceed(); }
/// <inheritdoc /> public string PresentSubtotal(ISubtotalResult raw, ISubtotal par, IEntitiesSerializer serializer) { m_Par = par; m_Depth = 0; return((raw?.Accept(this)?.Value as JObject)?.ToString()); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var voucherID = Parsing.Token(ref expr); var guids = new List <string>(); var guidT = Guid.Empty; // ReSharper disable once AccessToModifiedClosure while (Parsing.Token(ref expr, true, s => Guid.TryParse(s, out guidT)) != null) { guids.Add(guidT.ToString()); } Parsing.Eof(expr); var voucher = Accountant.SelectVoucher(voucherID); if (voucher == null) { throw new ApplicationException("找不到记账凭证"); } var sb = new StringBuilder(); foreach (var detail in voucher.Details.Where(vd => vd.Title is 1601 or 1701)) { if (guids.Count != 0 && !guids.Contains(detail.Content)) { continue; } var asset = Accountant.SelectAsset(Guid.Parse(detail.Content)); foreach (var item in asset.Schedule) { if (item is DispositionItem) { throw new InvalidOperationException("已经处置"); } if (item.Date < voucher.Date) { if (item.VoucherID == null) { throw new InvalidOperationException("尚未注册"); } } else { if (item.VoucherID != null) { throw new InvalidOperationException("注册过多"); } } } var id = asset.Schedule.FindIndex(it => it.Date >= voucher.Date); if (id != -1) { asset.Schedule.RemoveRange(id, asset.Schedule.Count - id); } asset.Schedule.Add(new DispositionItem { Date = voucher.Date, VoucherID = voucher.ID }); sb.Append(serializer.PresentAsset(asset).Wrap()); Accountant.Upsert(asset); } if (sb.Length > 0) { return(new DirtyText(sb.ToString())); } return(new PlainSucceed()); }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var content = Parsing.Token(ref expr); return(ParsingF.Optional(ref expr, "q") ? Query(content, ref expr) : Create(content, ref expr, serializer)); }
private IQueryResult Create(string content, ref string expr, IEntitiesSerializer serializer) { var currency = Parsing.Token(ref expr, false); var baseCurrency = Parsing.Token(ref expr, false); var lst = new List <Voucher>(); while (!string.IsNullOrWhiteSpace(expr)) { var date = Parsing.UniqueTime(ref expr); if (!date.HasValue) { var dayF = ParsingF.DoubleF(ref expr); var day = (int)dayF; // ReSharper disable once CompareOfFloatsByEqualityOperator if (day != dayF) { throw new ApplicationException("非整数日期"); } date = ClientDateTime.Today.Day < day ? ClientDateTime.Today.AddMonths(-1).AddDays(day - ClientDateTime.Today.Day) : ClientDateTime.Today.AddDays(day - ClientDateTime.Today.Day); } var from = ParsingF.DoubleF(ref expr); var to = ParsingF.DoubleF(ref expr); var voucher = new Voucher { Date = date.Value, Details = new List <VoucherDetail> { new VoucherDetail { Currency = baseCurrency, Title = 2241, SubTitle = 01, Content = content, Fund = -to }, new VoucherDetail { Currency = baseCurrency, Title = 3999, Fund = to }, new VoucherDetail { Currency = currency, Title = 3999, Fund = -from }, from >= 0 ? new VoucherDetail { Currency = currency, Title = 2241, SubTitle = 01, Content = content, Fund = from } : new VoucherDetail { Currency = currency, Title = 6603, Fund = from } } }; Accountant.Upsert(voucher); lst.Add(voucher); } if (lst.Any()) { return(new DirtyText(serializer.PresentVouchers(lst))); } return(new PlainSucceed()); }
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(); } } }
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var extraMonths = (int)(Parsing.Double(ref expr) ?? 6); var prefix = Parsing.Token(ref expr); Parsing.Eof(expr); var accts = Templates.Config.Accounts.Where(a => string.IsNullOrWhiteSpace(a.User) || ClientUser.Name == a.User).ToList(); var n = accts.Count; var until = ClientDateTime.Today.AddMonths(extraMonths); var aggs = new double[n]; var rst = new Dictionary <DateTime, double[, ]>(); for (var i = 0; i < n; i++) { aggs[i] = Accountant.RunGroupedQuery($"U{accts[i].User.AsUser()} @{accts[i].Currency}*({accts[i].QuickAsset}) [~.]``v").Fund; foreach (var(date, value) in GetItems(accts[i], serializer, until)) { if (date <= ClientDateTime.Today) { continue; } if (date > until) { continue; } if (value.IsZero()) { continue; } if (!rst.ContainsKey(date)) { rst.Add(date, new double[n, 2]); } if (value >= 0) { rst[date][i, 0] += value; } else { rst[date][i, 1] += value; } } } var sb = new StringBuilder(); sb.Append(prefix); sb.Append("Date "); for (var i = 0; i < n; i++) { var c = accts[i].Currency; sb.Append($"++++ {c} ++++".PadLeft(15)); sb.Append($"---- {c} ----".PadLeft(15)); sb.Append($"#### {c} ####".PadLeft(15)); } sb.AppendLine("@@@@ All @@@@".PadLeft(15)); { sb.Append(prefix); sb.Append("Today "); var sum = 0D; for (var i = 0; i < n; i++) { sum += aggs[i] * Accountant.From( ClientDateTime.Today, accts[i].Currency); sb.Append("".PadLeft(15)); sb.Append("".PadLeft(15)); sb.Append(aggs[i].AsCurrency(accts[i].Currency).PadLeft(15)); } sb.AppendLine(sum.AsCurrency(BaseCurrency.Now).PadLeft(15)); } foreach (var kvp in rst.OrderBy(kvp => kvp.Key)) { sb.Append(prefix); sb.Append($"{kvp.Key.AsDate()}"); var sum = 0D; for (var i = 0; i < n; i++) { aggs[i] += kvp.Value[i, 0] + kvp.Value[i, 1]; sum += aggs[i] * Accountant.From( kvp.Key, accts[i].Currency); if (!kvp.Value[i, 0].IsZero()) { sb.Append(kvp.Value[i, 0].AsCurrency(accts[i].Currency).PadLeft(15)); } else { sb.Append("".PadLeft(15)); } if (!kvp.Value[i, 1].IsZero()) { sb.Append(kvp.Value[i, 1].AsCurrency(accts[i].Currency).PadLeft(15)); } else { sb.Append("".PadLeft(15)); } sb.Append(aggs[i].AsCurrency(accts[i].Currency).PadLeft(15)); } sb.AppendLine(sum.AsCurrency(BaseCurrency.Now).PadLeft(15)); } return(new PlainText(sb.ToString())); }
/// <inheritdoc /> public IQueryResult Execute(string expr, IEntitiesSerializer serializer) => FirstExecutable(expr).Execute(expr, serializer);
/// <inheritdoc /> public override IQueryResult Execute(string expr, IEntitiesSerializer serializer) { var voucherID = Parsing.Token(ref expr); Guid?guid = null; var guidT = Guid.Empty; // ReSharper disable once AccessToModifiedClosure if (Parsing.Token(ref expr, true, s => Guid.TryParse(s, out guidT)) != null) { guid = guidT; } var name = Parsing.Token(ref expr); var lifeT = Parsing.Double(ref expr); Parsing.Eof(expr); var voucher = Accountant.SelectVoucher(voucherID); if (voucher == null) { throw new ApplicationException("找不到记账凭证"); } var detail = voucher.Details.Single( vd => (vd.Title == 1601 || vd.Title == 1701) && (!guid.HasValue || string.Equals( vd.Content, guid.ToString(), StringComparison.OrdinalIgnoreCase))); var isFixed = detail.Title == 1601; var life = (int?)lifeT ?? (isFixed ? 3 : 0); var asset = new Asset { StringID = detail.Content, Name = name, Date = voucher.Date, User = detail.User, Currency = detail.Currency, Value = detail.Fund, Salvage = life == 0 ? detail.Fund : isFixed ? detail.Fund * 0.05 : 0, Life = life, Title = detail.Title, Method = life == 0 ? DepreciationMethod.None : DepreciationMethod.StraightLine, DepreciationTitle = isFixed ? 1602 : 1702, DepreciationExpenseTitle = 6602, DepreciationExpenseSubTitle = isFixed ? 7 : 11, DevaluationTitle = isFixed ? 1603 : 1703, DevaluationExpenseTitle = 6701, DevaluationExpenseSubTitle = isFixed ? 5 : 6, Schedule = new List <AssetItem> { new AcquisitionItem { Date = voucher.Date, VoucherID = voucher.ID, // ReSharper disable once PossibleInvalidOperationException OrigValue = detail.Fund.Value, }, }, }; Accountant.Upsert(asset); // ReSharper disable once PossibleInvalidOperationException asset = Accountant.SelectAsset(asset.ID.Value); Accountant.Depreciate(asset); Accountant.Upsert(asset); return(new DirtyText(serializer.PresentAsset(asset).Wrap())); }
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(); } } }