feat(tenpayv3): 新增区块链电子发票相关接口

This commit is contained in:
Fu Diwei
2023-04-03 15:19:48 +08:00
parent 6e1aeb0798
commit 2f6216e609
52 changed files with 2636 additions and 6 deletions

View File

@@ -0,0 +1,12 @@
{
"mchid": "1900000109",
"fapiao_apply_id": "4200000444201910177461284488",
"apply_time": "2020-07-01T12:00:00+08:00",
"fapiao_information": [
{
"fapiao_id": "20200701123456",
"fapiao_status": "ISSUED",
"card_status": "INSERTED"
}
]
}

View File

@@ -0,0 +1,14 @@
{
"card_appid": "wxb1170446a4c0a5a2",
"card_template_information": {
"payee_name": "某公司",
"logo_url": "http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0",
"custom_cell": {
"words": "电子发票",
"description": "查看发票",
"jump_url": "http://www.qq.com",
"miniprogram_user_name": "gh_86a091e50ad4@app",
"miniprogram_path": "pages/xxxPage"
}
}
}

View File

@@ -0,0 +1,4 @@
{
"card_appid": "wxb1170446a4c0a5a2",
"card_id": "p4gLgvn_cxVCQez17kaBJnZHPcXs"
}

View File

@@ -0,0 +1,57 @@
{
"scene": "WITH_WECHATPAY",
"buyer_information": {
"type": "ORGANIZATION",
"name": "深圳市南山区测试企业",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890",
"phone": "18507550000",
"email": "123110@qq.com"
},
"fapiao_card_information": [
{
"fapiao_media_id": "ASNFZ4mrze/+3LqYdlQyEA==",
"fapiao_number": "12897794",
"fapiao_code": "044001911211",
"fapiao_time": "2020-07-01T12:00:00+08:00",
"check_code": "69001808340631374774",
"password": "006>299-375/326>2+7/*0-+<351059<80<4*/5>+<11631+*3030/5*37+/-243159658+013>3409*044>4-/1+/9->*>69501*6++1997--21",
"total_amount": 382895,
"tax_amount": 44050,
"amount": 338845,
"seller_information": {
"name": "深圳市南山区测试公司",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890"
},
"extra_information": {
"payee": "张三",
"reviewer": "李四",
"drawer": "王五"
},
"items": [
{
"tax_code": "3010101020203000000",
"goods_name": "出租汽车客运服务",
"specification": "A4",
"unit": "次",
"quantity": 100000000,
"unit_price": 380442000000,
"amount": 380442,
"tax_amount": 49458,
"total_amount": 429900,
"tax_rate": 1300,
"tax_prefer_mark": "NO_FAVORABLE",
"discount": false
}
],
"remark": "备注"
}
]
}

View File

@@ -0,0 +1,37 @@
{
"scene": "WITH_WECHATPAY",
"fapiao_apply_id": "4200000444201910177461284488",
"buyer_information": {
"type": "ORGANIZATION",
"name": "深圳市南山区测试企业",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890",
"phone": "18507550000",
"email": "123110@qq.com"
},
"fapiao_information": [
{
"fapiao_id": "20200701123456",
"total_amount": 382895,
"need_list": false,
"remark": "备注",
"items": [
{
"tax_code": "3010101020203000000",
"goods_category": "运输服务",
"goods_name": "出租汽车客运服务",
"specification": "A4",
"unit": "次",
"quantity": 100000000,
"total_amount": 429900,
"tax_rate": 1300,
"tax_prefer_mark": "NO_FAVORABLE",
"discount": false
}
]
}
]
}

View File

