Skip to content

Commit ca8147d

Browse files
feat: add verify vat invoice component (#342)
Co-authored-by: alex chow <zhouchuanglin@gmail.com>
1 parent c21c7d1 commit ca8147d

5 files changed

Lines changed: 169 additions & 5 deletions

File tree

src/Extensions/Components/BootstrapBlazor.BaiduOcr/BootstrapBlazor.BaiduOcr.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>7.0.2</Version>
4+
<Version>7.1.0</Version>
55
</PropertyGroup>
66

77
<PropertyGroup>

src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceEntity.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ public class InvoiceEntity
3232
/// <summary>
3333
/// 获得/设置 发票代码
3434
/// </summary>
35-
public string? InvoiceCode { get; set; }
35+
public string InvoiceCode { get; set; } = string.Empty;
3636

3737
/// <summary>
3838
/// 获得/设置 发票号码
3939
/// </summary>
40-
public string? InvoiceNum { get; set; }
40+
public string InvoiceNum { get; set; } = string.Empty;
4141

4242
/// <summary>
4343
/// 获得/设置 增值税发票左上角标志。 包含:通行费,销项负数、代开、收购、成品油、其他
@@ -47,7 +47,7 @@ public class InvoiceEntity
4747
/// <summary>
4848
/// 获得/设置 开票日期
4949
/// </summary>
50-
public string? InvoiceDate { get; set; }
50+
public string InvoiceDate { get; set; } = string.Empty;
5151

5252
/// <summary>
5353
/// 获得/设置 机打号码。仅增值税卷票含有此参数
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
namespace BootstrapBlazor.Components;
6+
7+
/// <summary>
8+
/// 发票验证真伪结果实体类
9+
/// </summary>
10+
public class InvoiceVerifyResult
11+
{
12+
/// <summary>
13+
/// 获得/设置 机器编号
14+
/// </summary>
15+
public string? MachineCode { get; set; }
16+
17+
/// <summary>
18+
/// 获得/设置 发票号码
19+
/// </summary>
20+
public string? InvoiceNum { get; set; }
21+
22+
/// <summary>
23+
/// 获得/设置 开票日期
24+
/// </summary>
25+
public string? InvoiceDate { get; set; }
26+
27+
/// <summary>
28+
/// 获得/设置 查验结果 查验成功返回 "0001",查验失败返回对应查验结果错误码
29+
/// </summary>
30+
public string? VerifyResult { get; set; }
31+
32+
/// <summary>
33+
/// 获得/设置 是否作废(冲红)。Y:已作废;H:已冲红;N:未作废
34+
/// </summary>
35+
public string? InvalidSign { get; set; }
36+
37+
/// <summary>
38+
/// 获得/设置 发票代码
39+
/// </summary>
40+
public string? InvoiceCode { get; set; }
41+
42+
/// <summary>
43+
/// 获得/设置 发票种类。即增值税专用发票、增值税电子专用发票、增值税普通发票、增值税普通发票(电子)、增值税普通发票(卷式)、通行费增值税电子普通发票、区块链电子发票、全电发票(专用发票)、全电发票(普通发票)、机动车销售发票、二手车销售发票、货物运输业增值税专用发票
44+
/// </summary>
45+
public string? InvoiceType { get; set; }
46+
47+
/// <summary>
48+
/// 获得/设置 校验码
49+
/// </summary>
50+
public string? CheckCode { get; set; }
51+
52+
/// <summary>
53+
/// 获得/设置 查验结果信息。查验成功且发票为真返回 "查验成功发票一致",查验失败返回对应错误原因
54+
/// </summary>
55+
public string? VerifyMessage { get; set; }
56+
57+
/// <summary>
58+
/// 获得/设置 发票实例
59+
/// </summary>
60+
public InvoiceEntity? Invoice { get; set; }
61+
}

src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/BaiduOcr.cs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,25 @@
44

55
using Baidu.Aip.Ocr;
66
using Microsoft.Extensions.Options;
7+
using Newtonsoft.Json.Linq;
78

89
namespace BootstrapBlazor.Components;
910

1011
internal class BaiduOcr : IBaiduOcr
1112
{
1213
protected IOptionsMonitor<BaiduOcrOption> Options { get; set; }
1314

15+
protected IHttpClientFactory HttpClientFactory { get; set; }
16+
1417
/// <summary>
1518
/// 构造函数
1619
/// </summary>
1720
/// <param name="options"></param>
18-
public BaiduOcr(IOptionsMonitor<BaiduOcrOption> options)
21+
/// <param name="httpClientFactory"></param>
22+
public BaiduOcr(IOptionsMonitor<BaiduOcrOption> options, IHttpClientFactory httpClientFactory)
1923
{
2024
Options = options;
25+
HttpClientFactory = httpClientFactory;
2126
}
2227

2328
/// <summary>
@@ -58,4 +63,89 @@ public Task<BaiduOcrResult<InvoiceEntity>> CheckVatInvoiceAsync(byte[] image, Ca
5863
}
5964
return ret;
6065
}, token);
66+
67+
/// <summary>
68+
/// 获得 Baidu AI AccessToken 方法
69+
/// </summary>
70+
/// <returns></returns>
71+
protected async Task<string> GetAccessToken()
72+
{
73+
var client = HttpClientFactory.CreateClient();
74+
var para = new Dictionary<string, string>()
75+
{
76+
{ "grant_type", "client_credentials" },
77+
{ "client_id", Options.CurrentValue.ApiKey },
78+
{ "client_secret", Options.CurrentValue.Secret }
79+
};
80+
81+
var resp = await client.PostAsync("https://aip.baidubce.com/oauth/2.0/token", new FormUrlEncodedContent(para));
82+
var ret = await resp.Content.ReadAsStringAsync();
83+
var doc = JObject.Parse(ret);
84+
return doc.Value<string>("access_token") ?? string.Empty;
85+
}
86+
87+
/// <summary>
88+
/// 增值税发票验真方法
89+
/// </summary>
90+
/// <param name="invoiceCode">发票代码</param>
91+
/// <param name="invoiceNum">发票号码</param>
92+
/// <param name="invoiceDate">开票日期格式 YYYYMMDD</param>
93+
/// <param name="invoiceType">发票种类 增值税专用发票:special_vat_invoice 增值税电子专用发票:elec_special_vat_invoice 增值税普通发票:normal_invoice 增值税普通发票(电子):elec_normal_invoice 增值税普通发票(卷式):roll_normal_invoice 通行费增值税电子普通发票:toll_elec_normal_invoice 区块链电子发票(目前仅支持深圳地区):blockchain_invoice 全电发票(专用发票):elec_invoice_special 全电发票(普通发票):elec_invoice_normal 货运运输业增值税专用发票:special_freight_transport_invoice 机动车销售发票:motor_vehicle_invoice 二手车销售发票:used_vehicle_invoice</param>
94+
/// <param name="checkCode">校验码 后六位</param>
95+
/// <param name="totalAmount">发票金额</param>
96+
/// <param name="token"></param>
97+
/// <returns></returns>
98+
public Task<BaiduOcrResult<InvoiceVerifyResult>> VerifyInvoiceAsync(string invoiceCode, string invoiceNum, string invoiceDate, string invoiceType, string? checkCode, string? totalAmount, CancellationToken token = default) => Task.Run(async () =>
99+
{
100+
var token = await GetAccessToken();
101+
var url = $"https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice_verification?access_token={token}";
102+
var client = HttpClientFactory.CreateClient();
103+
104+
// 拼装参数
105+
var para = new Dictionary<string, string>()
106+
{
107+
{ "invoice_code", invoiceCode },
108+
{ "invoice_num", invoiceNum },
109+
{ "invoice_date", invoiceDate },
110+
{ "invoice_type", invoiceType },
111+
};
112+
113+
if (!string.IsNullOrEmpty(checkCode))
114+
{
115+
para["check_code"] = checkCode;
116+
}
117+
if (!string.IsNullOrEmpty(totalAmount))
118+
{
119+
para["total_amount"] = totalAmount;
120+
}
121+
122+
// 提交数据
123+
var resp = await client.PostAsync(url, new FormUrlEncodedContent(para));
124+
var payload = await resp.Content.ReadAsStringAsync();
125+
var doc = JObject.Parse(payload);
126+
127+
var ret = new BaiduOcrResult<InvoiceVerifyResult>();
128+
if (doc.TryGetValue("words_result", out var v))
129+
{
130+
ret.Entity = new InvoiceVerifyResult()
131+
{
132+
MachineCode = doc.Value<string>("MachineCode"),
133+
InvoiceNum = doc.Value<string>("InvoiceNum"),
134+
InvoiceDate = doc.Value<string>("InvoiceDate"),
135+
VerifyResult = doc.Value<string>("VerifyResult"),
136+
InvalidSign = doc.Value<string>("InvalidSign"),
137+
InvoiceCode = doc.Value<string>("InvoiceCode"),
138+
InvoiceType = doc.Value<string>("InvoiceType"),
139+
CheckCode = doc.Value<string>("CheckCode"),
140+
VerifyMessage = doc.Value<string>("VerifyMessage"),
141+
Invoice = v.ToObject(typeof(InvoiceEntity)) as InvoiceEntity
142+
};
143+
}
144+
else
145+
{
146+
ret.ErrorCode = doc.Value<int>("error_code");
147+
ret.ErrorMessage = doc.Value<string>("error_msg");
148+
}
149+
return ret;
150+
}, token);
61151
}

