diff --git a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/BootstrapBlazor.BaiduOcr.csproj b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/BootstrapBlazor.BaiduOcr.csproj index 07db3bfed10..533d634b9e0 100644 --- a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/BootstrapBlazor.BaiduOcr.csproj +++ b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/BootstrapBlazor.BaiduOcr.csproj @@ -1,7 +1,7 @@ - 7.0.2 + 7.1.0 diff --git a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceEntity.cs b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceEntity.cs index eea3b286211..946be376b8e 100644 --- a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceEntity.cs +++ b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceEntity.cs @@ -32,12 +32,12 @@ public class InvoiceEntity /// /// 获得/设置 发票代码 /// - public string? InvoiceCode { get; set; } + public string InvoiceCode { get; set; } = string.Empty; /// /// 获得/设置 发票号码 /// - public string? InvoiceNum { get; set; } + public string InvoiceNum { get; set; } = string.Empty; /// /// 获得/设置 增值税发票左上角标志。 包含:通行费,销项负数、代开、收购、成品油、其他 @@ -47,7 +47,7 @@ public class InvoiceEntity /// /// 获得/设置 开票日期 /// - public string? InvoiceDate { get; set; } + public string InvoiceDate { get; set; } = string.Empty; /// /// 获得/设置 机打号码。仅增值税卷票含有此参数 diff --git a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceVerifyResult.cs b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceVerifyResult.cs new file mode 100644 index 00000000000..f08e7f9ad2d --- /dev/null +++ b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Models/InvoiceVerifyResult.cs @@ -0,0 +1,61 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 发票验证真伪结果实体类 +/// +public class InvoiceVerifyResult +{ + /// + /// 获得/设置 机器编号 + /// + public string? MachineCode { get; set; } + + /// + /// 获得/设置 发票号码 + /// + public string? InvoiceNum { get; set; } + + /// + /// 获得/设置 开票日期 + /// + public string? InvoiceDate { get; set; } + + /// + /// 获得/设置 查验结果 查验成功返回 "0001",查验失败返回对应查验结果错误码 + /// + public string? VerifyResult { get; set; } + + /// + /// 获得/设置 是否作废(冲红)。Y:已作废;H:已冲红;N:未作废 + /// + public string? InvalidSign { get; set; } + + /// + /// 获得/设置 发票代码 + /// + public string? InvoiceCode { get; set; } + + /// + /// 获得/设置 发票种类。即增值税专用发票、增值税电子专用发票、增值税普通发票、增值税普通发票(电子)、增值税普通发票(卷式)、通行费增值税电子普通发票、区块链电子发票、全电发票(专用发票)、全电发票(普通发票)、机动车销售发票、二手车销售发票、货物运输业增值税专用发票 + /// + public string? InvoiceType { get; set; } + + /// + /// 获得/设置 校验码 + /// + public string? CheckCode { get; set; } + + /// + /// 获得/设置 查验结果信息。查验成功且发票为真返回 "查验成功发票一致",查验失败返回对应错误原因 + /// + public string? VerifyMessage { get; set; } + + /// + /// 获得/设置 发票实例 + /// + public InvoiceEntity? Invoice { get; set; } +} diff --git a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/BaiduOcr.cs b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/BaiduOcr.cs index 3be6d723f68..6643ac950f9 100644 --- a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/BaiduOcr.cs +++ b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/BaiduOcr.cs @@ -4,6 +4,7 @@ using Baidu.Aip.Ocr; using Microsoft.Extensions.Options; +using Newtonsoft.Json.Linq; namespace BootstrapBlazor.Components; @@ -11,13 +12,17 @@ internal class BaiduOcr : IBaiduOcr { protected IOptionsMonitor Options { get; set; } + protected IHttpClientFactory HttpClientFactory { get; set; } + /// /// 构造函数 /// /// - public BaiduOcr(IOptionsMonitor options) + /// + public BaiduOcr(IOptionsMonitor options, IHttpClientFactory httpClientFactory) { Options = options; + HttpClientFactory = httpClientFactory; } /// @@ -58,4 +63,89 @@ public Task> CheckVatInvoiceAsync(byte[] image, Ca } return ret; }, token); + + /// + /// 获得 Baidu AI AccessToken 方法 + /// + /// + protected async Task GetAccessToken() + { + var client = HttpClientFactory.CreateClient(); + var para = new Dictionary() + { + { "grant_type", "client_credentials" }, + { "client_id", Options.CurrentValue.ApiKey }, + { "client_secret", Options.CurrentValue.Secret } + }; + + var resp = await client.PostAsync("https://aip.baidubce.com/oauth/2.0/token", new FormUrlEncodedContent(para)); + var ret = await resp.Content.ReadAsStringAsync(); + var doc = JObject.Parse(ret); + return doc.Value("access_token") ?? string.Empty; + } + + /// + /// 增值税发票验真方法 + /// + /// 发票代码 + /// 发票号码 + /// 开票日期格式 YYYYMMDD + /// 发票种类 增值税专用发票: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 + /// 校验码 后六位 + /// 发票金额 + /// + /// + public Task> VerifyInvoiceAsync(string invoiceCode, string invoiceNum, string invoiceDate, string invoiceType, string? checkCode, string? totalAmount, CancellationToken token = default) => Task.Run(async () => + { + var token = await GetAccessToken(); + var url = $"https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice_verification?access_token={token}"; + var client = HttpClientFactory.CreateClient(); + + // 拼装参数 + var para = new Dictionary() + { + { "invoice_code", invoiceCode }, + { "invoice_num", invoiceNum }, + { "invoice_date", invoiceDate }, + { "invoice_type", invoiceType }, + }; + + if (!string.IsNullOrEmpty(checkCode)) + { + para["check_code"] = checkCode; + } + if (!string.IsNullOrEmpty(totalAmount)) + { + para["total_amount"] = totalAmount; + } + + // 提交数据 + var resp = await client.PostAsync(url, new FormUrlEncodedContent(para)); + var payload = await resp.Content.ReadAsStringAsync(); + var doc = JObject.Parse(payload); + + var ret = new BaiduOcrResult(); + if (doc.TryGetValue("words_result", out var v)) + { + ret.Entity = new InvoiceVerifyResult() + { + MachineCode = doc.Value("MachineCode"), + InvoiceNum = doc.Value("InvoiceNum"), + InvoiceDate = doc.Value("InvoiceDate"), + VerifyResult = doc.Value("VerifyResult"), + InvalidSign = doc.Value("InvalidSign"), + InvoiceCode = doc.Value("InvoiceCode"), + InvoiceType = doc.Value("InvoiceType"), + CheckCode = doc.Value("CheckCode"), + VerifyMessage = doc.Value("VerifyMessage"), + Invoice = v.ToObject(typeof(InvoiceEntity)) as InvoiceEntity + }; + } + else + { + ret.ErrorCode = doc.Value("error_code"); + ret.ErrorMessage = doc.Value("error_msg"); + } + return ret; + }, token); } diff --git a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/IBaiduOcr.cs b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/IBaiduOcr.cs index 8edc8f7c747..e6b7b0817a1 100644 --- a/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/IBaiduOcr.cs +++ b/src/Extensions/Components/BootstrapBlazor.BaiduOcr/Services/IBaiduOcr.cs @@ -23,4 +23,17 @@ public interface IBaiduOcr /// /// Task CheckVatInvoiceJsonAsync(byte[] image, CancellationToken token = default); + + /// + /// 增值税发票验真方法 + /// + /// 发票代码 + /// 发票号码 + /// 开票日期格式 YYYYMMDD + /// 发票种类 增值税专用发票: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 + /// 校验码 + /// 发票金额 + /// + /// + public Task> VerifyInvoiceAsync(string invoiceCode, string invoiceNum, string invoiceDate, string invoiceType, string? checkCode, string? totalAmount, CancellationToken token = default); }