• 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

68.03
/AccountingServer.Shell/Serializer/JsonSerializer.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.Linq;
22
using AccountingServer.Entities;
23
using Newtonsoft.Json;
24
using Newtonsoft.Json.Linq;
25

26
namespace AccountingServer.Shell.Serializer;
27

28
/// <summary>
29
///     Json表达式
30
/// </summary>
31
public class JsonSerializer : IEntitiesSerializer
32
{
33
    private const string VoucherToken = "new Voucher";
34
    private const string AssetToken = "new Asset";
35
    private const string AmortToken = "new Amortization";
36

37
    /// <inheritdoc />
38
    public string PresentVoucher(Voucher voucher)
39
        => voucher == null
8✔
40
            ? $"{VoucherToken}{{\n\n}}"
41
            : VoucherToken + PresentJson(voucher).ToString(Formatting.Indented);
42

43
    /// <inheritdoc />
44
    public string PresentVoucherDetail(VoucherDetail detail)
45
        => PresentJson(detail).ToString(Formatting.Indented);
×
46

47
    /// <inheritdoc />
48
    public string PresentVoucherDetail(VoucherDetailR detail)
49
        => PresentVoucherDetail((VoucherDetail)detail);
×
50

51
    /// <inheritdoc />
52
    public Voucher ParseVoucher(string str)
53
    {
9✔
54
        if (str.StartsWith(VoucherToken, StringComparison.OrdinalIgnoreCase))
9✔
55
            str = str[VoucherToken.Length..];
8✔
56

57
        return ParseVoucher(ParseJson(str));
9✔
58
    }
7✔
59

60
    /// <inheritdoc />
61
    public string PresentVoucher(Voucher voucher, string inject) => throw new NotImplementedException();
×
62

63
    /// <inheritdoc />
64
    public VoucherDetail ParseVoucherDetail(string str) => ParseVoucherDetail(ParseJson(str));
×
65

66
    /// <inheritdoc />
67
    public string PresentAsset(Asset asset)
68
        => asset == null ? "null" : AssetToken + PresentJson(asset).ToString(Formatting.Indented);
5✔
69

70
    /// <inheritdoc />
71
    public Asset ParseAsset(string str)
72
    {
6✔
73
        if (str.StartsWith(AssetToken, StringComparison.OrdinalIgnoreCase))
6✔
74
            str = str[AssetToken.Length..];
5✔
75

76
        var obj = ParseJson(str);
6✔
77
        var dateStr = obj["date"]?.Value<string>();
4✔
78
        DateTime? date = null;
4✔
79
        if (dateStr != null)
4✔
80
            date = DateTimeParser.Parse(dateStr);
2✔
81
        var schedule = obj["schedule"];
4✔
82
        var typeStr = obj["method"]?.Value<string>();
4✔
83
        var method = DepreciationMethod.StraightLine;
4✔
84
        if (typeStr != null)
4✔
85
            Enum.TryParse(typeStr, out method);
4✔
86

87
        return new()
4✔
88
            {
89
                StringID = obj["id"]?.Value<string>(),
90
                Name = obj["name"]?.Value<string>(),
91
                Date = date,
92
                User = obj["user"]?.Value<string>(),
93
                Currency = obj["currency"]?.Value<string>(),
94
                Value = obj["value"]?.Value<double?>(),
95
                Salvage = obj["salvage"]?.Value<double?>(),
96
                Life = obj["life"]?.Value<int?>(),
97
                Title = obj["title"]?.Value<int?>(),
98
                Method = method,
99
                DepreciationTitle = obj["depreciation"]?["title"]?.Value<int?>(),
100
                DepreciationExpenseTitle = obj["depreciation"]?["expense"]?["title"]?.Value<int?>(),
101
                DepreciationExpenseSubTitle = obj["depreciation"]?["expense"]?["subtitle"]?.Value<int?>(),
102
                DevaluationTitle = obj["devaluation"]?["title"]?.Value<int?>(),
103
                DevaluationExpenseTitle = obj["devaluation"]?["expense"]?["title"]?.Value<int?>(),
104
                DevaluationExpenseSubTitle = obj["devaluation"]?["expense"]?["subtitle"]?.Value<int?>(),
105
                Remark = obj["remark"]?.Value<string>(),
106
                Schedule = schedule?.Select(ParseAssetItem).ToList() ?? new(),
107
            };
108
    }
4✔
109

110
    /// <inheritdoc />
111
    public string PresentAmort(Amortization amort)
112
        => amort == null ? "null" : AmortToken + PresentJson(amort).ToString(Formatting.Indented);
8✔
113

114
    /// <inheritdoc />
115
    public Amortization ParseAmort(string str)
116
    {
9✔
117
        if (str.StartsWith(AmortToken, StringComparison.OrdinalIgnoreCase))
9✔
118
            str = str[AmortToken.Length..];
8✔
119

120
        var obj = ParseJson(str);
9✔
121
        var dateStr = obj["date"]?.Value<string>();
7✔
122
        DateTime? date = null;
7✔
123
        if (dateStr != null)
7✔
124
            date = DateTimeParser.Parse(dateStr);
3✔
125
        var schedule = obj["schedule"];
7✔
126
        var typeStr = obj["interval"]?.Value<string>();
7✔
127
        var interval = AmortizeInterval.EveryDay;
7✔
128
        if (typeStr != null)
7✔
129
            Enum.TryParse(typeStr, out interval);
7✔
130

131
        return new()
7✔
132
            {
133
                StringID = obj["id"]?.Value<string>(),
134
                Name = obj["name"]?.Value<string>(),
135
                Date = date,
136
                User = obj["user"]?.Value<string>(),
137
                Value = obj["value"]?.Value<double?>(),
138
                TotalDays = obj["totalDays"]?.Value<int?>(),
139
                Interval = interval,
140
                Template = ParseVoucher(obj["template"]),
141
                Remark = obj["remark"]?.Value<string>(),
142
                Schedule = schedule?.Select(ParseAmortItem).ToList() ?? new(),
143
            };
144
    }
7✔
145

146
    public async IAsyncEnumerable<string> PresentVouchers(IAsyncEnumerable<Voucher> vouchers)
147
    {
×
148
        yield return "[\n";
×
149

150
        var flag = false;
×
151
        await foreach (var voucher in vouchers)
×
152
        {
×
153
            yield return (flag ? ",\n" : "") + PresentJson(voucher).ToString(Formatting.Indented);
×
154
            flag = true;
×
155
        }
×
156

157
        yield return "\n]";
×
158
    }
×
159

160
    public async IAsyncEnumerable<string> PresentVoucherDetails(IAsyncEnumerable<VoucherDetail> details)
161
    {
×
162
        yield return "[\n";
×
163

164
        var flag = false;
×
165
        await foreach (var detail in details)
×
166
        {
×
167
            yield return (flag ? ",\n" : "") + PresentJson(detail).ToString(Formatting.Indented);
×
168
            flag = true;
×
169
        }
×
170

171
        yield return "\n]";
×
172
    }
×
173

174
    public IAsyncEnumerable<string> PresentVoucherDetails(IAsyncEnumerable<VoucherDetailR> details)
175
        => PresentVoucherDetails(details.Cast<VoucherDetail>());
×
176

177
    public async IAsyncEnumerable<string> PresentAssets(IAsyncEnumerable<Asset> assets)
178
    {
×
179
        yield return "[\n";
×
180

181
        var flag = false;
×
182
        await foreach (var asset in assets)
×
183
        {
×
184
            yield return (flag ? ",\n" : "") + PresentJson(asset).ToString(Formatting.Indented);
×
185
            flag = true;
×
186
        }
×
187

188
        yield return "\n]";
×
189
    }
×
190

191
    public async IAsyncEnumerable<string> PresentAmorts(IAsyncEnumerable<Amortization> amorts)
192
    {
×
193
        yield return "[\n";
×
194

195
        var flag = false;
×
196
        await foreach (var amort in amorts)
×
197
        {
×
198
            yield return (flag ? ",\n" : "") + PresentJson(amort).ToString(Formatting.Indented);
×
199
            flag = true;
×
200
        }
×
201

202
        yield return "\n]";
×
203
    }
×
204

205
    private static JObject ParseJson(string str)
206
    {
24✔
207
        try
208
        {
24✔
209
            return JObject.Parse(str);
24✔
210
        }
211
        catch (JsonReaderException e)
6✔
212
        {
6✔
213
            throw new FormatException("无法识别Json", e);
6✔
214
        }
215
    }
18✔
216

217
    private static Voucher ParseVoucher(JToken obj)
218
    {
14✔
219
        var dateStr = obj["date"]?.Value<string>();
14✔
220
        DateTime? date = null;
14✔
221
        if (dateStr != null)
14✔
222
            date = DateTimeParser.Parse(dateStr);
6✔
223
        var detail = obj["detail"];
14✔
224
        var typeStr = obj["type"]?.Value<string>();
14✔
225
        var type = VoucherType.Ordinary;
14✔
226
        if (typeStr != null)
14✔
227
            Enum.TryParse(typeStr, out type);
14✔
228

229
        return new()
14✔
230
            {
231
                ID = obj["id"]?.Value<string>(),
232
                Date = date,
233
                Remark = obj["remark"]?.Value<string>(),
234
                Type = type,
235
                Details = detail?.Select(ParseVoucherDetail).ToList() ?? new(),
236
            };
237
    }
14✔
238

239
    private static AmortItem ParseAmortItem(JToken obj)
240
    {
14✔
241
        var dateStr = obj["date"]?.Value<string>();
14✔
242
        DateTime? date = null;
14✔
243
        if (dateStr != null)
14✔
244
            date = DateTimeParser.Parse(dateStr);
14✔
245

246
        return new()
14✔
247
            {
248
                Date = date,
249
                VoucherID = obj["voucherId"]?.Value<string>(),
250
                Amount = obj["amount"].Value<double>(),
251
                Remark = obj["remark"]?.Value<string>(),
252
                Value = obj["value"]?.Value<double?>() ?? 0,
253
            };
254
    }
14✔
255

256
    private AssetItem ParseAssetItem(JToken obj)
257
    {
16✔
258
        var dateStr = obj["date"]?.Value<string>();
16✔
259
        DateTime? date = null;
16✔
260
        if (dateStr != null)
16✔
261
            date = DateTimeParser.Parse(dateStr);
16✔
262
        var voucherId = obj["voucherId"]?.Value<string>();
16✔
263
        var value = obj["value"]?.Value<double?>() ?? 0;
16✔
264
        var remark = obj["remark"]?.Value<string>();
16✔
265

266
        return obj["type"]?.Value<string>() switch
×
267
            {
268
                "acquisition" => new AcquisitionItem
4✔
269
                    {
270
                        Date = date,
271
                        VoucherID = voucherId,
272
                        Value = value,
273
                        Remark = remark,
274
                        OrigValue = obj["origValue"].Value<double>(),
275
                    },
276
                "depreciate" => new DepreciateItem
4✔
277
                    {
278
                        Date = date,
279
                        VoucherID = voucherId,
280
                        Value = value,
281
                        Remark = remark,
282
                        Amount = obj["amount"].Value<double>(),
283
                    },
284
                "devalue" => new DevalueItem
4✔
285
                    {
286
                        Date = date,
287
                        VoucherID = voucherId,
288
                        Value = value,
289
                        Remark = remark,
290
                        FairValue = obj["fairValue"].Value<double>(),
291
                        Amount = obj["amount"].Value<double>(),
292
                    },
293
                "disposition" => new DispositionItem
4✔
294
                    {
295
                        Date = date, VoucherID = voucherId, Value = value, Remark = remark,
296
                    },
297
                _ => throw new ArgumentException("类型未知", nameof(obj)),
×
298
            };
299
    }
16✔
300

301
    private static JObject PresentJson(Voucher voucher)
302
        => new()
14✔
303
            {
304
                { "id", voucher.ID },
305
                { "date", voucher.Date?.ToString("yyyy-MM-dd") },
306
                { "remark", voucher.Remark },
307
                { "type", voucher.Type?.ToString() },
308
                { "detail", new JArray(voucher.Details.Select(PresentJson)) },
309
            };
310

311
    private static JObject PresentJson(VoucherDetail detail)
312
        => new()
28✔
313
            {
314
                { "user", detail.User },
315
                { "currency", detail.Currency },
316
                { "title", detail.Title },
317
                { "subtitle", detail.SubTitle },
318
                { "content", detail.Content },
319
                { "remark", detail.Remark },
320
                { "fund", detail.Fund },
321
            };
322

323
    private static VoucherDetail ParseVoucherDetail(JToken obj)
324
        => new()
28✔
325
            {
326
                User = obj["user"]?.Value<string>(),
327
                Currency = obj["currency"]?.Value<string>(),
328
                Title = obj["title"]?.Value<int?>(),
329
                SubTitle = obj["subtitle"]?.Value<int?>(),
330
                Content = obj["content"]?.Value<string>(),
331
                Remark = obj["remark"]?.Value<string>(),
332
                Fund = obj["fund"]?.Value<double?>(),
333
            };
334

335
    private static JObject PresentJson(Asset asset)
336
        => new()
4✔
337
            {
338
                { "id", asset.StringID },
339
                { "name", asset.Name },
340
                { "date", asset.Date?.ToString("yyyy-MM-dd") },
341
                { "user", asset.User },
342
                { "currency", asset.Currency },
343
                { "value", asset.Value },
344
                { "salvage", asset.Salvage },
345
                { "life", asset.Life },
346
                { "title", asset.Title },
347
                { "method", asset.Method?.ToString() },
348
                {
349
                    "depreciation",
350
                    new JObject
351
                        {
352
                            { "title", asset.DepreciationTitle },
353
                            {
354
                                "expense",
355
                                new JObject
356
                                    {
357
                                        { "title", asset.DepreciationExpenseTitle },
358
                                        { "subtitle", asset.DepreciationExpenseSubTitle },
359
                                    }
360
                            },
361
                        }
362
                },
363
                {
364
                    "devaluation",
365
                    new JObject
366
                        {
367
                            { "title", asset.DevaluationTitle },
368
                            {
369
                                "expense",
370
                                new JObject
371
                                    {
372
                                        { "title", asset.DevaluationExpenseTitle },
373
                                        { "subtitle", asset.DevaluationExpenseSubTitle },
374
                                    }
375
                            },
376
                        }
377
                },
378
                { "remark", asset.Remark },
379
                { "schedule", new JArray(asset.Schedule.Select(PresentJson)) },
380
            };
381

382
    private static JObject PresentJson(AssetItem item)
383
    {
16✔
384
        var obj = new JObject
16✔
385
            {
386
                { "date", item.Date?.ToString("yyyy-MM-dd") },
387
                { "voucherId", item.VoucherID },
388
                { "value", item.Value },
389
                { "remark", item.Remark },
390
            };
391

392
        switch (item)
16✔
393
        {
394
            case AcquisitionItem acq:
395
                obj["origValue"] = acq.OrigValue;
4✔
396
                obj["type"] = "acquisition";
4✔
397
                break;
4✔
398
            case DepreciateItem dep:
399
                obj["amount"] = dep.Amount;
4✔
400
                obj["type"] = "depreciate";
4✔
401
                break;
4✔
402
            case DevalueItem dev:
403
                obj["fairValue"] = dev.FairValue;
4✔
404
                obj["amount"] = dev.Amount;
4✔
405
                obj["type"] = "devalue";
4✔
406
                break;
4✔
407
            case DispositionItem:
408
                obj["type"] = "disposition";
4✔
409
                break;
4✔
410
        }
411

412
        return obj;
16✔
413
    }
16✔
414

415
    private static JObject PresentJson(Amortization amort)
416
        => new()
7✔
417
            {
418
                { "id", amort.StringID },
419
                { "name", amort.Name },
420
                { "date", amort.Date?.ToString("yyyy-MM-dd") },
421
                { "user", amort.User },
422
                { "value", amort.Value },
423
                { "totalDays", amort.TotalDays },
424
                { "interval", amort.Interval?.ToString() },
425
                { "template", PresentJson(amort.Template) },
426
                { "remark", amort.Remark },
427
                { "schedule", new JArray(amort.Schedule.Select(PresentJson)) },
428
            };
429

430
    private static JObject PresentJson(AmortItem item)
431
        => new()
14✔
432
            {
433
                { "date", item.Date?.ToString("yyyy-MM-dd") },
434
                { "voucherId", item.VoucherID },
435
                { "amount", item.Amount },
436
                { "value", item.Value },
437
                { "remark", item.Remark },
438
            };
439
}
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