protected override IQueryResult ExecuteResetHard(IQueryCompunded <IDistributedQueryAtom> distQuery, IQueryCompunded <IVoucherQueryAtom> query) => new NumberAffected( Accountant.SelectAssets(distQuery) .Sum( a => Accountant.DeleteVouchers( new IntersectQueries <IVoucherQueryAtom>( query ?? VoucherQueryUnconstrained.Instance, ParsingF.VoucherQuery( $"{{ T{a.DepreciationTitle.AsTitle()} {a.StringID.Quotation('\'')} Depreciation }} + {{ T{a.DevaluationTitle.AsTitle()} {a.StringID.Quotation('\'')} Devalue }}")))));
public void TestAggrEveryNullEqui(string rng, string incl) { var builder = new SubtotalBuilder(ParsingF.GroupedQuery($"``vD[{rng}]X[20170101]").Subtotal); var bal = new Balance[] { }; var res = builder.Build(bal); Assert.IsAssignableFrom <ISubtotalRoot>(res); var resx = (ISubtotalRoot)res; var lst = new List <Balance>(); foreach (var item in resx.Items) { Assert.IsAssignableFrom <ISubtotalDate>(item); var resxx = (ISubtotalDate)item; Assert.Null(resxx.Items); Assert.Equal(SubtotalLevel.Day, resxx.Level); lst.Add(new Balance { Date = resxx.Date, Fund = resxx.Fund }); } Assert.Equal(0, res.Fund); var lst0 = new List <Balance>(); if (incl[0] == '1') { lst0.Add(new Balance { Date = null, Fund = 0 }); } if (incl[1] == '1') { lst0.Add(new Balance { Date = new DateTime(2017, 01, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 0 }); } if (incl[2] == '1') { lst0.Add(new Balance { Date = new DateTime(2017, 01, 02, 0, 0, 0, DateTimeKind.Utc), Fund = 0 }); } if (incl[3] == '1') { lst0.Add(new Balance { Date = new DateTime(2017, 01, 03, 0, 0, 0, DateTimeKind.Utc), Fund = 0 }); } Assert.Equal(lst0, lst, new BalanceEqualityComparer()); }
public void TestMonth() { var builder = new SubtotalBuilder(ParsingF.GroupedQuery("`m").Subtotal); var bal = new[] { new Balance { Date = new DateTime(2017, 01, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 8 }, new Balance { Date = new DateTime(2017, 02, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 1 }, new Balance { Date = new DateTime(2017, 03, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 4 }, new Balance { Date = new DateTime(2017, 04, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 2 } }; var res = builder.Build(bal); Assert.IsAssignableFrom <ISubtotalRoot>(res); var resx = (ISubtotalRoot)res; var lst = new List <Balance>(); foreach (var item in resx.Items) { Assert.IsAssignableFrom <ISubtotalDate>(item); var resxx = (ISubtotalDate)item; Assert.Null(resxx.Items); Assert.Equal(SubtotalLevel.Month, resxx.Level); lst.Add(new Balance { Date = resxx.Date, Fund = resxx.Fund }); } Assert.Equal(bal.Sum(b => b.Fund), res.Fund); Assert.Equal(bal, lst, new BalanceEqualityComparer()); }
public virtual void RunTestA(bool expected, string query) { var voucher = new Voucher { ID = "59278b516c2f021e80f51912", Date = null, Type = VoucherType.Uncertain, Remark = "rmk1", Details = new List <VoucherDetail> { new VoucherDetail { Currency = "JPY", Title = 1001, SubTitle = 05, Content = "cont1", Fund = 123.45 }, new VoucherDetail { Currency = "JPY", Title = 1234, Remark = "remk2", Fund = -123.45 }, new VoucherDetail { Currency = "USD", Title = 2345, Content = "cont3", Fund = -77.66 }, new VoucherDetail { Currency = "USD", Title = 3456, SubTitle = 05, Content = "cont4", Remark = "remk4", Fund = 77.66 } } }; ResetVouchers(); PrepareVoucher(voucher); Assert.Equal(expected, RunQuery(ParsingF.VoucherQuery(query))); ResetVouchers(); }
private double VisitImpl(Inquiry inq, Func <string, string> gen) { var val = 0D; IFundFormatter fmt = new BaseFundFormatter(); if (!double.IsNaN(inq.Ratio)) { fmt = new RatioDecorator(fmt, inq.Ratio); } var o = $"[{(inq.IsLeftExtended ? "" : m_Rng.StartDate.AsDate())}~{m_Rng.EndDate.AsDate()}] {(inq.General ? "G" : "")}"; var query = ParsingF.GroupedQuery( $"{gen(o)}`{(inq.ByCurrency ? "C" : "")}{(inq.ByTitle ? "t" : "")}{(inq.BySubTitle ? "s" : "")}{(inq.ByContent ? "c" : "")}{(inq.ByRemark ? "r" : "")}{(inq.ByCurrency || inq.ByTitle || inq.BySubTitle || inq.ByContent || inq.ByRemark ? "" : "v")}{(!inq.ByCurrency ? "X" : "")}"); var gq = m_Accountant.SelectVoucherDetailsGrouped(query); if (inq.ByCurrency) { foreach (var grp in gq.Items.Cast <ISubtotalCurrency>()) { var curr = grp.Currency; // ReSharper disable once PossibleInvalidOperationException var ratio = m_Accountant.From(m_Rng.EndDate.Value, curr) * m_Accountant.To(m_Rng.EndDate.Value, m_BaseCurrency); var theFmt = new CurrencyDecorator(fmt, curr, ratio); val += theFmt.GetFund(grp.Fund); m_Sb.Append( new SubtotalVisitor(Composite.Merge(m_Path, inq.Name), theFmt, inq.HideContent) .PresentSubtotal(grp, query.Subtotal, m_Serializer)); } } else { val += fmt.GetFund(gq.Fund); m_Sb.Append( new SubtotalVisitor(Composite.Merge(m_Path, inq.Name), fmt, inq.HideContent) .PresentSubtotal(gq, query.Subtotal, m_Serializer)); } return(val); }
/// <inheritdoc /> public Voucher ParseVoucher(string expr) { if (!expr.StartsWith(TheToken, StringComparison.Ordinal)) { throw new FormatException("格式错误"); } expr = expr.Substring(TheToken.Length); if (ParsingF.Token(ref expr, false, s => s == "!") == null) { throw new NotImplementedException(); } var v = GetVoucher(ref expr); Parsing.TrimStartComment(ref expr); if (Parsing.Token(ref expr, false) != "}") { throw new FormatException("格式错误"); } Parsing.Eof(expr); return(v); }
/// <summary> /// 解析记账凭证表达式 /// </summary> /// <param name="expr">表达式</param> /// <returns>记账凭证</returns> private Voucher GetVoucher(ref string expr) { Parsing.TrimStartComment(ref expr); var id = Parsing.Quoted(ref expr, '^'); Parsing.TrimStartComment(ref expr); DateTime? date = ClientDateTime.Today; try { date = ParsingF.UniqueTime(ref expr); } catch (Exception) { // ignore } Parsing.TrimStartComment(ref expr); var remark = Parsing.Quoted(ref expr, '%'); Parsing.TrimStartComment(ref expr); var typeT = VoucherType.Ordinary; var type = Parsing.Token(ref expr, false, t => TryParse(t, out typeT)) != null ? (VoucherType?)typeT : null; Parsing.TrimStartComment(ref expr); var lst = new List<VoucherDetail>(); VoucherDetail d; while ((d = ParseVoucherDetail(ref expr)) != null) lst.Add(d); return new Voucher { ID = id, Remark = remark, Type = type, Date = date, Details = lst }; }
public void Parse(string expr) { var headerB = ParsingF.Line(ref expr); var header = headerB; var dateId = -1; var fundId = -1; var dateReg = new Regex(@"^trans(?:\.|action)\s+date$", RegexOptions.IgnoreCase); var fundReg = new Regex(@"^(?:amount|fund|value)$", RegexOptions.IgnoreCase); for (var i = 0; !string.IsNullOrWhiteSpace(header); i++) { var f = Next(ref header); if (dateReg.IsMatch(f)) { dateId = i; } else if (fundReg.IsMatch(f)) { fundId = i; } } if (dateId < 0) { header = headerB; var dateReg2 = new Regex(@"^date$", RegexOptions.IgnoreCase); for (var i = 0; !string.IsNullOrWhiteSpace(header); i++) { var f = Next(ref header); if (i == fundId) { continue; } if (dateReg2.IsMatch(f)) { dateId = i; } } if (dateId < 0) { throw new ApplicationException("找不到日期字段"); } } if (fundId < 0) { throw new ApplicationException("找不到金额字段"); } Items = new List <BankItem>(); while (!string.IsNullOrWhiteSpace(expr)) { var l = ParsingF.Line(ref expr); var item = new BankItem { Raw = l }; for (var i = 0; !string.IsNullOrWhiteSpace(l); i++) { var f = Next(ref l); if (i == dateId) { item.Date = ClientDateTime.Parse(f); } else if (i == fundId) { item.Fund = m_Dir * Convert.ToDouble(f); } } Items.Add(item); } }
public void RunTestYear(string dt, double?value, string query) => Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)) .SingleOrDefault(b => b.Date == dt.ToDateTime())?.Fund);
public bool IsNonCash(VoucherDetail detail) { m_CashQuery ??= CashAccounts.Select(sa => ParsingF.PureDetailQuery(sa.Query, new() { User = User, Today = DateTime.UtcNow.Date })).ToList(); return(detail.User == User && !m_CashQuery.Any(detail.IsMatch)); }
/// <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())); }
public void RunTestValue(double?value, string query) { Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)).SingleOrDefault()?.Fund); }
/// <summary> /// 找出未在资产计算表中注册的记账凭证,并尝试建立引用 /// </summary> /// <param name="asset">资产</param> /// <param name="rng">日期过滤器</param> /// <param name="query">检索式</param> /// <returns>未注册的记账凭证</returns> public IEnumerable <Voucher> RegisterVouchers(Asset asset, DateFilter rng, IQueryCompunded <IVoucherQueryAtom> query) { if (asset.Remark == Asset.IgnoranceMark) { yield break; } foreach ( var voucher in Db.SelectVouchers(ParsingF.VoucherQuery($"U{asset.User.AsUser()} T{asset.Title.AsTitle()} {asset.StringID.Quotation('\'')}")) .Where(v => v.IsMatch(query))) { if (voucher.Remark == Asset.IgnoranceMark) { continue; } if (asset.Schedule.Any(item => item.VoucherID == voucher.ID)) { continue; } // ReSharper disable once PossibleInvalidOperationException var value = voucher.Details.Single(d => d.Title == asset.Title && d.Content == asset.StringID).Fund.Value; if (value > 0) { var lst = asset.Schedule.Where(item => item.Date.Within(rng)) .Where( item => item is AcquisationItem && (!voucher.Date.HasValue || item.Date == voucher.Date) && (((AcquisationItem)item).OrigValue - value).IsZero()) .ToList(); if (lst.Count == 1) { lst[0].VoucherID = voucher.ID; } else { yield return(voucher); } } else if (value < 0) { var lst = asset.Schedule.Where(item => item.Date.Within(rng)) .Where( item => item is DispositionItem && (!voucher.Date.HasValue || item.Date == voucher.Date)) .ToList(); if (lst.Count == 1) { lst[0].VoucherID = voucher.ID; } else { yield return(voucher); } } else { yield return(voucher); } } foreach ( var voucher in Db.SelectVouchers( ParsingF.VoucherQuery($"U{asset.User.AsUser()} T{asset.DepreciationTitle.AsTitle()} {asset.StringID.Quotation('\'')}"))) { if (voucher.Remark == Asset.IgnoranceMark) { continue; } if (asset.Schedule.Any(item => item.VoucherID == voucher.ID)) { continue; } var lst = asset.Schedule.Where( item => item is DepreciateItem && (!voucher.Date.HasValue || item.Date == voucher.Date)) .ToList(); if (lst.Count == 1) { lst[0].VoucherID = voucher.ID; } else { yield return(voucher); } } foreach ( var voucher in Db.SelectVouchers( ParsingF.VoucherQuery($"U{asset.User.AsUser()} T{asset.DevaluationTitle.AsTitle()} {asset.StringID.Quotation('\'')}"))) { if (voucher.Remark == Asset.IgnoranceMark) { continue; } if (asset.Schedule.Any(item => item.VoucherID == voucher.ID)) { continue; } var lst = asset.Schedule.Where( item => item is DevalueItem && (!voucher.Date.HasValue || item.Date == voucher.Date)) .ToList(); if (lst.Count == 1) { lst[0].VoucherID = voucher.ID; } else { yield return(voucher); } } }
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()); }
public void TestCurrency() { var builder = new SubtotalBuilder(ParsingF.GroupedQuery("`C").Subtotal); var bal = new[] { new Balance { Currency = "JPY", Fund = 8 }, new Balance { Currency = "CNY", Fund = 1 }, new Balance { Currency = "USD", Fund = 4 }, new Balance { Currency = "CNY", Fund = 2 } }; var res = builder.Build(bal); Assert.IsAssignableFrom <ISubtotalRoot>(res); var resx = (ISubtotalRoot)res; var lst = new List <Balance>(); foreach (var item in resx.Items) { Assert.IsAssignableFrom <ISubtotalCurrency>(item); var resxx = (ISubtotalCurrency)item; Assert.Null(resxx.Items); lst.Add(new Balance { Currency = resxx.Currency, Fund = resxx.Fund }); } Assert.Equal(bal.Sum(b => b.Fund), res.Fund); Assert.Equal( new List <Balance> { new Balance { Currency = "JPY", Fund = 8 }, new Balance { Currency = "CNY", Fund = 3 }, new Balance { Currency = "USD", Fund = 4 } }, lst, new BalanceEqualityComparer()); }
public void TestAggrChangedEquivalent() { var builder = new SubtotalBuilder(ParsingF.GroupedQuery("`vDX[20170101]").Subtotal); var bal = new[] { new Balance { Currency = "JPY", Date = new DateTime(2017, 01, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 8 }, new Balance { Currency = "CNY", Date = new DateTime(2017, 01, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 1 }, new Balance { Currency = "USD", Date = new DateTime(2017, 01, 05, 0, 0, 0, DateTimeKind.Utc), Fund = 4 }, new Balance { Currency = "CNY", Date = new DateTime(2017, 01, 05, 0, 0, 0, DateTimeKind.Utc), Fund = 2 } }; var res = builder.Build(bal); Assert.IsAssignableFrom <ISubtotalRoot>(res); var resx = (ISubtotalRoot)res; var lst = new List <Balance>(); foreach (var item in resx.Items) { Assert.IsAssignableFrom <ISubtotalDate>(item); var resxx = (ISubtotalDate)item; Assert.Null(resxx.Items); Assert.Equal(SubtotalLevel.Day, resxx.Level); lst.Add(new Balance { Date = resxx.Date, Fund = resxx.Fund }); } Assert.Equal(8 * 456 + 1 + 4 * 789 + 2, res.Fund); Assert.Equal( new[] { new Balance { Date = new DateTime(2017, 01, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 8 * 456 + 1 }, new Balance { Date = new DateTime(2017, 01, 05, 0, 0, 0, DateTimeKind.Utc), Fund = 8 * 456 + 1 + 4 * 789 + 2 } }, lst, new BalanceEqualityComparer()); }
public virtual async Task RunTestA(bool expected, string query) { var voucher = new Voucher { ID = null, Date = null, Type = VoucherType.Uncertain, Remark = "rmk1", Details = new() { new() { User = "******", Currency = "JPY", Title = 1001, SubTitle = 05, Content = "cont1", Fund = 123.45, }, new() { User = "******", Currency = "JPY", Title = 1234, Remark = "remk2", Fund = -123.45, }, new() { User = "******", Currency = "USD", Title = 2345, Content = "cont3", Fund = -77.66, }, new() { User = "******", Currency = "USD", Title = 3456, SubTitle = 05, Content = "cont4", Remark = "remk4", Fund = 77.66, }, new() { User = "******", Currency = "EUR", Title = 1111, SubTitle = 22, Fund = 114514, }, }, }; await ResetVouchers(); await PrepareVoucher(voucher); Assert.Equal(expected, await RunQuery(ParsingF.VoucherQuery(query, Client))); await ResetVouchers(); }
public void TestTitleSubTitle() { var builder = new SubtotalBuilder(ParsingF.GroupedQuery("`ts").Subtotal); var bal = new[] { new Balance { Title = 4567, Fund = 8 }, new Balance { Title = 1234, Fund = 1 }, new Balance { Title = 6543, Fund = 4 }, new Balance { Title = 1234, Fund = 2 }, new Balance { Title = 4567, SubTitle = 01, Fund = 128 }, new Balance { Title = 1234, SubTitle = 02, Fund = 16 }, new Balance { Title = 6543, SubTitle = 01, Fund = 64 }, new Balance { Title = 1234, SubTitle = 08, Fund = 32 } }; var res = builder.Build(bal); Assert.IsAssignableFrom <ISubtotalRoot>(res); var resx = (ISubtotalRoot)res; var lst = new List <Balance>(); foreach (var item in resx.Items) { Assert.IsAssignableFrom <ISubtotalTitle>(item); var resxx = (ISubtotalTitle)item; foreach (var item2 in resxx.Items) { Assert.IsAssignableFrom <ISubtotalSubTitle>(item2); var resxxx = (ISubtotalSubTitle)item2; Assert.Null(resxxx.Items); lst.Add(new Balance { Title = resxx.Title, SubTitle = resxxx.SubTitle, Fund = resxxx.Fund }); } } Assert.Equal(bal.Sum(b => b.Fund), res.Fund); Assert.Equal( new List <Balance> { new Balance { Title = 4567, Fund = 8 }, new Balance { Title = 4567, SubTitle = 01, Fund = 128 }, new Balance { Title = 1234, Fund = 3 }, new Balance { Title = 1234, SubTitle = 02, Fund = 16 }, new Balance { Title = 1234, SubTitle = 08, Fund = 32 }, new Balance { Title = 6543, Fund = 4 }, new Balance { Title = 6543, SubTitle = 01, Fund = 64 } }, lst, new BalanceEqualityComparer()); }
/// <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)); }
public void RunTestUser(string user, double?value, string query) => Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)) .SingleOrDefault(b => b.User == user)?.Fund);
/// <inheritdoc /> public override async IAsyncEnumerable <string> Execute(string expr, Session session) { var csv = expr; expr = ParsingF.Line(ref csv); var parsed = new CsvParser(ParsingF.Optional(ref expr, "-")); if (ParsingF.Optional(ref expr, "mark")) { var filt = ParsingF.DetailQuery(ref expr, session.Client); ParsingF.Optional(ref expr, "as"); var marker = ParsingF.Token(ref expr); ParsingF.Eof(expr); if (string.IsNullOrWhiteSpace(marker)) { throw new FormatException("格式错误"); } parsed.Parse(csv); yield return($"{parsed.Items.Count} parsed\n"); await foreach (var s in RunMark(session, filt, parsed, marker)) { yield return(s); } } else if (ParsingF.Optional(ref expr, "unmark")) { var filt = ParsingF.DetailQuery(ref expr, session.Client); ParsingF.Eof(expr); await foreach (var s in RunUnmark(session, filt)) { yield return(s); } } else if (ParsingF.Optional(ref expr, "check")) { var filt = ParsingF.DetailQuery(ref expr, session.Client); ParsingF.Eof(expr); parsed.Parse(csv); yield return($"{parsed.Items.Count} parsed\n"); await foreach (var s in RunCheck(session, filt, parsed)) { yield return(s); } } else { ParsingF.Optional(ref expr, "auto"); var filt = ParsingF.DetailQuery(ref expr, session.Client); ParsingF.Optional(ref expr, "as"); var marker = ParsingF.Token(ref expr); ParsingF.Eof(expr); if (string.IsNullOrWhiteSpace(marker)) { throw new FormatException("格式错误"); } parsed.Parse(csv); yield return($"{parsed.Items.Count} parsed\n"); var markerFilt = new StmtVoucherDetailQuery( filt.VoucherQuery, new IntersectQueries <IDetailQueryAtom>( filt.ActualDetailFilter(), new StmtDetailQuery(marker))); var nullFilt = new StmtVoucherDetailQuery( filt.VoucherQuery, new IntersectQueries <IDetailQueryAtom>( filt.ActualDetailFilter(), new StmtDetailQuery(""))); var nmFilt = new StmtVoucherDetailQuery( filt.VoucherQuery, new IntersectQueries <IDetailQueryAtom>( filt.ActualDetailFilter(), new UnionQueries <IDetailQueryAtom>( new StmtDetailQuery(""), new StmtDetailQuery(marker)))); await foreach (var s in RunUnmark(session, markerFilt)) { yield return(s); } await foreach (var s in RunMark(session, nullFilt, parsed, marker)) { yield return(s); } await foreach (var s in RunCheck(session, nmFilt, parsed)) { yield return(s); } } }
public void RunTestCurrency(string currency, double?value, string query) => Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)) .SingleOrDefault(b => b.Currency == currency)?.Fund);
private List <Item> ParseItem(string currency, ref string expr) { var lst = new List <(VoucherDetail Detail, bool Actual)>(); while (true) { var actual = Parsing.Optional(ref expr, "!"); var vd = ParseVoucherDetail(currency, ref expr); if (vd == null) { break; } lst.Add((vd, actual)); } if (ParsingF.Token(ref expr, false, s => s == ":") == null) { return(null); } var resLst = new List <Item>(); var reg = new Regex( @"(?<num>[0-9]+(?:\.[0-9]+)?)(?:(?<equals>=[0-9]+(?:\.[0-9]+)?)|(?<plus>(?:\+[0-9]+(?:\.[0-9]+)?)+)|(?<minus>(?:-[0-9]+(?:\.[0-9]+)?)+))?"); while (true) { var res = Parsing.Token(ref expr, false, reg.IsMatch); if (res == null) { break; } var m = reg.Match(res); var fund0 = Convert.ToDouble(m.Groups["num"].Value); var fundd = 0D; if (m.Groups["equals"].Success) { fundd = fund0 - Convert.ToDouble(m.Groups["equals"].Value.Substring(1)); } else if (m.Groups["plus"].Success) { var sreg = new Regex(@"\+[0-9]+(?:\.[0-9]+)?"); foreach (Match sm in sreg.Matches(m.Groups["plus"].Value)) { fundd += Convert.ToDouble(sm.Value); } fund0 += fundd; } else if (m.Groups["minus"].Success) { var sreg = new Regex(@"-[0-9]+(?:\.[0-9]+)?"); foreach (Match sm in sreg.Matches(m.Groups["minus"].Value)) { fundd -= Convert.ToDouble(sm.Value); } } resLst.AddRange( lst.Select( d => new Item { Currency = d.Detail.Currency, Title = d.Detail.Title, SubTitle = d.Detail.SubTitle, Content = d.Detail.Content, Fund = fund0 / lst.Count, DiscountFund = fundd / lst.Count, Remark = d.Detail.Remark, UseActualFund = d.Actual })); } ParsingF.Optional(ref expr, ";"); return(resLst); }
public void RunTestContent(string content, double?value, string query) => Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)) .SingleOrDefault(b => b.Content == content)?.Fund);
/// <summary> /// 解析记账凭证表达式 /// </summary> /// <param name="expr">表达式</param> /// <returns>记账凭证</returns> private Voucher GetVoucher(ref string expr) { Parsing.TrimStartComment(ref expr); DateTime?date = ClientDateTime.Today; try { date = ParsingF.UniqueTime(ref expr); } catch (Exception) { // ignore } var currency = Parsing.Token(ref expr, false, s => s.StartsWith("@", StringComparison.Ordinal)) ?.Substring(1) .ToUpperInvariant() ?? BaseCurrency.Now; var lst = new List <Item>(); List <Item> ds; while ((ds = ParseItem(currency, ref expr))?.Any() == true) { lst.AddRange(ds); } var d = (double?)0D; var t = (double?)0D; var reg = new Regex(@"(?<dt>[dt])(?<num>[0-9]+(?:\.[0-9]{1,2})?|null)"); while (true) { var res = Parsing.Token(ref expr, false, reg.IsMatch); if (res == null) { break; } var m = reg.Match(res); var num = m.Groups["num"].Value == "null" ? (double?)null : Convert.ToDouble(m.Groups["num"].Value); if (m.Groups["dt"].Value == "d") { d += num; } else // if (m.Groups["dt"].Value == "t") { t += num; } } if (!d.HasValue && !t.HasValue) { throw new ApplicationException("不定项过多"); } var resLst = new List <VoucherDetail>(); VoucherDetail vd; var exprS = new AbbrSerializer(); while ((vd = exprS.ParseVoucherDetail(ref expr)) != null) { resLst.Add(vd); } // Don't use Enumerable.Sum, it ignores null values var actualVals = resLst.Aggregate((double?)0D, (s, dd) => s + dd.Fund); if (!d.HasValue || !t.HasValue) { if (!actualVals.HasValue) { throw new ApplicationException("不定项过多"); } var sum = lst.Sum(item => item.Fund - item.DiscountFund); if (!d.HasValue) { d = sum + t + actualVals; } else // if (!t.HasValue) { t = -(sum - d + actualVals); } } // ReSharper disable PossibleInvalidOperationException var total = lst.Sum(it => it.Fund.Value); foreach (var item in lst) { item.DiscountFund += d.Value / total * item.Fund.Value; item.Fund += t.Value / total * item.Fund; } // ReSharper restore PossibleInvalidOperationException foreach (var item in lst) { if (!item.UseActualFund) { continue; } item.Fund -= item.DiscountFund; item.DiscountFund = 0D; } var totalD = lst.Sum(it => it.DiscountFund); foreach (var grp in lst.GroupBy( it => new VoucherDetail { Currency = it.Currency, Title = it.Title, SubTitle = it.SubTitle, Content = it.Content, Remark = it.Remark }, new DetailEqualityComparer())) { // ReSharper disable once PossibleInvalidOperationException grp.Key.Fund = grp.Sum(it => it.Fund.Value); resLst.Add(grp.Key); } if (!totalD.IsZero()) { resLst.Add( new VoucherDetail { Currency = currency, Title = 6603, Fund = -totalD }); } return(new Voucher { Type = VoucherType.Ordinary, Date = date, Details = resLst }); }
public void RunTestRemark(string remark, double?value, string query) => Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)) .SingleOrDefault(b => b.Remark == remark)?.Fund);
public void RunTestTitleSubTitle(int?title, int?subTitle, double?value, string query) => Assert.Equal( value, m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)) .SingleOrDefault(b => b.Title == title && b.SubTitle == subTitle)?.Fund);
public void TestAggrEveryEqui(string rng, string incl) { var builder = new SubtotalBuilder(ParsingF.GroupedQuery($"``vD[{rng}]X[20170101]").Subtotal, m_Exchange); var bal = new[] { new Balance { Date = null, Currency = "JPY", Fund = 1 / 2D / 456D }, new Balance { Date = new DateTime(2017, 01, 02, 0, 0, 0, DateTimeKind.Utc), Currency = "JPY", Fund = 2 / 2D / 456D }, new Balance { Date = new DateTime(2017, 01, 04, 0, 0, 0, DateTimeKind.Utc), Currency = "JPY", Fund = 4 / 2D / 456D }, new Balance { Date = null, Currency = "USD", Fund = 1 / 2D / 789D }, new Balance { Date = new DateTime(2017, 01, 02, 0, 0, 0, DateTimeKind.Utc), Currency = "USD", Fund = 2 / 2D / 789D }, new Balance { Date = new DateTime(2017, 01, 04, 0, 0, 0, DateTimeKind.Utc), Currency = "USD", Fund = 4 / 2D / 789D } }; var res = builder.Build(bal); Assert.IsAssignableFrom <ISubtotalRoot>(res); var resx = (ISubtotalRoot)res; var lst = new List <Balance>(); foreach (var item in resx.Items) { Assert.IsAssignableFrom <ISubtotalDate>(item); var resxx = (ISubtotalDate)item; Assert.Null(resxx.Items); Assert.Equal(SubtotalLevel.Day, resxx.Level); lst.Add(new Balance { Date = resxx.Date, Fund = resxx.Fund }); } Assert.Equal(1 + 2 + 4, res.Fund); var lst0 = new List <Balance>(); if (incl[0] == '1') { lst0.Add(new Balance { Date = null, Fund = 1 }); } if (incl[1] == '1') { lst0.Add(new Balance { Date = new DateTime(2017, 01, 01, 0, 0, 0, DateTimeKind.Utc), Fund = 1 }); } if (incl[2] == '1') { lst0.Add(new Balance { Date = new DateTime(2017, 01, 02, 0, 0, 0, DateTimeKind.Utc), Fund = 1 + 2 }); } if (incl[3] == '1') { lst0.Add(new Balance { Date = new DateTime(2017, 01, 03, 0, 0, 0, DateTimeKind.Utc), Fund = 1 + 2 }); } if (incl[4] == '1') { lst0.Add( new Balance { Date = new DateTime(2017, 01, 04, 0, 0, 0, DateTimeKind.Utc), Fund = 1 + 2 + 4 }); } if (incl[5] == '1') { lst0.Add( new Balance { Date = new DateTime(2017, 01, 05, 0, 0, 0, DateTimeKind.Utc), Fund = 1 + 2 + 4 }); } Assert.Equal(lst0, lst, new BalanceEqualityComparer()); }