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

b1f6c1c4 / ProfessionalAccounting / 307

25 Sep 2023 04:48AM UTC coverage: 56.975% (-1.3%) from 58.254%
307

push

appveyor

b1f6c1c4
raw subtotal more controllable

5947 of 10438 relevant lines covered (56.97%)

125.9 hits per line

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

91.91
/AccountingServer.Shell/Serializer/ExprSerializer.cs
1
/* Copyright (C) 2020-2023 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.Text;
22
using AccountingServer.BLL;
23
using AccountingServer.BLL.Util;
24
using AccountingServer.Entities;
25
using AccountingServer.Shell.Util;
26
using static AccountingServer.BLL.Parsing.Facade;
27
using static AccountingServer.BLL.Parsing.FacadeF;
28

29
namespace AccountingServer.Shell.Serializer;
30

31
/// <summary>
32
///     实体表达式
33
/// </summary>
34
public class ExprSerializer : IClientDependable, IEntitySerializer
35
{
36
    private const string TheToken = "new Voucher {";
37

38
    public Client Client { private get; set; }
39

40
    /// <inheritdoc />
41
    public string PresentVoucher(Voucher voucher)
42
        => PresentVoucher(voucher, null);
30✔
43

44
    /// <inheritdoc />
45
    public string PresentVoucher(Voucher voucher, string inject)
46
    {
30✔
47
        var sb = new StringBuilder();
30✔
48
        sb.Append(TheToken);
30✔
49
        if (voucher == null)
30✔
50
        {
3✔
51
            sb.Append("\n");
3✔
52
            sb.Append("\n");
3✔
53
        }
3✔
54
        else
55
        {
27✔
56
            sb.Append($"{voucher.ID?.Quotation('^')}\n");
27✔
57
            if (voucher.Date.HasValue || inject == null)
27✔
58
                sb.Append($"{voucher.Date.AsDate()}\n");
27✔
59
            if (voucher.Remark != null)
27✔
60
                sb.Append($"{voucher.Remark.Quotation('%')}\n");
14✔
61
            if (voucher.Type.HasValue &&
27✔
62
                voucher.Type != VoucherType.Ordinary)
63
                sb.Append($"{voucher.Type}\n");
12✔
64

65
            if (inject != null)
27✔
66
                sb.Append($"{inject}\n");
×
67

68
            foreach (var d in voucher.Details)
121✔
69
                sb.Append(PresentVoucherDetail(d));
94✔
70
        }
27✔
71

72
        sb.Append('}');
30✔
73
        return sb.ToString();
30✔
74
    }
30✔
75

76
    /// <inheritdoc />
77
    public string PresentVoucherDetail(VoucherDetail detail)
78
    {
96✔
79
        var sb = new StringBuilder();
96✔
80
        var t = TitleManager.GetTitleName(detail.Title);
96✔
81
        sb.Append(
96✔
82
            detail.SubTitle.HasValue
83
                ? $"// {t}-{TitleManager.GetTitleName(detail.Title, detail.SubTitle)}\n"
84
                : $"// {t}\n");
85
        if (detail.User != Client.User)
96✔
86
            sb.Append($"{detail.User.AsUser()} ");
27✔
87
        if (detail.Currency != BaseCurrency.Now)
96✔
88
            sb.Append($"@{detail.Currency} ");
48✔
89
        sb.Append($"{detail.Title.AsTitle()}{detail.SubTitle.AsSubTitle()} ");
96✔
90
        if (detail.Content == null &&
96✔
91
            detail.Remark != null)
92
            sb.Append("''");
39✔
93
        else
94
            sb.Append(detail.Content?.Quotation('\''));
57✔
95
        sb.Append($" {detail.Remark?.Quotation('\"')} {detail.Fund}\n");
96✔
96
        return sb.ToString();
96✔
97
    }
96✔
98

99
    /// <inheritdoc />
100
    public string PresentVoucherDetail(VoucherDetailR detail)
101
        => $"{detail.Voucher.Date.AsDate()} {PresentVoucherDetail((VoucherDetail)detail)}";
2✔
102

103
    /// <inheritdoc />
104
    public Voucher ParseVoucher(string expr)
105
    {
34✔
106
        if (!expr.StartsWith(TheToken, StringComparison.Ordinal))
34✔
107
            throw new FormatException("格式错误");
2✔
108

109
        expr = expr[TheToken.Length..];
32✔
110
        var v = GetVoucher(ref expr);
32✔
111
        Parsing.TrimStartComment(ref expr);
32✔
112
        if (Parsing.Token(ref expr, false) != "}")
32✔
113
            throw new FormatException("格式错误" + expr);
2✔
114

115
        Parsing.Eof(expr);
30✔
116
        return v;
30✔
117
    }
30✔
118

119
    /// <inheritdoc />
120
    public virtual VoucherDetail ParseVoucherDetail(string expr)
121
    {
×
122
        var res = ParseVoucherDetail(ref expr);
×
123
        Parsing.Eof(expr);
×
124
        return res;
×
125
    }
×
126

127
    public string PresentAsset(Asset asset) => throw new NotImplementedException();
2✔
128
    public Asset ParseAsset(string str) => throw new NotImplementedException();
2✔
129
    public string PresentAmort(Amortization amort) => throw new NotImplementedException();
2✔
130
    public Amortization ParseAmort(string str) => throw new NotImplementedException();
2✔
131

132
    /// <summary>
133
    ///     解析记账凭证表达式
134
    /// </summary>
135
    /// <param name="expr">表达式</param>
136
    /// <returns>记账凭证</returns>
137
    private Voucher GetVoucher(ref string expr)
138
    {
32✔
139
        Parsing.TrimStartComment(ref expr);
32✔
140
        var id = Parsing.Quoted(ref expr, '^');
32✔
141
        Parsing.TrimStartComment(ref expr);
32✔
142
        DateTime? date = Client.Today;
32✔
143
        try
144
        {
32✔
145
            date = ParsingF.UniqueTime(ref expr, Client);
32✔
146
        }
15✔
147
        catch (Exception)
17✔
148
        {
17✔
149
            // ignore
150
        }
17✔
151

152
        Parsing.TrimStartComment(ref expr);
32✔
153
        var remark = Parsing.Quoted(ref expr, '%');
32✔
154
        Parsing.TrimStartComment(ref expr);
32✔
155
        var typeT = VoucherType.Ordinary;
32✔
156
        var type = Parsing.Token(ref expr, false, t => TryParse(t, out typeT)) != null ? (VoucherType?)typeT : null;
30✔
157
        Parsing.TrimStartComment(ref expr);
32✔
158

159
        var lst = new List<VoucherDetail>();
32✔
160
        VoucherDetail d;
161
        while ((d = ParseVoucherDetail(ref expr)) != null)
105✔
162
            lst.Add(d);
73✔
163

164
        return new()
32✔
165
            {
166
                ID = id,
167
                Remark = remark,
168
                Type = type,
169
                Date = date,
170
                Details = lst,
171
            };
172
    }
32✔
173

174
    /// <summary>
175
    ///     解析记账凭证类别表达式
176
    /// </summary>
177
    /// <param name="s">表达式</param>
178
    /// <param name="typeT">记账凭证类别</param>
179
    /// <returns>是否解析成功</returns>
180
    private static bool TryParse(string s, out VoucherType typeT)
181
    {
30✔
182
        // Don't use Enum.TryParse here:
183
        // Enum.TryParse("1001", out _) gives true
184
        switch (s)
30✔
185
        {
186
            case "Ordinary":
187
                typeT = VoucherType.Ordinary;
×
188
                return true;
×
189
            case "Carry":
190
                typeT = VoucherType.Carry;
2✔
191
                return true;
2✔
192
            case "AnnualCarry":
193
                typeT = VoucherType.AnnualCarry;
2✔
194
                return true;
2✔
195
            case "Depreciation":
196
                typeT = VoucherType.Depreciation;
2✔
197
                return true;
2✔
198
            case "Devalue":
199
                typeT = VoucherType.Devalue;
2✔
200
                return true;
2✔
201
            case "Amortization":
202
                typeT = VoucherType.Amortization;
2✔
203
                return true;
2✔
204
            case "Uncertain":
205
                typeT = VoucherType.Uncertain;
2✔
206
                return true;
2✔
207
            default:
208
                typeT = VoucherType.General;
18✔
209
                return false;
18✔
210
        }
211
    }
30✔
212

213
    public VoucherDetail ParseVoucherDetail(ref string expr)
214
    {
119✔
215
        var lst = new List<string>();
119✔
216

217
        Parsing.TrimStartComment(ref expr);
119✔
218
        var user = Parsing.Token(ref expr, false, static t => t.StartsWith("U", StringComparison.Ordinal))
117✔
219
            .ParseUserSpec(Client);
220
        var currency = Parsing.Token(ref expr, false, static t => t.StartsWith("@", StringComparison.Ordinal))?[1..]
117✔
221
                .ToUpperInvariant()
222
            ?? BaseCurrency.Now;
223
        Parsing.TrimStartComment(ref expr);
119✔
224
        var title = Parsing.Title(ref expr);
119✔
225
        if (title == null)
119✔
226
            if (!AlternativeTitle(ref expr, lst, ref title))
51✔
227
                return null;
39✔
228

229
        double? fund;
230

231
        while (true)
171✔
232
        {
171✔
233
            Parsing.TrimStartComment(ref expr);
171✔
234
            if ((fund = Parsing.Double(ref expr)) != null)
171✔
235
                break;
67✔
236

237
            Parsing.TrimStartComment(ref expr);
104✔
238
            if (Parsing.Optional(ref expr, "null"))
104✔
239
                break;
3✔
240
            if (Parsing.Optional(ref expr, "/"))
101✔
241
                break;
10✔
242

243
            if (lst.Count > 2)
91✔
244
                throw new ArgumentException("语法错误", nameof(expr));
×
245

246
            Parsing.TrimStartComment(ref expr);
91✔
247
            lst.Add(Parsing.Token(ref expr));
91✔
248
        }
91✔
249

250
        var content = lst.Count >= 1 ? lst[0] : null;
80✔
251
        var remark = lst.Count >= 2 ? lst[1] : null;
80✔
252

253
        if (content == "G()")
80✔
254
            content = Guid.NewGuid().ToString().ToUpperInvariant();
×
255

256
        if (remark == "G()")
80✔
257
            remark = Guid.NewGuid().ToString().ToUpperInvariant();
×
258

259
        return new()
80✔
260
            {
261
                User = user,
262
                Currency = currency,
263
                Title = title.Title,
264
                SubTitle = title.SubTitle,
265
                Content = string.IsNullOrEmpty(content) ? null : content,
266
                Fund = fund,
267
                Remark = string.IsNullOrEmpty(remark) ? null : remark,
268
            };
269
    }
119✔
270

271
    protected virtual bool AlternativeTitle(ref string expr, ICollection<string> lst, ref ITitle title) => false;
9✔
272
}
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

© 2025 Coveralls, Inc