コード例 #1
0
 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 }}")))));
コード例 #2
0
        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());
        }
コード例 #3
0
        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());
        }
コード例 #4
0
        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();
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        /// <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);
        }
コード例 #7
0
        /// <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
                };
        }
コード例 #8
0
        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);
            }
        }
コード例 #9
0
 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);
コード例 #10
0
 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));
 }
コード例 #11
0
        /// <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()));
        }
コード例 #12
0
 public void RunTestValue(double?value, string query)
 {
     Assert.Equal(
         value,
         m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query)).SingleOrDefault()?.Fund);
 }
コード例 #13
0
        /// <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);
                }
            }
        }
コード例 #14
0
        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());
        }
コード例 #15
0
        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());
        }
コード例 #16
0
        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());
        }
コード例 #17
0
    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();
    }
コード例 #18
0
        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());
        }
コード例 #19
0
        /// <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));
        }
コード例 #20
0
 public void RunTestUser(string user, double?value, string query)
 => Assert.Equal(
     value,
     m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query))
     .SingleOrDefault(b => b.User == user)?.Fund);
コード例 #21
0
    /// <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);
            }
        }
    }
コード例 #22
0
 public void RunTestCurrency(string currency, double?value, string query)
 => Assert.Equal(
     value,
     m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query))
     .SingleOrDefault(b => b.Currency == currency)?.Fund);
コード例 #23
0
        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);
        }
コード例 #24
0
 public void RunTestContent(string content, double?value, string query)
 => Assert.Equal(
     value,
     m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query))
     .SingleOrDefault(b => b.Content == content)?.Fund);
コード例 #25
0
        /// <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
            });
        }
コード例 #26
0
 public void RunTestRemark(string remark, double?value, string query)
 => Assert.Equal(
     value,
     m_Adapter.SelectVoucherDetailsGrouped(ParsingF.GroupedQuery(query))
     .SingleOrDefault(b => b.Remark == remark)?.Fund);
コード例 #27
0
 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);
コード例 #28
0
        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());
        }