Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>7.0.2</Version>
<Version>7.1.0</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ public class InvoiceEntity
/// <summary>
/// 获得/设置 发票代码
/// </summary>
public string? InvoiceCode { get; set; }
public string InvoiceCode { get; set; } = string.Empty;

/// <summary>
/// 获得/设置 发票号码
/// </summary>
public string? InvoiceNum { get; set; }
public string InvoiceNum { get; set; } = string.Empty;

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

/// <summary>
/// 获得/设置 机打号码。仅增值税卷票含有此参数
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// 发票验证真伪结果实体类
/// </summary>
public class InvoiceVerifyResult
{
/// <summary>
/// 获得/设置 机器编号
/// </summary>
public string? MachineCode { get; set; }

/// <summary>
/// 获得/设置 发票号码
/// </summary>
public string? InvoiceNum { get; set; }

/// <summary>
/// 获得/设置 开票日期
/// </summary>
public string? InvoiceDate { get; set; }

/// <summary>
/// 获得/设置 查验结果 查验成功返回 "0001",查验失败返回对应查验结果错误码
/// </summary>
public string? VerifyResult { get; set; }

/// <summary>
/// 获得/设置 是否作废(冲红)。Y:已作废;H:已冲红;N:未作废
/// </summary>
public string? InvalidSign { get; set; }

/// <summary>
/// 获得/设置 发票代码
/// </summary>
public string? InvoiceCode { get; set; }

/// <summary>
/// 获得/设置 发票种类。即增值税专用发票、增值税电子专用发票、增值税普通发票、增值税普通发票(电子)、增值税普通发票(卷式)、通行费增值税电子普通发票、区块链电子发票、全电发票(专用发票)、全电发票(普通发票)、机动车销售发票、二手车销售发票、货物运输业增值税专用发票
/// </summary>
public string? InvoiceType { get; set; }

/// <summary>
/// 获得/设置 校验码
/// </summary>
public string? CheckCode { get; set; }

/// <summary>
/// 获得/设置 查验结果信息。查验成功且发票为真返回 "查验成功发票一致",查验失败返回对应错误原因
/// </summary>
public string? VerifyMessage { get; set; }

/// <summary>
/// 获得/设置 发票实例
/// </summary>
public InvoiceEntity? Invoice { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@

using Baidu.Aip.Ocr;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;

namespace BootstrapBlazor.Components;

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

protected IHttpClientFactory HttpClientFactory { get; set; }

/// <summary>
/// 构造函数
/// </summary>
/// <param name="options"></param>
public BaiduOcr(IOptionsMonitor<BaiduOcrOption> options)
/// <param name="httpClientFactory"></param>
public BaiduOcr(IOptionsMonitor<BaiduOcrOption> options, IHttpClientFactory httpClientFactory)
{
Options = options;
HttpClientFactory = httpClientFactory;
}

/// <summary>
Expand Down Expand Up @@ -58,4 +63,89 @@ public Task<BaiduOcrResult<InvoiceEntity>> CheckVatInvoiceAsync(byte[] image, Ca
}
return ret;
}, token);

/// <summary>
/// 获得 Baidu AI AccessToken 方法
/// </summary>
/// <returns></returns>
protected async Task<string> GetAccessToken()
{
var client = HttpClientFactory.CreateClient();
var para = new Dictionary<string, string>()
{
{ "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<string>("access_token") ?? string.Empty;
}

/// <summary>
/// 增值税发票验真方法
/// </summary>
/// <param name="invoiceCode">发票代码</param>
/// <param name="invoiceNum">发票号码</param>
/// <param name="invoiceDate">开票日期格式 YYYYMMDD</param>
/// <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>
/// <param name="checkCode">校验码 后六位</param>
/// <param name="totalAmount">发票金额</param>
/// <param name="token"></param>
/// <returns></returns>
public Task<BaiduOcrResult<InvoiceVerifyResult>> 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<string, string>()
{
{ "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<InvoiceVerifyResult>();
if (doc.TryGetValue("words_result", out var v))
{
ret.Entity = new InvoiceVerifyResult()
{
MachineCode = doc.Value<string>("MachineCode"),
InvoiceNum = doc.Value<string>("InvoiceNum"),
InvoiceDate = doc.Value<string>("InvoiceDate"),
VerifyResult = doc.Value<string>("VerifyResult"),
InvalidSign = doc.Value<string>("InvalidSign"),
InvoiceCode = doc.Value<string>("InvoiceCode"),
InvoiceType = doc.Value<string>("InvoiceType"),
CheckCode = doc.Value<string>("CheckCode"),
VerifyMessage = doc.Value<string>("VerifyMessage"),
Invoice = v.ToObject(typeof(InvoiceEntity)) as InvoiceEntity
};
}
else
{
ret.ErrorCode = doc.Value<int>("error_code");
ret.ErrorMessage = doc.Value<string>("error_msg");
}
return ret;
}, token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,17 @@ public interface IBaiduOcr
/// <param name="token"></param>
/// <returns></returns>
Task<string> CheckVatInvoiceJsonAsync(byte[] image, CancellationToken token = default);

/// <summary>
/// 增值税发票验真方法
/// </summary>
/// <param name="invoiceCode">发票代码</param>
/// <param name="invoiceNum">发票号码</param>
/// <param name="invoiceDate">开票日期格式 YYYYMMDD</param>
/// <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>
/// <param name="checkCode">校验码</param>
/// <param name="totalAmount">发票金额</param>
/// <param name="token"></param>
/// <returns></returns>
public Task<BaiduOcrResult<InvoiceVerifyResult>> VerifyInvoiceAsync(string invoiceCode, string invoiceNum, string invoiceDate, string invoiceType, string? checkCode, string? totalAmount, CancellationToken token = default);
}