• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

b1f6c1c4 / ProfessionalAccounting / 320

16 Oct 2024 05:07PM UTC coverage: 55.799% (-1.1%) from 56.944%
320

push

appveyor

b1f6c1c4
final taobao

6264 of 11226 relevant lines covered (55.8%)

126.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

1.25
/AccountingServer.Shell/CheckShell.cs
1
/* Copyright (C) 2020-2024 b1f6c1c4
2
 *
3
 * This file is part of ProfessionalAccounting.
4
 *
5
 * ProfessionalAccounting is free software: you can redistribute it and/or
6
 * modify it under the terms of the GNU Affero General Public License as
7
 * published by the Free Software Foundation, version 3.
8
 *
9
 * ProfessionalAccounting is distributed in the hope that it will be useful, but
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
12
 * for more details.
13
 *
14
 * You should have received a copy of the GNU Affero General Public License
15
 * along with ProfessionalAccounting.  If not, see
16
 * <https://www.gnu.org/licenses/>.
17
 */
18

19
using System;
20
using System.Collections.Generic;
21
using System.Linq;
22
using AccountingServer.BLL.Util;
23
using AccountingServer.Entities;
24
using AccountingServer.Entities.Util;
25
using AccountingServer.Shell.Serializer;
26
using AccountingServer.Shell.Util;
27
using static AccountingServer.BLL.Parsing.Facade;
28

29
namespace AccountingServer.Shell;
30