src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/IBaiduOcr.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,17 @@ public interface IBaiduOcr
2323
/// <param name="token"></param>
2424
/// <returns></returns>
2525
Task<string> CheckVatInvoiceJsonAsync(byte[] image, CancellationToken token = default);
26+
27+
/// <summary>
28+
/// 增值税发票验真方法
29+
/// </summary>
30+
/// <param name="invoiceCode">发票代码</param>
31+
/// <param name="invoiceNum">发票号码</param>
32+
/// <param name="invoiceDate">开票日期格式 YYYYMMDD</param>
33+
/// <param name="invoiceType">发票种类 增值税专用发票:special_vat_invoice 增值税电子专用发票:elec_special_vat_invoice 增值税普通发票:normal_invoice 增值税普通发票(电子):elec_normal_invoice 增值税普通发票(卷式):roll_normal_invoice 通行费增值税电子普通发票:toll_elec_normal_invoice 区块链电子发票(目前仅支持深圳地区):blockchain_invoice 全电发票(专用发票):elec_invoice_special 全电发票(普通发票):elec_invoice_normal 货运运输业增值税专用发票:special_freight_transport_invoice 机动车销售发票:motor_vehicle_invoice 二手车销售发票:used_vehicle_invoice</param>
34+
/// <param name="checkCode">校验码</param>
35+
/// <param name="totalAmount">发票金额</param>
36+
/// <param name="token"></param>
37+
/// <returns></returns>
38+
public Task<BaiduOcrResult<InvoiceVerifyResult>> VerifyInvoiceAsync(string invoiceCode, string invoiceNum, string invoiceDate, string invoiceType, string? checkCode, string? totalAmount, CancellationToken token = default);
2639
}

0 commit comments

Comments
 (0)