@@ -0,0 +1,74 @@
{
"total_count": 5,
"fapiao_information": [
{
"fapiao_id": "20200701123456",
"status": "ISSUED",
"blue_fapiao": {
"fapiao_code": "044001911211",
"fapiao_number": "12897794",
"check_code": "69001808340631374774",
"password": "006>299-375/326>2+7/*0-+<351059<80<4*/5>+<11631+*3030/5*37+/-243159658+013>3409*044>4-/1+/9->*>69501*6+21997--21",
"fapiao_time": "2020-07-01T12:00:00+08:00"
},
"red_fapiao": {
"fapiao_code": "044001911211",
"fapiao_number": "12897794",
"check_code": "69001808340631374774",
"password": "006>299-375/326>2+7/*0-+<351059<80<4*/5>+<11631+*3030/5*37+/-243159658+013>3409*044>4-/1+/9->*>69501*6+21997--21",
"fapiao_time": "2020-07-01T12:00:00+08:00"
},
"card_information": {
"card_appid": "wxab8acb865bb1637e",
"card_openid": "plN5twRbHym_j-QcqCzstl0HmwEs",
"card_id": "p4gLgvlAYSEOpeXGFVJRFxgop6iY",
"card_code": "379550244162",
"card_status": "INSERT_ACCEPTED"
},
"total_amount": 382895,
"tax_amount": 44050,
"amount": 338845,
"seller_information": {
"name": "深圳市南山区测试公司",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890"
},
"buyer_information": {
"type": "ORGANIZATION",
"name": "深圳市南山区测试企业",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890",
"phone": "pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPttdY+aQ6zB",
"email": "pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPttdY+aQ6za"
},
"extra_information": {
"payee": "张三",
"reviewer": "李四",
"drawer": "王五"
},
"items": [
{
"tax_code": "3010101020203000000",
"goods_name": "出租汽车客运服务",
"specification": "A4",
"unit": "次",
"quantity": 100000000,
"unit_price": 380442000000,
"amount": 380442,
"tax_amount": 49458,
"total_amount": 429900,
"tax_rate": 1300,
"tax_prefer_mark": "NO_FAVORABLE",
"discount": false
}
],
"remark": "备注"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"fapiao_download_info_list": [
{
"download_url": "https://pay.wechatpay.cn/invoicing/fapiao/fapiao-file",
"fapiao_id": "20200701123456",
"status": "ISSUED"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"seller_information": {
"name": "深圳市南山区测试公司",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890"
},
"extra_information": {
"payee": "张三",
"reviewer": "李四",
"drawer": "王五"
}
}

View File

@@ -0,0 +1,10 @@
{
"reverse_reason": "退款",
"fapiao_information": [
{
"fapiao_id": "20200701123456",
"fapiao_code": "044001911211",
"fapiao_number": "12897794"
}
]
}

View File

@@ -0,0 +1,5 @@
{
"digest": "addca90a6a290b9642dbaccffdf01e8c22aa348940b2e96754169ba08c19e5db",
"digest_alogrithm": "SM3",
"file_type": "PDF"
}

View File

@@ -0,0 +1,13 @@
{
"offset": "0",
"limit": 5,
"data": [
{
"tax_code": "3010101020203000000",
"goods_name": "出租汽车客运服务",
"tax_rate": 1300,
"tax_prefer_mark": "NO_FAVORABLE"
}
],
"total_count": 20
}

View File

@@ -0,0 +1,11 @@
{
"type": "ORGANIZATION",
"name": "深圳市南山区测试企业",
"taxpayer_id": "202003261233701778",
"address": "深圳市南山区深南大道10000号",
"telephone": "075512345678",
"bank_name": "测试银行",
"bank_account": "62001234567890",
"phone": "18507550000",
"email": "123110@qq.com"
}

View File

@@ -0,0 +1,5 @@
{
"miniprogram_appid": "wxb1170446a4c0a5a2",
"miniprogram_path": "pages/xxxPage",
"miniprogram_user_name": "gh_86a091e50ad4@app"
}

View File

@@ -647,6 +647,88 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
AssertMockRequestModel(reqB2, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, cipher));
}
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /new-tax-control-fapiao/fapiao-applications")]
public async Task TestEncryptRequestSensitiveProperty_CreateNewTaxControlFapiaoApplicationRequest()
{
static Models.CreateNewTaxControlFapiaoApplicationRequest GenerateMockRequestModel()
{
return new Models.CreateNewTaxControlFapiaoApplicationRequest()
{
Buyer = new Models.CreateNewTaxControlFapiaoApplicationRequest.Types.Buyer()
{
UserMobileNumber = MOCK_PLAIN_STR,
UserEmail = MOCK_PLAIN_STR
}
};
}
static void AssertMockRequestModel(Models.CreateNewTaxControlFapiaoApplicationRequest request, Func<string, string> decryptor)
{
Assert.NotEqual(MOCK_PLAIN_STR, request.Buyer!.UserMobileNumber!);
Assert.NotEqual(MOCK_PLAIN_STR, request.Buyer!.UserEmail!);
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserMobileNumber!));
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserEmail!));
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
}
var reqA1 = GenerateMockRequestModel();
CreateMockClientUseRSA(autoEncrypt: false).EncryptRequestSensitiveProperty(reqA1);
AssertMockRequestModel(reqA1, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, cipher));
var reqA2 = GenerateMockRequestModel();
CreateMockClientUseSM2(autoEncrypt: false).EncryptRequestSensitiveProperty(reqA2);
AssertMockRequestModel(reqA2, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, cipher));
var reqB1 = GenerateMockRequestModel();
await CreateMockClientUseRSA(autoEncrypt: true).ExecuteCreateNewTaxControlFapiaoApplicationAsync(reqB1);
AssertMockRequestModel(reqB1, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, cipher));
var reqB2 = GenerateMockRequestModel();
await CreateMockClientUseSM2(autoEncrypt: true).ExecuteCreateNewTaxControlFapiaoApplicationAsync(reqB2);
AssertMockRequestModel(reqB2, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, cipher));
}
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}/insert-cards")]
public async Task TestEncryptRequestSensitiveProperty_CreateNewTaxControlFapiaoApplicationCardRequest()
{
static Models.CreateNewTaxControlFapiaoApplicationCardRequest GenerateMockRequestModel()
{
return new Models.CreateNewTaxControlFapiaoApplicationCardRequest()
{
Buyer = new Models.CreateNewTaxControlFapiaoApplicationCardRequest.Types.Buyer()
{
UserMobileNumber = MOCK_PLAIN_STR,
UserEmail = MOCK_PLAIN_STR
}
};
}
static void AssertMockRequestModel(Models.CreateNewTaxControlFapiaoApplicationCardRequest request, Func<string, string> decryptor)
{
Assert.NotEqual(MOCK_PLAIN_STR, request.Buyer!.UserMobileNumber!);
Assert.NotEqual(MOCK_PLAIN_STR, request.Buyer!.UserEmail!);
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserMobileNumber!));
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserEmail!));
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
}
var reqA1 = GenerateMockRequestModel();
CreateMockClientUseRSA(autoEncrypt: false).EncryptRequestSensitiveProperty(reqA1);
AssertMockRequestModel(reqA1, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, cipher));
var reqA2 = GenerateMockRequestModel();
CreateMockClientUseSM2(autoEncrypt: false).EncryptRequestSensitiveProperty(reqA2);
AssertMockRequestModel(reqA2, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, cipher));
var reqB1 = GenerateMockRequestModel();
await CreateMockClientUseRSA(autoEncrypt: true).ExecuteCreateNewTaxControlFapiaoApplicationCardAsync(reqB1);
AssertMockRequestModel(reqB1, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, cipher));
var reqB2 = GenerateMockRequestModel();
await CreateMockClientUseSM2(autoEncrypt: true).ExecuteCreateNewTaxControlFapiaoApplicationCardAsync(reqB2);
AssertMockRequestModel(reqB2, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, cipher));
}
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /payroll-card/authentications/pre-order-with-auth")]
public async Task TestEncryptRequestSensitiveProperty_PreOrderWithAuthPayrollCardAuthenticationRequest()
{

View File

@@ -380,6 +380,103 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
AssertMockResponseModel(resB2);
}
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}")]
public async Task TestDecryptResponseSensitiveProperty_GetNewTaxControlFapiaoApplicationByFapiaoApplyId()
{
static Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdResponse GenerateMockResponseModel(Func<string, string> encryptor)
{
return new Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdResponse()
{
RawStatus = (int)HttpStatusCode.OK,
FapiaoList = new Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdResponse.Types.Fapiao[]
{
new Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdResponse.Types.Fapiao()
{
Buyer = new Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdResponse.Types.Fapiao.Types.Buyer()
{
UserMobileNumber = encryptor.Invoke(MOCK_PLAIN_STR),
UserEmail = encryptor.Invoke(MOCK_PLAIN_STR)
}
}
}
};
}
static void AssertMockResponseModel(Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdResponse response)
{
Assert.Equal(MOCK_PLAIN_STR, response.FapiaoList[0]!.Buyer!.UserMobileNumber!);
Assert.Equal(MOCK_PLAIN_STR, response.FapiaoList[0]!.Buyer!.UserEmail!);
}
var resA1 = GenerateMockResponseModel((plain) => Utilities.RSAUtility.EncryptWithECBByCertificate(RSA_PEM_CERTIFICATE, plain));
CreateMockClientUseRSA(autoDecrypt: false).DecryptResponseSensitiveProperty(resA1);
AssertMockResponseModel(resA1);
var resA2 = GenerateMockResponseModel((plain) => Utilities.SM2Utility.EncryptByCertificate(SM2_PEM_CERTIFICATE, plain));
CreateMockClientUseSM2(autoDecrypt: false).DecryptResponseSensitiveProperty(resA2);
AssertMockResponseModel(resA2);
var resB1 = await CreateMockClientUseRSA(
autoDecrypt: true,
mockResponseContent: new FlurlSystemTextJsonSerializer().Serialize(
GenerateMockResponseModel((plain) => Utilities.RSAUtility.EncryptWithECBByCertificate(RSA_PEM_CERTIFICATE, plain))
)
).ExecuteGetNewTaxControlFapiaoApplicationByFapiaoApplyIdAsync(new Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdRequest());
AssertMockResponseModel(resB1);
var resB2 = await CreateMockClientUseSM2(
autoDecrypt: true,
mockResponseContent: new FlurlSystemTextJsonSerializer().Serialize(
GenerateMockResponseModel((plain) => Utilities.SM2Utility.EncryptByCertificate(SM2_PEM_CERTIFICATE, plain))
)
).ExecuteGetNewTaxControlFapiaoApplicationByFapiaoApplyIdAsync(new Models.GetNewTaxControlFapiaoApplicationByFapiaoApplyIdRequest());
AssertMockResponseModel(resB2);
}
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /new-tax-control-fapiao/user-title")]
public async Task TestDecryptResponseSensitiveProperty_GetNewTaxControlFapiaoUserTitle()
{
static Models.GetNewTaxControlFapiaoUserTitleResponse GenerateMockResponseModel(Func<string, string> encryptor)
{
return new Models.GetNewTaxControlFapiaoUserTitleResponse()
{
RawStatus = (int)HttpStatusCode.OK,
UserMobileNumber = encryptor.Invoke(MOCK_PLAIN_STR),
UserEmail = encryptor.Invoke(MOCK_PLAIN_STR)
};
}
static void AssertMockResponseModel(Models.GetNewTaxControlFapiaoUserTitleResponse response)
{
Assert.Equal(MOCK_PLAIN_STR, response.UserMobileNumber!);
Assert.Equal(MOCK_PLAIN_STR, response.UserEmail!);
}
var resA1 = GenerateMockResponseModel((plain) => Utilities.RSAUtility.EncryptWithECBByCertificate(RSA_PEM_CERTIFICATE, plain));
CreateMockClientUseRSA(autoDecrypt: false).DecryptResponseSensitiveProperty(resA1);
AssertMockResponseModel(resA1);
var resA2 = GenerateMockResponseModel((plain) => Utilities.SM2Utility.EncryptByCertificate(SM2_PEM_CERTIFICATE, plain));
CreateMockClientUseSM2(autoDecrypt: false).DecryptResponseSensitiveProperty(resA2);
AssertMockResponseModel(resA2);
var resB1 = await CreateMockClientUseRSA(
autoDecrypt: true,
mockResponseContent: new FlurlSystemTextJsonSerializer().Serialize(
GenerateMockResponseModel((plain) => Utilities.RSAUtility.EncryptWithECBByCertificate(RSA_PEM_CERTIFICATE, plain))
)
).ExecuteGetNewTaxControlFapiaoUserTitleAsync(new Models.GetNewTaxControlFapiaoUserTitleRequest());
AssertMockResponseModel(resB1);
var resB2 = await CreateMockClientUseSM2(
autoDecrypt: true,
mockResponseContent: new FlurlSystemTextJsonSerializer().Serialize(
GenerateMockResponseModel((plain) => Utilities.SM2Utility.EncryptByCertificate(SM2_PEM_CERTIFICATE, plain))
)
).ExecuteGetNewTaxControlFapiaoUserTitleAsync(new Models.GetNewTaxControlFapiaoUserTitleRequest());
AssertMockResponseModel(resB2);
}
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}")]
public async Task TestDecryptResponseSensitiveProperty_GetPartnerTransferBatchDetailByDetailIdResponse()
{