31
/// <summary>
32
///     检验表达式解释器
33
/// </summary>
34
internal class CheckShell : IShellComponent
35
{
36
    /// <inheritdoc />
37
    public IAsyncEnumerable<string> Execute(string expr, Session session)
38
        => expr.Rest() switch
×
39
            {
40
                "1" => BasicCheck(session),
×
41
                "2" => AdvancedCheck(session),
×
42
                "3" => UpsertCheck(session),
×
43
                var x when x.StartsWith("4", StringComparison.Ordinal) => DuplicationCheck(session, x.Rest()),
×
44
                _ => throw new InvalidOperationException("表达式无效"),
×
45
            };
46

47
    /// <inheritdoc />
48
    public bool IsExecutable(string expr) => expr.Initial() == "chk";
6✔
49

50
    /// <summary>
51
    ///     检查每张会计记账凭证借贷方是否相等
52
    /// </summary>
53
    /// <param name="session">客户端会话</param>
54
    /// <returns>有误的会计记账凭证表达式</returns>
55
    private async IAsyncEnumerable<string> BasicCheck(Session session)
56
    {
×
57
        Voucher old = null;
×
58
        await foreach (var (voucher, user, curr, v) in
×
59
                       session.Accountant.SelectUnbalancedVouchersAsync(VoucherQueryUnconstrained.Instance))
×
60
        {
×
61
            if (old != null && voucher.ID != old.ID)
×
62
                yield return session.Serializer.PresentVoucher(old).Wrap();
×
63
            old = voucher;
×
64

65
            yield return $"/* {user.AsUser()} {curr.AsCurrency()}: Debit - Credit = {v:R} */\n";
×
66
        }
×
67

68
        if (old != null)
×
69
            yield return session.Serializer.PresentVoucher(old).Wrap();
×
70
    }
×
71

72
    /// <summary>
73
    ///     检查每科目每内容借贷方向
74
    /// </summary>
75
    /// <param name="session">客户端会话</param>
76
    /// <returns>发生错误的信息</returns>
77
    private async IAsyncEnumerable<string> AdvancedCheck(Session session)
78
    {
×
79
        foreach (var title in TitleManager.Titles)
×
80
        {
×
81
            if (!title.IsVirtual)
×
82
                if (Math.Abs(title.Direction) == 1)
×
83
                    await foreach (var s in DoCheck(
×
84
                                       session.Accountant
85
                                           .RunVoucherQueryAsync(
86
                                               $"{title.Id.AsTitle()}00 {(title.Direction < 0 ? ">" : "<")} G")
87
                                           .SelectMany(v
88
                                               => v.Details.Where(d => d.Title == title.Id)
×
89
                                                   .Select(d => (Voucher: v, Detail: d)).ToAsyncEnumerable()),
×
90
                                       $"{title.Id.AsTitle()}00"))
91
                        yield return s;
×
92
                else if (Math.Abs(title.Direction) == 2)
×
93
                    foreach (var s in DoCheck(
×
94
                                 title.Direction,
95
                                 await session.Accountant.RunGroupedQueryAsync($"{title.Id.AsTitle()}00 G`CcD"),
96
                                 $"{title.Id.AsTitle()}00"))
97
                        yield return s;
×
98

99
            foreach (var subTitle in title.SubTitles)
×
100
                if (Math.Abs(subTitle.Direction) == 1)
×
101
                    await foreach (var s in DoCheck(
×
102
                                       session.Accountant.RunVoucherQueryAsync(
103
                                               $"{title.Id.AsTitle()}{subTitle.Id.AsSubTitle()} {(subTitle.Direction < 0 ? ">" : "<")} G")
104
                                           .SelectMany(v
105
                                               => v.Details.Where(d => d.Title == title.Id && d.SubTitle == subTitle.Id)
×
106
                                                   .Select(d => (Voucher: v, Detail: d)).ToAsyncEnumerable()),
×
107
                                       $"{title.Id.AsTitle()}{subTitle.Id.AsSubTitle()}"))
108
                        yield return s;
×
109
                else if (Math.Abs(subTitle.Direction) == 2)
×
110
                    foreach (var s in DoCheck(
×
111
                                 subTitle.Direction,
112
                                 await session.Accountant.RunGroupedQueryAsync(
113
                                     $"{title.Id.AsTitle()}{subTitle.Id.AsSubTitle()} G`CcD"),
114
                                 $"{title.Id.AsTitle()}{subTitle.Id.AsSubTitle()}"))
115
                        yield return s;
×
116
        }
×
117
    }
×
118

119
    private static IEnumerable<string> DoCheck(int dir, ISubtotalResult res, string info)
120
    {
×
121
        foreach (var grpC in res.Items.Cast<ISubtotalCurrency>())
×
122
        foreach (var grpc in grpC.Items.Cast<ISubtotalContent>())
×
123
        foreach (var grpd in grpc.Items.Cast<ISubtotalDate>())
×
124
            switch (dir)
×
125
            {
126
                case > 0 when grpd.Fund.IsNonNegative():
×
127
                case < 0 when grpd.Fund.IsNonPositive():
×
128
                    continue;
×
129
                default:
130
                    yield return $"{grpd.Date:yyyyMMdd} {info} {grpc.Content}:{grpC.Currency.AsCurrency()} {grpd.Fund:R}\n";
×
131
                    break;
×
132
            }
133
    }
×
134

135
    private static async IAsyncEnumerable<string> DoCheck(IAsyncEnumerable<(Voucher Voucher, VoucherDetail Detail)> res,
136
        string info)
137
    {
×
138
        await foreach (var (v, d) in res)
×
139
        {
×
140
            if (d.Remark == "reconciliation")
×
141
                continue;
×
142

143
            yield return $"{v.ID} {v.Date:yyyyMMdd} {info} {d.Content}:{d.Fund!.Value:R}\n";
×
144
        }
×
145
    }
×
146

147
    private async IAsyncEnumerable<string> UpsertCheck(Session session)
148
    {
×
149
        yield return "Reading...\n";
×
150
        var lst = await session.Accountant.RunVoucherQueryAsync("U A").ToListAsync();
×
151
        yield return $"Read {lst.Count} vouchers, writing...\n";
×
152
        await session.Accountant.UpsertAsync(lst);
×
153
        yield return "Written\n";
×
154
    }
×
155

156
    private async IAsyncEnumerable<string> DuplicationCheck(Session session, string expr)
157
    {
×
158
        var query = Parsing.VoucherQuery(ref expr, session.Client);
×
159
        Parsing.Eof(expr);
×
160
        await foreach (var (v, ids) in session.Accountant.SelectDuplicatedVouchersAsync(query))
×
161
        {
×
162
            yield return $"// Date = {v.Date.AsDate()} Duplication = {ids.Count}\n";
×
163
            foreach (var id in ids)
×
164
                yield return $"//   ^{id}^\n";
×
165
            yield return session.Serializer.PresentVoucher(v).Wrap();
×
166
        }
×
167
    }
×
168
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc